DDR3 support for AMD Fam10.
authorZheng Bao <zheng.bao@amd.com>
Fri, 23 Apr 2010 17:32:48 +0000 (17:32 +0000)
committerStefan Reinauer <stepan@openbios.org>
Fri, 23 Apr 2010 17:32:48 +0000 (17:32 +0000)
Signed-off-by: Zheng Bao <zheng.bao@amd.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5481 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

31 files changed:
src/northbridge/amd/amdfam10/amdfam10.h
src/northbridge/amd/amdfam10/raminit_amdmct.c
src/northbridge/amd/amdmct/amddefs.h
src/northbridge/amd/amdmct/mct_ddr3/mct_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mct_d.h [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctprob.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctproc.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctrci.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mctwl.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mport_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c [new file with mode: 0644]
src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h [new file with mode: 0644]
src/northbridge/amd/amdmct/wrappers/mcti_d.c

index 81dec8858d2cffd844958af551fcad4a9222473b..49046fb5317c2e305f153dffc2365bc5a09bf45c 100644 (file)
@@ -996,7 +996,11 @@ struct mem_info { // pernode
        u8 rsv[1];
 } __attribute__((packed));
 #else
-#include "../amdmct/mct/mct_d.h"
+ #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+  #include "../amdmct/mct_ddr3/mct_d.h"
+ #else
+  #include "../amdmct/mct/mct_d.h"
+ #endif
 #endif
 
 struct link_pair_t {
index 0a298727b77c18c0be4577f6e86b27fbbf6adb8f..09bdd704370c51eed5c0a7eb0c42516ca88fb3e3 100644 (file)
@@ -30,6 +30,54 @@ static  void print_t(const char *strval)
        printk(BIOS_DEBUG, "%s", strval);
 #endif
 }
+
+#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+#include "amdfam10.h"
+#include "../amdmct/wrappers/mcti.h"
+#include "../amdmct/amddefs.h"
+#include "../amdmct/mct_ddr3/mwlc_d.h"
+#include "../amdmct/mct_ddr3/mct_d.h"
+#include "../amdmct/mct_ddr3/mct_d_gcc.h"
+
+#include "../amdmct/wrappers/mcti_d.c"
+#include "../amdmct/mct_ddr3/mct_d.c"
+
+#include "../amdmct/mct_ddr3/mctmtr_d.c"
+#include "../amdmct/mct_ddr3/mctcsi_d.c"
+#include "../amdmct/mct_ddr3/mctecc_d.c"
+#include "../amdmct/mct_ddr3/mctdqs_d.c"
+#include "../amdmct/mct_ddr3/mctsrc.c"
+#include "../amdmct/mct_ddr3/mctsdi.c"
+#include "../amdmct/mct_ddr3/mctproc.c"
+#include "../amdmct/mct_ddr3/mctprob.c"
+#include "../amdmct/mct_ddr3/mcthwl.c"
+#include "../amdmct/mct_ddr3/mctwl.c"
+#include "../amdmct/mct_ddr3/mport_d.c"
+#include "../amdmct/mct_ddr3/mutilc_d.c"
+#include "../amdmct/mct_ddr3/modtrdim.c"
+#include "../amdmct/mct_ddr3/mhwlc_d.c"
+#include "../amdmct/mct_ddr3/mctrci.c"
+#include "../amdmct/mct_ddr3/mctsrc1p.c"
+#include "../amdmct/mct_ddr3/mcttmrl.c"
+#include "../amdmct/mct_ddr3/mcthdi.c"
+#include "../amdmct/mct_ddr3/mctndi_d.c"
+#include "../amdmct/mct_ddr3/mctchi_d.c"
+
+#if CONFIG_CPU_SOCKET_TYPE == 0x10
+//TODO: S1G1?
+#elif CONFIG_CPU_SOCKET_TYPE == 0x11
+//AM3
+#include "../amdmct/mct_ddr3/mctardk5.c"
+#elif CONFIG_CPU_SOCKET_TYPE == 0x12
+//F (1207), Fr2, G (1207)
+#include "../amdmct/mct_ddr3/mctardk6.c"
+#elif CONFIG_CPU_SOCKET_TYPE == 0x13
+//ASB2
+#include "../amdmct/mct_ddr3/mctardk5.c"
+#endif
+
+#else  /* DDR2 */
+
 #include "amdfam10.h"
 #include "../amdmct/wrappers/mcti.h"
 #include "../amdmct/amddefs.h"
@@ -65,6 +113,8 @@ static  void print_t(const char *strval)
 
 #include "../amdmct/mct/mct_fd.c"
 
+#endif /* DDR2 */
+
 int mctRead_SPD(u32 smaddr, u32 reg)
 {
        return spd_read_byte(smaddr, reg);
@@ -141,9 +191,15 @@ u32 mctGetLogicalCPUID(u32 Node)
        case 0x10042:
                ret = AMD_RB_C2;
                break;
+       case 0x10043:
+               ret = AMD_RB_C3;
+               break;
        case 0x10062:
                ret = AMD_DA_C2;
                break;
+       case 0x10063:
+               ret = AMD_DA_C3;
+               break;
        case 0x10080:
                ret = AMD_HY_D0;
                break;
index 1b75888b123c6af7c95ce9321cafcef59ff48f1b..452de331b1fe90f108040a1b48866eb29338ae37 100644 (file)
@@ -43,6 +43,8 @@
 #define        AMD_RB_C2       0x01000000      /* Shanghai C2 */
 #define        AMD_DA_C2       0x02000000      /* XXXX C2 */
 #define        AMD_HY_D0       0x04000000      /* Istanbul D0 */
+#define        AMD_RB_C3       0x08000000      /* ??? C3 */
+#define        AMD_DA_C3       0x10000000      /* XXXX C3 */
 
 /*
  * Groups - Create as many as you wish, from the above public values
 #define        AMD_DR_LT_B3    (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_BA)
 #define        AMD_DR_GT_B0    (AMD_DR_ALL & ~(AMD_DR_B0))
 #define        AMD_DR_ALL      (AMD_DR_Bx)
-#define        AMD_FAM10_ALL   (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0)
+#define        AMD_FAM10_ALL   (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | AMD_DA_C3 | AMD_DA_C2)
 #define        AMD_FAM10_GT_B0 (AMD_FAM10_ALL & ~(AMD_DR_B0))
+#define AMD_DR_Cx       (AMD_RB_C2 | AMD_DA_C2 | AMD_RB_C3 | AMD_DA_C3)
+#define AMD_DR_Dx       (AMD_HY_D0)
+
 
 /*
  *  Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH CPUPLATFORMTYPE RETURN VALUE
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
new file mode 100644 (file)
index 0000000..453a8ba
--- /dev/null
@@ -0,0 +1,3725 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Description: Main memory controller system configuration for DDR 3 */
+
+/* KNOWN ISSUES - ERRATA
+ *
+ * Trtp is not calculated correctly when the controller is in 64-bit mode, it
+ * is 1 busclock off.  No fix planned.  The controller is not ordinarily in
+ * 64-bit mode.
+ *
+ * 32 Byte burst not supported. No fix planned. The controller is not
+ * ordinarily in 64-bit mode.
+ *
+ * Trc precision does not use extra Jedec defined fractional component.
+ * InsteadTrc (course) is rounded up to nearest 1 ns.
+ *
+ * Mini and Micro DIMM not supported. Only RDIMM, UDIMM, SO-DIMM defined types
+ * supported.
+ */
+
+static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA);
+static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA);
+static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static u8 NodePresent_D(u8 Node);
+static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void GetPresetmaxF_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static u16 Get_Fk_D(u8 k);
+static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i);
+static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void mct_DramInit(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_SyncDCTsReady(struct DCTStatStruc *pDCTstat);
+static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_AfterGetCLT(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat,\
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 mct_DIMMPresence(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void Set_OtherTiming(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_Twrwr(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_Twrrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat);
+static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
+                                       u32 dev, u32 index_reg);
+static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat, u8 dct,
+                                       u32 dev, u32 index_reg);
+static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
+                               u32 dev, u32 index_reg, u32 index);
+static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat, u8 dct,
+                               u32 dev, u32 index_reg, u32 index);
+static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void mct_init(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat);
+static void clear_legacy_Mode(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static void SetCSTriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static u32 mct_NodePresent_D(void);
+static void mct_OtherTiming(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA);
+static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat);
+static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat);
+void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat);
+static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat);
+void mct_ClrWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat);
+static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA);
+static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct);
+
+static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dimm);
+static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2);
+static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat);
+static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void SyncSetting(struct DCTStatStruc *pDCTstat);
+static u8 crcCheck(u8 smbaddr);
+
+/*See mctAutoInitMCT header for index relationships to CL and T*/
+static const u16 Table_F_k[]   = {00,200,266,333,400,533 };
+static const u8 Tab_BankAddr[] = {0x3F,0x01,0x09,0x3F,0x3F,0x11,0x0A,0x19,0x12,0x1A,0x21,0x22,0x23};
+static const u8 Table_DQSRcvEn_Offset[] = {0x00,0x01,0x10,0x11,0x2};
+
+/****************************************************************************
+   Describe how platform maps MemClk pins to logical DIMMs. The MemClk pins
+   are identified based on BKDG definition of Fn2x88[MemClkDis] bitmap.
+   AGESA will base on this value to disable unused MemClk to save power.
+
+   If MEMCLK_MAPPING or MEMCLK_MAPPING contains all zeroes, AGESA will use
+   default MemClkDis setting based on package type.
+
+   Example:
+   BKDG definition of Fn2x88[MemClkDis] bitmap for AM3 package is like below:
+        Bit AM3/S1g3 pin name
+        0   M[B,A]_CLK_H/L[0]
+        1   M[B,A]_CLK_H/L[1]
+        2   M[B,A]_CLK_H/L[2]
+        3   M[B,A]_CLK_H/L[3]
+        4   M[B,A]_CLK_H/L[4]
+        5   M[B,A]_CLK_H/L[5]
+        6   M[B,A]_CLK_H/L[6]
+        7   M[B,A]_CLK_H/L[7]
+
+   And platform has the following routing:
+        CS0   M[B,A]_CLK_H/L[4]
+        CS1   M[B,A]_CLK_H/L[2]
+        CS2   M[B,A]_CLK_H/L[3]
+        CS3   M[B,A]_CLK_H/L[5]
+
+   Then:
+                        ;    CS0        CS1        CS2        CS3        CS4        CS5        CS6        CS7
+   MEMCLK_MAPPING  EQU    00010000b, 00000100b, 00001000b, 00100000b, 00000000b, 00000000b, 00000000b, 00000000b
+*/
+
+/* Note: If you are not sure about the pin mappings at initial stage, we dont have to disable MemClk.
+ * Set entries in the tables all 0xFF. */
+static const u8 Tab_L1CLKDis[]  = {0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04};
+static const u8 Tab_AM3CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00};
+static const u8 Tab_S1CLKDis[]  = {0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const u8 Tab_ManualCLKDis[]= {0x10, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00};
+
+static const u8 Table_Comp_Rise_Slew_20x[] = {7, 3, 2, 2, 0xFF};
+static const u8 Table_Comp_Rise_Slew_15x[] = {7, 7, 3, 2, 0xFF};
+static const u8 Table_Comp_Fall_Slew_20x[] = {7, 5, 3, 2, 0xFF};
+static const u8 Table_Comp_Fall_Slew_15x[] = {7, 7, 5, 3, 0xFF};
+
+static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+{
+       /*
+        * Memory may be mapped contiguously all the way up to 4GB (depending on setup
+        * options).  It is the responsibility of PCI subsystem to create an uncacheable
+        * IO region below 4GB and to adjust TOP_MEM downward prior to any IO mapping or
+        * accesses.  It is the same responsibility of the CPU sub-system prior to
+        * accessing LAPIC.
+        *
+        * Slot Number is an external convention, and is determined by OEM with accompanying
+        * silk screening.  OEM may choose to use Slot number convention which is consistent
+        * with DIMM number conventions.  All AMD engineering platforms do.
+        *
+        * Build Requirements:
+        * 1. MCT_SEG0_START and MCT_SEG0_END macros to begin and end the code segment,
+        *    defined in mcti.inc.
+        *
+        * Run-Time Requirements:
+        * 1. Complete Hypertransport Bus Configuration
+        * 2. SMBus Controller Initialized
+        * 1. BSP in Big Real Mode
+        * 2. Stack at SS:SP, located somewhere between A000:0000 and F000:FFFF
+        * 3. Checksummed or Valid NVRAM bits
+        * 4. MCG_CTL=-1, MC4_CTL_EN=0 for all CPUs
+        * 5. MCi_STS from shutdown/warm reset recorded (if desired) prior to entry
+        * 6. All var MTRRs reset to zero
+        * 7. State of NB_CFG.DisDatMsk set properly on all CPUs
+        * 8. All CPUs at 2Ghz Speed (unless DQS training is not installed).
+        * 9. All cHT links at max Speed/Width (unless DQS training is not installed).
+        *
+        *
+        * Global relationship between index values and item values:
+        *
+        * pDCTstat.CASL pDCTstat.Speed
+        * j CL(j)       k   F(k)
+        * --------------------------
+        * 0 2.0         -   -
+        * 1 3.0         1   200 Mhz
+        * 2 4.0         2   266 Mhz
+        * 3 5.0         3   333 Mhz
+        * 4 6.0         4   400 Mhz
+        * 5 7.0         5   533 Mhz
+        * 6 8.0         6   667 Mhz
+        * 7 9.0         7   800 Mhz
+        */
+       u8 Node, NodesWmem;
+       u32 node_sys_base;
+
+restartinit:
+       mctInitMemGPIOs_A_D();          /* Set any required GPIOs*/
+       NodesWmem = 0;
+       node_sys_base = 0;
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               pDCTstat->Node_ID = Node;
+               pDCTstat->dev_host = PA_HOST(Node);
+               pDCTstat->dev_map = PA_MAP(Node);
+               pDCTstat->dev_dct = PA_DCT(Node);
+               pDCTstat->dev_nbmisc = PA_NBMISC(Node);
+               pDCTstat->NodeSysBase = node_sys_base;
+
+               mct_init(pMCTstat, pDCTstat);
+               mctNodeIDDebugPort_D();
+               pDCTstat->NodePresent = NodePresent_D(Node);
+               if (pDCTstat->NodePresent) {            /* See if Node is there*/
+                       clear_legacy_Mode(pMCTstat, pDCTstat);
+                       pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
+
+                       mct_InitialMCT_D(pMCTstat, pDCTstat);
+
+                       mctSMBhub_Init(Node);           /* Switch SMBUS crossbar to proper node*/
+
+                       mct_initDCT(pMCTstat, pDCTstat);
+                       if (pDCTstat->ErrCode == SC_FatalErr) {
+                               goto fatalexit;         /* any fatal errors?*/
+                       } else if (pDCTstat->ErrCode < SC_StopError) {
+                               NodesWmem++;
+                       }
+               }       /* if Node present */
+               node_sys_base = pDCTstat->NodeSysBase;
+               node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
+       }
+       if (NodesWmem == 0) {
+               printk(BIOS_DEBUG, "No Nodes?!\n");
+               goto fatalexit;
+       }
+
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
+       SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are ready for accesses.*/
+
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D: HTMemMapInit_D\n");
+       HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory into system address space.*/
+       mctHookAfterHTMap();
+
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
+       CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC CPU cacheability */
+       mctHookAfterCPU();                      /* Setup external northbridge(s) */
+
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
+       DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable and DQS signal timing*/
+
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
+       UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA sizing */
+
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+       mct_OtherTiming(pMCTstat, pDCTstatA);
+
+       if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st pass of DIMM spare enabled*/
+               goto restartinit;
+       }
+
+       InterleaveNodes_D(pMCTstat, pDCTstatA);
+       InterleaveChannels_D(pMCTstat, pDCTstatA);
+
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
+       if (ECCInit_D(pMCTstat, pDCTstatA)) {           /* Setup ECC control and ECC check-bits*/
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
+               MCTMemClr_D(pMCTstat,pDCTstatA);
+       }
+
+       mct_FinalMCT_D(pMCTstat, (pDCTstatA + 0) );     /* Node 0 */
+       printk(BIOS_DEBUG, "All Done\n");
+       return;
+
+fatalexit:
+       die("mct_d: fatalexit");
+}
+
+static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 ret;
+
+       if (mctGet_NVbits(NV_CS_SpareCTL)) {
+               if (MCT_DIMM_SPARE_NO_WARM) {
+                       /* Do no warm-reset DIMM spare */
+                       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+                               LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA);
+                               ret = 0;
+                       } else {
+                               mct_ResetDataStruct_D(pMCTstat, pDCTstatA);
+                               pMCTstat->GStatus |= 1 << GSB_EnDIMMSpareNW;
+                               ret = 1;
+                       }
+               } else {
+                       /* Do warm-reset DIMM spare */
+                       if (mctGet_NVbits(NV_DQSTrainCTL))
+                               mctWarmReset_D();
+                       ret = 0;
+               }
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       u8 nv_DQSTrainCTL;
+
+       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+               return;
+       }
+
+       nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
+       /* FIXME: BOZO- DQS training every time*/
+       nv_DQSTrainCTL = 1;
+
+       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
+       phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
+
+       if (nv_DQSTrainCTL) {
+               mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
+               /* TODO: should be in mctHookBeforeAnyTraining */
+               _WRMSR(0x26C, 0x04040404, 0x04040404);
+               _WRMSR(0x26D, 0x04040404, 0x04040404);
+               _WRMSR(0x26E, 0x04040404, 0x04040404);
+               _WRMSR(0x26F, 0x04040404, 0x04040404);
+               mct_WriteLevelization_HW(pMCTstat, pDCTstatA);
+
+               TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
+
+               mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
+
+               /* Second Pass never used for Barcelona! */
+               /* TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass); */
+
+               mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
+
+               /* FIXME - currently uses calculated value      TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+               mctHookAfterAnyTraining();
+               mctSaveDQSSigTmg_D();
+
+               MCTMemClr_D(pMCTstat, pDCTstatA);
+       } else {
+               mctGetDQSSigTmg_D();    /* get values into data structure */
+               LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA);       /* load values into registers.*/
+               /* mctDoWarmResetMemClr_D(); */
+               MCTMemClr_D(pMCTstat, pDCTstatA);
+       }
+}
+
+static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node, Receiver, Channel, Dir, DIMM;
+       u32 dev;
+       u32 index_reg;
+       u32 reg;
+       u32 index;
+       u32 val;
+       u8 ByteLane;
+       u8 txdqs;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+
+               if (pDCTstat->DCTSysLimit) {
+                       dev = pDCTstat->dev_dct;
+                       for (Channel = 0;Channel < 2; Channel++) {
+                               /* there are four receiver pairs,
+                                  loosely associated with chipselects.*/
+                               index_reg = 0x98 + Channel * 0x100;
+                               for (Receiver = 0; Receiver < 8; Receiver += 2) {
+                                       /* Set Receiver Enable Values */
+                                       mct_SetRcvrEnDly_D(pDCTstat,
+                                               0, /* RcvrEnDly */
+                                               1, /* FinalValue, From stack */
+                                               Channel,
+                                               Receiver,
+                                               dev, index_reg,
+                                               (Receiver >> 1) * 3 + 0x10, /* Addl_Index */
+                                               2); /* Pass Second Pass ? */
+                                       /* Restore Write levelization training data */
+                                       for (ByteLane = 0; ByteLane < 9; ByteLane ++) {
+                                               txdqs = pDCTstat->CH_D_B_TxDqs[Channel][Receiver >> 1][ByteLane];
+                                               index = Table_DQSRcvEn_Offset[ByteLane >> 1];
+                                               index += (Receiver >> 1) * 3 + 0x10 + 0x20; /* Addl_Index */
+                                               val = Get_NB32_index_wait(dev, 0x98 + 0x100*Channel, index);
+                                               if (ByteLane & 1) { /* odd byte lane */
+                                                       val &= ~(0xFF << 16);
+                                                       val |= txdqs << 16;
+                                               } else {
+                                                       val &= ~0xFF;
+                                                       val |= txdqs;
+                                               }
+                                               Set_NB32_index_wait(dev, 0x98 + 0x100*Channel, index, val);
+                                       }
+                               }
+                       }
+                       for (Channel = 0; Channel<2; Channel++) {
+                               SetEccDQSRcvrEn_D(pDCTstat, Channel);
+                       }
+
+                       for (Channel = 0; Channel < 2; Channel++) {
+                               u8 *p;
+                               index_reg = 0x98 + Channel * 0x100;
+
+                               /* NOTE:
+                                * when 400, 533, 667, it will support dimm0/1/2/3,
+                                * and set conf for dimm0, hw will copy to dimm1/2/3
+                                * set for dimm1, hw will copy to dimm3
+                                * Rev A/B only support DIMM0/1 when 800Mhz and above
+                                *   + 0x100 to next dimm
+                                * Rev C support DIMM0/1/2/3 when 800Mhz and above
+                                *   + 0x100 to next dimm
+                               */
+                               for (DIMM = 0; DIMM < 4; DIMM++) {
+                                       if (DIMM == 0) {
+                                               index = 0;      /* CHA Write Data Timing Low */
+                                       } else {
+                                               if (pDCTstat->Speed >= 4) {
+                                                       index = 0x100 * DIMM;
+                                               } else {
+                                                       break;
+                                               }
+                                       }
+                                       for (Dir = 0; Dir < 2; Dir++) {/* RD/WR */
+                                               p = pDCTstat->CH_D_DIR_B_DQS[Channel][DIMM][Dir];
+                                               val = stream_to_int(p); /* CHA Read Data Timing High */
+                                               Set_NB32_index_wait(dev, index_reg, index+1, val);
+                                               val = stream_to_int(p+4); /* CHA Write Data Timing High */
+                                               Set_NB32_index_wait(dev, index_reg, index+2, val);
+                                               val = *(p+8); /* CHA Write ECC Timing */
+                                               Set_NB32_index_wait(dev, index_reg, index+3, val);
+                                               index += 4;
+                                       }
+                               }
+                       }
+
+                       for (Channel = 0; Channel<2; Channel++) {
+                               reg = 0x78 + Channel * 0x100;
+                               val = Get_NB32(dev, reg);
+                               val &= ~(0x3ff<<22);
+                               val |= ((u32) pDCTstat->CH_MaxRdLat[Channel] << 22);
+                               val &= ~(1<<DqsRcvEnTrain);
+                               Set_NB32(dev, reg, val);        /* program MaxRdLatency to correspond with current delay*/
+                       }
+               }
+       }
+}
+
+static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+       u32 NextBase, BottomIO;
+       u8 _MemHoleRemap, DramHoleBase, DramHoleOffset;
+       u32 HoleSize, DramSelBaseAddr;
+
+       u32 val;
+       u32 base;
+       u32 limit;
+       u32 dev, devx;
+       struct DCTStatStruc *pDCTstat;
+
+       _MemHoleRemap = mctGet_NVbits(NV_MemHole);
+
+       if (pMCTstat->HoleBase == 0) {
+               DramHoleBase = mctGet_NVbits(NV_BottomIO);
+       } else {
+               DramHoleBase = pMCTstat->HoleBase >> (24-8);
+       }
+
+       BottomIO = DramHoleBase << (24-8);
+
+       NextBase = 0;
+       pDCTstat = pDCTstatA + 0;
+       dev = pDCTstat->dev_map;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               devx = pDCTstat->dev_map;
+               DramSelBaseAddr = 0;
+               pDCTstat = pDCTstatA + Node; /* ??? */
+               if (!pDCTstat->GangedMode) {
+                       DramSelBaseAddr = pDCTstat->NodeSysLimit - pDCTstat->DCTSysLimit;
+                       /*In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */
+                       val = pDCTstat->NodeSysLimit;
+                       if ((val & 0xFF) == 0xFE) {
+                               DramSelBaseAddr++;
+                               val++;
+                       }
+                       pDCTstat->DCTSysLimit = val;
+               }
+
+               base  = pDCTstat->DCTSysBase;
+               limit = pDCTstat->DCTSysLimit;
+               if (limit > base) {
+                       base  += NextBase;
+                       limit += NextBase;
+                       DramSelBaseAddr += NextBase;
+                       printk(BIOS_DEBUG, " Node: %02x  base: %02x  limit: %02x  BottomIO: %02x\n", Node, base, limit, BottomIO);
+
+                       if (_MemHoleRemap) {
+                               if ((base < BottomIO) && (limit >= BottomIO)) {
+                                       /* HW Dram Remap */
+                                       pDCTstat->Status |= 1 << SB_HWHole;
+                                       pMCTstat->GStatus |= 1 << GSB_HWHole;
+                                       pDCTstat->DCTSysBase = base;
+                                       pDCTstat->DCTSysLimit = limit;
+                                       pDCTstat->DCTHoleBase = BottomIO;
+                                       pMCTstat->HoleBase = BottomIO;
+                                       HoleSize = _4GB_RJ8 - BottomIO; /* HoleSize[39:8] */
+                                       if ((DramSelBaseAddr > 0) && (DramSelBaseAddr < BottomIO))
+                                               base = DramSelBaseAddr;
+                                       val = ((base + HoleSize) >> (24-8)) & 0xFF;
+                                       DramHoleOffset = val;
+                                       val <<= 8; /* shl 16, rol 24 */
+                                       val |= DramHoleBase << 24;
+                                       val |= 1  << DramHoleValid;
+                                       Set_NB32(devx, 0xF0, val); /* Dram Hole Address Reg */
+                                       pDCTstat->DCTSysLimit += HoleSize;
+                                       base = pDCTstat->DCTSysBase;
+                                       limit = pDCTstat->DCTSysLimit;
+                               } else if (base == BottomIO) {
+                                       /* SW Node Hoist */
+                                       pMCTstat->GStatus |= 1<<GSB_SpIntRemapHole;
+                                       pDCTstat->Status |= 1<<SB_SWNodeHole;
+                                       pMCTstat->GStatus |= 1<<GSB_SoftHole;
+                                       pMCTstat->HoleBase = base;
+                                       limit -= base;
+                                       base = _4GB_RJ8;
+                                       limit += base;
+                                       pDCTstat->DCTSysBase = base;
+                                       pDCTstat->DCTSysLimit = limit;
+                               } else {
+                                       /* No Remapping.  Normal Contiguous mapping */
+                                       pDCTstat->DCTSysBase = base;
+                                       pDCTstat->DCTSysLimit = limit;
+                               }
+                       } else {
+                               /*No Remapping.  Normal Contiguous mapping*/
+                               pDCTstat->DCTSysBase = base;
+                               pDCTstat->DCTSysLimit = limit;
+                       }
+                       base |= 3;              /* set WE,RE fields*/
+                       pMCTstat->SysLimit = limit;
+               }
+               Set_NB32(dev, 0x40 + (Node << 3), base); /* [Node] + Dram Base 0 */
+
+               val = limit & 0xFFFF0000;
+               val |= Node;
+               Set_NB32(dev, 0x44 + (Node << 3), val); /* set DstNode */
+
+               printk(BIOS_DEBUG, " Node: %02x  base: %02x  limit: %02x \n", Node, base, limit);
+               limit = pDCTstat->DCTSysLimit;
+               if (limit) {
+                       NextBase = (limit & 0xFFFF0000) + 0x10000;
+               }
+       }
+
+       /* Copy dram map from Node 0 to Node 1-7 */
+       for (Node = 1; Node < MAX_NODES_SUPPORTED; Node++) {
+               u32 reg;
+               pDCTstat = pDCTstatA + Node;
+               devx = pDCTstat->dev_map;
+
+               if (pDCTstat->NodePresent) {
+                       reg = 0x40;             /*Dram Base 0*/
+                       do {
+                               val = Get_NB32(dev, reg);
+                               Set_NB32(devx, reg, val);
+                               reg += 4;
+                       } while ( reg < 0x80);
+               } else {
+                       break;                  /* stop at first absent Node */
+               }
+       }
+
+       /*Copy dram map to F1x120/124*/
+       mct_HTMemMapExt(pMCTstat, pDCTstatA);
+}
+
+static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+
+       /* Initiates a memory clear operation for all node. The mem clr
+        * is done in paralel. After the memclr is complete, all processors
+        * status are checked to ensure that memclr has completed.
+        */
+       u8 Node;
+       struct DCTStatStruc *pDCTstat;
+
+       if (!mctGet_NVbits(NV_DQSTrainCTL)){
+               /* FIXME: callback to wrapper: mctDoWarmResetMemClr_D */
+       } else {        /* NV_DQSTrainCTL == 1 */
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+                       pDCTstat = pDCTstatA + Node;
+
+                       if (pDCTstat->NodePresent) {
+                               DCTMemClr_Init_D(pMCTstat, pDCTstat);
+                       }
+               }
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+                       pDCTstat = pDCTstatA + Node;
+
+                       if (pDCTstat->NodePresent) {
+                               DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+                       }
+               }
+       }
+}
+
+static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+       u32 dev;
+       u32 reg;
+
+       /* Initiates a memory clear operation on one node */
+       if (pDCTstat->DCTSysLimit) {
+               dev = pDCTstat->dev_dct;
+               reg = 0x110;
+
+               do {
+                       val = Get_NB32(dev, reg);
+               } while (val & (1 << MemClrBusy));
+
+               val |= (1 << MemClrInit);
+               Set_NB32(dev, reg, val);
+       }
+}
+
+static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       /* Ensures that memory clear has completed on all node.*/
+       u8 Node;
+       struct DCTStatStruc *pDCTstat;
+
+       if (!mctGet_NVbits(NV_DQSTrainCTL)){
+               /* callback to wrapper: mctDoWarmResetMemClr_D */
+       } else {        /* NV_DQSTrainCTL == 1 */
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+                       pDCTstat = pDCTstatA + Node;
+
+                       if (pDCTstat->NodePresent) {
+                               DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+                       }
+               }
+       }
+}
+
+static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+       u32 dev = pDCTstat->dev_dct;
+       u32 reg;
+
+       /* Ensure that a memory clear operation has completed on one node */
+       if (pDCTstat->DCTSysLimit){
+               reg = 0x110;
+
+               do {
+                       val = Get_NB32(dev, reg);
+               } while (val & (1 << MemClrBusy));
+
+               do {
+                       val = Get_NB32(dev, reg);
+               } while (!(val & (1 << Dr_MemClrStatus)));
+       }
+
+       val = 0x0FE40FC0;               /* BKDG recommended */
+       val |= MCCH_FlushWrOnStpGnt;    /* Set for S3 */
+       Set_NB32(dev, 0x11C, val);
+}
+
+static u8 NodePresent_D(u8 Node)
+{
+       /*
+        * Determine if a single Hammer Node exists within the network.
+        */
+       u32 dev;
+       u32 val;
+       u32 dword;
+       u8 ret = 0;
+
+       dev = PA_HOST(Node);            /*test device/vendor id at host bridge  */
+       val = Get_NB32(dev, 0);
+       dword = mct_NodePresent_D();    /* FIXME: BOZO -11001022h rev for F */
+       if (val == dword) {             /* AMD Hammer Family CPU HT Configuration */
+               if (oemNodePresent_D(Node, &ret))
+                       goto finish;
+               /* Node ID register */
+               val = Get_NB32(dev, 0x60);
+               val &= 0x07;
+               dword = Node;
+               if (val  == dword)      /* current nodeID = requested nodeID ? */
+                       ret = 1;
+       }
+finish:
+       return ret;
+}
+
+static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       /*
+        * Initialize DRAM on single Athlon 64/Opteron Node.
+        */
+       u8 stopDCTflag;
+       u32 val;
+
+       ClearDCT_D(pMCTstat, pDCTstat, dct);
+       stopDCTflag = 1;                /*preload flag with 'disable' */
+       /* enable DDR3 support */
+       val = Get_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100);
+       val |= 1 << Ddr3Mode;
+       Set_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100, val);
+       if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
+               printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_DIMMPresence Done\n");
+               if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
+                       printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
+                       if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+                               printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D Done\n");
+                               if (AutoConfig_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+                                       printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D Done\n");
+                                       if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+                                               printk(BIOS_DEBUG, "\t\tDCTInit_D: PlatformSpec_D Done\n");
+                                               stopDCTflag = 0;
+                                               if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
+                                                       printk(BIOS_DEBUG, "\t\tDCTInit_D: StartupDCT_D\n");
+                                                       StartupDCT_D(pMCTstat, pDCTstat, dct);   /*yeaahhh! */
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (stopDCTflag) {
+               u32 reg_off = dct * 0x100;
+               val = 1<<DisDramInterface;
+               Set_NB32(pDCTstat->dev_dct, reg_off+0x94, val);
+               /*To maximize power savings when DisDramInterface=1b,
+                 all of the MemClkDis bits should also be set.*/
+               val = 0xFF000000;
+               Set_NB32(pDCTstat->dev_dct, reg_off+0x88, val);
+       } else {
+               /* mct_EnDllShutdownSR */
+       }
+}
+
+static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       /* Wait (and block further access to dram) for all DCTs to be ready,
+        * by polling all InitDram bits and waiting for possible memory clear
+        * operations to be complete.  Read MemClkFreqVal bit to see if
+        * the DIMMs are present in this node.
+        */
+       u8 Node;
+       u32 val;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               mct_SyncDCTsReady(pDCTstat);
+       }
+       /* v6.1.3 */
+       /* re-enable phy compensation engine when dram init is completed on all nodes. */
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               if (pDCTstat->NodePresent) {
+                       if (pDCTstat->DIMMValidDCT[0] > 0 || pDCTstat->DIMMValidDCT[1] > 0) {
+                               /* re-enable phy compensation engine when dram init on both DCTs is completed. */
+                               val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8);
+                               val &= ~(1 << DisAutoComp);
+                               Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8, val);
+                       }
+               }
+       }
+       /* wait 750us before any memory access can be made. */
+       mct_Wait(15000);
+}
+
+static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       /* Read MemClkFreqVal bit to see if the DIMMs are present in this node.
+        * If the DIMMs are present then set the DRAM Enable bit for this node.
+        *
+        * Setting dram init starts up the DCT state machine, initializes the
+        * dram devices with MRS commands, and kicks off any
+        * HW memory clear process that the chip is capable of. The sooner
+        * that dram init is set for all nodes, the faster the memory system
+        * initialization can complete. Thus, the init loop is unrolled into
+        * two loops so as to start the processeses for non BSP nodes sooner.
+        * This procedure will not wait for the process to finish.
+        * Synchronization is handled elsewhere.
+        */
+       u32 val;
+       u32 dev;
+       u32 reg_off = dct * 0x100;
+
+       dev = pDCTstat->dev_dct;
+       val = Get_NB32(dev, 0x94 + reg_off);
+       if (val & (1<<MemClkFreqVal)) {
+               mctHookBeforeDramInit();        /* generalized Hook */
+               if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)))
+                   mct_DramInit(pMCTstat, pDCTstat, dct);
+               AfterDramInit_D(pDCTstat, dct);
+               mctHookAfterDramInit();         /* generalized Hook*/
+       }
+}
+
+static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 reg_end;
+       u32 dev = pDCTstat->dev_dct;
+       u32 reg = 0x40 + 0x100 * dct;
+       u32 val = 0;
+
+       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+               reg_end = 0x78 + 0x100 * dct;
+       } else {
+               reg_end = 0xA4 + 0x100 * dct;
+       }
+
+       while(reg < reg_end) {
+               Set_NB32(dev, reg, val);
+               reg += 4;
+       }
+
+       val = 0;
+       dev = pDCTstat->dev_map;
+       reg = 0xF0;
+       Set_NB32(dev, reg, val);
+}
+
+static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 i;
+       u16 Twr, Trtp;
+       u16 Trp, Trrd, Trcd, Tras, Trc;
+       u8 Trfc[4];
+       u16 Tfaw;
+       u32 DramTimingLo, DramTimingHi;
+       u8 tCK16x;
+       u16 Twtr;
+       u8 LDIMM;
+       u8 MTB16x;
+       u8 byte;
+       u32 dword;
+       u32 dev;
+       u32 reg_off;
+       u32 val;
+       u16 smbaddr;
+
+       /* Gather all DIMM mini-max values for cycle timing data */
+       Trp = 0;
+       Trrd = 0;
+       Trcd = 0;
+       Trtp = 0;
+       Tras = 0;
+       Trc = 0;
+       Twr = 0;
+       Twtr = 0;
+       for (i=0; i < 4; i++)
+               Trfc[i] = 0;
+       Tfaw = 0;
+
+       for ( i = 0; i< MAX_DIMMS_SUPPORTED; i++) {
+               LDIMM = i >> 1;
+               if (pDCTstat->DIMMValid & (1 << i)) {
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
+
+                       val = mctRead_SPD(smbaddr, SPD_MTBDivisor); /* MTB=Dividend/Divisor */
+                       MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 0xFF)<<4);
+                       MTB16x /= val; /* transfer to MTB*16 */
+
+                       byte = mctRead_SPD(smbaddr, SPD_tRPmin);
+                       val = byte * MTB16x;
+                       if (Trp < val)
+                               Trp = val;
+
+                       byte = mctRead_SPD(smbaddr, SPD_tRRDmin);
+                       val = byte * MTB16x;
+                       if (Trrd < val)
+                               Trrd = val;
+
+                       byte = mctRead_SPD(smbaddr, SPD_tRCDmin);
+                       val = byte * MTB16x;
+                       if (Trcd < val)
+                               Trcd = val;
+
+                       byte = mctRead_SPD(smbaddr, SPD_tRTPmin);
+                       val = byte * MTB16x;
+                       if (Trtp < val)
+                               Trtp = val;
+
+                       byte = mctRead_SPD(smbaddr, SPD_tWRmin);
+                       val = byte * MTB16x;
+                       if (Twr < val)
+                               Twr = val;
+
+                       byte = mctRead_SPD(smbaddr, SPD_tWTRmin);
+                       val = byte * MTB16x;
+                       if (Twtr < val)
+                               Twtr = val;
+
+                       val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xFF;
+                       val >>= 4;
+                       val <<= 8;
+                       val |= mctRead_SPD(smbaddr, SPD_tRCmin) & 0xFF;
+                       val *= MTB16x;
+                       if (Trc < val)
+                               Trc = val;
+
+                       byte = mctRead_SPD(smbaddr, SPD_Density) & 0xF;
+                       if (Trfc[LDIMM] < byte)
+                               Trfc[LDIMM] = byte;
+
+                       val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xF;
+                       val <<= 8;
+                       val |= (mctRead_SPD(smbaddr, SPD_tRASmin) & 0xFF);
+                       val *= MTB16x;
+                       if (Tras < val)
+                               Tras = val;
+
+                       val = mctRead_SPD(smbaddr, SPD_Upper_tFAW) & 0xF;
+                       val <<= 8;
+                       val |= mctRead_SPD(smbaddr, SPD_tFAWmin) & 0xFF;
+                       val *= MTB16x;
+                       if (Tfaw < val)
+                               Tfaw = val;
+               }       /* Dimm Present */
+       }
+
+       /* Convert  DRAM CycleTiming values and store into DCT structure */
+       byte = pDCTstat->DIMMAutoSpeed;
+       if (byte == 7)
+               tCK16x = 20;
+       else if (byte == 6)
+               tCK16x = 24;
+       else if (byte == 5)
+               tCK16x = 30;
+       else
+               tCK16x = 40;
+
+       /* Notes:
+        1. All secondary time values given in SPDs are in binary with units of ns.
+        2. Some time values are scaled by 16, 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, tCK16x, is scaled by 16 to match time values
+       */
+
+       /* Tras */
+       pDCTstat->DIMMTras = (u16)Tras;
+       val = Tras / tCK16x;
+       if (Tras % tCK16x) {    /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TrasT)
+               val = Min_TrasT;
+       else if (val > Max_TrasT)
+               val = Max_TrasT;
+       pDCTstat->Tras = val;
+
+       /* Trp */
+       pDCTstat->DIMMTrp = Trp;
+       val = Trp / tCK16x;
+       if (Trp % tCK16x) {     /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TrpT)
+               val = Min_TrpT;
+       else if (val > Max_TrpT)
+               val = Max_TrpT;
+       pDCTstat->Trp = val;
+
+       /*Trrd*/
+       pDCTstat->DIMMTrrd = Trrd;
+       val = Trrd / tCK16x;
+       if (Trrd % tCK16x) {    /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TrrdT)
+               val = Min_TrrdT;
+       else if (val > Max_TrrdT)
+               val = Max_TrrdT;
+       pDCTstat->Trrd = val;
+
+       /* Trcd */
+       pDCTstat->DIMMTrcd = Trcd;
+       val = Trcd / tCK16x;
+       if (Trcd % tCK16x) {    /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TrcdT)
+               val = Min_TrcdT;
+       else if (val > Max_TrcdT)
+               val = Max_TrcdT;
+       pDCTstat->Trcd = val;
+
+       /* Trc */
+       pDCTstat->DIMMTrc = Trc;
+       val = Trc / tCK16x;
+       if (Trc % tCK16x) {     /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TrcT)
+               val = Min_TrcT;
+       else if (val > Max_TrcT)
+               val = Max_TrcT;
+       pDCTstat->Trc = val;
+
+       /* Trtp */
+       pDCTstat->DIMMTrtp = Trtp;
+       val = Trtp / tCK16x;
+       if (Trtp % tCK16x) {
+               val ++;
+       }
+       if (val < Min_TrtpT)
+               val = Min_TrtpT;
+       else if (val > Max_TrtpT)
+               val = Max_TrtpT;
+       pDCTstat->Trtp = val;
+
+       /* Twr */
+       pDCTstat->DIMMTwr = Twr;
+       val = Twr / tCK16x;
+       if (Twr % tCK16x) {     /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TwrT)
+               val = Min_TwrT;
+       else if (val > Max_TwrT)
+               val = Max_TwrT;
+       pDCTstat->Twr = val;
+
+       /* Twtr */
+       pDCTstat->DIMMTwtr = Twtr;
+       val = Twtr / tCK16x;
+       if (Twtr % tCK16x) {    /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TwtrT)
+               val = Min_TwtrT;
+       else if (val > Max_TwtrT)
+               val = Max_TwtrT;
+       pDCTstat->Twtr = val;
+
+       /* Trfc0-Trfc3 */
+       for (i=0; i<4; i++)
+               pDCTstat->Trfc[i] = Trfc[i];
+
+       /* Tfaw */
+       pDCTstat->DIMMTfaw = Tfaw;
+       val = Tfaw / tCK16x;
+       if (Tfaw % tCK16x) {    /* round up number of busclocks */
+               val++;
+       }
+       if (val < Min_TfawT)
+               val = Min_TfawT;
+       else if (val > Max_TfawT)
+               val = Max_TfawT;
+       pDCTstat->Tfaw = val;
+
+       mctAdjustAutoCycTmg_D();
+
+       /* Program DRAM Timing values */
+       DramTimingLo = 0;       /* Dram Timing Low init */
+       val = pDCTstat->CASL - 2; /* pDCTstat.CASL to reg. definition */
+       DramTimingLo |= val;
+
+       val = pDCTstat->Trcd - Bias_TrcdT;
+       DramTimingLo |= val<<4;
+
+       val = pDCTstat->Trp - Bias_TrpT;
+       val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+       DramTimingLo |= val<<7;
+
+       val = pDCTstat->Trtp - Bias_TrtpT;
+       DramTimingLo |= val<<10;
+
+       val = pDCTstat->Tras - Bias_TrasT;
+       DramTimingLo |= val<<12;
+
+       val = pDCTstat->Trc - Bias_TrcT;
+       DramTimingLo |= val<<16;
+
+       val = pDCTstat->Trrd - Bias_TrrdT;
+       DramTimingLo |= val<<22;
+
+       DramTimingHi = 0;       /* Dram Timing High init */
+       val = pDCTstat->Twtr - Bias_TwtrT;
+       DramTimingHi |= val<<8;
+
+       val = 2;
+       DramTimingHi |= val<<16;
+
+       val = 0;
+       for (i=4;i>0;i--) {
+               val <<= 3;
+               val |= Trfc[i-1];
+       }
+       DramTimingHi |= val << 20;
+
+       dev = pDCTstat->dev_dct;
+       reg_off = 0x100 * dct;
+       /* Twr */
+       val = pDCTstat->Twr;
+       if (val == 10)
+               val = 9;
+       else if (val == 12)
+               val = 10;
+       val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+       val -= Bias_TwrT;
+       val <<= 4;
+       dword = Get_NB32(dev, 0x84 + reg_off);
+       dword &= ~0x70;
+       dword |= val;
+       Set_NB32(dev, 0x84 + reg_off, dword);
+
+       /* Tfaw */
+       val = pDCTstat->Tfaw;
+       val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+       val -= Bias_TfawT;
+       val >>= 1;
+       val <<= 28;
+       dword = Get_NB32(dev, 0x94 + reg_off);
+       dword &= ~0xf0000000;
+       dword |= val;
+       Set_NB32(dev, 0x94 + reg_off, dword);
+
+       /* dev = pDCTstat->dev_dct; */
+       /* reg_off = 0x100 * dct; */
+
+       if (pDCTstat->Speed > 4) {
+               val = Get_NB32(dev, 0x88 + reg_off);
+               val &= 0xFF000000;
+               DramTimingLo |= val;
+       }
+       Set_NB32(dev, 0x88 + reg_off, DramTimingLo);    /*DCT Timing Low*/
+
+       if (pDCTstat->Speed > 4) {
+               DramTimingLo |= 1 << DisAutoRefresh;
+       }
+       DramTimingHi |= 0x000018FF;
+       Set_NB32(dev, 0x8c + reg_off, DramTimingHi);    /*DCT Timing Hi*/
+
+       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+}
+
+static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       /* 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.
+        *
+        * 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 is only applies when user
+        * timing mode is 'Auto'.
+        */
+
+       /* Get primary timing (CAS Latency and Cycle Time) */
+       if (pDCTstat->Speed == 0) {
+               mctGet_MaxLoadFreq(pDCTstat);
+
+               /* and Factor in presets (setup options, Si cap, etc.) */
+               GetPresetmaxF_D(pMCTstat, pDCTstat);
+
+               /* Go get best T and CL as specified by DIMM mfgs. and OEM */
+               SPDGetTCL_D(pMCTstat, pDCTstat, dct);
+               /* skip callback mctForce800to1067_D */
+               pDCTstat->Speed = pDCTstat->DIMMAutoSpeed;
+               pDCTstat->CASL = pDCTstat->DIMMCASL;
+
+       }
+       mct_AfterGetCLT(pMCTstat, pDCTstat, dct);
+
+       SPD2ndTiming(pMCTstat, pDCTstat, dct);
+
+       printk(BIOS_DEBUG, "AutoCycTiming: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "AutoCycTiming: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "AutoCycTiming: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "AutoCycTiming: Done\n\n");
+
+       mctHookAfterAutoCycTmg();
+
+       return pDCTstat->ErrCode;
+}
+
+static void GetPresetmaxF_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       /* 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
+        * DCTStatStruc.PresetmaxFreq.
+        */
+       u16 proposedFreq;
+       u16 word;
+
+       /* Get CPU Si Revision defined limit (NPT) */
+       proposedFreq = 533;      /* Rev F0 programmable max memclock is */
+
+       /*Get User defined limit if  "limit" mode */
+       if ( mctGet_NVbits(NV_MCTUSRTMGMODE) == 1) {
+               word = Get_Fk_D(mctGet_NVbits(NV_MemCkVal) + 1);
+               if (word < proposedFreq)
+                       proposedFreq = word;
+
+               /* Get Platform defined limit */
+               word = mctGet_NVbits(NV_MAX_MEMCLK);
+               if (word < proposedFreq)
+                       proposedFreq = word;
+
+               word = pDCTstat->PresetmaxFreq;
+               if (word > proposedFreq)
+                       word = proposedFreq;
+
+               pDCTstat->PresetmaxFreq = word;
+       }
+       /* Check F3xE8[DdrMaxRate] for maximum DRAM data rate support */
+}
+
+static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       /* Find the best T and CL primary timing parameter pair, per Mfg.,
+        * for the given set of DIMMs, and store into DCTStatStruc
+        * (.DIMMAutoSpeed and .DIMMCASL). See "Global relationship between
+        *  index values and item values" for definition of CAS latency
+        *  index (j) and Frequency index (k).
+        */
+       u8 i, CASLatLow, CASLatHigh;
+       u16 tAAmin16x;
+       u8 MTB16x;
+       u16 tCKmin16x;
+       u16 tCKproposed16x;
+       u8 CLactual, CLdesired, CLT_Fail;
+
+       u8 smbaddr, byte, bytex;
+
+       CASLatLow = 0xFF;
+       CASLatHigh = 0xFF;
+       tAAmin16x = 0;
+       tCKmin16x = 0;
+       CLT_Fail = 0;
+
+       for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
+               if (pDCTstat->DIMMValid & (1 << i)) {
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
+                       /* 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.
+                        */
+                       byte = mctRead_SPD(smbaddr, SPD_CASLow);
+                       CASLatLow &= byte;
+                       byte = mctRead_SPD(smbaddr, SPD_CASHigh);
+                       CASLatHigh &= byte;
+                       /* Step 2: Determine tAAmin(all) which is the largest tAAmin
+                          value for all modules on the memory channel (SPD byte 16). */
+                       byte = mctRead_SPD(smbaddr, SPD_MTBDivisor);
+
+                       MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 0xFF)<<4);
+                       MTB16x /= byte; /* transfer to MTB*16 */
+
+                       byte = mctRead_SPD(smbaddr, SPD_tAAmin);
+                       if (tAAmin16x < byte * MTB16x)
+                               tAAmin16x = byte * MTB16x;
+                       /* Step 3: Determine tCKmin(all) which is the largest tCKmin
+                          value for all modules on the memory channel (SPD byte 12). */
+                       byte = mctRead_SPD(smbaddr, SPD_tCKmin);
+
+                       if (tCKmin16x < byte * MTB16x)
+                               tCKmin16x = byte * MTB16x;
+               }
+       }
+       /* calculate tCKproposed16x */
+       tCKproposed16x =  16000 / pDCTstat->PresetmaxFreq;
+       if (tCKmin16x > tCKproposed16x)
+               tCKproposed16x = tCKmin16x;
+
+       /* mctHookTwo1333DimmOverride(); */
+       /* For UDIMM, if there are two DDR3-1333 on the same channel,
+          downgrade DDR speed to 1066. */
+
+       /* TODO: get user manual tCK16x(Freq.) and overwrite current tCKproposed16x if manual. */
+       if (tCKproposed16x == 20)
+               pDCTstat->TargetFreq = 7;
+       else if (tCKproposed16x <= 24) {
+               pDCTstat->TargetFreq = 6;
+               tCKproposed16x = 24;
+       }
+       else if (tCKproposed16x <= 30) {
+               pDCTstat->TargetFreq = 5;
+               tCKproposed16x = 30;
+       }
+       else {
+               pDCTstat->TargetFreq = 4;
+               tCKproposed16x = 40;
+       }
+       /* Running through this loop twice:
+          - First time find tCL at target frequency
+          - Second tim find tCL at 400MHz */
+
+       for (;;) {
+               CLT_Fail = 0;
+               /* 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 = tAAmin16x / tCKproposed16x;
+               if (tAAmin16x % tCKproposed16x)
+                       CLdesired ++;
+               /* Step 5: Chose an actual CAS Latency (CLactual) that is greather 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. */
+               for (i = 0, CLactual = 4; i < 15; i++, CLactual++) {
+                       if ((CASLatHigh << 8 | CASLatLow) & (1 << i)) {
+                               if (CLdesired <= CLactual)
+                                       break;
+                       }
+               }
+               if (i == 15)
+                       CLT_Fail = 1;
+               /* 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 (CLactual * tCKproposed16x > 320)
+                       CLT_Fail = 1;
+               /* get CL and T */
+               if (!CLT_Fail) {
+                       bytex = CLactual - 2;
+                       if (tCKproposed16x == 20)
+                               byte = 7;
+                       else if (tCKproposed16x == 24)
+                               byte = 6;
+                       else if (tCKproposed16x == 30)
+                               byte = 5;
+                       else
+                               byte = 4;
+               } else {
+                       /* mctHookManualCLOverride */
+                       /* TODO: */
+               }
+
+               if (tCKproposed16x != 40) {
+                       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+                               pDCTstat->DIMMAutoSpeed = byte;
+                               pDCTstat->DIMMCASL = bytex;
+                               break;
+                       } else {
+                               pDCTstat->TargetCASL = bytex;
+                               tCKproposed16x = 40;
+                       }
+               } else {
+                       pDCTstat->DIMMAutoSpeed = byte;
+                       pDCTstat->DIMMCASL = bytex;
+                       break;
+               }
+       }
+
+       printk(BIOS_DEBUG, "SPDGetTCL_D: DIMMCASL %x\n", pDCTstat->DIMMCASL);
+       printk(BIOS_DEBUG, "SPDGetTCL_D: DIMMAutoSpeed %x\n", pDCTstat->DIMMAutoSpeed);
+
+       printk(BIOS_DEBUG, "SPDGetTCL_D: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "SPDGetTCL_D: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "SPDGetTCL_D: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "SPDGetTCL_D: Done\n\n");
+}
+
+static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 dev;
+       u32 reg;
+       u32 val;
+
+       mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
+
+       if (pDCTstat->GangedMode == 1) {
+               mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
+       }
+
+       if ( pDCTstat->_2Tmode == 2) {
+               dev = pDCTstat->dev_dct;
+               reg = 0x94 + 0x100 * dct; /* Dram Configuration Hi */
+               val = Get_NB32(dev, reg);
+               val |= 1 << 20;                /* 2T CMD mode */
+               Set_NB32(dev, reg, val);
+       }
+
+       mct_PlatformSpec(pMCTstat, pDCTstat, dct);
+       if (pDCTstat->DIMMAutoSpeed == 4)
+               InitPhyCompensation(pMCTstat, pDCTstat, dct);
+       mctHookAfterPSCfg();
+
+       return pDCTstat->ErrCode;
+}
+
+static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 DramControl, DramTimingLo, Status;
+       u32 DramConfigLo, DramConfigHi, DramConfigMisc, DramConfigMisc2;
+       u32 val;
+       u32 reg_off;
+       u32 dev;
+       u16 word;
+       u32 dword;
+       u8 byte;
+
+       DramConfigLo = 0;
+       DramConfigHi = 0;
+       DramConfigMisc = 0;
+       DramConfigMisc2 = 0;
+
+       /* set bank addessing and Masks, plus CS pops */
+       SPDSetBanks_D(pMCTstat, pDCTstat, dct);
+       if (pDCTstat->ErrCode == SC_StopError)
+               goto AutoConfig_exit;
+
+       /* map chip-selects into local address space */
+       StitchMemory_D(pMCTstat, pDCTstat, dct);
+       InterleaveBanks_D(pMCTstat, pDCTstat, dct);
+
+       /* temp image of status (for convenience). RO usage! */
+       Status = pDCTstat->Status;
+
+       dev = pDCTstat->dev_dct;
+       reg_off = 0x100 * dct;
+
+
+       /* Build Dram Control Register Value */
+       DramConfigMisc2 = Get_NB32 (dev, 0xA8 + reg_off);       /* Dram Control*/
+       DramControl = Get_NB32 (dev, 0x78 + reg_off);           /* Dram Control*/
+
+       /* FIXME: Skip mct_checkForDxSupport */
+       /* REV_CALL mct_DoRdPtrInit if not Dx */
+       if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
+               val = 5;
+       else
+               val = 6;
+       DramControl &= ~0xFF;
+       DramControl |= val;     /* RdPrtInit = 6 for Cx CPU */
+
+       if (mctGet_NVbits(NV_CLKHZAltVidC3))
+               DramControl |= 1<<16; /* check */
+
+       DramControl |= 0x00002A00;
+
+       /* FIXME: Skip for Ax versions */
+       /* callback not required - if (!mctParityControl_D()) */
+       if (Status & (1 << SB_128bitmode))
+               DramConfigLo |= 1 << Width128;  /* 128-bit mode (normal) */
+
+       word = dct;
+       dword = X4Dimm;
+       while (word < 8) {
+               if (pDCTstat->Dimmx4Present & (1 << word))
+                       DramConfigLo |= 1 << dword;     /* X4Dimm[3:0] */
+               word++;
+               word++;
+               dword++;
+       }
+
+       if (!(Status & (1 << SB_Registered)))
+               DramConfigLo |= 1 << UnBuffDimm;        /* Unbufferd DIMMs */
+
+       if (mctGet_NVbits(NV_ECC_CAP))
+               if (Status & (1 << SB_ECCDIMMs))
+                       if ( mctGet_NVbits(NV_ECC))
+                               DramConfigLo |= 1 << DimmEcEn;
+
+       DramConfigLo = mct_DisDllShutdownSR(pMCTstat, pDCTstat, DramConfigLo, dct);
+
+       /* Build Dram Config Hi Register Value */
+       dword = pDCTstat->Speed;
+       DramConfigHi |= dword - 1;      /* get MemClk encoding */
+       DramConfigHi |= 1 << MemClkFreqVal;
+
+       if (Status & (1 << SB_Registered))
+               if ((pDCTstat->Dimmx4Present != 0) && (pDCTstat->Dimmx8Present != 0))
+                       /* set only if x8 Registered DIMMs in System*/
+                       DramConfigHi |= 1 << RDqsEn;
+
+       if (mctGet_NVbits(NV_CKE_CTL))
+               /*Chip Select control of CKE*/
+               DramConfigHi |= 1 << 16;
+
+       /* Control Bank Swizzle */
+       if (0) /* call back not needed mctBankSwizzleControl_D()) */
+               DramConfigHi &= ~(1 << BankSwizzleMode);
+       else
+               DramConfigHi |= 1 << BankSwizzleMode; /* recommended setting (default) */
+
+       /* Check for Quadrank DIMM presence */
+       if ( pDCTstat->DimmQRPresent != 0) {
+               byte = mctGet_NVbits(NV_4RANKType);
+               if (byte == 2)
+                       DramConfigHi |= 1 << 17;        /* S4 (4-Rank SO-DIMMs) */
+               else if (byte == 1)
+                       DramConfigHi |= 1 << 18;        /* R4 (4-Rank Registered DIMMs) */
+       }
+
+       if (0) /* call back not needed mctOverrideDcqBypMax_D ) */
+               val = mctGet_NVbits(NV_BYPMAX);
+       else
+               val = 0x0f; /* recommended setting (default) */
+       DramConfigHi |= val << 24;
+
+       if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Bx))
+               DramConfigHi |= 1 << DcqArbBypassEn;
+
+       /* Build MemClkDis Value from Dram Timing Lo and
+          Dram Config Misc Registers
+        1. We will assume that MemClkDis field has been preset prior to this
+           point.
+        2. We will only set MemClkDis bits if a DIMM is NOT present AND if:
+           NV_AllMemClks <>0 AND SB_DiagClks ==0 */
+
+       /* Dram Timing Low (owns Clock Enable bits) */
+       DramTimingLo = Get_NB32(dev, 0x88 + reg_off);
+       if (mctGet_NVbits(NV_AllMemClks) == 0) {
+               /* Special Jedec SPD diagnostic bit - "enable all clocks" */
+               if (!(pDCTstat->Status & (1<<SB_DiagClks))) {
+                       const u8 *p;
+                       const u32 *q;
+                       p = Tab_ManualCLKDis;
+                       q = (u32 *)p;
+
+                       byte = mctGet_NVbits(NV_PACK_TYPE);
+                       if (byte == PT_L1)
+                               p = Tab_L1CLKDis;
+                       else if (byte == PT_M2 || byte == PT_AS)
+                               p = Tab_AM3CLKDis;
+                       else
+                               p = Tab_S1CLKDis;
+
+                       dword = 0;
+                       byte = 0xFF;
+                       while(dword < MAX_CS_SUPPORTED) {
+                               if (pDCTstat->CSPresent & (1<<dword)){
+                                       /* re-enable clocks for the enabled CS */
+                                       val = p[dword];
+                                       byte &= ~val;
+                               }
+                               dword++ ;
+                       }
+                       DramTimingLo |= byte << 24;
+               }
+       }
+
+       printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %x\n", DramControl);
+       printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %x\n", DramTimingLo);
+       printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %x\n", DramConfigMisc);
+       printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %x\n", DramConfigMisc2);
+       printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo: %x\n", DramConfigLo);
+       printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi: %x\n", DramConfigHi);
+
+       /* Write Values to the registers */
+       Set_NB32(dev, 0x78 + reg_off, DramControl);
+       Set_NB32(dev, 0x88 + reg_off, DramTimingLo);
+       Set_NB32(dev, 0xA0 + reg_off, DramConfigMisc);
+       DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, DramConfigMisc2);
+       Set_NB32(dev, 0xA8 + reg_off, DramConfigMisc2);
+       Set_NB32(dev, 0x90 + reg_off, DramConfigLo);
+       ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
+       dword = Get_NB32(dev, 0x94 + reg_off);
+       DramConfigHi |= dword;
+       mct_SetDramConfigHi_D(pDCTstat, dct, DramConfigHi);
+       mct_EarlyArbEn_D(pMCTstat, pDCTstat);
+       mctHookAfterAutoCfg();
+
+       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+       printk(BIOS_DEBUG, "AutoConfig: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "AutoConfig: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "AutoConfig: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "AutoConfig: Done\n\n");
+AutoConfig_exit:
+       return pDCTstat->ErrCode;
+}
+
+static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       /* Set bank addressing, program Mask values and build a chip-select
+        * population map. This routine programs PCI 0:24N:2x80 config register
+        * and PCI 0:24N:2x60,64,68,6C config registers (CS Mask 0-3).
+        */
+       u8 ChipSel, Rows, Cols, Ranks, Banks;
+       u32 BankAddrReg, csMask;
+
+       u32 val;
+       u32 reg;
+       u32 dev;
+       u32 reg_off;
+       u8 byte;
+       u16 word;
+       u32 dword;
+       u16 smbaddr;
+
+       dev = pDCTstat->dev_dct;
+       reg_off = 0x100 * dct;
+
+       BankAddrReg = 0;
+       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel+=2) {
+               byte = ChipSel;
+               if ((pDCTstat->Status & (1 << SB_64MuxedMode)) && ChipSel >=4)
+                       byte -= 3;
+
+               if (pDCTstat->DIMMValid & (1<<byte)) {
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, (ChipSel + dct));
+
+                       byte = mctRead_SPD(smbaddr, SPD_Addressing);
+                       Rows = (byte >> 3) & 0x7; /* Rows:0b=12-bit,... */
+                       Cols = byte & 0x7; /* Cols:0b=9-bit,... */
+
+                       byte = mctRead_SPD(smbaddr, SPD_Density);
+                       Banks = (byte >> 4) & 7; /* Banks:0b=3-bit,... */
+
+                       byte = mctRead_SPD(smbaddr, SPD_Organization);
+                       Ranks = ((byte >> 3) & 7) + 1;
+
+                       /* Configure 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.
+                        */
+                       byte = Cols;
+                       if (Banks == 1)
+                               byte |= 4;
+
+                       byte |= Rows << 3;      /* RRRBCC internal encode */
+
+                       for (dword=0; dword < 13; dword++) {
+                               if (byte == Tab_BankAddr[dword])
+                                       break;
+                       }
+
+                       if (dword > 12)
+                               continue;
+
+                       /* bit no. of CS field in address mapping reg.*/
+                       dword <<= (ChipSel<<1);
+                       BankAddrReg |= dword;
+
+                       /* Mask value=(2pow(rows+cols+banks+3)-1)>>8,
+                          or 2pow(rows+cols+banks-5)-1*/
+                       csMask = 0;
+
+                       byte = Rows + Cols;             /* cl=rows+cols*/
+                       byte += 21;                     /* row:12+col:9 */
+                       byte -= 2;                      /* 3 banks - 5 */
+
+                       if (pDCTstat->Status & (1 << SB_128bitmode))
+                               byte++;         /* double mask size if in 128-bit mode*/
+
+                       csMask |= 1 << byte;
+                       csMask--;
+
+                       /*set ChipSelect population indicator even bits*/
+                       pDCTstat->CSPresent |= (1<<ChipSel);
+                       if (Ranks >= 2)
+                               /*set ChipSelect population indicator odd bits*/
+                               pDCTstat->CSPresent |= 1 << (ChipSel + 1);
+
+                       reg = 0x60+(ChipSel<<1) + reg_off;      /*Dram CS Mask Register */
+                       val = csMask;
+                       val &= 0x1FF83FE0;      /* Mask out reserved bits.*/
+                       Set_NB32(dev, reg, val);
+               } else {
+                       if (pDCTstat->DIMMSPDCSE & (1<<ChipSel))
+                               pDCTstat->CSTestFail |= (1<<ChipSel);
+               }       /* if DIMMValid*/
+       }       /* while ChipSel*/
+
+       SetCSTriState(pMCTstat, pDCTstat, dct);
+       SetCKETriState(pMCTstat, pDCTstat, dct);
+       SetODTTriState(pMCTstat, pDCTstat, dct);
+
+       if (pDCTstat->Status & (1 << SB_128bitmode)) {
+               SetCSTriState(pMCTstat, pDCTstat, 1); /* force dct1) */
+               SetCKETriState(pMCTstat, pDCTstat, 1); /* force dct1) */
+               SetODTTriState(pMCTstat, pDCTstat, 1); /* force dct1) */
+       }
+
+       word = pDCTstat->CSPresent;
+       mctGetCS_ExcludeMap();          /* mask out specified chip-selects */
+       word ^= pDCTstat->CSPresent;
+       pDCTstat->CSTestFail |= word;   /* enable ODT to disabled DIMMs */
+       if (!pDCTstat->CSPresent)
+               pDCTstat->ErrCode = SC_StopError;
+
+       reg = 0x80 + reg_off;           /* Bank Addressing Register */
+       Set_NB32(dev, reg, BankAddrReg);
+
+       pDCTstat->CSPresent_DCT[dct] = pDCTstat->CSPresent;
+       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+       printk(BIOS_DEBUG, "SPDSetBanks: CSPresent %x\n", pDCTstat->CSPresent_DCT[dct]);
+       printk(BIOS_DEBUG, "SPDSetBanks: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "SPDSetBanks: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "SPDSetBanks: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "SPDSetBanks: Done\n\n");
+}
+
+static void SPDCalcWidth_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       /* Per SPDs, 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.
+        */
+       u8 i;
+       u8 smbaddr, smbaddr1;
+       u8 byte, byte1;
+
+       /* Check Symmetry of Channel A and Channel B DIMMs
+         (must be matched for 128-bit mode).*/
+       for (i=0; i < MAX_DIMMS_SUPPORTED; i += 2) {
+               if ((pDCTstat->DIMMValid & (1 << i)) && (pDCTstat->DIMMValid & (1<<(i+1)))) {
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+                       smbaddr1 = Get_DIMMAddress_D(pDCTstat, i+1);
+
+                       byte = mctRead_SPD(smbaddr, SPD_Addressing) & 0x7;
+                       byte1 = mctRead_SPD(smbaddr1, SPD_Addressing) & 0x7;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+
+                       byte =   mctRead_SPD(smbaddr, SPD_Density) & 0x0f;
+                       byte1 =  mctRead_SPD(smbaddr1, SPD_Density) & 0x0f;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+
+                       byte = mctRead_SPD(smbaddr, SPD_Organization) & 0x7;
+                       byte1 = mctRead_SPD(smbaddr1, SPD_Organization) & 0x7;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+
+                       byte = (mctRead_SPD(smbaddr, SPD_Organization) >> 3) & 0x7;
+                       byte1 = (mctRead_SPD(smbaddr1, SPD_Organization) >> 3) & 0x7;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+
+                       byte = mctRead_SPD(smbaddr, SPD_DMBANKS) & 7;    /* #ranks-1 */
+                       byte1 = mctRead_SPD(smbaddr1, SPD_DMBANKS) & 7;   /* #ranks-1 */
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+
+               }
+       }
+
+}
+
+static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       /* Requires that Mask values for each bank be programmed first and that
+        * the chip-select population indicator is correctly set.
+        */
+       u8 b = 0;
+       u32 nxtcsBase, curcsBase;
+       u8 p, q;
+       u32 Sizeq, BiggestBank;
+       u8 _DSpareEn;
+
+       u16 word;
+       u32 dev;
+       u32 reg;
+       u32 reg_off;
+       u32 val;
+
+       dev = pDCTstat->dev_dct;
+       reg_off = 0x100 * dct;
+
+       _DSpareEn = 0;
+
+       /* CS Sparing 1=enabled, 0=disabled */
+       if (mctGet_NVbits(NV_CS_SpareCTL) & 1) {
+               if (MCT_DIMM_SPARE_NO_WARM) {
+                       /* Do no warm-reset DIMM spare */
+                       if (pMCTstat->GStatus & 1 << GSB_EnDIMMSpareNW) {
+                               word = pDCTstat->CSPresent;
+                               val = bsf(word);
+                               word &= ~(1<<val);
+                               if (word)
+                                       /* Make sure at least two chip-selects are available */
+                                       _DSpareEn = 1;
+                               else
+                                       pDCTstat->ErrStatus |= 1 << SB_SpareDis;
+                       }
+               } else {
+                       if (!mctGet_NVbits(NV_DQSTrainCTL)) { /*DQS Training 1=enabled, 0=disabled */
+                               word = pDCTstat->CSPresent;
+                               val = bsf(word);
+                               word &= ~(1 << val);
+                               if (word)
+                                       /* Make sure at least two chip-selects are available */
+                                       _DSpareEn = 1;
+                               else
+                                       pDCTstat->ErrStatus |= 1 << SB_SpareDis;
+                       }
+               }
+       }
+
+       nxtcsBase = 0;          /* Next available cs base ADDR[39:8] */
+       for (p=0; p < MAX_DIMMS_SUPPORTED; p++) {
+               BiggestBank = 0;
+               for (q = 0; q < MAX_CS_SUPPORTED; q++) { /* from DIMMS to CS */
+                       if (pDCTstat->CSPresent & (1 << q)) {  /* bank present? */
+                               reg  = 0x40 + (q << 2) + reg_off;  /* Base[q] reg.*/
+                               val = Get_NB32(dev, reg);
+                               if (!(val & 3)) {       /* (CSEnable|Spare==1)bank is enabled already? */
+                                       reg = 0x60 + (q << 1) + reg_off; /*Mask[q] reg.*/
+                                       val = Get_NB32(dev, reg);
+                                       val >>= 19;
+                                       val++;
+                                       val <<= 19;
+                                       Sizeq = val;  /* never used */
+                                       if (val > BiggestBank) {
+                                               /*Bingo! possibly Map this chip-select next! */
+                                               BiggestBank = val;
+                                               b = q;
+                                       }
+                               }
+                       }       /*if bank present */
+               }       /* while q */
+               if (BiggestBank !=0) {
+                       curcsBase = nxtcsBase;          /* curcsBase=nxtcsBase*/
+                       /* DRAM CS Base b Address Register offset */
+                       reg = 0x40 + (b << 2) + reg_off;
+                       if (_DSpareEn) {
+                               BiggestBank = 0;
+                               val = 1 << Spare;       /* Spare Enable*/
+                       } else {
+                               val = curcsBase;
+                               val |= 1 << CSEnable;   /* Bank Enable */
+                       }
+                       if (((reg - 0x40) >> 2) & 1) {
+                               if (!(pDCTstat->Status & (1 << SB_Registered))) {
+                                       u16  dimValid;
+                                       dimValid = pDCTstat->DIMMValid;
+                                       if (dct & 1)
+                                               dimValid <<= 1;
+                                       if ((dimValid & pDCTstat->MirrPresU_NumRegR) != 0) {
+                                               val |= 1 << onDimmMirror;
+                                       }
+                               }
+                       }
+                       Set_NB32(dev, reg, val);
+                       if (_DSpareEn)
+                               _DSpareEn = 0;
+                       else
+                               /* let nxtcsBase+=Size[b] */
+                               nxtcsBase += BiggestBank;
+               }
+
+               /* bank present but disabled?*/
+               if ( pDCTstat->CSTestFail & (1 << p)) {
+                       /* DRAM CS Base b Address Register offset */
+                       reg = (p << 2) + 0x40 + reg_off;
+                       val = 1 << TestFail;
+                       Set_NB32(dev, reg, val);
+               }
+       }
+
+       if (nxtcsBase) {
+               pDCTstat->DCTSysLimit = nxtcsBase - 1;
+               mct_AfterStitchMemory(pMCTstat, pDCTstat, dct);
+       }
+
+       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+       printk(BIOS_DEBUG, "StitchMemory: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "StitchMemory: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "StitchMemory: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "StitchMemory: Done\n\n");
+}
+
+static u16 Get_Fk_D(u8 k)
+{
+       return Table_F_k[k]; /* FIXME: k or k<<1 ? */
+}
+
+static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       /* Check DIMMs present, verify checksum, flag SDRAM type,
+        * build population indicator bitmaps, and preload bus loading
+        * of DIMMs into DCTStatStruc.
+        * MAAload=number of devices on the "A" bus.
+        * MABload=number of devices on the "B" bus.
+        * MAAdimms=number of DIMMs on the "A" bus slots.
+        * MABdimms=number of DIMMs on the "B" bus slots.
+        * DATAAload=number of ranks on the "A" bus slots.
+        * DATABload=number of ranks on the "B" bus slots.
+        */
+       u16 i, j;
+       u8 smbaddr;
+       u8 SPDCtrl;
+       u16 RegDIMMPresent, MaxDimms;
+       u8 devwidth;
+       u16 DimmSlots;
+       u8 byte = 0, bytex;
+
+       /* preload data structure with addrs */
+       mctGet_DIMMAddr(pDCTstat, pDCTstat->Node_ID);
+
+       DimmSlots = MaxDimms = mctGet_NVbits(NV_MAX_DIMMS);
+
+       SPDCtrl = mctGet_NVbits(NV_SPDCHK_RESTRT);
+
+       RegDIMMPresent = 0;
+       pDCTstat->DimmQRPresent = 0;
+
+       for (i = 0;  i< MAX_DIMMS_SUPPORTED; i++) {
+               if (i >= MaxDimms)
+                       break;
+
+               if ((pDCTstat->DimmQRPresent & (1 << i)) || (i < DimmSlots)) {
+                       int status;
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+                       status = mctRead_SPD(smbaddr, SPD_ByteUse);
+                       if (status >= 0) { /* SPD access is ok */
+                               pDCTstat->DIMMPresent |= 1 << i;
+                               if (crcCheck(smbaddr)) { /* CRC is OK */
+                                       byte = mctRead_SPD(smbaddr, SPD_TYPE);
+                                       if (byte == JED_DDR3SDRAM) {
+                                               /*Dimm is 'Present'*/
+                                               pDCTstat->DIMMValid |= 1 << i;
+                                       }
+                               } else {
+                                       pDCTstat->DIMMSPDCSE = 1 << i;
+                                       if (SPDCtrl == 0) {
+                                               pDCTstat->ErrStatus |= 1 << SB_DIMMChkSum;
+                                               pDCTstat->ErrCode = SC_StopError;
+                                       } else {
+                                               /*if NV_SPDCHK_RESTRT is set to 1, ignore faulty SPD checksum*/
+                                               pDCTstat->ErrStatus |= 1<<SB_DIMMChkSum;
+                                               byte = mctRead_SPD(smbaddr, SPD_TYPE);
+                                               if (byte == JED_DDR3SDRAM)
+                                                       pDCTstat->DIMMValid |= 1 << i;
+                                       }
+                               }
+                               /* Check module type */
+                               byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE) & 0x7;
+                               if (byte == JED_RDIMM || byte == JED_MiniRDIMM)
+                                       RegDIMMPresent |= 1 << i;
+                               /* Check ECC capable */
+                               byte = mctRead_SPD(smbaddr, SPD_BusWidth);
+                               if (byte & JED_ECC) {
+                                       /* DIMM is ECC capable */
+                                       pDCTstat->DimmECCPresent |= 1 << i;
+                               }
+                               /* Check if x4 device */
+                               devwidth = mctRead_SPD(smbaddr, SPD_Organization) & 0x7; /* 0:x4,1:x8,2:x16 */
+                               if (devwidth == 0) {
+                                       /* DIMM is made with x4 or x16 drams */
+                                       pDCTstat->Dimmx4Present |= 1 << i;
+                               } else if (devwidth == 1) {
+                                       pDCTstat->Dimmx8Present |= 1 << i;
+                               } else if (devwidth == 2) {
+                                       pDCTstat->Dimmx16Present |= 1 << i;
+                               }
+
+                               byte = (mctRead_SPD(smbaddr, SPD_Organization) >> 3);
+                               byte &= 7;
+                               if (byte == 3) { /* 4ranks */
+                                       /* if any DIMMs are QR, we have to make two passes through DIMMs*/
+                                       if ( pDCTstat->DimmQRPresent == 0) {
+                                               MaxDimms <<= 1;
+                                       }
+                                       if (i < DimmSlots) {
+                                               pDCTstat->DimmQRPresent |= (1 << i) | (1 << (i+4));
+                                       } else {
+                                               pDCTstat->MAdimms[i & 1] --;
+                                       }
+                                       byte = 1;       /* upper two ranks of QR DIMM will be counted on another DIMM number iteration*/
+                               } else if (byte == 1) { /* 2ranks */
+                                       pDCTstat->DimmDRPresent |= 1 << i;
+                               }
+                               bytex = devwidth;
+                               if (devwidth == 0)
+                                       bytex = 16;
+                               else if (devwidth == 1)
+                                       bytex = 8;
+                               else if (devwidth == 2)
+                                       bytex = 4;
+
+                               byte++;         /* al+1=rank# */
+                               if (byte == 2)
+                                       bytex <<= 1;    /*double Addr bus load value for dual rank DIMMs*/
+
+                               j = i & (1<<0);
+                               pDCTstat->DATAload[j] += byte;  /*number of ranks on DATA bus*/
+                               pDCTstat->MAload[j] += bytex;   /*number of devices on CMD/ADDR bus*/
+                               pDCTstat->MAdimms[j]++;         /*number of DIMMs on A bus */
+
+                               /* check address mirror support for unbuffered dimm */
+                               /* check number of registers on a dimm for registered dimm */
+                               byte = mctRead_SPD(smbaddr, SPD_AddressMirror);
+                               if (RegDIMMPresent & (1 << i)) {
+                                       if ((byte & 3) > 1)
+                                               pDCTstat->MirrPresU_NumRegR |= 1 << i;
+                               } else {
+                                       if ((byte & 1) == 1)
+                                               pDCTstat->MirrPresU_NumRegR |= 1 << i;
+                               }
+                               /* Get byte62: Reference Raw Card information. We dont need it now. */
+                               /* byte = mctRead_SPD(smbaddr, 62); */
+                               /* Get Control word values for RC3. We dont need it. */
+                               byte = mctRead_SPD(smbaddr, 70);
+                               pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); /* C3 = SPD byte 70 [7:4] */
+                               /* Get Control word values for RC4, and RC5 */
+                               byte = mctRead_SPD(smbaddr, 71);
+                               pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 2); /* RC4 = SPD byte 71 [3:0] */
+                               pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); /* RC5 = SPD byte 71 [7:4] */
+                       }
+               }
+       }
+       printk(BIOS_DEBUG, "\t DIMMPresence: DIMMValid=%x\n", pDCTstat->DIMMValid);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DIMMPresent=%x\n", pDCTstat->DIMMPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: RegDIMMPresent=%x\n", RegDIMMPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DimmECCPresent=%x\n", pDCTstat->DimmECCPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DimmPARPresent=%x\n", pDCTstat->DimmPARPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx4Present=%x\n", pDCTstat->Dimmx4Present);
+       printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx8Present=%x\n", pDCTstat->Dimmx8Present);
+       printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx16Present=%x\n", pDCTstat->Dimmx16Present);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DimmPlPresent=%x\n", pDCTstat->DimmPlPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DimmDRPresent=%x\n", pDCTstat->DimmDRPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DimmQRPresent=%x\n", pDCTstat->DimmQRPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DATAload[0]=%x\n", pDCTstat->DATAload[0]);
+       printk(BIOS_DEBUG, "\t DIMMPresence: MAload[0]=%x\n", pDCTstat->MAload[0]);
+       printk(BIOS_DEBUG, "\t DIMMPresence: MAdimms[0]=%x\n", pDCTstat->MAdimms[0]);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DATAload[1]=%x\n", pDCTstat->DATAload[1]);
+       printk(BIOS_DEBUG, "\t DIMMPresence: MAload[1]=%x\n", pDCTstat->MAload[1]);
+       printk(BIOS_DEBUG, "\t DIMMPresence: MAdimms[1]=%x\n", pDCTstat->MAdimms[1]);
+
+       if (pDCTstat->DIMMValid != 0) { /* If any DIMMs are present...*/
+               if (RegDIMMPresent != 0) {
+                       if ((RegDIMMPresent ^ pDCTstat->DIMMValid) !=0) {
+                               /* module type DIMM mismatch (reg'ed, unbuffered) */
+                               pDCTstat->ErrStatus |= 1<<SB_DimmMismatchM;
+                               pDCTstat->ErrCode = SC_StopError;
+                       } else{
+                               /* all DIMMs are registered */
+                               pDCTstat->Status |= 1<<SB_Registered;
+                       }
+               }
+               if (pDCTstat->DimmECCPresent != 0) {
+                       if ((pDCTstat->DimmECCPresent ^ pDCTstat->DIMMValid )== 0) {
+                               /* all DIMMs are ECC capable */
+                               pDCTstat->Status |= 1<<SB_ECCDIMMs;
+                       }
+               }
+               if (pDCTstat->DimmPARPresent != 0) {
+                       if ((pDCTstat->DimmPARPresent ^ pDCTstat->DIMMValid) == 0) {
+                               /*all DIMMs are Parity capable */
+                               pDCTstat->Status |= 1<<SB_PARDIMMs;
+                       }
+               }
+       } else {
+               /* no DIMMs present or no DIMMs that qualified. */
+               pDCTstat->ErrStatus |= 1<<SB_NoDimms;
+               pDCTstat->ErrCode = SC_StopError;
+       }
+
+       printk(BIOS_DEBUG, "\t DIMMPresence: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "\t DIMMPresence: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "\t DIMMPresence: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "\t DIMMPresence: Done\n\n");
+
+       mctHookAfterDIMMpre();
+
+       return pDCTstat->ErrCode;
+}
+
+static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i)
+{
+       u8 *p;
+
+       p = pDCTstat->DIMMAddr;
+       /* mct_BeforeGetDIMMAddress(); */
+       return p[i];
+}
+
+static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+       u8 err_code;
+
+       /* Config. DCT0 for Ganged or unganged mode */
+       DCTInit_D(pMCTstat, pDCTstat, 0);
+       if (pDCTstat->ErrCode == SC_FatalErr) {
+               /* Do nothing goto exitDCTInit; any fatal errors? */
+       } else {
+               /* Configure DCT1 if unganged and enabled*/
+               if (!pDCTstat->GangedMode) {
+                       if ( pDCTstat->DIMMValidDCT[1] > 0) {
+                               err_code = pDCTstat->ErrCode;           /* save DCT0 errors */
+                               pDCTstat->ErrCode = 0;
+                               DCTInit_D(pMCTstat, pDCTstat, 1);
+                               if (pDCTstat->ErrCode == 2)             /* DCT1 is not Running */
+                                       pDCTstat->ErrCode = err_code;   /* Using DCT0 Error code to update pDCTstat.ErrCode */
+                       } else {
+                               val = 1 << DisDramInterface;
+                               Set_NB32(pDCTstat->dev_dct, 0x100 + 0x94, val);
+                       }
+               }
+       }
+/* exitDCTInit: */
+}
+
+static void mct_DramInit(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat);
+       mct_DramInit_Sw_D(pMCTstat, pDCTstat, dct);
+       /* mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct); */
+}
+
+static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u8 byte;
+       u8 bytex;
+       u32 val;
+       u32 reg;
+
+       byte = bytex = pDCTstat->DIMMValid;
+       bytex &= 0x55;          /* CHA DIMM pop */
+       pDCTstat->DIMMValidDCT[0] = bytex;
+
+       byte &= 0xAA;           /* CHB DIMM popa */
+       byte >>= 1;
+       pDCTstat->DIMMValidDCT[1] = byte;
+
+       if (byte != bytex) {
+               pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO);
+       } else {
+               byte = mctGet_NVbits(NV_Unganged);
+               if (byte)
+                       pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO); /* Set temp. to avoid setting of ganged mode */
+
+               if (!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) {
+                       pDCTstat->GangedMode = 1;
+                       /* valid 128-bit mode population. */
+                       pDCTstat->Status |= 1 << SB_128bitmode;
+                       reg = 0x110;
+                       val = Get_NB32(pDCTstat->dev_dct, reg);
+                       val |= 1 << DctGangEn;
+                       Set_NB32(pDCTstat->dev_dct, reg, val);
+               }
+               if (byte)       /* NV_Unganged */
+                       pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); /* Clear so that there is no DIMM missmatch error */
+       }
+       return pDCTstat->ErrCode;
+}
+
+u32 Get_NB32(u32 dev, u32 reg)
+{
+       return pci_read_config32(dev, reg);
+}
+
+void Set_NB32(u32 dev, u32 reg, u32 val)
+{
+       pci_write_config32(dev, reg, val);
+}
+
+
+u32 Get_NB32_index(u32 dev, u32 index_reg, u32 index)
+{
+       u32 dword;
+
+       Set_NB32(dev, index_reg, index);
+       dword = Get_NB32(dev, index_reg+0x4);
+
+       return dword;
+}
+
+void Set_NB32_index(u32 dev, u32 index_reg, u32 index, u32 data)
+{
+       Set_NB32(dev, index_reg, index);
+       Set_NB32(dev, index_reg + 0x4, data);
+}
+
+u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index)
+{
+
+       u32 dword;
+
+
+       index &= ~(1 << DctAccessWrite);
+       Set_NB32(dev, index_reg, index);
+       do {
+               dword = Get_NB32(dev, index_reg);
+       } while (!(dword & (1 << DctAccessDone)));
+       dword = Get_NB32(dev, index_reg + 0x4);
+
+       return dword;
+}
+
+void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 index, u32 data)
+{
+       u32 dword;
+
+
+       Set_NB32(dev, index_reg + 0x4, data);
+       index |= (1 << DctAccessWrite);
+       Set_NB32(dev, index_reg, index);
+       do {
+               dword = Get_NB32(dev, index_reg);
+       } while (!(dword & (1 << DctAccessDone)));
+
+}
+
+static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       /* Get platform specific config/timing values from the interface layer
+        * and program them into DCT.
+        */
+
+       u32 dev = pDCTstat->dev_dct;
+       u32 index_reg;
+       u8 i, i_start, i_end;
+
+       if (pDCTstat->GangedMode) {
+               SyncSetting(pDCTstat);
+               /* mct_SetupSync_D */
+               i_start = 0;
+               i_end = 2;
+       } else {
+               i_start = dct;
+               i_end = dct + 1;
+       }
+       for (i=i_start; i<i_end; i++) {
+               index_reg = 0x98 + (i * 0x100);
+               Set_NB32_index_wait(dev, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
+               Set_NB32_index_wait(dev, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
+       }
+
+       return pDCTstat->ErrCode;
+
+}
+
+static void mct_SyncDCTsReady(struct DCTStatStruc *pDCTstat)
+{
+       u32 dev;
+       u32 val;
+
+       if (pDCTstat->NodePresent) {
+               dev = pDCTstat->dev_dct;
+
+               if ((pDCTstat->DIMMValidDCT[0] ) || (pDCTstat->DIMMValidDCT[1])) {              /* This Node has dram */
+                       do {
+                               val = Get_NB32(dev, 0x110);
+                       } while (!(val & (1 << DramEnabled)));
+               }
+       }       /* Node is present */
+}
+
+static void mct_AfterGetCLT(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       if (!pDCTstat->GangedMode) {
+               if (dct == 0 ) {
+                       pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
+                       if (pDCTstat->DIMMValidDCT[dct] == 0)
+                               pDCTstat->ErrCode = SC_StopError;
+               } else {
+                       pDCTstat->CSPresent = 0;
+                       pDCTstat->CSTestFail = 0;
+                       pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
+                       if (pDCTstat->DIMMValidDCT[dct] == 0)
+                               pDCTstat->ErrCode = SC_StopError;
+               }
+       }
+}
+
+static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 ret;
+       u32 val;
+
+       if ( dct == 0) {
+               SPDCalcWidth_D(pMCTstat, pDCTstat);
+               ret = mct_setMode(pMCTstat, pDCTstat);
+       } else {
+               ret = pDCTstat->ErrCode;
+       }
+
+       if (pDCTstat->DIMMValidDCT[0] == 0) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94);
+               val |= 1 << DisDramInterface;
+               Set_NB32(pDCTstat->dev_dct, 0x94, val);
+       }
+       if (pDCTstat->DIMMValidDCT[1] == 0) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+               val |= 1 << DisDramInterface;
+               Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+       }
+
+       printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "SPDCalcWidth: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "SPDCalcWidth: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "SPDCalcWidth: Done\n");
+       /* Disable dram interface before DRAM init */
+
+       return ret;
+}
+
+static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 val;
+       u32 dword;
+       u32 dev;
+       u32 reg;
+       u8 _MemHoleRemap;
+       u32 DramHoleBase;
+
+       _MemHoleRemap = mctGet_NVbits(NV_MemHole);
+       DramHoleBase = mctGet_NVbits(NV_BottomIO);
+       DramHoleBase <<= 8;
+       /* Increase hole size so;[31:24]to[31:16]
+        * it has granularity of 128MB shl eax,8
+        * Set 'effective' bottom IOmov DramHoleBase,eax
+        */
+       pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
+
+       /* In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */
+       if (!pDCTstat->GangedMode) {
+               dev = pDCTstat->dev_dct;
+               pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit;
+               /* if DCT0 and DCT1 both exist, set DctSelBaseAddr[47:27] to the top of DCT0 */
+               if (dct == 0) {
+                       if (pDCTstat->DIMMValidDCT[1] > 0) {
+                               dword = pDCTstat->DCTSysLimit + 1;
+                               dword += pDCTstat->NodeSysBase;
+                               dword >>= 8; /* scale [39:8] to [47:27],and to F2x110[31:11] */
+                               if ((dword >= DramHoleBase) && _MemHoleRemap) {
+                                       pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
+                                       val = pMCTstat->HoleBase;
+                                       val >>= 16;
+                                       val = (((~val) & 0xFF) + 1);
+                                       val <<= 8;
+                                       dword += val;
+                               }
+                               reg = 0x110;
+                               val = Get_NB32(dev, reg);
+                               val &= 0x7F;
+                               val |= dword;
+                               val |= 3;  /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */
+                               Set_NB32(dev, reg, val);
+
+                               reg = 0x114;
+                               val = dword;
+                               Set_NB32(dev, reg, val);
+                       }
+               } else {
+                       /* Program the DctSelBaseAddr value to 0
+                          if DCT 0 is disabled */
+                       if (pDCTstat->DIMMValidDCT[0] == 0) {
+                               dword = pDCTstat->NodeSysBase;
+                               dword >>= 8;
+                               if ((dword >= DramHoleBase) && _MemHoleRemap) {
+                                       pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
+                                       val = pMCTstat->HoleBase;
+                                       val >>= 8;
+                                       val &= ~(0xFFFF);
+                                       val |= (((~val) & 0xFFFF) + 1);
+                                       dword += val;
+                               }
+                               reg = 0x114;
+                               val = dword;
+                               Set_NB32(dev, reg, val);
+
+                               reg = 0x110;
+                               val |= 3;       /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */
+                               Set_NB32(dev, reg, val);
+                       }
+               }
+       } else {
+               pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit;
+       }
+       printk(BIOS_DEBUG, "AfterStitch pDCTstat->NodeSysBase = %x\n", pDCTstat->NodeSysBase);
+       printk(BIOS_DEBUG, "mct_AfterStitchMemory: pDCTstat->NodeSysLimit = %x\n", pDCTstat->NodeSysLimit);
+}
+
+static u8 mct_DIMMPresence(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 ret;
+
+       if ( dct == 0)
+               ret = DIMMPresence_D(pMCTstat, pDCTstat);
+       else
+               ret = pDCTstat->ErrCode;
+
+       return ret;
+}
+
+/* mct_BeforeGetDIMMAddress inline in C */
+
+static void mct_OtherTiming(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               if (pDCTstat->NodePresent) {
+                       if (pDCTstat->DIMMValidDCT[0]) {
+                               pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[0];
+                               Set_OtherTiming(pMCTstat, pDCTstat, 0);
+                       }
+                       if (pDCTstat->DIMMValidDCT[1] && !pDCTstat->GangedMode ) {
+                               pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[1];
+                               Set_OtherTiming(pMCTstat, pDCTstat, 1);
+                       }
+               }       /* Node is present*/
+       }       /* while Node */
+}
+
+static void Set_OtherTiming(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 reg;
+       u32 reg_off = 0x100 * dct;
+       u32 val;
+       u32 dword;
+       u32 dev = pDCTstat->dev_dct;
+
+       Get_DqsRcvEnGross_Diff(pDCTstat, dev, 0x98 + reg_off);
+       Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98 + reg_off);
+       Get_Trdrd(pMCTstat, pDCTstat, dct);
+       Get_Twrwr(pMCTstat, pDCTstat, dct);
+       Get_Twrrd(pMCTstat, pDCTstat, dct);
+       Get_TrwtTO(pMCTstat, pDCTstat, dct);
+       Get_TrwtWB(pMCTstat, pDCTstat);
+
+       reg = 0x8C + reg_off;           /* Dram Timing Hi */
+       val = Get_NB32(dev, reg);
+       val &= 0xffff0300;
+       dword = pDCTstat->TrwtTO;
+       val |= dword << 4;
+       dword = pDCTstat->Twrrd & 3;
+       val |= dword << 10;
+       dword = pDCTstat->Twrwr & 3;
+       val |= dword << 12;
+       dword = pDCTstat->Trdrd & 3;
+       val |= dword << 14;
+       dword = pDCTstat->TrwtWB;
+       val |= dword;
+       Set_NB32(dev, reg, val);
+
+       reg = 0x78 + reg_off;
+       val = Get_NB32(dev, reg);
+       val &= 0xFFFFC0FF;
+       dword = pDCTstat->Twrrd >> 2;
+       val |= dword << 8;
+       dword = pDCTstat->Twrwr >> 2;
+       val |= dword << 10;
+       dword = pDCTstat->Trdrd >> 2;
+       val |= dword << 12;
+       Set_NB32(dev, reg, val);
+}
+
+static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       int8_t Trdrd;
+
+       Trdrd = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - pDCTstat->DqsRcvEnGrossMin) >> 1) + 1;
+       if (Trdrd > 8)
+               Trdrd = 8;
+       pDCTstat->Trdrd = Trdrd;
+}
+
+static void Get_Twrwr(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       int8_t Twrwr = 0;
+
+       Twrwr = ((int8_t)(pDCTstat->WrDatGrossMax - pDCTstat->WrDatGrossMin) >> 1) + 2;
+
+       if (Twrwr < 2)
+               Twrwr = 2;
+       else if (Twrwr > 9)
+               Twrwr = 9;
+
+       pDCTstat->Twrwr = Twrwr;
+}
+
+static void Get_Twrrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 LDplus1;
+       int8_t Twrrd;
+
+       LDplus1 = Get_Latency_Diff(pMCTstat, pDCTstat, dct);
+
+       Twrrd = ((int8_t)(pDCTstat->WrDatGrossMax - pDCTstat->DqsRcvEnGrossMin) >> 1) + 4 - LDplus1;
+
+       if (Twrrd < 2)
+               Twrrd = 2;
+       else if (Twrrd > 10)
+               Twrrd = 10;
+       pDCTstat->Twrrd = Twrrd;
+}
+
+static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 LDplus1;
+       int8_t TrwtTO;
+
+       LDplus1 = Get_Latency_Diff(pMCTstat, pDCTstat, dct);
+
+       TrwtTO = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - pDCTstat->WrDatGrossMin) >> 1) + LDplus1;
+
+       pDCTstat->TrwtTO = TrwtTO;
+}
+
+static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat)
+{
+       /* TrwtWB ensures read-to-write data-bus turnaround.
+          This value should be one more than the programmed TrwtTO.*/
+       pDCTstat->TrwtWB = pDCTstat->TrwtTO;
+}
+
+static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+                          struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 reg_off =  0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val1, val2;
+
+       val1 = Get_NB32(dev, reg_off + 0x88) & 0xF;
+       val2 = (Get_NB32(dev, reg_off + 0x84) >> 20) & 7;
+
+       return val1 - val2;
+}
+
+static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
+                                       u32 dev, u32 index_reg)
+{
+       u8 Smallest, Largest;
+       u32 val;
+       u8 byte, bytex;
+
+       /* The largest DqsRcvEnGrossDelay of any DIMM minus the
+          DqsRcvEnGrossDelay of any other DIMM is equal to the Critical
+          Gross Delay Difference (CGDD) */
+       /* DqsRcvEn byte 1,0 */
+       val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x10);
+       Largest = val & 0xFF;
+       Smallest = (val >> 8) & 0xFF;
+
+       /* DqsRcvEn byte 3,2 */
+       val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x11);
+       byte = val & 0xFF;
+       bytex = (val >> 8) & 0xFF;
+       if (bytex < Smallest)
+               Smallest = bytex;
+       if (byte > Largest)
+               Largest = byte;
+
+       /* DqsRcvEn byte 5,4 */
+       val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x20);
+       byte = val & 0xFF;
+       bytex = (val >> 8) & 0xFF;
+       if (bytex < Smallest)
+               Smallest = bytex;
+       if (byte > Largest)
+               Largest = byte;
+
+       /* DqsRcvEn byte 7,6 */
+       val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x21);
+       byte = val & 0xFF;
+       bytex = (val >> 8) & 0xFF;
+       if (bytex < Smallest)
+               Smallest = bytex;
+       if (byte > Largest)
+               Largest = byte;
+
+       if (pDCTstat->DimmECCPresent> 0) {
+               /*DqsRcvEn Ecc */
+               val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x12);
+               byte = val & 0xFF;
+               bytex = (val >> 8) & 0xFF;
+               if (bytex < Smallest)
+                       Smallest = bytex;
+               if (byte > Largest)
+                       Largest = byte;
+       }
+
+       pDCTstat->DqsRcvEnGrossMax = Largest;
+       pDCTstat->DqsRcvEnGrossMin = Smallest;
+}
+
+static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat,
+                                       u8 dct, u32 dev, u32 index_reg)
+{
+       u8 Smallest, Largest;
+       u32 val;
+       u8 byte, bytex;
+
+       /* The largest WrDatGrossDlyByte of any DIMM minus the
+         WrDatGrossDlyByte of any other DIMM is equal to CGDD */
+       if (pDCTstat->DIMMValid & (1 << 0)) {
+               val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x01);       /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM0 */
+               Largest = val & 0xFF;
+               Smallest = (val >> 8) & 0xFF;
+       }
+       if (pDCTstat->DIMMValid & (1 << 2)) {
+               val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x101);      /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM1 */
+               byte = val & 0xFF;
+               bytex = (val >> 8) & 0xFF;
+               if (bytex < Smallest)
+                       Smallest = bytex;
+               if (byte > Largest)
+                       Largest = byte;
+       }
+
+       /* If Cx, 2 more dimm need to be checked to find out the largest and smallest */
+       if (pDCTstat->LogicalCPUID & AMD_DR_Cx) {
+               if (pDCTstat->DIMMValid & (1 << 4)) {
+                       val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x201);      /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM2 */
+                       byte = val & 0xFF;
+                       bytex = (val >> 8) & 0xFF;
+                       if (bytex < Smallest)
+                               Smallest = bytex;
+                       if (byte > Largest)
+                               Largest = byte;
+               }
+               if (pDCTstat->DIMMValid & (1 << 6)) {
+                       val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x301);      /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM2 */
+                       byte = val & 0xFF;
+                       bytex = (val >> 8) & 0xFF;
+                       if (bytex < Smallest)
+                               Smallest = bytex;
+                       if (byte > Largest)
+                               Largest = byte;
+               }
+       }
+
+       pDCTstat->WrDatGrossMax = Largest;
+       pDCTstat->WrDatGrossMin = Smallest;
+}
+
+static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
+                                       u32 dev, u32 index_reg,
+                                       u32 index)
+{
+       u8 Smallest, Largest;
+       u8 i;
+       u8 byte;
+       u32 val;
+       u16 word;
+       u8 ecc_reg = 0;
+
+       Smallest = 7;
+       Largest = 0;
+
+       if (index == 0x12)
+               ecc_reg = 1;
+
+       for (i=0; i < 8; i+=2) {
+               if ( pDCTstat->DIMMValid & (1 << i)) {
+                       val = Get_NB32_index_wait(dev, index_reg, index);
+                       val &= 0x00E000E0;
+                       byte = (val >> 5) & 0xFF;
+                       if (byte < Smallest)
+                               Smallest = byte;
+                       if (byte > Largest)
+                               Largest = byte;
+                       if (!(ecc_reg)) {
+                               byte = (val >> (16 + 5)) & 0xFF;
+                               if (byte < Smallest)
+                                       Smallest = byte;
+                               if (byte > Largest)
+                                       Largest = byte;
+                       }
+               }
+       index += 3;
+       }       /* while ++i */
+
+       word = Smallest;
+       word <<= 8;
+       word |= Largest;
+
+       return word;
+}
+
+static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat,
+                                       u8 dct, u32 dev, u32 index_reg,
+                                       u32 index)
+{
+       u8 Smallest, Largest;
+       u8 i, j;
+       u32 val;
+       u8 byte;
+       u16 word;
+
+       Smallest = 3;
+       Largest = 0;
+       for (i=0; i < 2; i++) {
+               val = Get_NB32_index_wait(dev, index_reg, index);
+               val &= 0x60606060;
+               val >>= 5;
+               for (j=0; j < 4; j++) {
+                       byte = val & 0xFF;
+                       if (byte < Smallest)
+                               Smallest = byte;
+                       if (byte > Largest)
+                               Largest = byte;
+                       val >>= 8;
+               }       /* while ++j */
+               index++;
+       }       /*while ++i*/
+
+       if (pDCTstat->DimmECCPresent > 0) {
+               index++;
+               val = Get_NB32_index_wait(dev, index_reg, index);
+               val &= 0x00000060;
+               val >>= 5;
+               byte = val & 0xFF;
+               if (byte < Smallest)
+                       Smallest = byte;
+               if (byte > Largest)
+                       Largest = byte;
+       }
+
+       word = Smallest;
+       word <<= 8;
+       word |= Largest;
+
+       return word;
+}
+
+static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       mct_ClrClToNB_D(pMCTstat, pDCTstat);
+       mct_ClrWbEnhWsbDis_D(pMCTstat, pDCTstat);
+}
+
+static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
+{
+       mct_SetClToNB_D(pMCTstat, pDCTstat);
+       mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
+}
+
+static u32 mct_NodePresent_D(void)
+{
+       u32 val;
+       val = 0x12001022;
+       return val;
+}
+
+static void mct_init(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat)
+{
+       u32 lo, hi;
+       u32 addr;
+
+       pDCTstat->GangedMode = 0;
+       pDCTstat->DRPresent = 1;
+
+       /* enable extend PCI configuration access */
+       addr = 0xC001001F;
+       _RDMSR(addr, &lo, &hi);
+       if (hi & (1 << (46-32))) {
+               pDCTstat->Status |= 1 << SB_ExtConfig;
+       } else {
+               hi |= 1 << (46-32);
+               _WRMSR(addr, lo, hi);
+       }
+}
+
+static void clear_legacy_Mode(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u32 reg;
+       u32 val;
+       u32 dev = pDCTstat->dev_dct;
+
+       /* Clear Legacy BIOS Mode bit */
+       reg = 0x94;
+       val = Get_NB32(dev, reg);
+       val &= ~(1<<LegacyBiosMode);
+       Set_NB32(dev, reg, val);
+
+       reg = 0x94 + 0x100;
+       val = Get_NB32(dev, reg);
+       val &= ~(1<<LegacyBiosMode);
+       Set_NB32(dev, reg, val);
+}
+
+static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+       u32 Drambase, Dramlimit;
+       u32 val;
+       u32 reg;
+       u32 dev;
+       u32 devx;
+       u32 dword;
+       struct DCTStatStruc *pDCTstat;
+
+       pDCTstat = pDCTstatA + 0;
+       dev = pDCTstat->dev_map;
+
+       /* Copy dram map from F1x40/44,F1x48/4c,
+         to F1x120/124(Node0),F1x120/124(Node1),...*/
+       for (Node=0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               devx = pDCTstat->dev_map;
+
+               /* get base/limit from Node0 */
+               reg = 0x40 + (Node << 3);               /* Node0/Dram Base 0 */
+               val = Get_NB32(dev, reg);
+               Drambase = val >> ( 16 + 3);
+
+               reg = 0x44 + (Node << 3);               /* Node0/Dram Base 0 */
+               val = Get_NB32(dev, reg);
+               Dramlimit = val >> (16 + 3);
+
+               /* set base/limit to F1x120/124 per Node */
+               if (pDCTstat->NodePresent) {
+                       reg = 0x120;            /* F1x120,DramBase[47:27] */
+                       val = Get_NB32(devx, reg);
+                       val &= 0xFFE00000;
+                       val |= Drambase;
+                       Set_NB32(devx, reg, val);
+
+                       reg = 0x124;
+                       val = Get_NB32(devx, reg);
+                       val &= 0xFFE00000;
+                       val |= Dramlimit;
+                       Set_NB32(devx, reg, val);
+
+                       if ( pMCTstat->GStatus & ( 1 << GSB_HWHole)) {
+                               reg = 0xF0;
+                               val = Get_NB32(devx, reg);
+                               val |= (1 << DramMemHoistValid);
+                               val &= ~(0xFF << 24);
+                               dword = (pMCTstat->HoleBase >> (24 - 8)) & 0xFF;
+                               dword <<= 24;
+                               val |= dword;
+                               Set_NB32(devx, reg, val);
+                       }
+
+               }
+       }
+}
+
+static void SetCSTriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 val;
+       u32 dev = pDCTstat->dev_dct;
+       u32 index_reg = 0x98 + 0x100 * dct;
+       u32 index;
+       u16 word;
+
+       /* Tri-state unused chipselects when motherboard
+          termination is available */
+
+       /* FIXME: skip for Ax */
+
+       word = pDCTstat->CSPresent;
+       if (pDCTstat->Status & (1 << SB_Registered)) {
+               word |= (word & 0x55) << 1;
+       }
+       word = (~word) & 0xFF;
+       index  = 0x0c;
+       val = Get_NB32_index_wait(dev, index_reg, index);
+       val |= word;
+       Set_NB32_index_wait(dev, index_reg, index, val);
+}
+
+static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 val;
+       u32 dev;
+       u32 index_reg = 0x98 + 0x100 * dct;
+       u32 index;
+       u16 word;
+
+       /* Tri-state unused CKEs when motherboard termination is available */
+
+       /* FIXME: skip for Ax */
+
+       dev = pDCTstat->dev_dct;
+       word = pDCTstat->CSPresent;
+
+       index  = 0x0c;
+       val = Get_NB32_index_wait(dev, index_reg, index);
+       if ((word & 0x55) == 0)
+               val |= 1 << 12;
+
+       if ((word & 0xAA) == 0)
+               val |= 1 << 13;
+
+       Set_NB32_index_wait(dev, index_reg, index, val);
+}
+
+static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 val;
+       u32 dev;
+       u32 index_reg = 0x98 + 0x100 * dct;
+       u8 cs;
+       u32 index;
+       u8 odt;
+       u8 max_dimms;
+
+       /* FIXME: skip for Ax */
+
+       dev = pDCTstat->dev_dct;
+
+       /* Tri-state unused ODTs when motherboard termination is available */
+       max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
+       odt = 0x0F;     /* ODT tri-state setting */
+
+       if (pDCTstat->Status & (1 <<SB_Registered)) {
+               for (cs = 0; cs < 8; cs += 2) {
+                       if (pDCTstat->CSPresent & (1 << cs)) {
+                               odt &= ~(1 << (cs / 2));
+                               if (mctGet_NVbits(NV_4RANKType) != 0) { /* quad-rank capable platform */
+                                       if (pDCTstat->CSPresent & (1 << (cs + 1)))
+                                               odt &= ~(4 << (cs / 2));
+                               }
+                       }
+               }
+       } else {                /* AM3 package */
+               val = ~(pDCTstat->CSPresent);
+               odt = val & 9;  /* swap bits 1 and 2 */
+               if (val & (1 << 1))
+                       odt |= 1 << 2;
+               if (val & (1 << 2))
+                       odt |= 1 << 1;
+       }
+
+       index  = 0x0C;
+       val = Get_NB32_index_wait(dev, index_reg, index);
+       val |= ((odt & 0xFF) << 8);     /* set bits 11:8 ODTTriState[3:0] */
+       Set_NB32_index_wait(dev, index_reg, index, val);
+
+}
+
+static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 i;
+       u32 index_reg = 0x98 + 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+       u32 valx = 0;
+       u32 dword;
+       const u8 *p;
+
+       val = Get_NB32_index_wait(dev, index_reg, 0x00);
+       dword = 0;
+       for (i=0; i < 6; i++) {
+               switch (i) {
+                       case 0:
+                       case 4:
+                               p = Table_Comp_Rise_Slew_15x;
+                               valx = p[(val >> 16) & 3];
+                               break;
+                       case 1:
+                       case 5:
+                               p = Table_Comp_Fall_Slew_15x;
+                               valx = p[(val >> 16) & 3];
+                               break;
+                       case 2:
+                               p = Table_Comp_Rise_Slew_20x;
+                               valx = p[(val >> 8) & 3];
+                               break;
+                       case 3:
+                               p = Table_Comp_Fall_Slew_20x;
+                               valx = p[(val >> 8) & 3];
+                               break;
+
+               }
+               dword |= valx << (5 * i);
+       }
+
+       /* Override/Exception */
+       if (!pDCTstat->GangedMode) {
+               i = 0; /* use i for the dct setting required */
+               if (pDCTstat->MAdimms[0] < 4)
+                       i = 1;
+               if (((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) && (pDCTstat->MAdimms[i] == 4))
+                       dword &= 0xF18FFF18;
+                       index_reg = 0x98;       /* force dct = 0 */
+       }
+
+       Set_NB32_index_wait(dev, index_reg, 0x0a, dword);
+}
+
+static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u32 reg;
+       u32 val;
+       u32 dev = pDCTstat->dev_dct;
+
+       /* GhEnhancement #18429 modified by askar: For low NB CLK :
+        * Memclk ratio, the DCT may need to arbitrate early to avoid
+        * unnecessary bubbles.
+        * bit 19 of F2x[1,0]78 Dram  Control Register, set this bit only when
+        * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 (inclusive)
+        */
+       reg = 0x78;
+       val = Get_NB32(dev, reg);
+
+       if (pDCTstat->LogicalCPUID & (AMD_DR_Bx | AMD_DR_Cx))
+               val |= (1 << EarlyArbEn);
+       else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
+               val |= (1 << EarlyArbEn);
+
+       Set_NB32(dev, reg, val);
+}
+
+static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u32 reg;
+       u32 val;
+       u32 tmp;
+       u32 rem;
+       u32 dev = pDCTstat->dev_dct;
+       u32  hi, lo;
+       u8 NbDid = 0;
+
+       /* Check if NB COF >= 4*Memclk, if it is not, return a fatal error
+        */
+
+       /* 3*(Fn2xD4[NBFid]+4)/(2^NbDid)/(3+Fn2x94[MemClkFreq]) */
+       _RDMSR(0xC0010071, &lo, &hi);
+       if (lo & (1 << 22))
+               NbDid |= 1;
+
+       reg = 0x94;
+       val = Get_NB32(dev, reg);
+       if (!(val & (1 << MemClkFreqVal)))
+               val = Get_NB32(dev, reg + 0x100);       /* get the DCT1 value */
+
+       val &= 0x07;
+       val += 3;
+       if (NbDid)
+               val <<= 1;
+       tmp = val;
+
+       dev = pDCTstat->dev_nbmisc;
+       reg = 0xD4;
+       val = Get_NB32(dev, reg);
+       val &= 0x1F;
+       val += 3;
+       val *= 3;
+       val = val / tmp;
+       rem = val % tmp;
+       tmp >>= 1;
+
+       /* Yes this could be nicer but this was how the asm was.... */
+       if (val < 3) {                          /* NClk:MemClk < 3:1 */
+               return 0;
+       } else if (val > 4) {                   /* NClk:MemClk >= 5:1 */
+               return 0;
+       } else if ((val == 4) && (rem > tmp)) { /* NClk:MemClk > 4.5:1 */
+               return 0;
+       } else {
+               return 1;                       /* 3:1 <= NClk:MemClk <= 4.5:1*/
+       }
+}
+
+static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+       u32 i;
+       struct DCTStatStruc *pDCTstat;
+       u32 start, stop;
+       u8 *p;
+       u16 host_serv1, host_serv2;
+
+       /* Initialize Data structures by clearing all entries to 0 */
+       p = (u8 *) pMCTstat;
+       for (i = 0; i < sizeof(struct MCTStatStruc); i++) {
+               p[i] = 0;
+       }
+
+       for (Node = 0; Node < 8; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               host_serv1 = pDCTstat->HostBiosSrvc1;
+               host_serv2 = pDCTstat->HostBiosSrvc2;
+
+               p = (u8 *) pDCTstat;
+               start = 0;
+               stop = ((u32) &((struct DCTStatStruc *)0)->CH_MaxRdLat[2]);
+               for (i = start; i < stop ; i++) {
+                       p[i] = 0;
+               }
+
+               start = ((u32) &((struct DCTStatStruc *)0)->CH_D_BC_RCVRDLY[2][4]);
+               stop = sizeof(struct DCTStatStruc);
+               for (i = start; i < stop; i++) {
+                       p[i] = 0;
+               }
+               pDCTstat->HostBiosSrvc1 = host_serv1;
+               pDCTstat->HostBiosSrvc2 = host_serv2;
+       }
+}
+
+static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u8 i;
+       u32 reg_off, dword;
+       u32 dev = pDCTstat->dev_dct;
+
+       if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+               if ((pDCTstat->Speed == 3))
+                       dword = 0x00000800;
+               else
+                       dword = 0x00000000;
+               for (i=0; i < 2; i++) {
+                       reg_off = 0x100 * i;
+                       Set_NB32(dev,  0x98 + reg_off, 0x0D000030);
+                       Set_NB32(dev,  0x9C + reg_off, dword);
+                       Set_NB32(dev,  0x98 + reg_off, 0x4D040F30);
+               }
+       }
+}
+
+static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+
+       /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
+       if (pDCTstat->LogicalCPUID & (AMD_DA_C2 | AMD_RB_C3)) {
+               Set_NB32(dev,  0x9C + reg_off, 0x1c);
+               Set_NB32(dev,  0x98 + reg_off, 0x4D0FE006);
+               Set_NB32(dev,  0x9C + reg_off, 0x13d);
+               Set_NB32(dev,  0x98 + reg_off, 0x4D0FE007);
+       }
+
+       return DramConfigLo | /* DisDllShutdownSR */ 1 << 27;
+}
+
+void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat)
+{
+       u32 lo, hi;
+       u32 msr;
+
+       /* FIXME: Maybe check the CPUID? - not for now. */
+       /* pDCTstat->LogicalCPUID; */
+
+       msr = BU_CFG2;
+       _RDMSR(msr, &lo, &hi);
+       lo |= 1 << ClLinesToNbDis;
+       _WRMSR(msr, lo, hi);
+}
+
+void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat)
+{
+
+       u32 lo, hi;
+       u32 msr;
+
+       /* FIXME: Maybe check the CPUID? - not for now. */
+       /* pDCTstat->LogicalCPUID; */
+
+       msr = BU_CFG2;
+       _RDMSR(msr, &lo, &hi);
+       if (!pDCTstat->ClToNB_flag)
+               lo &= ~(1<<ClLinesToNbDis);
+       _WRMSR(msr, lo, hi);
+
+}
+
+void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u32 lo, hi;
+       u32 msr;
+
+       /* FIXME: Maybe check the CPUID? - not for now. */
+       /* pDCTstat->LogicalCPUID; */
+
+       msr = BU_CFG;
+       _RDMSR(msr, &lo, &hi);
+       hi |= (1 << WbEnhWsbDis_D);
+       _WRMSR(msr, lo, hi);
+}
+
+void mct_ClrWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u32 lo, hi;
+       u32 msr;
+
+       /* FIXME: Maybe check the CPUID? - not for now. */
+       /* pDCTstat->LogicalCPUID; */
+
+       msr = BU_CFG;
+       _RDMSR(msr, &lo, &hi);
+       hi &= ~(1 << WbEnhWsbDis_D);
+       _WRMSR(msr, lo, hi);
+}
+
+static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dimm)
+{
+       u8 DimmsInstalled = dimm;
+       u32 DramTermDyn = 0;
+       u8 Speed = pDCTstat->Speed;
+
+       if (mctGet_NVbits(NV_MAX_DIMMS) == 4) {
+               if (pDCTstat->CSPresent & 0xF0) {
+                       if (DimmsInstalled == 1)
+                               if (Speed == 7)
+                                       DramTermDyn |= 1 << 10;
+                               else
+                                       DramTermDyn |= 1 << 11;
+                       else
+                               if (Speed == 4)
+                                       DramTermDyn |= 1 << 11;
+                               else
+                                       DramTermDyn |= 1 << 10;
+               } else {
+                       if (DimmsInstalled != 1) {
+                               if (Speed == 7)
+                                       DramTermDyn |= 1 << 10;
+                               else
+                                       DramTermDyn |= 1 << 11;
+                       }
+               }
+       } else {
+               if (DimmsInstalled != 1)
+                       DramTermDyn |= 1 << 11;
+       }
+       return DramTermDyn;
+}
+
+void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 DramMRS, dword;
+       u8 byte;
+
+       DramMRS = 0;
+
+       /* Set chip select CKE control mode */
+       if (mctGet_NVbits(NV_CKE_CTL)) {
+               if (pDCTstat->CSPresent == 3) {
+                       u16 word;
+                       word = pDCTstat->DIMMSPDCSE;
+                       if (dct == 0)
+                               word &= 0b01010100;
+                       else
+                               word &= 0b10101000;
+                       if (word == 0)
+                               DramMRS |= 1 << 23;
+               }
+       }
+       /*
+        DRAM MRS Register
+        DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
+       */
+       DramMRS |= 1 << 2;
+       /* Dram nominal termination: */
+       byte = pDCTstat->MAdimms[dct];
+       if (!(pDCTstat->Status & (1 << SB_Registered))) {
+               DramMRS |= 1 << 7; /* 60 ohms */
+               if (byte & 2) {
+                       if (pDCTstat->Speed < 6)
+                               DramMRS |= 1 << 8; /* 40 ohms */
+                       else
+                               DramMRS |= 1 << 9; /* 30 ohms */
+               }
+       }
+       /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
+       if (!(pDCTstat->Status & (1 << SB_Registered))) {
+               if (byte >= 2) {
+                       if (pDCTstat->Speed == 7)
+                               DramMRS |= 1 << 10;
+                       else
+                               DramMRS |= 1 << 11;
+               }
+       } else {
+               DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, byte);
+       }
+
+       /* burst length control */
+       if (pDCTstat->Status & (1 << SB_128bitmode))
+               DramMRS |= 1 << 1;
+       /* Qoff=0, output buffers enabled */
+       /* Tcwl */
+       DramMRS |= (pDCTstat->Speed - 4) << 20;
+       /* ASR=1, auto self refresh */
+       /* SRT=0 */
+       DramMRS |= 1 << 18;
+
+       dword = Get_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84);
+       dword &= ~0x00FC2F8F;
+       dword |= DramMRS;
+       Set_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84, dword);
+}
+
+void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct,
+                               u32 DramConfigHi)
+{
+       /* Bug#15114: Comp. update interrupted by Freq. change can cause
+        * subsequent update to be invalid during any MemClk frequency change:
+        * Solution: From the bug report:
+        *  1. A software-initiated frequency change should be wrapped into the
+        *     following sequence :
+        *      - a) Disable Compensation (F2[1, 0]9C_x08[30] )
+        *      b) Reset the Begin Compensation bit (D3CMP->COMP_CONFIG[0]) in all the compensation engines
+        *      c) Do frequency change
+        *      d) Enable Compensation (F2[1, 0]9C_x08[30] )
+        *  2. A software-initiated Disable Compensation should always be
+        *     followed by step b) of the above steps.
+        * Silicon Status: Fixed In Rev B0
+        *
+        * Errata#177: DRAM Phy Automatic Compensation Updates May Be Invalid
+        * Solution: BIOS should disable the phy automatic compensation prior
+        * to initiating a memory clock frequency change as follows:
+        *  1. Disable PhyAutoComp by writing 1'b1 to F2x[1, 0]9C_x08[30]
+        *  2. Reset the Begin Compensation bits by writing 32'h0 to
+        *     F2x[1, 0]9C_x4D004F00
+        *  3. Perform frequency change
+        *  4. Enable PhyAutoComp by writing 1'b0 to F2x[1, 0]9C_08[30]
+        *  In addition, any time software disables the automatic phy
+        *   compensation it should reset the begin compensation bit per step 2.
+        *   Silicon Status: Fixed in DR-B0
+        */
+
+       u32 dev = pDCTstat->dev_dct;
+       u32 index_reg = 0x98 + 0x100 * dct;
+       u32 index;
+
+       u32 val;
+
+       index = 0x08;
+       val = Get_NB32_index_wait(dev, index_reg, index);
+       if (!(val & (1 << DisAutoComp)))
+               Set_NB32_index_wait(dev, index_reg, index, val | (1 << DisAutoComp));
+
+       mct_Wait(100);
+
+       Set_NB32(dev, 0x94 + 0x100 * dct, DramConfigHi);
+}
+
+static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+       struct DCTStatStruc *pDCTstat;
+
+       /* Errata 178
+        *
+        * Bug#15115: Uncertainty In The Sync Chain Leads To Setup Violations
+        *            In TX FIFO
+        * Solution: BIOS should program DRAM Control Register[RdPtrInit] =
+        *            5h, (F2x[1, 0]78[3:0] = 5h).
+        * Silicon Status: Fixed In Rev B0
+        *
+        * Bug#15880: Determine validity of reset settings for DDR PHY timing.
+        * Solutiuon: At least, set WrDqs fine delay to be 0 for DDR3 training.
+        */
+       for (Node = 0; Node < 8; Node++) {
+               pDCTstat = pDCTstatA + Node;
+
+               if (pDCTstat->NodePresent)
+                       mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
+                       mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
+                       mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
+       }
+}
+
+static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 Receiver;
+       u32 dev = pDCTstat->dev_dct;
+       u32 reg_off = 0x100 * dct;
+       u32 addr;
+       u32 lo, hi;
+       u8 wrap32dis = 0;
+       u8 valid = 0;
+
+       /* Skip reset DLL for B3 */
+       if (pDCTstat->LogicalCPUID & AMD_DR_B3) {
+               return;
+       }
+
+       addr = HWCR;
+       _RDMSR(addr, &lo, &hi);
+       if(lo & (1<<17)) {              /* save the old value */
+               wrap32dis = 1;
+       }
+       lo |= (1<<17);                  /* HWCR.wrap32dis */
+       /* Setting wrap32dis allows 64-bit memory references in 32bit mode */
+       _WRMSR(addr, lo, hi);
+
+       pDCTstat->Channel = dct;
+       Receiver = mct_InitReceiver_D(pDCTstat, dct);
+       /* there are four receiver pairs, loosely associated with chipselects.*/
+       for (; Receiver < 8; Receiver += 2) {
+               if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver)) {
+                       addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, dct, Receiver, &valid);
+                       if (valid) {
+                               mct_Read1LTestPattern_D(pMCTstat, pDCTstat, addr);      /* cache fills */
+
+                               /* Write 0000_8000h to register F2x[1,0]9C_xD080F0C */
+                               Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00008000);
+                               mct_Wait(80); /* wait >= 300ns */
+
+                               /* Write 0000_0000h to register F2x[1,0]9C_xD080F0C */
+                               Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00000000);
+                               mct_Wait(800); /* wait >= 2us */
+                               break;
+                       }
+               }
+       }
+
+       if(!wrap32dis) {
+               addr = HWCR;
+               _RDMSR(addr, &lo, &hi);
+               lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
+               _WRMSR(addr, lo, hi);
+       }
+}
+
+static void mct_EnableDatIntlv_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+
+       /*  Enable F2x110[DctDatIntlv] */
+       /* Call back not required mctHookBeforeDatIntlv_D() */
+       /* FIXME Skip for Ax */
+       if (!pDCTstat->GangedMode) {
+               val = Get_NB32(dev, 0x110);
+               val |= 1 << 5;                  /* DctDatIntlv */
+               Set_NB32(dev, 0x110, val);
+
+               /* FIXME Skip for Cx */
+               dev = pDCTstat->dev_nbmisc;
+               val = Get_NB32(dev, 0x8C);      /* NB Configuration Hi */
+               val |= 1 << (36-32);            /* DisDatMask */
+               Set_NB32(dev, 0x8C, val);
+       }
+}
+
+static void SetDllSpeedUp_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 val;
+       u32 dev = pDCTstat->dev_dct;
+       u32 reg_off = 0x100 * dct;
+
+       if (pDCTstat->Speed >= 7) { /* DDR1600 and above */
+               /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F10 */
+               Set_NB32(dev, reg_off + 0x98, 0x0D080F10);
+               val = Get_NB32(dev, reg_off + 0x9C);
+               val |= 1 < 13;
+               Set_NB32(dev, reg_off + 0x9C, val);
+               Set_NB32(dev, reg_off + 0x98, 0x4D080F10);
+
+               /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F11 */
+               Set_NB32(dev, reg_off + 0x98, 0x0D080F11);
+               val = Get_NB32(dev, reg_off + 0x9C);
+               val |= 1 < 13;
+               Set_NB32(dev, reg_off + 0x9C, val);
+               Set_NB32(dev, reg_off + 0x98, 0x4D080F11);
+
+               /* Set bit13 PowerDown to register F2x[1, 0]98_x0D088F30 */
+               Set_NB32(dev, reg_off + 0x98, 0x0D088F30);
+               val = Get_NB32(dev, reg_off + 0x9C);
+               val |= 1 < 13;
+               Set_NB32(dev, reg_off + 0x9C, val);
+               Set_NB32(dev, reg_off + 0x98, 0x4D088F30);
+
+               /* Set bit13 PowerDown to register F2x[1, 0]98_x0D08CF30 */
+               Set_NB32(dev, reg_off + 0x98, 0x0D08CF30);
+               val = Get_NB32(dev, reg_off + 0x9C);
+               val |= 1 < 13;
+               Set_NB32(dev, reg_off + 0x9C, val);
+               Set_NB32(dev, reg_off + 0x98, 0x4D08CF30);
+
+       }
+}
+
+static void SyncSetting(struct DCTStatStruc *pDCTstat)
+{
+       /* set F2x78[ChSetupSync] when F2x[1, 0]9C_x04[AddrCmdSetup, CsOdtSetup,
+        * CkeSetup] setups for one DCT are all 0s and at least one of the setups,
+        * F2x[1, 0]9C_x04[AddrCmdSetup, CsOdtSetup, CkeSetup], of the other
+        * controller is 1
+        */
+       u32 cha, chb;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+
+       cha = pDCTstat->CH_ADDR_TMG[0] & 0x0202020;
+       chb = pDCTstat->CH_ADDR_TMG[1] & 0x0202020;
+
+       if ((cha != chb) && ((cha == 0) || (chb == 0))) {
+               val = Get_NB32(dev, 0x78);
+               val |= 1 << ChSetupSync;
+               Set_NB32(dev, 0x78, val);
+       }
+}
+
+static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
+
+       u32 val;
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+
+       if (pDCTstat->LogicalCPUID & (AMD_DR_B2 | AMD_DR_B3)) {
+               mct_Wait(10000);        /* Wait 50 us*/
+               val = Get_NB32(dev, 0x110);
+               if (!(val & (1 << DramEnabled))) {
+                       /* If 50 us expires while DramEnable =0 then do the following */
+                       val = Get_NB32(dev, 0x90 + reg_off);
+                       val &= ~(1 << Width128);                /* Program Width128 = 0 */
+                       Set_NB32(dev, 0x90 + reg_off, val);
+
+                       val = Get_NB32_index_wait(dev, 0x98 + reg_off, 0x05);   /* Perform dummy CSR read to F2x09C_x05 */
+
+                       if (pDCTstat->GangedMode) {
+                               val = Get_NB32(dev, 0x90 + reg_off);
+                               val |= 1 << Width128;           /* Program Width128 = 0 */
+                               Set_NB32(dev, 0x90 + reg_off, val);
+                       }
+               }
+       }
+}
+
+/* ==========================================================
+ *  6-bit Bank Addressing Table
+ *  RR=rows-13 binary
+ *  B=Banks-2 binary
+ *  CCC=Columns-9 binary
+ * ==========================================================
+ *  DCT        CCCBRR  Rows    Banks   Columns 64-bit CS Size
+ *  Encoding
+ *  0000       000000  13      2       9       128MB
+ *  0001       001000  13      2       10      256MB
+ *  0010       001001  14      2       10      512MB
+ *  0011       010000  13      2       11      512MB
+ *  0100       001100  13      3       10      512MB
+ *  0101       001101  14      3       10      1GB
+ *  0110       010001  14      2       11      1GB
+ *  0111       001110  15      3       10      2GB
+ *  1000       010101  14      3       11      2GB
+ *  1001       010110  15      3       11      4GB
+ *  1010       001111  16      3       10      4GB
+ *  1011       010111  16      3       11      8GB
+ */
+u8 crcCheck(u8 smbaddr)
+{
+       u8 byte_use;
+       u8 Index;
+       u16 CRC;
+       u8 byte, i;
+
+       byte_use = mctRead_SPD(smbaddr, SPD_ByteUse);
+       if (byte_use & 0x80)
+               byte_use = 117;
+       else
+               byte_use = 126;
+
+       CRC = 0;
+       for (Index = 0; Index < byte_use; Index ++) {
+               byte = mctRead_SPD(smbaddr, Index);
+               CRC ^= byte << 8;
+               for (i=0; i<8; i++) {
+                       if (CRC & 0x8000) {
+                               CRC <<= 1;
+                               CRC ^= 0x1021;
+                       } else
+                               CRC <<= 1;
+               }
+       }
+       return CRC == (mctRead_SPD(smbaddr, SPD_byte_127) << 8 | mctRead_SPD(smbaddr, SPD_byte_126));
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
new file mode 100644 (file)
index 0000000..bef9dfe
--- /dev/null
@@ -0,0 +1,794 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Description: Include file for all generic DDR 3 MCT files.
+ */
+#ifndef MCT_D_H
+#define MCT_D_H
+
+/*===========================================================================
+       CPU - K8/FAM10
+===========================================================================*/
+#define PT_L1          0               /* CPU Package Type */
+#define PT_M2          1
+#define PT_S1          2
+#define PT_GR          3
+#define PT_AS          4
+#define PT_C3          5
+
+#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 BSCRate        1               /* reg bit field=rate of dram scrubber for ecc*/
+                                       /* memory initialization (ecc and check-bits).*/
+                                       /* 1=40 ns/64 bytes.*/
+#define FirstPass      1               /* First pass through RcvEn training*/
+#define SecondPass     2               /* Second pass through Rcven training*/
+
+#define RCVREN_MARGIN  6               /* number of DLL taps to delay beyond first passing position*/
+#define MAXASYNCLATCTL_2       2       /* Max Async Latency Control value*/
+#define MAXASYNCLATCTL_3       3       /* Max Async Latency Control value*/
+
+#define DQS_FAIL       1
+#define DQS_PASS       0
+#define DQS_WRITEDIR   1
+#define DQS_READDIR    0
+#define MIN_DQS_WNDW   3
+#define secPassOffset  6
+#define Pass1MemClkDly 0x20            /* Add 1/2 Memlock delay */
+#define MAX_RD_LAT     0x3FF
+#define MIN_FENCE      14
+#define MAX_FENCE      20
+#define MIN_DQS_WR_FENCE       14
+#define MAX_DQS_WR_FENCE       20
+#define FenceTrnFinDlySeed     19
+#define EarlyArbEn     19
+
+#define PA_HOST(Node)  ((((0x18+Node) << 3)+0) << 12)  /* Node 0 Host Bus function PCI Address bits [15:0]*/
+#define PA_MAP(Node)   ((((0x18+Node) << 3)+1) << 12)  /* Node 0 MAP function PCI Address bits [15:0]*/
+#define PA_DCT(Node)   ((((0x18+Node) << 3)+2) << 12)  /* Node 0 DCT function PCI Address bits [15:0]*/
+/* #define PA_EXT_DCT  (((00 << 3)+4) << 8) */ /*Node 0 DCT extended configuration registers*/
+/* #define PA_DCTADDL  (((00 << 3)+2) << 8) */ /*Node x DCT function, Additional Registers PCI Address bits [15:0]*/
+/* #define PA_EXT_DCTADDL (((00 << 3)+5) << 8) */      /*Node x DCT function, Additional Registers PCI Address bits [15:0]*/
+
+#define PA_NBMISC(Node)        ((((0x18+Node) << 3)+3) << 12)  /*Node 0 Misc PCI Address bits [15:0]*/
+/* #define PA_NBDEVOP  (((00 << 3)+3) << 8) */  /*Node 0 Misc PCI Address bits [15:0]*/
+
+#define DCC_EN         1               /* X:2:0x94[19]*/
+#define ILD_Lmt        3               /* X:2:0x94[18:16]*/
+
+#define EncodedTSPD    0x00191709      /* encodes which SPD byte to get T from*/
+                                       /* versus CL X, CL X-.5, and CL X-1*/
+
+#define Bias_TrpT      5               /* bias to convert bus clocks to bit field value*/
+#define Bias_TrrdT     4
+#define Bias_TrcdT     5
+#define Bias_TrasT     15
+#define Bias_TrcT      11
+#define Bias_TrtpT     4
+#define Bias_TwrT      4
+#define Bias_TwtrT     4
+#define Bias_TfawT     14
+
+#define Min_TrpT       5               /* min programmable value in busclocks */
+#define Max_TrpT       12              /* max programmable value in busclocks */
+#define Min_TrrdT      4
+#define Max_TrrdT      7
+#define Min_TrcdT      5
+#define Max_TrcdT      12
+#define Min_TrasT      15
+#define Max_TrasT      30
+#define Min_TrcT       11
+#define Max_TrcT       42
+#define Min_TrtpT      4
+#define Max_TrtpT      7
+#define Min_TwrT       5
+#define Max_TwrT       12
+#define Min_TwtrT      4
+#define Max_TwtrT      7
+#define Min_TfawT      16
+#define Max_TfawT      32
+
+/*common register bit names*/
+#define DramHoleValid          0       /* func 1, offset F0h, bit 0*/
+#define DramMemHoistValid      1       /* func 1, offset F0h, bit 1*/
+#define CSEnable               0       /* func 2, offset 40h-5C, bit 0*/
+#define Spare                  1       /* func 2, offset 40h-5C, bit 1*/
+#define TestFail               2       /* func 2, offset 40h-5C, bit 2*/
+#define DqsRcvEnTrain          18      /* func 2, offset 78h, bit 18*/
+#define EnDramInit             31      /* func 2, offset 7Ch, bit 31*/
+#define DisAutoRefresh         18      /* func 2, offset 8Ch, bit 18*/
+#define InitDram               0       /* func 2, offset 90h, bit 0*/
+#define BurstLength32          10      /* func 2, offset 90h, bit 10*/
+#define Width128               11      /* func 2, offset 90h, bit 11*/
+#define X4Dimm                 12      /* func 2, offset 90h, bit 12*/
+#define UnBuffDimm             16      /* func 2, offset 90h, bit 16*/
+#define DimmEcEn               19      /* func 2, offset 90h, bit 19*/
+#define MemClkFreqVal          3       /* func 2, offset 94h, bit 3*/
+#define RDqsEn                 12      /* func 2, offset 94h, bit 12*/
+#define DisDramInterface       14      /* func 2, offset 94h, bit 14*/
+#define DctAccessWrite         30      /* func 2, offset 98h, bit 30*/
+#define DctAccessDone          31      /* func 2, offset 98h, bit 31*/
+#define MemClrStatus           0       /* func 2, offset A0h, bit 0*/
+#define PwrSavingsEn           10      /* func 2, offset A0h, bit 10*/
+#define Mod64BitMux            4       /* func 2, offset A0h, bit 4*/
+#define DisableJitter          1       /* func 2, offset A0h, bit 1*/
+#define MemClrDis              1       /* func 3, offset F8h, FNC 4, bit 1*/
+#define SyncOnUcEccEn          2       /* func 3, offset 44h, bit 2*/
+#define Dr_MemClrStatus        10      /* func 3, offset 110h, bit 10*/
+#define MemClrBusy             9       /* func 3, offset 110h, bit 9*/
+#define DctGangEn              4       /* func 3, offset 110h, bit 4*/
+#define MemClrInit             3       /* func 3, offset 110h, bit 3*/
+#define SendZQCmd              29      /* func 2, offset 7Ch, bit 29 */
+#define AssertCke              28      /* func 2, offset 7Ch, bit 28*/
+#define DeassertMemRstX        27      /* func 2, offset 7Ch, bit 27*/
+#define SendMrsCmd             26      /* func 2, offset 7Ch, bit 26*/
+#define SendAutoRefresh        25      /* func 2, offset 7Ch, bit 25*/
+#define SendPchgAll            24      /* func 2, offset 7Ch, bit 24*/
+#define DisDqsBar              6       /* func 2, offset 90h, bit 6*/
+#define DramEnabled            8       /* func 2, offset 110h, bit 8*/
+#define LegacyBiosMode         9       /* func 2, offset 94h, bit 9*/
+#define PrefDramTrainMode      28      /* func 2, offset 11Ch, bit 28*/
+#define FlushWr                30      /* func 2, offset 11Ch, bit 30*/
+#define DisAutoComp            30      /* func 2, offset 9Ch, Index 8, bit 30*/
+#define DqsRcvTrEn             13      /* func 2, offset 9Ch, Index 8, bit 13*/
+#define ForceAutoPchg          23      /* func 2, offset 90h, bit 23*/
+#define ClLinesToNbDis         15      /* Bu_CFG2, bit 15*/
+#define WbEnhWsbDis_D          (48-32)
+#define PhyFenceTrEn           3       /* func 2, offset 9Ch, Index 8, bit 3 */
+#define ParEn                  8       /* func 2, offset 90h, bit 8 */
+#define DcqArbBypassEn         19      /* func 2, offset 94h, bit 19 */
+#define ActiveCmdAtRst         1       /* func 2, offset A8H, bit 1 */
+#define FlushWrOnStpGnt        29      /* func 2, offset 11Ch, bit 29 */
+#define BankSwizzleMode        22      /* func 2, offset 94h, bit 22 */
+#define ChSetupSync            15      /* func 2, offset 78h, bit 15 */
+
+#define Ddr3Mode       8               /* func 2, offset 94h, bit 8 */
+#define EnterSelfRef   17              /* func 2, offset 90h, bit 17 */
+#define onDimmMirror   3               /* func 2, offset 5C:40h, bit 3 */
+#define OdtSwizzle     6               /* func 2, offset A8h, bit 6 */
+#define FreqChgInProg  21              /* func 2, offset 94h, bit 21 */
+#define ExitSelfRef    1               /* func 2, offset 90h, bit 1 */
+
+#define SubMemclkRegDly                5       /* func 2, offset A8h, bit 5 */
+#define Ddr3FourSocketCh       2       /* func 2, offset A8h, bit 2 */
+#define SendControlWord                30      /* func 2, offset 7Ch, bit 30 */
+
+/*=============================================================================
+       SW Initialization
+============================================================================*/
+#define DLL_Enable     1
+#define OCD_Default    2
+#define OCD_Exit       3
+
+/*=============================================================================
+       Jedec DDR II
+=============================================================================*/
+#define SPD_ByteUse    0
+#define SPD_TYPE       2               /*SPD byte read location*/
+       #define JED_DDRSDRAM    0x07    /*Jedec defined bit field*/
+       #define JED_DDR2SDRAM   0x08    /*Jedec defined bit field*/
+       #define JED_DDR3SDRAM   0x0B    /* Jedec defined bit field*/
+
+#define SPD_DIMMTYPE   3
+#define SPD_ATTRIB     21
+       #define JED_DIFCKMSK    0x20    /*Differential Clock Input*/
+       #define JED_REGADCMSK   0x11    /*Registered Address/Control*/
+       #define JED_PROBEMSK    0x40    /*Analysis Probe installed*/
+       #define JED_RDIMM       0x1     /* RDIMM */
+       #define JED_MiniRDIMM   0x5     /* Mini-RDIMM */
+#define SPD_Density    4               /* Bank address bits,SDRAM capacity */
+#define SPD_Addressing 5               /* Row/Column address bits */
+#define SPD_Organization       7               /* rank#,Device width */
+#define SPD_BusWidth   8               /* ECC, Bus width */
+       #define JED_ECC         8       /* ECC capability */
+
+#define SPD_MTBDividend                10
+#define SPD_MTBDivisor         11
+#define SPD_tCKmin             12
+#define SPD_CASLow             14
+#define SPD_CASHigh            15
+#define SPD_tAAmin             16
+
+#define SPD_DEVATTRIB  22
+#define SPD_EDCTYPE    11
+       #define JED_ADRCPAR     0x04
+
+#define SPD_tWRmin             17
+#define SPD_tRCDmin            18
+#define SPD_tRRDmin            19
+#define SPD_tRPmin             20
+#define SPD_Upper_tRAS_tRC     21
+#define SPD_tRASmin            22
+#define SPD_tRCmin             23
+#define SPD_tWTRmin            26
+#define SPD_tRTPmin            27
+#define SPD_Upper_tFAW         28
+#define SPD_tFAWmin            29
+
+#define SPD_RefRawCard         62
+#define SPD_AddressMirror      63
+#define SPD_RegManufactureID_L 65  /* not used */
+#define SPD_RegManufactureID_H 66  /* not used */
+#define SPD_RegManRevID                67  /* not used */
+
+#define SPD_byte_126           126
+#define SPD_byte_127           127
+
+#define SPD_ROWSZ      3
+#define SPD_COLSZ      4
+#define SPD_LBANKS     17              /*number of [logical] banks on each device*/
+#define SPD_DMBANKS    5               /*number of physical banks on dimm*/
+       #define SPDPLBit        4       /* Dram package bit*/
+#define SPD_BANKSZ     31              /*capacity of physical bank*/
+#define SPD_DEVWIDTH   13
+#define SPD_CASLAT     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_TRCRFC     40
+#define SPD_TRC        41
+#define SPD_TRFC       42
+
+#define SPD_MANDATEYR  93              /*Module Manufacturing Year (BCD)*/
+
+#define SPD_MANDATEWK  94              /*Module Manufacturing Week (BCD)*/
+
+/*-----------------------------
+       Jdec DDR II related equates
+-----------------------------*/
+#define MYEAR06        6       /* Manufacturing Year BCD encoding of 2006 - 06d*/
+#define MWEEK24        0x24    /* Manufacturing Week BCD encoding of June - 24d*/
+
+/*=============================================================================
+       Macros
+=============================================================================*/
+
+#define _2GB_RJ8       (2<<(30-8))
+#define _4GB_RJ8       (4<<(30-8))
+#define _4GB_RJ4       (4<<(30-4))
+
+#define BigPagex8_RJ8  (1<<(17+3-8))   /*128KB * 8 >> 8 */
+
+/*=============================================================================
+       Global MCT Status Structure
+=============================================================================*/
+struct MCTStatStruc {
+       u32 GStatus;            /* Global Status bitfield*/
+       u32 HoleBase;           /* If not zero, BASE[39:8] (system address)
+                                     of sub 4GB dram hole for HW remapping.*/
+       u32 Sub4GCacheTop;      /* If not zero, the 32-bit top of cacheable memory.*/
+       u32 SysLimit;           /* LIMIT[39:8] (system address)*/
+};
+
+/*=============================================================================
+       Global MCT Configuration Status Word (GStatus)
+=============================================================================*/
+/*These should begin at bit 0 of GStatus[31:0]*/
+#define GSB_MTRRshort  0               /* Ran out of MTRRs while mapping memory*/
+#define GSB_ECCDIMMs   1               /* All banks of all Nodes are ECC capable*/
+#define GSB_DramECCDis 2               /* Dram ECC requested but not enabled.*/
+#define GSB_SoftHole   3               /* A Node Base gap was created*/
+#define GSB_HWHole     4               /* A HW dram remap was created*/
+#define GSB_NodeIntlv  5               /* Node Memory interleaving was enabled*/
+#define GSB_SpIntRemapHole     16      /* Special condition for Node Interleave and HW remapping*/
+#define GSB_EnDIMMSpareNW      17      /* Indicates that DIMM Spare can be used without a warm reset */
+                                       /* NOTE: This is a local bit used by memory code */
+
+/*===============================================================================
+       Local DCT Status structure (a structure for each DCT)
+===============================================================================*/
+#include "mwlc_d.h"            /* I have to */
+
+struct DCTStatStruc {          /* A per Node structure*/
+/* DCTStatStruct_F -  start */
+       u8 Node_ID;             /* Node ID of current controller*/
+       u8 ErrCode;             /* Current error condition of Node
+               0= no error
+               1= Variance Error, DCT is running but not in an optimal configuration.
+               2= Stop Error, DCT is NOT running
+               3= Fatal Error, DCT/MCT initialization has been halted.*/
+       u32 ErrStatus;          /* Error Status bit Field */
+       u32 Status;             /* Status bit Field*/
+       u8 DIMMAddr[8];         /* SPD address of DIMM controlled by MA0_CS_L[0,1]*/
+               /* SPD address of..MB0_CS_L[0,1]*/
+               /* SPD address of..MA1_CS_L[0,1]*/
+               /* SPD address of..MB1_CS_L[0,1]*/
+               /* SPD address of..MA2_CS_L[0,1]*/
+               /* SPD address of..MB2_CS_L[0,1]*/
+               /* SPD address of..MA3_CS_L[0,1]*/
+               /* SPD address of..MB3_CS_L[0,1]*/
+       u16 DIMMPresent;                /*For each bit n 0..7, 1=DIMM n is present.
+               DIMM#  Select Signal
+               0  MA0_CS_L[0,1]
+               1  MB0_CS_L[0,1]
+               2  MA1_CS_L[0,1]
+               3  MB1_CS_L[0,1]
+               4  MA2_CS_L[0,1]
+               5  MB2_CS_L[0,1]
+               6  MA3_CS_L[0,1]
+               7  MB3_CS_L[0,1]*/
+       u16 DIMMValid;          /* For each bit n 0..7, 1=DIMM n is valid and is/will be configured*/
+       u16 DIMMMismatch;       /* For each bit n 0..7, 1=DIMM n is mismatched, channel B is always considered the mismatch */
+       u16 DIMMSPDCSE;         /* For each bit n 0..7, 1=DIMM n SPD checksum error*/
+       u16 DimmECCPresent;     /* For each bit n 0..7, 1=DIMM n is ECC capable.*/
+       u16 DimmPARPresent;     /* For each bit n 0..7, 1=DIMM n is ADR/CMD Parity capable.*/
+       u16 Dimmx4Present;      /* For each bit n 0..7, 1=DIMM n contains x4 data devices.*/
+       u16 Dimmx8Present;      /* For each bit n 0..7, 1=DIMM n contains x8 data devices.*/
+       u16 Dimmx16Present;     /* For each bit n 0..7, 1=DIMM n contains x16 data devices.*/
+       u16 DIMM2Kpage;         /* For each bit n 0..7, 1=DIMM n contains 1K page devices.*/
+       u8 MAload[2];           /* Number of devices loading MAA bus*/
+               /* Number of devices loading MAB bus*/
+       u8 MAdimms[2];          /*Number of DIMMs loading CH A*/
+               /* Number of DIMMs loading CH B*/
+       u8 DATAload[2];         /*Number of ranks loading CH A DATA*/
+               /* Number of ranks loading CH B DATA*/
+       u8 DIMMAutoSpeed;       /*Max valid Mfg. Speed of DIMMs
+               1=200Mhz
+               2=266Mhz
+               3=333Mhz
+               4=400Mhz
+               5=533Mhz*/
+       u8 DIMMCASL;            /* Min valid Mfg. CL bitfield
+               0=2.0
+               1=3.0
+               2=4.0
+               3=5.0
+               4=6.0 */
+       u16 DIMMTrcd;           /* Minimax Trcd*40 (ns) of DIMMs*/
+       u16 DIMMTrp;            /* Minimax Trp*40 (ns) of DIMMs*/
+       u16 DIMMTrtp;           /* Minimax Trtp*40 (ns) of DIMMs*/
+       u16 DIMMTras;           /* Minimax Tras*40 (ns) of DIMMs*/
+       u16 DIMMTrc;            /* Minimax Trc*40 (ns) of DIMMs*/
+       u16 DIMMTwr;            /* Minimax Twr*40 (ns) of DIMMs*/
+       u16 DIMMTrrd;           /* Minimax Trrd*40 (ns) of DIMMs*/
+       u16 DIMMTwtr;           /* Minimax Twtr*40 (ns) of DIMMs*/
+       u8 Speed;               /* Bus Speed (to set Controller)
+               1=200Mhz
+               2=266Mhz
+               3=333Mhz
+               4=400Mhz */
+       u8 CASL;                /* CAS latency DCT setting
+               0=2.0
+               1=3.0
+               2=4.0
+               3=5.0
+               4=6.0 */
+       u8 Trcd;                /* DCT Trcd (busclocks) */
+       u8 Trp;                 /* DCT Trp (busclocks) */
+       u8 Trtp;                /* DCT Trtp (busclocks) */
+       u8 Tras;                /* DCT Tras (busclocks) */
+       u8 Trc;                 /* DCT Trc (busclocks) */
+       u8 Twr;                 /* DCT Twr (busclocks) */
+       u8 Trrd;                /* DCT Trrd (busclocks) */
+       u8 Twtr;                /* DCT Twtr (busclocks) */
+       u8 Trfc[4];             /* DCT Logical DIMM0 Trfc
+               0=75ns (for 256Mb devs)
+               1=105ns (for 512Mb devs)
+               2=127.5ns (for 1Gb devs)
+               3=195ns (for 2Gb devs)
+               4=327.5ns (for 4Gb devs) */
+               /* DCT Logical DIMM1 Trfc (see Trfc0 for format) */
+               /* DCT Logical DIMM2 Trfc (see Trfc0 for format) */
+               /* DCT Logical DIMM3 Trfc (see Trfc0 for format) */
+       u16 CSPresent;          /* For each bit n 0..7, 1=Chip-select n is present */
+       u16 CSTestFail;         /* For each bit n 0..7, 1=Chip-select n is present but disabled */
+       u32 DCTSysBase;         /* BASE[39:8] (system address) of this Node's DCTs. */
+       u32 DCTHoleBase;        /* If not zero, BASE[39:8] (system address) of dram hole for HW remapping.  Dram hole exists on this Node's DCTs. */
+       u32 DCTSysLimit;        /* LIMIT[39:8] (system address) of this Node's DCTs */
+       u16 PresetmaxFreq;      /* Maximum OEM defined DDR frequency
+               200=200Mhz (DDR400)
+               266=266Mhz (DDR533)
+               333=333Mhz (DDR667)
+               400=400Mhz (DDR800) */
+       u8 _2Tmode;             /* 1T or 2T CMD mode (slow access mode)
+               1=1T
+               2=2T */
+       u8 TrwtTO;              /* DCT TrwtTO (busclocks)*/
+       u8 Twrrd;               /* DCT Twrrd (busclocks)*/
+       u8 Twrwr;               /* DCT Twrwr (busclocks)*/
+       u8 Trdrd;               /* DCT Trdrd (busclocks)*/
+       u32 CH_ODC_CTL[2];      /* Output Driver Strength (see BKDG FN2:Offset 9Ch, index 00h*/
+       u32 CH_ADDR_TMG[2];     /* Address Bus Timing (see BKDG FN2:Offset 9Ch, index 04h*/
+               /* Output Driver Strength (see BKDG FN2:Offset 9Ch, index 20h*/
+               /* Address Bus Timing (see BKDG FN2:Offset 9Ch, index 24h*/
+       u16 CH_EccDQSLike[2];   /* CHA DQS ECC byte like...*/
+       u8 CH_EccDQSScale[2];   /* CHA DQS ECC byte scale*/
+               /* CHA DQS ECC byte like...*/
+               /* CHA DQS ECC byte scale*/
+       u8 MaxAsyncLat;         /* Max Asynchronous Latency (ns)*/
+       /* NOTE: Not used in Barcelona - u8 CH_D_RCVRDLY[2][4]; */
+               /* CHA DIMM 0 - 4 Receiver Enable Delay*/
+               /* CHB DIMM 0 - 4 Receiver Enable Delay */
+       /* NOTE: Not used in Barcelona - u8 CH_D_B_DQS[2][2][8]; */
+               /* CHA Byte 0-7 Write DQS Delay */
+               /* CHA Byte 0-7 Read DQS Delay */
+               /* CHB Byte 0-7 Write DQS Delay */
+               /* CHB Byte 0-7 Read DQS Delay */
+       u32 PtrPatternBufA;     /* Ptr on stack to aligned DQS testing pattern*/
+       u32 PtrPatternBufB;     /* Ptr on stack to aligned DQS testing pattern*/
+       u8 Channel;             /* Current Channel (0= CH A, 1=CH B)*/
+       u8 ByteLane;            /* Current Byte Lane (0..7)*/
+       u8 Direction;           /* Current DQS-DQ training write direction (0=read, 1=write)*/
+       u8 Pattern;             /* Current pattern*/
+       u8 DQSDelay;            /* Current DQS delay value*/
+       u32 TrainErrors;        /* Current Training Errors*/
+
+       u32 AMC_TSC_DeltaLo;    /* Time Stamp Counter measurement of AMC, Low dword*/
+       u32 AMC_TSC_DeltaHi;    /* Time Stamp Counter measurement of AMC, High dword*/
+       /* NOTE: Not used in Barcelona - */
+       u8 CH_D_DIR_MaxMin_B_Dly[2][2][2][8];
+               /* CH A byte lane 0 - 7 minimum filtered window  passing DQS delay value*/
+               /* CH A byte lane 0 - 7 maximum filtered window  passing DQS delay value*/
+               /* CH B byte lane 0 - 7 minimum filtered window  passing DQS delay value*/
+               /* CH B byte lane 0 - 7 maximum filtered window  passing DQS delay value*/
+               /* CH A byte lane 0 - 7 minimum filtered window  passing DQS delay value*/
+               /* CH A byte lane 0 - 7 maximum filtered window  passing DQS delay value*/
+               /* CH B byte lane 0 - 7 minimum filtered window  passing DQS delay value*/
+               /* CH B byte lane 0 - 7 maximum filtered window  passing DQS delay value*/
+       u32 LogicalCPUID;       /* The logical CPUID of the node*/
+       u16 HostBiosSrvc1;      /* Word sized general purpose field for use by host BIOS.  Scratch space.*/
+       u32 HostBiosSrvc2;      /* Dword sized general purpose field for use by host BIOS.  Scratch space.*/
+       u16 DimmQRPresent;      /* QuadRank DIMM present?*/
+       u16 DimmTrainFail;      /* Bitmap showing which dimms failed training*/
+       u16 CSTrainFail;        /* Bitmap showing which chipselects failed training*/
+       u16 DimmYr06;           /* Bitmap indicating which Dimms have a manufactur's year code <= 2006*/
+       u16 DimmWk2406;         /* Bitmap indicating which Dimms have a manufactur's week code <= 24 of 2006 (June)*/
+       u16 DimmDRPresent;      /* Bitmap indicating that Dual Rank Dimms are present*/
+       u16 DimmPlPresent;      /* Bitmap indicating that Planar (1) or Stacked (0) Dimms are present.*/
+       u16 ChannelTrainFai;    /* Bitmap showing the chanel informaiton about failed Chip Selects
+               0 in any bit field indicates Channel 0
+               1 in any bit field indicates Channel 1 */
+       u16 DIMMTfaw;           /* Minimax Tfaw*16 (ns) of DIMMs */
+       u8 Tfaw;                /* DCT Tfaw (busclocks) */
+       u16 CSUsrTestFail;      /* Chip selects excluded by user */
+/* DCTStatStruct_F -  end */
+
+       u16 CH_MaxRdLat[2];     /* Max Read Latency (ns) for DCT 0*/
+               /* Max Read Latency (ns) for DCT 1*/
+       u8 CH_D_DIR_B_DQS[2][4][2][9];  /* [A/B] [DIMM1-4] [R/W] [DQS] */
+               /* CHA DIMM0 Byte 0 - 7 and Check Write DQS Delay*/
+               /* CHA DIMM0 Byte 0 - 7 and Check Read DQS Delay*/
+               /* CHA DIMM1 Byte 0 - 7 and Check Write DQS Delay*/
+               /* CHA DIMM1 Byte 0 - 7 and Check Read DQS Delay*/
+               /* CHB DIMM0 Byte 0 - 7 and Check Write DQS Delay*/
+               /* CHB DIMM0 Byte 0 - 7 and Check Read DQS Delay*/
+               /* CHB DIMM1 Byte 0 - 7 and Check Write DQS Delay*/
+               /* CHB DIMM1 Byte 0 - 7 and Check  Read DQS Delay*/
+       u8 CH_D_B_TxDqs[2][4][9];   /* [A/B] [DIMM1-4] [DQS] */
+               /* CHA DIMM0 Byte 0 - 7  TxDqs */
+               /* CHA DIMM0 Byte 0 - 7  TxDqs */
+               /* CHA DIMM1 Byte 0 - 7  TxDqs */
+               /* CHA DIMM1 Byte 0 - 7  TxDqs */
+               /* CHB DIMM0 Byte 0 - 7  TxDqs */
+               /* CHB DIMM0 Byte 0 - 7  TxDqs */
+               /* CHB DIMM1 Byte 0 - 7  TxDqs */
+               /* CHB DIMM1 Byte 0 - 7  TxDqs */
+       u8 CH_D_B_RCVRDLY[2][4][8];     /* [A/B] [DIMM0-3] [DQS] */
+               /* CHA DIMM 0 Receiver Enable Delay*/
+               /* CHA DIMM 1 Receiver Enable Delay*/
+               /* CHA DIMM 2 Receiver Enable Delay*/
+               /* CHA DIMM 3 Receiver Enable Delay*/
+
+               /* CHB DIMM 0 Receiver Enable Delay*/
+               /* CHB DIMM 1 Receiver Enable Delay*/
+               /* CHB DIMM 2 Receiver Enable Delay*/
+               /* CHB DIMM 3 Receiver Enable Delay*/
+       u8 CH_D_BC_RCVRDLY[2][4];
+               /* CHA DIMM 0 - 4 Check Byte Receiver Enable Delay*/
+               /* CHB DIMM 0 - 4 Check Byte Receiver Enable Delay*/
+       u8 DIMMValidDCT[2];     /* DIMM# in DCT0*/
+                               /* DIMM# in DCT1*/
+       u16 CSPresent_DCT[2];   /* DCT# CS mapping */
+       u16 MirrPresU_NumRegR;  /* Address mapping from edge connect to DIMM present for unbuffered dimm
+                                  Number of registers on the dimm for registered dimm */
+       u8 MaxDCTs;             /* Max number of DCTs in system*/
+       /* NOTE: removed u8 DCT. Use ->dev_ for pci R/W; */     /*DCT pointer*/
+       u8 GangedMode;          /* Ganged mode enabled, 0 = disabled, 1 = enabled*/
+       u8 DRPresent;           /* Family 10 present flag, 0 = n0t Fam10, 1 = Fam10*/
+       u32 NodeSysLimit;       /* BASE[39:8],for DCT0+DCT1 system address*/
+       u8 WrDatGrossH;
+       u8 DqsRcvEnGrossL;
+       /* NOTE: Not used - u8 NodeSpeed */             /* Bus Speed (to set Controller) */
+               /* 1=200Mhz */
+               /* 2=266Mhz */
+               /* 3=333Mhz */
+       /* NOTE: Not used - u8 NodeCASL */      /* CAS latency DCT setting */
+               /* 0=2.0 */
+               /* 1=3.0 */
+               /* 2=4.0 */
+               /* 3=5.0 */
+               /* 4=6.0 */
+       u8 TrwtWB;
+       u8 CurrRcvrCHADelay;    /* for keep current RcvrEnDly of chA*/
+       u16 T1000;              /* get the T1000 figure (cycle time (ns)*1K)*/
+       u8 DqsRcvEn_Pass;       /* for TrainRcvrEn byte lane pass flag*/
+       u8 DqsRcvEn_Saved;      /* for TrainRcvrEn byte lane saved flag*/
+       u8 SeedPass1Remainder;  /* for Phy assisted DQS receiver enable training*/
+
+       /* for second pass  - Second pass should never run for Fam10*/
+       /* NOTE: Not used for Barcelona - u8 CH_D_B_RCVRDLY_1[2][4][8]; */      /* CHA DIMM 0 Receiver Enable Delay */
+               /* CHA DIMM 1 Receiver Enable Delay*/
+               /* CHA DIMM 2 Receiver Enable Delay*/
+               /* CHA DIMM 3 Receiver Enable Delay*/
+
+               /* CHB DIMM 0 Receiver Enable Delay*/
+               /* CHB DIMM 1 Receiver Enable Delay*/
+               /* CHB DIMM 2 Receiver Enable Delay*/
+               /* CHB DIMM 3 Receiver Enable Delay*/
+
+       u8 ClToNB_flag; /* is used to restore ClLinesToNbDis bit after memory */
+       u32 NodeSysBase;        /* for channel interleave usage */
+
+/* New for LB Support */
+       u8 NodePresent;
+       u32 dev_host;
+       u32 dev_map;
+       u32 dev_dct;
+       u32 dev_nbmisc;
+       u8 TargetFreq;
+       u8 TargetCASL;
+       u8 CtrlWrd3;
+       u8 CtrlWrd4;
+       u8 CtrlWrd5;
+       u8 DqsRdWrPos_Saved;
+       u8 DqsRcvEnGrossMax;
+       u8 DqsRcvEnGrossMin;
+       u8 WrDatGrossMax;
+       u8 WrDatGrossMin;
+
+       u16 RegMan1Present;     /* DIMM present bitmap of Register manufacture 1 */
+       u16 RegMan2Present;     /* DIMM present bitmap of Register manufacture 2 */
+
+       struct _sMCTStruct *C_MCTPtr;
+       struct _sDCTStruct *C_DCTPtr[2];
+       /* struct _sDCTStruct *C_DCT1Ptr; */
+
+       struct _sMCTStruct s_C_MCTPtr;
+       struct _sDCTStruct s_C_DCTPtr[2];
+       /* struct _sDCTStruct s_C_DCT1Ptr[8]; */
+};
+
+/*===============================================================================
+       Local Error Status Codes (DCTStatStruc.ErrCode)
+===============================================================================*/
+#define SC_RunningOK           0
+#define SC_VarianceErr         1       /* Running non-optimally*/
+#define SC_StopError           2       /* Not Running*/
+#define SC_FatalErr            3       /* Fatal Error, MCTB has exited immediately*/
+
+/*===============================================================================
+       Local Error Status (DCTStatStruc.ErrStatus[31:0])
+===============================================================================*/
+#define SB_NoDimms             0
+#define SB_DIMMChkSum          1
+#define SB_DimmMismatchM       2       /* dimm module type(buffer) mismatch*/
+#define SB_DimmMismatchT       3       /* dimm CL/T mismatch*/
+#define SB_DimmMismatchO       4       /* dimm organization mismatch (128-bit)*/
+#define SB_NoTrcTrfc           5       /* SPD missing Trc or Trfc info*/
+#define SB_NoCycTime           6       /* SPD missing byte 23 or 25*/
+#define SB_BkIntDis            7       /* Bank interleave requested but not enabled*/
+#define SB_DramECCDis          8       /* Dram ECC requested but not enabled*/
+#define SB_SpareDis            9       /* Online spare requested but not enabled*/
+#define SB_MinimumMode         10      /* Running in Minimum Mode*/
+#define SB_NORCVREN            11      /* No DQS Receiver Enable pass window found*/
+#define SB_CHA2BRCVREN         12      /* DQS Rcvr En pass window CHA to CH B too large*/
+#define SB_SmallRCVR           13      /* DQS Rcvr En pass window too small (far right of dynamic range)*/
+#define SB_NODQSPOS            14      /* No DQS-DQ passing positions*/
+#define SB_SMALLDQS            15      /* DQS-DQ passing window too small*/
+#define SB_DCBKScrubDis        16      /* DCache scrub requested but not enabled */
+
+/*===============================================================================
+       Local Configuration Status (DCTStatStruc.Status[31:0])
+===============================================================================*/
+#define SB_Registered          0       /* All DIMMs are Registered*/
+#define SB_ECCDIMMs            1       /* All banks ECC capable*/
+#define SB_PARDIMMs            2       /* All banks Addr/CMD Parity capable*/
+#define SB_DiagClks            3       /* Jedec ALL slots clock enable diag mode*/
+#define SB_128bitmode          4       /* DCT in 128-bit mode operation*/
+#define SB_64MuxedMode         5       /* DCT in 64-bit mux'ed mode.*/
+#define SB_2TMode              6       /* 2T CMD timing mode is enabled.*/
+#define SB_SWNodeHole          7       /* Remapping of Node Base on this Node to create a gap.*/
+#define SB_HWHole              8       /* Memory Hole created on this Node using HW remapping.*/
+#define SB_Over400MHz          9       /* DCT freq >= 400MHz flag*/
+#define SB_DQSPos_Pass2        10      /* Using for TrainDQSPos DIMM0/1, when freq>=400MHz*/
+#define SB_DQSRcvLimit         11      /* Using for DQSRcvEnTrain to know we have reached to upper bound.*/
+#define SB_ExtConfig           12      /* Indicator the default setting for extend PCI configuration support*/
+
+
+/*===============================================================================
+       NVRAM/run-time-configurable Items
+===============================================================================*/
+/*Platform Configuration*/
+#define NV_PACK_TYPE           0       /* CPU Package Type (2-bits)
+                                           0=NPT L1
+                                           1=NPT M2
+                                           2=NPT S1*/
+#define NV_MAX_NODES           1       /* Number of Nodes/Sockets (4-bits)*/
+#define NV_MAX_DIMMS           2       /* Number of DIMM slots for the specified Node ID (4-bits)*/
+#define NV_MAX_MEMCLK          3       /* Maximum platform demonstrated Memclock (10-bits)
+                                           200=200Mhz (DDR400)
+                                           266=266Mhz (DDR533)
+                                           333=333Mhz (DDR667)
+                                           400=400Mhz (DDR800)*/
+#define NV_ECC_CAP             4       /* Bus ECC capable (1-bits)
+                                           0=Platform not capable
+                                           1=Platform is capable*/
+#define NV_4RANKType           5       /* Quad Rank DIMM slot type (2-bits)
+                                           0=Normal
+                                           1=R4 (4-Rank Registered DIMMs in AMD server configuration)
+                                           2=S4 (Unbuffered SO-DIMMs)*/
+#define NV_BYPMAX              6       /* Value to set DcqBypassMax field (See Function 2, Offset 94h, [27:24] of BKDG for field definition).
+                                           4=4 times bypass (normal for non-UMA systems)
+                                           7=7 times bypass (normal for UMA systems)*/
+#define NV_RDWRQBYP            7       /* Value to set RdWrQByp field (See Function 2, Offset A0h, [3:2] of BKDG for field definition).
+                                           2=8 times (normal for non-UMA systems)
+                                           3=16 times (normal for UMA systems)*/
+
+
+/*Dram Timing*/
+#define NV_MCTUSRTMGMODE       10      /* User Memclock Mode (2-bits)
+                                           0=Auto, no user limit
+                                           1=Auto, user limit provided in NV_MemCkVal
+                                           2=Manual, user value provided in NV_MemCkVal*/
+#define NV_MemCkVal            11      /* Memory Clock Value (2-bits)
+                                           0=200Mhz
+                                           1=266Mhz
+                                           2=333Mhz
+                                           3=400Mhz*/
+
+/*Dram Configuration*/
+#define NV_BankIntlv           20      /* Dram Bank (chip-select) Interleaving (1-bits)
+                                           0=disable
+                                           1=enable*/
+#define NV_AllMemClks          21      /* Turn on All DIMM clocks (1-bits)
+                                           0=normal
+                                           1=enable all memclocks*/
+#define NV_SPDCHK_RESTRT       22      /* SPD Check control bitmap (1-bits)
+                                           0=Exit current node init if any DIMM has SPD checksum error
+                                           1=Ignore faulty SPD checksums (Note: DIMM cannot be enabled)*/
+#define NV_DQSTrainCTL         23      /* DQS Signal Timing Training Control
+                                           0=skip DQS training
+                                           1=perform DQS training*/
+#define NV_NodeIntlv           24      /* Node Memory Interleaving (1-bits)
+                                           0=disable
+                                           1=enable*/
+#define NV_BurstLen32          25      /* BurstLength32 for 64-bit mode (1-bits)
+                                           0=disable (normal)
+                                           1=enable (4 beat burst when width is 64-bits)*/
+
+/*Dram Power*/
+#define NV_CKE_PDEN            30      /* CKE based power down mode (1-bits)
+                                           0=disable
+                                           1=enable*/
+#define NV_CKE_CTL             31      /* CKE based power down control (1-bits)
+                                           0=per Channel control
+                                           1=per Chip select control*/
+#define NV_CLKHZAltVidC3       32      /* Memclock tri-stating during C3 and Alt VID (1-bits)
+                                           0=disable
+                                           1=enable*/
+
+/*Memory Map/Mgt.*/
+#define NV_BottomIO            40      /* Bottom of 32-bit IO space (8-bits)
+                                           NV_BottomIO[7:0]=Addr[31:24]*/
+#define NV_BottomUMA           41      /* Bottom of shared graphics dram (8-bits)
+                                           NV_BottomUMA[7:0]=Addr[31:24]*/
+#define NV_MemHole             42      /* Memory Hole Remapping (1-bits)
+                                           0=disable
+                                           1=enable  */
+
+/*ECC*/
+#define NV_ECC                 50      /* Dram ECC enable*/
+#define NV_NBECC               52      /* ECC MCE enable*/
+#define NV_ChipKill            53      /* Chip-Kill ECC Mode enable*/
+#define NV_ECCRedir            54      /* Dram ECC Redirection enable*/
+#define NV_DramBKScrub         55      /* Dram ECC Background Scrubber CTL*/
+#define NV_L2BKScrub           56      /* L2 ECC Background Scrubber CTL*/
+#define NV_DCBKScrub           57      /* DCache ECC Background Scrubber CTL*/
+#define NV_CS_SpareCTL         58      /* Chip Select Spare Control bit 0:
+                                              0=disable Spare
+                                              1=enable Spare */
+                                       /* Chip Select Spare Control bit 1-4:
+                                            Reserved, must be zero*/
+#define NV_SyncOnUnEccEn       61      /* SyncOnUnEccEn control
+                                          0=disable
+                                          1=enable*/
+#define NV_Unganged            62
+
+#define NV_ChannelIntlv        63      /* Channel Interleaving (3-bits)
+                                       xx0b = disable
+                                       yy1b = enable with DctSelIntLvAddr set to yyb */
+
+
+#ifndef MAX_NODES_SUPPORTED
+#define MAX_NODES_SUPPORTED    8
+#endif
+
+#ifndef MAX_DIMMS_SUPPORTED
+#define MAX_DIMMS_SUPPORTED    8
+#endif
+
+#ifndef MAX_CS_SUPPORTED
+#define MAX_CS_SUPPORTED       8
+#endif
+
+#ifndef MCT_DIMM_SPARE_NO_WARM
+#define MCT_DIMM_SPARE_NO_WARM 0
+#endif
+
+u32 Get_NB32(u32 dev, u32 reg);
+void Set_NB32(u32 dev, u32 reg, u32 val);
+u32 Get_NB32_index(u32 dev, u32 index_reg, u32 index);
+void Set_NB32_index(u32 dev, u32 index_reg, u32 index, u32 data);
+u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index);
+void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 index, u32 data);
+u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val);
+void mct_ForceAutoPrecharge_D(struct DCTStatStruc *pDCTstat, u32 dct);
+u32 Modify_D3CMP(struct DCTStatStruc *pDCTstat, u32 dct, u32 value);
+u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass);
+u32 SetupDqsPattern_1PassA(u8 Pass);
+u32 SetupDqsPattern_1PassB(u8 Pass);
+u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
+u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
+void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+u32 mctGetLogicalCPUID(u32 Node);
+u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u8 Pass);
+void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,struct DCTStatStruc *pDCTstatA);
+void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 FinalValue, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 Pass);
+void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel);
+void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 dct);
+void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
+void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct, u32 DramConfigHi);
+void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
+void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 Pass);
+void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 _DisableDramECC);
+u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val);
+void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct);
+void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 node);
+void mctSMBhub_Init(u32 node);
+int mctRead_SPD(u32 smaddr, u32 reg);
+void InterleaveNodes_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+
+void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass);
+u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct);
+void mct_Wait(u32 cycles);
+u8 mct_RcvrRankEnabled_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 Channel, u8 ChipSel);
+u32 mct_GetRcvrSysAddr_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 channel, u8 receiver, u8 *valid);
+void mct_Read1LTestPattern_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 addr);
+
+#endif
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
new file mode 100644 (file)
index 0000000..4b36207
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static inline void _WRMSR(u32 addr, u32 lo, u32 hi)
+{
+       __asm__ volatile (
+               "wrmsr"
+               :
+               :"c"(addr),"a"(lo), "d" (hi)
+               );
+}
+
+static inline void _RDMSR(u32 addr, u32 *lo, u32 *hi)
+{
+       __asm__ volatile (
+               "rdmsr"
+               :"=a"(*lo), "=d" (*hi)
+               :"c"(addr)
+               );
+}
+
+static inline void _RDTSC(u32 *lo, u32 *hi)
+{
+       __asm__ volatile (
+                "rdtsc"
+                : "=a" (*lo), "=d"(*hi)
+                );
+}
+
+static inline void _cpu_id(u32 addr, u32 *val)
+{
+       __asm__ volatile(
+                "cpuid"
+                : "=a" (val[0]),
+                  "=b" (val[1]),
+                  "=c" (val[2]),
+                  "=d" (val[3])
+                : "0" (addr));
+
+}
+
+static u32 bsr(u32 x)
+{
+       u8 i;
+       u32 ret = 0;
+
+       for(i=31; i>0; i--) {
+               if(x & (1<<i)) {
+                       ret = i;
+                       break;
+               }
+       }
+
+       return ret;
+
+}
+
+static u32 bsf(u32 x)
+{
+       u8 i;
+       u32 ret = 32;
+
+       for(i=0; i<32; i++) {
+               if(x & (1<<i)) {
+                       ret = i;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+#define _MFENCE asm volatile ( "mfence")
+
+#define _SFENCE asm volatile ( "sfence" )
+
+/* prevent speculative execution of following instructions */
+#define _EXECFENCE asm volatile ("outb %al, $0xed")
+
+static inline u32 read_cr4(void)
+{
+       u32 cr4;
+       __asm__ volatile ("movl %%cr4, %0" : "=r" (cr4));
+       return cr4;
+}
+
+static inline void write_cr4(u32 cr4)
+{
+       __asm__ volatile ("movl %0, %%cr4" : : "r" (cr4));
+}
+
+u32 SetUpperFSbase(u32 addr_hi);
+
+static void proc_CLFLUSH(u32 addr_hi)
+{
+       SetUpperFSbase(addr_hi);
+
+       __asm__ volatile (
+               /* clflush fs:[eax] */
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+                "clflush %%fs:(%0)\n\t"
+               "mfence\n\t"
+                ::"a" (addr_hi<<8)
+       );
+}
+
+
+static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 line_num)
+{
+       __asm__ volatile (
+               /*prevent speculative execution of following instructions*/
+               /* FIXME: needed ? */
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+               "1:\n\t"
+               "movdqa (%3), %%xmm0\n\t"
+               "movntdq %%xmm0, %%fs:(%0)\n\t" /* xmm0 is 128 bit */
+               "addl %1, %0\n\t"
+               "addl %1, %3\n\t"
+               "loop 1b\n\t"
+               "mfence\n\t"
+
+                :: "a" (addr_lo), "d" (16), "c" (line_num * 4), "b"(buf_a)
+       );
+
+}
+
+static u32 read32_fs(u32 addr_lo)
+{
+       u32 value;
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+               "movl %%fs:(%1), %0\n\t"
+               :"=b"(value): "a" (addr_lo)
+       );
+       return value;
+}
+
+#ifdef UNUSED_CODE
+static u8 read8_fs(u32 addr_lo)
+{
+       u8 byte;
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+               "movb %%fs:(%1), %b0\n\t"
+               "mfence\n\t"
+               :"=b"(byte): "a" (addr_lo)
+       );
+       return byte;
+}
+#endif
+
+static void FlushDQSTestPattern_L9(u32 addr_lo)
+{
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+               "clflush %%fs:-128(%%ecx)\n\t"
+               "clflush %%fs:-64(%%ecx)\n\t"
+               "clflush %%fs:(%%ecx)\n\t"
+               "clflush %%fs:64(%%ecx)\n\t"
+
+               "clflush %%fs:-128(%%eax)\n\t"
+               "clflush %%fs:-64(%%eax)\n\t"
+               "clflush %%fs:(%%eax)\n\t"
+               "clflush %%fs:64(%%eax)\n\t"
+
+               "clflush %%fs:-128(%%ebx)\n\t"
+
+                ::  "b" (addr_lo+128+8*64), "c"(addr_lo+128),
+                    "a"(addr_lo+128+4*64)
+       );
+
+}
+
+static __attribute__((noinline)) void FlushDQSTestPattern_L18(u32 addr_lo)
+{
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+               "clflush %%fs:-128(%%eax)\n\t"
+               "clflush %%fs:-64(%%eax)\n\t"
+               "clflush %%fs:(%%eax)\n\t"
+               "clflush %%fs:64(%%eax)\n\t"
+
+               "clflush %%fs:-128(%%edi)\n\t"
+               "clflush %%fs:-64(%%edi)\n\t"
+               "clflush %%fs:(%%edi)\n\t"
+               "clflush %%fs:64(%%edi)\n\t"
+
+               "clflush %%fs:-128(%%ebx)\n\t"
+               "clflush %%fs:-64(%%ebx)\n\t"
+               "clflush %%fs:(%%ebx)\n\t"
+               "clflush %%fs:64(%%ebx)\n\t"
+
+               "clflush %%fs:-128(%%ecx)\n\t"
+               "clflush %%fs:-64(%%ecx)\n\t"
+               "clflush %%fs:(%%ecx)\n\t"
+               "clflush %%fs:64(%%ecx)\n\t"
+
+               "clflush %%fs:-128(%%edx)\n\t"
+               "clflush %%fs:-64(%%edx)\n\t"
+
+                :: "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
+                   "d" (addr_lo +128+16*64), "a"(addr_lo+128),
+                   "D"(addr_lo+128+4*64)
+       );
+}
+
+static void ReadL18TestPattern(u32 addr_lo)
+{
+       /* set fs and use fs prefix to access the mem */
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"                  /* _EXECFENCE */
+               "movl %%fs:-128(%%esi), %%eax\n\t"      /* TestAddr cache line */
+               "movl %%fs:-64(%%esi), %%eax\n\t"       /* +1 */
+               "movl %%fs:(%%esi), %%eax\n\t"          /* +2 */
+               "movl %%fs:64(%%esi), %%eax\n\t"        /* +3 */
+
+               "movl %%fs:-128(%%edi), %%eax\n\t"      /* +4 */
+               "movl %%fs:-64(%%edi), %%eax\n\t"       /* +5 */
+               "movl %%fs:(%%edi), %%eax\n\t"          /* +6 */
+               "movl %%fs:64(%%edi), %%eax\n\t"        /* +7 */
+
+               "movl %%fs:-128(%%ebx), %%eax\n\t"      /* +8 */
+               "movl %%fs:-64(%%ebx), %%eax\n\t"       /* +9 */
+               "movl %%fs:(%%ebx), %%eax\n\t"          /* +10 */
+               "movl %%fs:64(%%ebx), %%eax\n\t"        /* +11 */
+
+               "movl %%fs:-128(%%ecx), %%eax\n\t"      /* +12 */
+               "movl %%fs:-64(%%ecx), %%eax\n\t"       /* +13 */
+               "movl %%fs:(%%ecx), %%eax\n\t"          /* +14 */
+               "movl %%fs:64(%%ecx), %%eax\n\t"        /* +15 */
+
+               "movl %%fs:-128(%%edx), %%eax\n\t"      /* +16 */
+               "movl %%fs:-64(%%edx), %%eax\n\t"       /* +17 */
+               "mfence\n\t"
+
+                :: "a"(0), "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
+                   "d" (addr_lo +128+16*64), "S"(addr_lo+128),
+                   "D"(addr_lo+128+4*64)
+       );
+
+}
+
+static void ReadL9TestPattern(u32 addr_lo)
+{
+
+       /* set fs and use fs prefix to access the mem */
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"                  /* _EXECFENCE */
+
+               "movl %%fs:-128(%%ecx), %%eax\n\t"      /* TestAddr cache line */
+               "movl %%fs:-64(%%ecx), %%eax\n\t"       /* +1 */
+               "movl %%fs:(%%ecx), %%eax\n\t"          /* +2 */
+               "movl %%fs:64(%%ecx), %%eax\n\t"        /* +3 */
+
+               "movl %%fs:-128(%%edx), %%eax\n\t"      /* +4 */
+               "movl %%fs:-64(%%edx), %%eax\n\t"       /* +5 */
+               "movl %%fs:(%%edx), %%eax\n\t"          /* +6 */
+               "movl %%fs:64(%%edx), %%eax\n\t"        /* +7 */
+
+               "movl %%fs:-128(%%ebx), %%eax\n\t"      /* +8 */
+               "mfence\n\t"
+
+                :: "a"(0), "b" (addr_lo+128+8*64), "c"(addr_lo+128),
+                   "d"(addr_lo+128+4*64)
+       );
+
+}
+
+static void ReadMaxRdLat1CLTestPattern_D(u32 addr)
+{
+       SetUpperFSbase(addr);
+
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"                  /* _EXECFENCE */
+               "movl %%fs:-128(%%esi), %%eax\n\t"      /* TestAddr cache line */
+               "movl %%fs:-64(%%esi), %%eax\n\t"       /* +1 */
+               "movl %%fs:(%%esi), %%eax\n\t"          /* +2 */
+               "mfence\n\t"
+                :: "a"(0), "S"((addr<<8)+128)
+       );
+
+}
+
+static void WriteMaxRdLat1CLTestPattern_D(u32 buf, u32 addr)
+{
+       SetUpperFSbase(addr);
+
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+               "1:\n\t"
+               "movdqa (%3), %%xmm0\n\t"
+               "movntdq %%xmm0, %%fs:(%0)\n\t" /* xmm0 is 128 bit */
+               "addl %1, %0\n\t"
+               "addl %1, %3\n\t"
+               "loop 1b\n\t"
+               "mfence\n\t"
+
+                :: "a" (addr<<8), "d" (16), "c" (3 * 4), "b"(buf)
+       );
+}
+
+static void FlushMaxRdLatTestPattern_D(u32 addr)
+{
+       /*  Flush a pattern of 72 bit times (per DQ) from cache.
+        * This procedure is used to ensure cache miss on the next read training.
+        */
+
+       SetUpperFSbase(addr);
+
+       __asm__ volatile (
+               "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+               "clflush %%fs:-128(%%esi)\n\t"   /* TestAddr cache line */
+               "clflush %%fs:-64(%%esi)\n\t"    /* +1 */
+               "clflush %%fs:(%%esi)\n\t"  /* +2 */
+               "mfence\n\t"
+
+                :: "S"((addr<<8)+128)
+       );
+}
+
+static u32 stream_to_int(u8 *p)
+{
+       int i;
+       u32 val;
+       u32 valx;
+
+       val = 0;
+
+       for(i=3; i>=0; i--) {
+               val <<= 8;
+               valx = *(p+i);
+               val |= valx;
+       }
+
+       return val;
+}
+
+#ifdef UNUSED_CODE
+static void oemSet_NB32(u32 addr, u32 val, u8 *valid)
+{
+}
+
+static u32 oemGet_NB32(u32 addr,  u8 *valid)
+{
+       *valid = 0;
+       return 0xffffffff;
+}
+#endif
+
+static u8 oemNodePresent_D(u8 Node, u8 *ret)
+{
+       *ret = 0;
+       return 0;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
new file mode 100644 (file)
index 0000000..72502c0
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
+                               u32 *AddrTmgCTL, u32 *ODC_CTL,
+                               u8 *CMDmode);
+
+void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+                        struct DCTStatStruc *pDCTstat, u32 dct)
+{
+       Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
+                               pDCTstat->MAload[dct],
+                               &(pDCTstat->CH_ADDR_TMG[dct]), &(pDCTstat->CH_ODC_CTL[dct]),
+                               &pDCTstat->_2Tmode);
+
+       pDCTstat->CH_EccDQSLike[0]  = 0x0403;
+       pDCTstat->CH_EccDQSScale[0] = 0x70;
+       pDCTstat->CH_EccDQSLike[1]  = 0x0403;
+       pDCTstat->CH_EccDQSScale[1] = 0x70;
+
+       pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;        /* 60ohms */
+}
+
+/*
+ *  In: MAAdimms   - number of DIMMs on the channel
+ *    : Speed      - Speed (see DCTStatstruc.Speed for definition)
+ *    : MAAload    - number of address bus loads on the channel
+ * Out: AddrTmgCTL - Address Timing Control Register Value
+ *    : ODC_CTL    - Output Driver Compensation Control Register Value
+ *    : CMDmode    - CMD mode
+ */
+static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
+                               u32 *AddrTmgCTL, u32 *ODC_CTL,
+                               u8 *CMDmode)
+{
+       *AddrTmgCTL = 0;
+       *ODC_CTL = 0;
+       *CMDmode = 1;
+
+       if(MAAdimms == 1) {
+               if(MAAload >= 16) {
+                       if(Speed == 4)
+                               *AddrTmgCTL = 0x003B0000;
+                       else if (Speed == 5)
+                               *AddrTmgCTL = 0x00380000;
+                       else if (Speed == 6)
+                               *AddrTmgCTL = 0x00360000;
+                       else
+                               *AddrTmgCTL = 0x00340000;
+               } else {
+                       *AddrTmgCTL = 0x00000000;
+               }
+               *ODC_CTL = 0x00113222;
+               *CMDmode = 1;
+       } else /* if(MAAdimms == 0) */ {
+               if(Speed == 4) {
+                       *CMDmode = 1;
+                       *AddrTmgCTL = 0x00390039;
+               } else if(Speed == 5) {
+                       *CMDmode = 1;
+                       *AddrTmgCTL = 0x00350037;
+               } else if(Speed == 6) {
+                       *CMDmode = 2;
+                       *AddrTmgCTL = 0x00000035;
+               } else {
+                       *CMDmode = 2;
+                       *AddrTmgCTL = 0x00000033;
+               }
+               *ODC_CTL = 0x00223323;
+       }
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c b/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
new file mode 100644 (file)
index 0000000..8a843e6
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* The socket type F (1207), Fr2, G (1207) are not tested.
+ */
+
+static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
+                               u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL,
+                               u8 *CMDmode);
+
+
+void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+                        struct DCTStatStruc *pDCTstat, u32 dct)
+{
+       Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
+                               pDCTstat->MAload[dct], pDCTstat->DATAload[dct],
+                               &(pDCTstat->CH_ADDR_TMG[dct]), &(pDCTstat->CH_ODC_CTL[dct]),
+                               &pDCTstat->_2Tmode);
+
+       if (pDCTstat->GangedMode == 1 && dct == 0)
+               Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[1], pDCTstat->Speed,
+                                    pDCTstat->MAload[1], pDCTstat->DATAload[1],
+                                    &(pDCTstat->CH_ADDR_TMG[1]), &(pDCTstat->CH_ODC_CTL[1]),
+                                    &pDCTstat->_2Tmode);
+
+       pDCTstat->CH_EccDQSLike[0]  = 0x0302;
+       pDCTstat->CH_EccDQSLike[1]  = 0x0302;
+
+}
+
+/*
+ *  In: MAAdimms   - number of DIMMs on the channel
+ *    : Speed      - Speed (see DCTStatstruc.Speed for definition)
+ *    : MAAload    - number of address bus loads on the channel
+ *    : DATAAload  - number of ranks on the channel
+ * Out: AddrTmgCTL - Address Timing Control Register Value
+ *    : ODC_CTL    - Output Driver Compensation Control Register Value
+ *    : CMDmode    - CMD mode
+ */
+static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
+                               u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL,
+                               u8 *CMDmode)
+{
+       *AddrTmgCTL = 0;
+       *ODC_CTL = 0;
+       *CMDmode = 1;
+
+       if (mctGet_NVbits(NV_MAX_DIMMS) == 4) {
+               if(Speed == 4) {
+                       *AddrTmgCTL = 0x00000000;
+               } else if (Speed == 5) {
+                       *AddrTmgCTL = 0x003C3C3C;
+                       if (MAAdimms > 1)
+                               *AddrTmgCTL = 0x003A3C3A;
+               } else if (Speed == 6) {
+                       if (MAAdimms == 1)
+                               *AddrTmgCTL = 0x003A3A3A;
+                       else
+                               *AddrTmgCTL = 0x00383A38;
+               } else {
+                       if (MAAdimms == 1)
+                               *AddrTmgCTL = 0x00373937;
+                       else
+                               *AddrTmgCTL = 0x00353935;
+               }
+       }
+       else {
+               if(Speed == 4) {
+                       *AddrTmgCTL = 0x00000000;
+                       if (MAAdimms == 3)
+                               *AddrTmgCTL = 0x00380038;
+               } else if (Speed == 5) {
+                       if (MAAdimms == 1)
+                               *AddrTmgCTL = 0x003C3C3C;
+                       else if (MAAdimms == 2)
+                               *AddrTmgCTL = 0x003A3C3A;
+                       else
+                               *AddrTmgCTL = 0x00373C37;
+               } else if (Speed == 6) {
+                       if (MAAdimms == 1)
+                               *AddrTmgCTL = 0x003A3A3A;
+                       else if (MAAdimms == 2)
+                               *AddrTmgCTL = 0x00383A38;
+                       else
+                               *AddrTmgCTL = 0x00343A34;
+               } else {
+                       if (MAAdimms == 1)
+                               *AddrTmgCTL = 0x00393939;
+                       else if (MAAdimms == 2)
+                               *AddrTmgCTL = 0x00363936;
+                       else
+                               *AddrTmgCTL = 0x00303930;
+               }
+       }
+
+       if ((MAAdimms == 1) && (MAAload < 4))
+               *ODC_CTL = 0x20113222;
+       else
+               *ODC_CTL = 0x20223222;
+
+       *CMDmode = 1;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c
new file mode 100644 (file)
index 0000000..05b01d7
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+void InterleaveChannels_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+{
+
+       u8 Node;
+       u32 DramBase, DctSelBase;
+       u8 DctSelIntLvAddr, DctSelHi;
+       u8 HoleValid = 0;
+       u32 HoleSize, HoleBase = 0;
+       u32 val, tmp;
+       u32 dct0_size, dct1_size;
+       struct DCTStatStruc *pDCTstat;
+
+       /* HoleValid - indicates whether the current Node contains hole.
+        * HoleSize - indicates whether there is IO hole in the whole system
+        * memory.
+        */
+
+       /* call back to wrapper not needed ManualChannelInterleave_D(); */
+       /* call back - DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv);*/      /* override interleave */
+       /* Manually set: typ=5, otherwise typ=7. */
+       DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv); /* typ=5: Hash*: exclusive OR of address bits[20:16, 6]. */
+
+       if (DctSelIntLvAddr & 1) {
+               DctSelIntLvAddr >>= 1;
+               HoleSize = 0;
+               if ((pMCTstat->GStatus & (1 << GSB_SoftHole)) ||
+                    (pMCTstat->GStatus & (1 << GSB_HWHole))) {
+                       if (pMCTstat->HoleBase) {
+                               HoleBase = pMCTstat->HoleBase >> 8;
+                               HoleSize = HoleBase & 0xFFFF0000;
+                               HoleSize |= ((~HoleBase) + 1) & 0xFFFF;
+                       }
+               }
+               Node = 0;
+               while (Node < MAX_NODES_SUPPORTED) {
+                       pDCTstat = pDCTstatA + Node;
+                       val = Get_NB32(pDCTstat->dev_map, 0xF0);
+                       if (val & (1 << DramHoleValid))
+                               HoleValid = 1;
+                       if (!pDCTstat->GangedMode && pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1]) {
+                               DramBase = pDCTstat->NodeSysBase >> 8;
+                               dct1_size = ((pDCTstat->NodeSysLimit) + 2) >> 8;
+                               dct0_size = Get_NB32(pDCTstat->dev_dct, 0x114);
+                                       if (dct0_size >= 0x10000) {
+                                               dct0_size -= HoleSize;
+                                       }
+
+                               dct0_size -= DramBase;
+                               dct1_size -= dct0_size;
+                               DctSelHi = 0x05;                /* DctSelHiRngEn = 1, DctSelHi = 0 */
+                               if (dct1_size == dct0_size) {
+                                       dct1_size = 0;
+                                       DctSelHi = 0x04;        /* DctSelHiRngEn = 0 */
+                               } else if (dct1_size > dct0_size ) {
+                                       dct1_size = dct0_size;
+                                       DctSelHi = 0x07;        /* DctSelHiRngEn = 1, DctSelHi = 1 */
+                               }
+                               dct0_size = dct1_size;
+                               dct0_size += DramBase;
+                               dct0_size += dct1_size;
+                               if (dct0_size >= HoleBase)      /* if DctSelBaseAddr > HoleBase */
+                                       dct0_size += HoleSize;
+                               DctSelBase = dct0_size;
+
+                               if (dct1_size == 0)
+                                       dct0_size = 0;
+                               dct0_size -= dct1_size;         /* DctSelBaseOffset = DctSelBaseAddr - Interleaved region */
+                               Set_NB32(pDCTstat->dev_dct, 0x114, dct0_size);
+
+                               if (dct1_size == 0)
+                                       dct1_size = DctSelBase;
+                               val = Get_NB32(pDCTstat->dev_dct, 0x110);
+                               val &= 0x7F8;
+                               val |= dct1_size;
+                               val |= DctSelHi;
+                               val |= (DctSelIntLvAddr << 6) & 0xFF;
+                               Set_NB32(pDCTstat->dev_dct, 0x110, val);
+
+                               if (HoleValid) {
+                                       tmp = DramBase;
+                                       val = DctSelBase;
+                                       if (val < HoleBase) {   /* DctSelBaseAddr < DramHoleBase */
+                                               val -= DramBase;
+                                               val >>= 1;
+                                               tmp += val;
+                                       }
+                                       tmp += HoleSize;
+                                       val = Get_NB32(pDCTstat->dev_map, 0xF0);        /* DramHoleOffset */
+                                       val &= 0xFFFF007F;
+                                       val |= (tmp & ~0xFFFF007F);
+                                       Set_NB32(pDCTstat->dev_map, 0xF0, val);
+                               }
+                       }
+                       printk(BIOS_DEBUG, "InterleaveChannels_D: Node %x\n", Node);
+                       printk(BIOS_DEBUG, "InterleaveChannels_D: Status %x\n", pDCTstat->Status);
+                       printk(BIOS_DEBUG, "InterleaveChannels_D: ErrStatus %x\n", pDCTstat->ErrStatus);
+                       printk(BIOS_DEBUG, "InterleaveChannels_D: ErrCode %x\n", pDCTstat->ErrCode);
+                       Node++;
+               }
+       }
+       printk(BIOS_DEBUG, "InterleaveChannels_D: Done\n\n");
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
new file mode 100644 (file)
index 0000000..4cf0fa8
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Low swap bit vs bank size encoding (physical, not logical address bit)
+ * ;To calculate the number by hand, add the number of Bank address bits
+ * ;(2 or 3) to the number of column address bits, plus 3 (the logical
+ * ;page size), and subtract 8.
+ */
+static const u8 Tab_int_D[] = {6,7,7,8,8,8,8,8,9,9,8,9};
+
+void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 ChipSel, EnChipSels;
+       u32 AddrLoMask, AddrHiMask;
+       u32 AddrLoMaskN, AddrHiMaskN, MemSize = 0;
+       u8 DoIntlv, _CsIntCap;
+       u32 BitDelta, BankEncd = 0;
+
+       u32 dev;
+       u32 reg;
+       u32 reg_off;
+       u32 val;
+       u32 val_lo, val_hi;
+
+       DoIntlv = mctGet_NVbits(NV_BankIntlv);
+       _CsIntCap = 0;
+       EnChipSels = 0;
+
+       dev = pDCTstat->dev_dct;
+       reg_off = 0x100 * dct;
+
+       ChipSel = 0;            /* Find out if current configuration is capable */
+       while (DoIntlv && (ChipSel < MAX_CS_SUPPORTED)) {
+               reg = 0x40+(ChipSel<<2) + reg_off;      /* Dram CS Base 0 */
+               val = Get_NB32(dev, reg);
+               if ( val & (1<<CSEnable)) {
+                       EnChipSels++;
+                       reg = 0x60+((ChipSel>>1)<<2)+reg_off; /*Dram CS Mask 0 */
+                       val = Get_NB32(dev, reg);
+                       val >>= 19;
+                       val &= 0x3ff;
+                       val++;
+                       if (EnChipSels == 1)
+                               MemSize = val;
+                       else
+                               /*If mask sizes not same then skip */
+                               if (val != MemSize)
+                                       break;
+                       reg = 0x80 + reg_off;           /*Dram Bank Addressing */
+                       val = Get_NB32(dev, reg);
+                       val >>= (ChipSel>>1)<<2;
+                       val &= 0x0f;
+                       if(EnChipSels == 1)
+                               BankEncd = val;
+                       else
+                               /*If number of Rows/Columns not equal, skip */
+                               if (val != BankEncd)
+                                       break;
+               }
+               ChipSel++;
+       }
+       if (ChipSel == MAX_CS_SUPPORTED) {
+               if ((EnChipSels == 2) || (EnChipSels == 4) || (EnChipSels == 8))
+                       _CsIntCap = 1;
+       }
+
+       if (DoIntlv) {
+               if(!_CsIntCap) {
+                       pDCTstat->ErrStatus |= 1<<SB_BkIntDis;
+                       DoIntlv = 0;
+               }
+       }
+
+       if(DoIntlv) {
+               val = Tab_int_D[BankEncd];
+               if (pDCTstat->Status & (1<<SB_128bitmode))
+                       val++;
+
+               AddrLoMask = (EnChipSels - 1)  << val;
+               AddrLoMaskN = ~AddrLoMask;
+
+               val = bsf(MemSize) + 19;
+               AddrHiMask = (EnChipSels -1) << val;
+               AddrHiMaskN = ~AddrHiMask;
+
+               BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask);
+
+               for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) {
+                       reg = 0x40+(ChipSel<<2) + reg_off;      /*Dram CS Base 0 */
+                       val = Get_NB32(dev, reg);
+                       if (val & 3) {
+                               val_lo = val & AddrLoMask;
+                               val_hi = val & AddrHiMask;
+                               val &= AddrLoMaskN;
+                               val &= AddrHiMaskN;
+                               val_lo <<= BitDelta;
+                               val_hi >>= BitDelta;
+                               val |= val_lo;
+                               val |= val_hi;
+                               Set_NB32(dev, reg, val);
+
+                               if(ChipSel & 1)
+                                       continue;
+
+                               reg = 0x60 + ((ChipSel>>1)<<2) + reg_off; /*Dram CS Mask 0 */
+                               val = Get_NB32(dev, reg);
+                               val_lo = val & AddrLoMask;
+                               val_hi = val & AddrHiMask;
+                               val &= AddrLoMaskN;
+                               val &= AddrHiMaskN;
+                               val_lo <<= BitDelta;
+                               val_hi >>= BitDelta;
+                               val |= val_lo;
+                               val |= val_hi;
+                               Set_NB32(dev, reg, val);
+                       }
+               }
+       }       /* DoIntlv */
+
+       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+       printk(BIOS_DEBUG, "InterleaveBanks_D: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "InterleaveBanks_D: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "InterleaveBanks_D: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "InterleaveBanks_D: Done\n\n");
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
new file mode 100644 (file)
index 0000000..db930ef
--- /dev/null
@@ -0,0 +1,1312 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u16 like,
+                               u8 scale, u8 ChipSel);
+static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 ChipSel);
+static u8 MiddleDQS_D(u8 min, u8 max);
+static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 cs_start);
+static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 cs_start);
+static void WriteDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo);
+static void WriteL18TestPattern_D(struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo);
+static void WriteL9TestPattern_D(struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo);
+static u16 CompareDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 addr_lo);
+static void FlushDQSTestPattern_D(struct DCTStatStruc *pDCTstat,
+                                       u32 addr_lo);
+static void SetTargetWTIO_D(u32 TestAddr);
+static void ResetTargetWTIO_D(void);
+static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo);
+static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 ChipSel,
+                                       u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
+void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index);
+u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u8 ChipSel);
+static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u8 cs_start);
+u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel,
+                               u8 receiver, u8 *valid);
+static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u32 *buffer);
+
+static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 ChipSel,
+                                     u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
+
+static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 ChipSel);
+
+#define DQS_TRAIN_DEBUG 0
+
+static void print_debug_dqs(const char *str, u32 val, u8 level)
+{
+#if DQS_TRAIN_DEBUG > 0
+       if (DQS_TRAIN_DEBUG >= level) {
+               printk(BIOS_DEBUG, "%s%x\n", str, val);
+       }
+#endif
+}
+
+static void print_debug_dqs_pair(const char *str, u32 val, const char *str2, u32 val2, u8 level)
+{
+#if DQS_TRAIN_DEBUG > 0
+       if (DQS_TRAIN_DEBUG >= level) {
+               printk(BIOS_DEBUG, "%s%08x%s%08x\n", str, val, str2, val2);
+       }
+#endif
+}
+
+/*Warning:  These must be located so they do not cross a logical 16-bit segment boundary!*/
+const static u32 TestPatternJD1a_D[] = {
+       0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF, /* QW0-1, ALL-EVEN */
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW2-3, ALL-EVEN */
+       0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF, /* QW4-5, ALL-EVEN */
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW6-7, ALL-EVEN */
+       0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, /* QW0-1, DQ0-ODD */
+       0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, /* QW2-3, DQ0-ODD */
+       0x01010101,0x01010101,0xFeFeFeFe,0xFeFeFeFe, /* QW4-5, DQ0-ODD */
+       0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, /* QW6-7, DQ0-ODD */
+       0x02020202,0x02020202,0x02020202,0x02020202, /* QW0-1, DQ1-ODD */
+       0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW2-3, DQ1-ODD */
+       0xFdFdFdFd,0xFdFdFdFd,0x02020202,0x02020202, /* QW4-5, DQ1-ODD */
+       0x02020202,0x02020202,0x02020202,0x02020202, /* QW6-7, DQ1-ODD */
+       0x04040404,0x04040404,0xfBfBfBfB,0xfBfBfBfB, /* QW0-1, DQ2-ODD */
+       0x04040404,0x04040404,0x04040404,0x04040404, /* QW2-3, DQ2-ODD */
+       0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW4-5, DQ2-ODD */
+       0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW6-7, DQ2-ODD */
+       0x08080808,0x08080808,0xF7F7F7F7,0xF7F7F7F7, /* QW0-1, DQ3-ODD */
+       0x08080808,0x08080808,0x08080808,0x08080808, /* QW2-3, DQ3-ODD */
+       0xF7F7F7F7,0xF7F7F7F7,0x08080808,0x08080808, /* QW4-5, DQ3-ODD */
+       0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW6-7, DQ3-ODD */
+       0x10101010,0x10101010,0x10101010,0x10101010, /* QW0-1, DQ4-ODD */
+       0xeFeFeFeF,0xeFeFeFeF,0x10101010,0x10101010, /* QW2-3, DQ4-ODD */
+       0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW4-5, DQ4-ODD */
+       0xeFeFeFeF,0xeFeFeFeF,0x10101010,0x10101010, /* QW6-7, DQ4-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW0-1, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0x20202020,0x20202020, /* QW2-3, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW4-5, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW6-7, DQ5-ODD */
+       0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW0-1, DQ6-ODD */
+       0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, /* QW2-3, DQ6-ODD */
+       0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, /* QW4-5, DQ6-ODD */
+       0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, /* QW6-7, DQ6-ODD */
+       0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, /* QW0-1, DQ7-ODD */
+       0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, /* QW2-3, DQ7-ODD */
+       0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, /* QW4-5, DQ7-ODD */
+       0x80808080,0x80808080,0x80808080,0x80808080  /* QW6-7, DQ7-ODD */
+};
+const static u32 TestPatternJD1b_D[] = {
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW0,CHA-B, ALL-EVEN */
+       0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, /* QW1,CHA-B, ALL-EVEN */
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW2,CHA-B, ALL-EVEN */
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW3,CHA-B, ALL-EVEN */
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW4,CHA-B, ALL-EVEN */
+       0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, /* QW5,CHA-B, ALL-EVEN */
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW6,CHA-B, ALL-EVEN */
+       0x00000000,0x00000000,0x00000000,0x00000000, /* QW7,CHA-B, ALL-EVEN */
+       0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW0,CHA-B, DQ0-ODD */
+       0x01010101,0x01010101,0x01010101,0x01010101, /* QW1,CHA-B, DQ0-ODD */
+       0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW2,CHA-B, DQ0-ODD */
+       0x01010101,0x01010101,0x01010101,0x01010101, /* QW3,CHA-B, DQ0-ODD */
+       0x01010101,0x01010101,0x01010101,0x01010101, /* QW4,CHA-B, DQ0-ODD */
+       0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW5,CHA-B, DQ0-ODD */
+       0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW6,CHA-B, DQ0-ODD */
+       0x01010101,0x01010101,0x01010101,0x01010101, /* QW7,CHA-B, DQ0-ODD */
+       0x02020202,0x02020202,0x02020202,0x02020202, /* QW0,CHA-B, DQ1-ODD */
+       0x02020202,0x02020202,0x02020202,0x02020202, /* QW1,CHA-B, DQ1-ODD */
+       0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW2,CHA-B, DQ1-ODD */
+       0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW3,CHA-B, DQ1-ODD */
+       0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW4,CHA-B, DQ1-ODD */
+       0x02020202,0x02020202,0x02020202,0x02020202, /* QW5,CHA-B, DQ1-ODD */
+       0x02020202,0x02020202,0x02020202,0x02020202, /* QW6,CHA-B, DQ1-ODD */
+       0x02020202,0x02020202,0x02020202,0x02020202, /* QW7,CHA-B, DQ1-ODD */
+       0x04040404,0x04040404,0x04040404,0x04040404, /* QW0,CHA-B, DQ2-ODD */
+       0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW1,CHA-B, DQ2-ODD */
+       0x04040404,0x04040404,0x04040404,0x04040404, /* QW2,CHA-B, DQ2-ODD */
+       0x04040404,0x04040404,0x04040404,0x04040404, /* QW3,CHA-B, DQ2-ODD */
+       0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW4,CHA-B, DQ2-ODD */
+       0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW5,CHA-B, DQ2-ODD */
+       0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW6,CHA-B, DQ2-ODD */
+       0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW7,CHA-B, DQ2-ODD */
+       0x08080808,0x08080808,0x08080808,0x08080808, /* QW0,CHA-B, DQ3-ODD */
+       0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW1,CHA-B, DQ3-ODD */
+       0x08080808,0x08080808,0x08080808,0x08080808, /* QW2,CHA-B, DQ3-ODD */
+       0x08080808,0x08080808,0x08080808,0x08080808, /* QW3,CHA-B, DQ3-ODD */
+       0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW4,CHA-B, DQ3-ODD */
+       0x08080808,0x08080808,0x08080808,0x08080808, /* QW5,CHA-B, DQ3-ODD */
+       0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW6,CHA-B, DQ3-ODD */
+       0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW7,CHA-B, DQ3-ODD */
+       0x10101010,0x10101010,0x10101010,0x10101010, /* QW0,CHA-B, DQ4-ODD */
+       0x10101010,0x10101010,0x10101010,0x10101010, /* QW1,CHA-B, DQ4-ODD */
+       0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW2,CHA-B, DQ4-ODD */
+       0x10101010,0x10101010,0x10101010,0x10101010, /* QW3,CHA-B, DQ4-ODD */
+       0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW4,CHA-B, DQ4-ODD */
+       0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW5,CHA-B, DQ4-ODD */
+       0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW6,CHA-B, DQ4-ODD */
+       0x10101010,0x10101010,0x10101010,0x10101010, /* QW7,CHA-B, DQ4-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW0,CHA-B, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW1,CHA-B, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW2,CHA-B, DQ5-ODD */
+       0x20202020,0x20202020,0x20202020,0x20202020, /* QW3,CHA-B, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW4,CHA-B, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW5,CHA-B, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW6,CHA-B, DQ5-ODD */
+       0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW7,CHA-B, DQ5-ODD */
+       0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW0,CHA-B, DQ6-ODD */
+       0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW1,CHA-B, DQ6-ODD */
+       0x40404040,0x40404040,0x40404040,0x40404040, /* QW2,CHA-B, DQ6-ODD */
+       0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW3,CHA-B, DQ6-ODD */
+       0x40404040,0x40404040,0x40404040,0x40404040, /* QW4,CHA-B, DQ6-ODD */
+       0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW5,CHA-B, DQ6-ODD */
+       0x40404040,0x40404040,0x40404040,0x40404040, /* QW6,CHA-B, DQ6-ODD */
+       0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW7,CHA-B, DQ6-ODD */
+       0x80808080,0x80808080,0x80808080,0x80808080, /* QW0,CHA-B, DQ7-ODD */
+       0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, /* QW1,CHA-B, DQ7-ODD */
+       0x80808080,0x80808080,0x80808080,0x80808080, /* QW2,CHA-B, DQ7-ODD */
+       0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, /* QW3,CHA-B, DQ7-ODD */
+       0x80808080,0x80808080,0x80808080,0x80808080, /* QW4,CHA-B, DQ7-ODD */
+       0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, /* QW5,CHA-B, DQ7-ODD */
+       0x80808080,0x80808080,0x80808080,0x80808080, /* QW6,CHA-B, DQ7-ODD */
+       0x80808080,0x80808080,0x80808080,0x80808080  /* QW7,CHA-B, DQ7-ODD */
+};
+
+void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA, u8 Pass)
+{
+       u8 Node;
+       struct DCTStatStruc *pDCTstat;
+       u32 val;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+
+               if (pDCTstat->DCTSysLimit) {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x78);
+                       val |= 1 <<DqsRcvEnTrain;
+                       Set_NB32(pDCTstat->dev_dct, 0x78, val);
+                       val = Get_NB32(pDCTstat->dev_dct, 0x78 + 0x100);
+                       val |= 1 <<DqsRcvEnTrain;
+                       Set_NB32(pDCTstat->dev_dct, 0x78 + 0x100, val);
+                       mct_TrainRcvrEn_D(pMCTstat, pDCTstat, Pass);
+               }
+       }
+}
+
+static void SetEccDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
+{
+       u8 channel;
+       u8 direction;
+
+       for (channel = 0; channel < 2; channel++){
+               for (direction = 0; direction < 2; direction++) {
+                       pDCTstat->Channel = channel;    /* Channel A or B */
+                       pDCTstat->Direction = direction; /* Read or write */
+                       CalcEccDQSPos_D(pMCTstat, pDCTstat, pDCTstat->CH_EccDQSLike[channel], pDCTstat->CH_EccDQSScale[channel], ChipSel);
+                       print_debug_dqs_pair("\t\tSetEccDQSRdWrPos: channel ", channel, direction==DQS_READDIR? " R dqs_delay":" W dqs_delay",  pDCTstat->DQSDelay, 2);
+                       pDCTstat->ByteLane = 8;
+                       StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+                       mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, ChipSel);
+               }
+       }
+}
+
+static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u16 like, u8 scale, u8 ChipSel)
+{
+       u8 DQSDelay0, DQSDelay1;
+       u16 DQSDelay;
+
+       if (pDCTstat->Status & (1 << SB_Registered)) {
+               return;
+       }
+
+       pDCTstat->ByteLane = like & 0xff;
+       GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+       DQSDelay0 = pDCTstat->DQSDelay;
+
+       pDCTstat->ByteLane = (like >> 8) & 0xff;
+       GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+       DQSDelay1 = pDCTstat->DQSDelay;
+
+       if (DQSDelay0>DQSDelay1) {
+               DQSDelay = DQSDelay0 - DQSDelay1;
+       } else {
+               DQSDelay = DQSDelay1 - DQSDelay0;
+       }
+
+       DQSDelay = DQSDelay * (~scale);
+
+       DQSDelay += 0x80;       /* round it */
+
+       DQSDelay >>= 8;         /* 256 */
+
+       if (DQSDelay0>DQSDelay1) {
+               DQSDelay = DQSDelay1 - DQSDelay;
+       } else {
+               DQSDelay += DQSDelay1;
+       }
+
+       pDCTstat->DQSDelay = (u8)DQSDelay;
+}
+
+static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 cs_start)
+{
+       u32 Errors;
+       u8 Channel, DQSWrDelay;
+       u8 _DisableDramECC = 0;
+       u32 PatternBuffer[292];
+       u8 _Wrap32Dis = 0, _SSE2 = 0;
+       u8 dqsWrDelay_end;
+
+       u32 addr;
+       u32 cr4;
+       u32 lo, hi;
+
+       print_debug_dqs("\nTrainDQSRdWrPos: Node_ID ", pDCTstat->Node_ID, 0);
+       cr4 = read_cr4();
+       if (cr4 & (1<<9)) {
+               _SSE2 = 1;
+       }
+       cr4 |= (1<<9);          /* OSFXSR enable SSE2 */
+       write_cr4(cr4);
+
+       addr = HWCR;
+       _RDMSR(addr, &lo, &hi);
+       if (lo & (1<<17)) {
+               _Wrap32Dis = 1;
+       }
+       lo |= (1<<17);          /* HWCR.wrap32dis */
+       _WRMSR(addr, lo, hi);   /* allow 64-bit memory references in real mode */
+
+       /* Disable ECC correction of reads on the dram bus. */
+       _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
+
+       SetupDqsPattern_D(pMCTstat, pDCTstat, PatternBuffer);
+
+       /* mct_BeforeTrainDQSRdWrPos_D */
+       dqsWrDelay_end = 0x20;
+
+       Errors = 0;
+       for (Channel = 0; Channel < 2; Channel++) {
+               print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ",Channel, 1);
+               pDCTstat->Channel = Channel;
+
+               if (pDCTstat->DIMMValidDCT[Channel] == 0)       /* mct_BeforeTrainDQSRdWrPos_D */
+                       continue;
+
+               pDCTstat->DqsRdWrPos_Saved = 0;
+               for ( DQSWrDelay = 0; DQSWrDelay < dqsWrDelay_end; DQSWrDelay++) {
+                       pDCTstat->DQSDelay = DQSWrDelay;
+                       pDCTstat->Direction = DQS_WRITEDIR;
+                       mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
+
+                       print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DQSWrDelay ", DQSWrDelay, 2);
+                       TrainReadDQS_D(pMCTstat, pDCTstat, cs_start);
+                       print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 2);
+                       if (pDCTstat->DqsRdWrPos_Saved == 0xFF)
+                               break;
+
+                       print_debug_dqs("\t\tTrainDQSRdWrPos: 22 TrainErrors ",pDCTstat->TrainErrors, 2);
+                       if (pDCTstat->TrainErrors == 0) {
+                                       break;
+                       }
+                       Errors |= pDCTstat->TrainErrors;
+               }
+
+               pDCTstat->DqsRdWrPos_Saved = 0;
+               if (DQSWrDelay < dqsWrDelay_end) {
+                       Errors = 0;
+
+                       print_debug_dqs("\tTrainDQSRdWrPos: 231 DQSWrDelay ", DQSWrDelay, 1);
+                       TrainWriteDQS_D(pMCTstat, pDCTstat, cs_start);
+               }
+               print_debug_dqs("\tTrainDQSRdWrPos: 232 Errors ", Errors, 1);
+               pDCTstat->ErrStatus |= Errors;
+       }
+
+#if DQS_TRAIN_DEBUG > 0
+       {
+               u8 val;
+               u8 i;
+               u8 Channel, Receiver, Dir;
+               u8 *p;
+
+               for (Dir = 0; Dir < 2; Dir++) {
+                       if (Dir == 1) {
+                               print_debug("TrainDQSRdWrPos: CH_D_DIR_B_DQS WR:\n");
+                       } else {
+                               print_debug("TrainDQSRdWrPos: CH_D_DIR_B_DQS RD:\n");
+                       }
+                       for (Channel = 0; Channel < 2; Channel++) {
+                               print_debug("Channel:"); print_debug_hex8(Channel); print_debug("\n");
+                               for (Receiver = cs_start; Receiver < (cs_start + 2); Receiver += 2) {
+                                       print_debug("\t\tReceiver:"); print_debug_hex8(Receiver);
+                                       p = pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][Dir];
+                                       print_debug(": ");
+                                       for (i=0;i<8; i++) {
+                                               val  = p[i];
+                                               print_debug_hex8(val);
+                                               print_debug(" ");
+                                       }
+                                       print_debug("\n");
+                               }
+                       }
+               }
+
+       }
+#endif
+       if (_DisableDramECC) {
+               mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
+       }
+       if (!_Wrap32Dis) {
+               addr = HWCR;
+               _RDMSR(addr, &lo, &hi);
+               lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
+               _WRMSR(addr, lo, hi);
+       }
+       if (!_SSE2){
+               cr4 = read_cr4();
+               cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
+               write_cr4(cr4);
+       }
+
+       printk(BIOS_DEBUG, "TrainDQSRdWrPos: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "TrainDQSRdWrPos: TrainErrors %x\n", pDCTstat->TrainErrors);
+       printk(BIOS_DEBUG, "TrainDQSRdWrPos: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "TrainDQSRdWrPos: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "TrainDQSRdWrPos: Done\n\n");
+}
+
+static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 *buffer)
+{
+       /* 1. Set the Pattern type (0 or 1) in DCTStatstruc.Pattern
+        * 2. Copy the pattern from ROM to Cache, aligning on 16 byte boundary
+        * 3. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufA
+        */
+
+       u32 *buf;
+       u16 i;
+
+       buf = (u32 *)(((u32)buffer + 0x10) & (0xfffffff0));
+       if (pDCTstat->Status & (1<<SB_128bitmode)) {
+               pDCTstat->Pattern = 1;  /* 18 cache lines, alternating qwords */
+               for (i=0; i<16*18; i++)
+                       buf[i] = TestPatternJD1b_D[i];
+       } else {
+               pDCTstat->Pattern = 0;  /* 9 cache lines, sequential qwords */
+               for (i=0; i<16*9; i++)
+                       buf[i] = TestPatternJD1a_D[i];
+       }
+       pDCTstat->PtrPatternBufA = (u32)buf;
+}
+
+static void TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 cs_start)
+{
+       u32 Errors;
+       u8 ChipSel, DQSDelay;
+       u8 RnkDlySeqPassMin=0, RnkDlySeqPassMax=0xFF, RnkDlyFilterMin=0, RnkDlyFilterMax=0xFF;
+       u8 RnkDlySeqPassMinTot=0, RnkDlySeqPassMaxTot=0xFF, RnkDlyFilterMinTot=0, RnkDlyFilterMaxTot=0xFF;
+       u8 LastTest ,LastTestTot;
+       u32 TestAddr;
+       u8 ByteLane;
+       u8 MutualCSPassW[128];
+       u8 BanksPresent;
+       u8 dqsDelay_end;
+       u8 tmp, valid, tmp1;
+       u16 word;
+
+       /* MutualCSPassW: each byte represents a bitmap of pass/fail per
+        * ByteLane.  The indext within MutualCSPassW is the delay value
+        * given the results.
+        */
+       print_debug_dqs("\t\t\tTrainDQSPos begin ", 0, 3);
+
+       Errors = 0;
+       BanksPresent = 0;
+
+       dqsDelay_end = 32;
+       /* Bitmapped status per delay setting, 0xff=All positions
+        * passing (1= PASS). Set the entire array.
+        */
+       for (DQSDelay=0; DQSDelay<128; DQSDelay++) {
+               MutualCSPassW[DQSDelay] = 0xFF;
+       }
+
+       for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) { /* logical register chipselects 0..7 */
+               print_debug_dqs("\t\t\t\tTrainDQSPos: 11 ChipSel ", ChipSel, 4);
+
+               if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel)) {
+                       print_debug_dqs("\t\t\t\tmct_RcvrRankEnabled_D CS not enabled ", ChipSel, 4);
+                       continue;
+               }
+
+               BanksPresent = 1;       /* flag for atleast one bank is present */
+               TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel, &valid);
+               if (!valid) {
+                       print_debug_dqs("\t\t\t\tAddress not supported on current CS ", TestAddr, 4);
+                       continue;
+               }
+
+               print_debug_dqs("\t\t\t\tTrainDQSPos: 12 TestAddr ", TestAddr, 4);
+               SetUpperFSbase(TestAddr);       /* fs:eax=far ptr to target */
+
+               if (pDCTstat->Direction==DQS_READDIR) {
+                       print_debug_dqs("\t\t\t\tTrainDQSPos: 13 for read ", 0, 4);
+                       WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr<<8);
+               }
+
+               for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) {
+                       print_debug_dqs("\t\t\t\t\tTrainDQSPos: 141 DQSDelay ", DQSDelay, 5);
+
+                       tmp = 0xFF;
+                       tmp1 = DQSDelay;
+                       if (pDCTstat->Direction == DQS_READDIR) {
+                               tmp &= MutualCSPassW[DQSDelay];
+                               tmp1 += dqsDelay_end;
+                       }
+                       tmp &= MutualCSPassW[tmp1];
+
+                       if (tmp == 0) {
+                               continue;/* skip current delay value if other chipselects have failed all 8 bytelanes */
+                       }
+
+                       pDCTstat->DQSDelay = DQSDelay;
+                       mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
+                       print_debug_dqs("\t\t\t\t\tTrainDQSPos: 142 MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+
+                       if (pDCTstat->Direction == DQS_WRITEDIR) {
+                               print_debug_dqs("\t\t\t\t\tTrainDQSPos: 143 for write", 0, 5);
+                               WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr<<8);
+                       }
+
+                       print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 Pattern ", pDCTstat->Pattern, 5);
+                       ReadDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr<<8);
+/* print_debug_dqs("\t\t\t\t\tTrainDQSPos: 145 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); */
+                       word = CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); /* 0=fail, 1=pass */
+                       print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 1 ", word, 3);
+
+                       print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 3);
+                       word &= ~(pDCTstat->DqsRdWrPos_Saved); /* mask out bytelanes that already passed */
+                       word &= ~(pDCTstat->DqsRdWrPos_Saved << 8);
+                       print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 2 ", word, 3);
+
+                       tmp = DQSDelay;
+                       if (pDCTstat->Direction == DQS_READDIR) {
+                               MutualCSPassW[tmp] &= word >> 8;
+                               tmp += dqsDelay_end;
+                       }
+                       MutualCSPassW[tmp] &= word & 0xFF;
+
+                       print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 \tMutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+
+                       SetTargetWTIO_D(TestAddr);
+                       FlushDQSTestPattern_D(pDCTstat, TestAddr<<8);
+                       ResetTargetWTIO_D();
+               }
+
+       }
+
+       if (pDCTstat->Direction == DQS_READDIR) {
+               dqsDelay_end <<= 1;
+       }
+
+       if (BanksPresent) {
+               u8 mask_pass = 0;
+               for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+                       print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane ",ByteLane, 4);
+                       if (!(pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane))) {
+                               pDCTstat->ByteLane = ByteLane;
+                               LastTest = DQS_FAIL;            /* Analyze the results */
+                               LastTestTot = DQS_FAIL;
+                               /* RnkDlySeqPassMin = 0; */
+                               /* RnkDlySeqPassMax = 0; */
+                               RnkDlyFilterMax = 0;
+                               RnkDlyFilterMin = 0;
+                               RnkDlyFilterMaxTot = 0;
+                               RnkDlyFilterMinTot = 0;
+                               for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) {
+                                       if (MutualCSPassW[DQSDelay] & (1 << ByteLane)) {
+                                               print_debug_dqs("\t\t\t\t\tTrainDQSPos: 321 DQSDelay ", DQSDelay, 5);
+                                               print_debug_dqs("\t\t\t\t\tTrainDQSPos: 322 MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+                                               if (pDCTstat->Direction == DQS_READDIR)
+                                                       tmp = 0x20;
+                                               else
+                                                       tmp = 0;
+                                               if (DQSDelay >= tmp) {
+                                                       RnkDlySeqPassMax = DQSDelay;
+                                                       if (LastTest == DQS_FAIL) {
+                                                               RnkDlySeqPassMin = DQSDelay; /* start sequential run */
+                                                       }
+                                                       if ((RnkDlySeqPassMax - RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)){
+                                                               RnkDlyFilterMin = RnkDlySeqPassMin;
+                                                               RnkDlyFilterMax = RnkDlySeqPassMax;
+                                                       }
+                                                       LastTest = DQS_PASS;
+                                               }
+
+                                               if (pDCTstat->Direction == DQS_READDIR) {
+                                                       RnkDlySeqPassMaxTot = DQSDelay;
+                                                       if (LastTestTot == DQS_FAIL)
+                                                               RnkDlySeqPassMinTot = DQSDelay;
+                                                       if ((RnkDlySeqPassMaxTot - RnkDlySeqPassMinTot)>(RnkDlyFilterMaxTot-RnkDlyFilterMinTot)){
+                                                               RnkDlyFilterMinTot = RnkDlySeqPassMinTot;
+                                                               RnkDlyFilterMaxTot = RnkDlySeqPassMaxTot;
+                                                       }
+                                                       LastTestTot = DQS_PASS;
+                                               }
+                                       } else {
+                                               LastTest = DQS_FAIL;
+                                               LastTestTot = DQS_FAIL;
+                                       }
+                               }
+                               print_debug_dqs("\t\t\t\tTrainDQSPos: 33 RnkDlySeqPassMax ", RnkDlySeqPassMax, 4);
+                               if (RnkDlySeqPassMax == 0) {
+                                       Errors |= 1<<SB_NODQSPOS; /* no passing window */
+                               } else {
+                                       print_debug_dqs_pair("\t\t\t\tTrainDQSPos: 34 RnkDlyFilter: ", RnkDlyFilterMin, " ",  RnkDlyFilterMax, 4);
+                                       if (((RnkDlyFilterMax - RnkDlyFilterMin) < MIN_DQS_WNDW)){
+                                               Errors |= 1 << SB_SMALLDQS;
+                                       } else {
+                                               u8 middle_dqs;
+                                               /* mctEngDQSwindow_Save_D Not required for arrays */
+                                               if (pDCTstat->Direction == DQS_READDIR)
+                                                       middle_dqs = MiddleDQS_D(RnkDlyFilterMinTot, RnkDlyFilterMaxTot);
+                                               else
+                                                       middle_dqs = MiddleDQS_D(RnkDlyFilterMin, RnkDlyFilterMax);
+                                               pDCTstat->DQSDelay = middle_dqs;
+                                               mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, cs_start);  /* load the register with the value */
+                                               if (pDCTstat->Direction == DQS_READDIR)
+                                                       StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMinTot, RnkDlyFilterMaxTot); /* store the value into the data structure */
+                                               else
+                                                       StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMin, RnkDlyFilterMax); /* store the value into the data structure */
+                                               print_debug_dqs("\t\t\t\tTrainDQSPos: 42 middle_dqs : ",middle_dqs, 4);
+                                               pDCTstat->DqsRdWrPos_Saved |= 1 << ByteLane;
+                                       }
+                               }
+                       } /* if (pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane)) */
+               }
+               print_debug_dqs("\t\t\t\tTrainDQSPos: 41 mask_pass ",mask_pass, 3);
+       }
+/* skipLocMiddle: */
+       pDCTstat->TrainErrors = Errors;
+
+       print_debug_dqs("\t\t\tTrainDQSPos: Errors ", Errors, 3);
+}
+
+static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 ChipSel,
+                                       u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
+{
+       pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
+               [pDCTstat->Direction]
+               [0]
+               [pDCTstat->ByteLane] = RnkDlyFilterMin;
+       pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
+               [pDCTstat->Direction]
+               [1]
+               [pDCTstat->ByteLane] = RnkDlyFilterMax;
+}
+
+static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 ChipSel)
+{
+       /* Store the DQSDelay value, found during a training sweep, into the DCT
+        * status structure for this node
+        */
+
+       /* When 400, 533, 667, it will support dimm0/1/2/3,
+        * and set conf for dimm0, hw will copy to dimm1/2/3
+        * set for dimm1, hw will copy to dimm3
+        * Rev A/B only support DIMM0/1 when 800Mhz and above + 0x100 to next dimm
+        * Rev C support DIMM0/1/2/3 when 800Mhz and above  + 0x100 to next dimm
+        */
+
+       /* FindDQSDatDimmVal_D is not required since we use an array */
+       u8 dn = 0;
+
+       dn = ChipSel>>1; /* if odd or even logical DIMM */
+
+       pDCTstat->CH_D_DIR_B_DQS[pDCTstat->Channel][dn][pDCTstat->Direction][pDCTstat->ByteLane] =
+                                       pDCTstat->DQSDelay;
+}
+
+static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 ChipSel,
+                                       u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
+{
+       u8 dn;
+
+       if (pDCTstat->Direction == DQS_WRITEDIR) {
+               dn = ChipSel >> 1;
+               RnkDlyFilterMin += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
+               RnkDlyFilterMax += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
+               pDCTstat->DQSDelay += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
+       } else {
+               RnkDlyFilterMin <<= 1;
+               RnkDlyFilterMax <<= 1;
+               pDCTstat->DQSDelay <<= 1;
+       }
+       mctEngDQSwindow_Save_D(pMCTstat, pDCTstat, ChipSel, RnkDlyFilterMin, RnkDlyFilterMax);
+       StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+}
+
+static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
+{
+       u8 dn = 0;
+
+       /* When 400, 533, 667, it will support dimm0/1/2/3,
+        * and set conf for dimm0, hw will copy to dimm1/2/3
+        * set for dimm1, hw will copy to dimm3
+        * Rev A/B only support DIMM0/1 when 800Mhz and above + 0x100 to next dimm
+        * Rev C support DIMM0/1/2/3 when 800Mhz and above  + 0x100 to next dimm
+        */
+
+       /* FindDQSDatDimmVal_D is not required since we use an array */
+       dn = ChipSel >> 1; /*if odd or even logical DIMM */
+
+       pDCTstat->DQSDelay =
+               pDCTstat->CH_D_DIR_B_DQS[pDCTstat->Channel][dn][pDCTstat->Direction][pDCTstat->ByteLane];
+}
+
+/* FindDQSDatDimmVal_D is not required since we use an array */
+
+static u8 MiddleDQS_D(u8 min, u8 max)
+{
+       u8 size;
+       size = max-min;
+       if (size % 2)
+               size++;         /* round up if the size isn't even. */
+       return ( min + (size >> 1));
+}
+
+static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 cs_start)
+{
+       print_debug_dqs("\t\tTrainReadPos ", 0, 2);
+       pDCTstat->Direction = DQS_READDIR;
+       TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
+}
+
+static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 cs_start)
+{
+       pDCTstat->Direction = DQS_WRITEDIR;
+       print_debug_dqs("\t\tTrainWritePos", 0, 2);
+       TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
+}
+
+static void proc_IOCLFLUSH_D(u32 addr_hi)
+{
+       SetTargetWTIO_D(addr_hi);
+       proc_CLFLUSH(addr_hi);
+       ResetTargetWTIO_D();
+}
+
+static u8 ChipSelPresent_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 Channel, u8 ChipSel)
+{
+       u32 val;
+       u32 reg;
+       u32 dev = pDCTstat->dev_dct;
+       u32 reg_off;
+       u8 ret = 0;
+
+       if (!pDCTstat->GangedMode) {
+               reg_off = 0x100 * Channel;
+       } else {
+               reg_off = 0;
+       }
+
+       if (ChipSel < MAX_CS_SUPPORTED){
+               reg = 0x40 + (ChipSel << 2) + reg_off;
+               val = Get_NB32(dev, reg);
+               if (val & ( 1 << 0))
+                       ret = 1;
+       }
+
+       return ret;
+}
+
+/* proc_CLFLUSH_D located in mct_gcc.h */
+
+static void WriteDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo)
+{
+       /* Write a pattern of 72 bit times (per DQ), to test dram functionality.
+        * The pattern is a stress pattern which exercises both ISI and
+        * crosstalk.  The number of cache lines to fill is dependent on DCT
+        * width mode and burstlength.
+        * Mode BL  Lines Pattern no.
+        * ----+---+-------------------
+        * 64   4         9     0
+        * 64   8         9     0
+        * 64M  4         9     0
+        * 64M  8         9     0
+        * 128  4         18    1
+        * 128  8         N/A   -
+        */
+       if (pDCTstat->Pattern == 0)
+               WriteL9TestPattern_D(pDCTstat, TestAddr_lo);
+       else
+               WriteL18TestPattern_D(pDCTstat, TestAddr_lo);
+}
+
+static void WriteL18TestPattern_D(struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo)
+{
+       u8 *buf;
+
+       buf = (u8 *)pDCTstat->PtrPatternBufA;
+       WriteLNTestPattern(TestAddr_lo, buf, 18);
+
+}
+
+static void WriteL9TestPattern_D(struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo)
+{
+       u8 *buf;
+
+       buf = (u8 *)pDCTstat->PtrPatternBufA;
+       WriteLNTestPattern(TestAddr_lo, buf, 9);
+}
+
+static u16 CompareDQSTestPattern_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 addr_lo)
+{
+       /* Compare a pattern of 72 bit times (per DQ), to test dram functionality.
+        * The pattern is a stress pattern which exercises both ISI and
+        * crosstalk.  The number of cache lines to fill is dependent on DCT
+        * width mode and burstlength.
+        * Mode BL  Lines Pattern no.
+        * ----+---+-------------------
+        * 64   4         9     0
+        * 64   8         9     0
+        * 64M  4         9     0
+        * 64M  8         9     0
+        * 128  4         18    1
+        * 128  8         N/A   -
+        */
+
+       u32 *test_buf;
+       u16 MEn1Results, bitmap;
+       u8 bytelane;
+       u8 i;
+       u32 value;
+       u8 j;
+       u32 value_test;
+       u32 value_r, value_r_test;
+       u8 pattern, channel, BeatCnt;
+       struct DCTStatStruc *ptrAddr;
+
+       ptrAddr = pDCTstat;
+       pattern = pDCTstat->Pattern;
+       channel = pDCTstat->Channel;
+       test_buf = (u32 *)pDCTstat->PtrPatternBufA;
+
+       if (pattern && channel) {
+               addr_lo += 8; /* second channel */
+               test_buf+= 2;
+       }
+
+       bytelane = 0;
+       bitmap = 0xFFFF;
+       MEn1Results = 0xFFFF;
+       BeatCnt = 0;
+       for (i=0; i < (9 * 64 / 4); i++) { /* /4 due to next loop */
+               value = read32_fs(addr_lo);
+               value_test = *test_buf;
+
+               print_debug_dqs_pair("\t\t\t\t\t\ttest_buf = ", (u32)test_buf, " value = ", value_test, 7);
+               print_debug_dqs_pair("\t\t\t\t\t\ttaddr_lo = ", addr_lo, " value = ", value, 7);
+
+               if (pDCTstat->Direction == DQS_READDIR) {
+                       if (BeatCnt != 0) {
+                               value_r = *test_buf;
+                               if (pattern)
+                                       value_r_test = read32_fs(addr_lo - 16);
+                               else
+                                       value_r_test = read32_fs(addr_lo - 8);
+                       }
+                       print_debug_dqs_pair("\t\t\t\t\t\t\ttest_buf = ", (u32)test_buf, " value_r_test = ", value_r, 7);
+                       print_debug_dqs_pair("\t\t\t\t\t\t\ttaddr_lo = ", addr_lo, " value_r = ", value_r_test, 7);
+               }
+
+               for (j = 0; j < (4 * 8); j += 8) {
+                       if (((value >> j) & 0xff) != ((value_test >> j) & 0xff)) {
+                               bitmap &= ~(1 << bytelane);
+                       }
+
+                       if (pDCTstat->Direction == DQS_READDIR) {
+                               if (BeatCnt != 0) {
+                                       if  (((value_r >> j) & 0xff) != ((value_r_test >> j) & 0xff)) {
+                                               MEn1Results &= ~(1 << bytelane);
+                                       }
+                               }
+                       }
+                       bytelane++;
+                       bytelane &= 0x7;
+               }
+
+               print_debug_dqs("\t\t\t\t\t\tbitmap = ", bitmap, 7);
+               print_debug_dqs("\t\t\t\t\t\tMEn1Results = ", MEn1Results, 7);
+
+               if (!bitmap)
+                       break;
+
+               if (bytelane == 0){
+                       BeatCnt += 4;
+                       if (!(pDCTstat->Status & (1 <<SB_128bitmode))) {
+                               if (BeatCnt == 8) BeatCnt = 0; /* 8 beat burst */
+                       } else {
+                               if (BeatCnt == 4) BeatCnt = 0; /* 4 beat burst */
+                       }
+                       if (pattern == 1) { /* dual channel */
+                               addr_lo += 8; /* skip over other channel's data */
+                               test_buf += 2;
+                       }
+               }
+               addr_lo += 4;
+               test_buf += 1;
+       }
+
+       if (pDCTstat->Direction == DQS_READDIR) {
+               bitmap &= 0xFF;
+               bitmap |= MEn1Results << 8;
+       }
+
+       print_debug_dqs("\t\t\t\t\t\tbitmap = ", bitmap, 6);
+
+       return bitmap;
+}
+
+static void FlushDQSTestPattern_D(struct DCTStatStruc *pDCTstat,
+                                       u32 addr_lo)
+{
+       /* Flush functions in mct_gcc.h */
+       if (pDCTstat->Pattern == 0){
+               FlushDQSTestPattern_L9(addr_lo);
+       } else {
+               FlushDQSTestPattern_L18(addr_lo);
+       }
+}
+
+static void SetTargetWTIO_D(u32 TestAddr)
+{
+       u32 lo, hi;
+       hi = TestAddr >> 24;
+       lo = TestAddr << 8;
+       _WRMSR(0xC0010016, lo, hi);             /* IORR0 Base */
+       hi = 0xFF;
+       lo = 0xFC000800;                        /* 64MB Mask */
+       _WRMSR(0xC0010017, lo, hi);             /* IORR0 Mask */
+}
+
+static void ResetTargetWTIO_D(void)
+{
+       u32 lo, hi;
+
+       hi = 0;
+       lo = 0;
+       _WRMSR(0xc0010017, lo, hi); /* IORR0 Mask */
+}
+
+static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u32 TestAddr_lo)
+{
+       /* Read a pattern of 72 bit times (per DQ), to test dram functionality.
+        * The pattern is a stress pattern which exercises both ISI and
+        * crosstalk.  The number of cache lines to fill is dependent on DCT
+        * width mode and burstlength.
+        * Mode BL  Lines Pattern no.
+        * ----+---+-------------------
+        * 64   4         9     0
+        * 64   8         9     0
+        * 64M  4         9     0
+        * 64M  8         9     0
+        * 128  4         18    1
+        * 128  8         N/A   -
+        */
+       if (pDCTstat->Pattern == 0)
+               ReadL9TestPattern(TestAddr_lo);
+       else
+               ReadL18TestPattern(TestAddr_lo);
+       _MFENCE;
+}
+
+u32 SetUpperFSbase(u32 addr_hi)
+{
+       /* Set the upper 32-bits of the Base address, 4GB aligned) for the
+        * FS selector.
+        */
+       u32 lo, hi;
+       u32 addr;
+       lo = 0;
+       hi = addr_hi>>24;
+       addr = FS_Base;
+       _WRMSR(addr, lo, hi);
+       return addr_hi<<8;
+}
+
+void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index)
+{
+       u32 val;
+
+       val = Get_NB32_index_wait(dev, index_reg, index);
+       Set_NB32_index_wait(dev, index_reg, index, val);
+}
+
+/* mctEngDQSwindow_Save_D not required with arrays */
+
+void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+       u8 ChipSel;
+       struct DCTStatStruc *pDCTstat;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               if (pDCTstat->DCTSysLimit) {
+                       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
+                               TrainDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
+                               SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
+                       }
+               }
+       }
+}
+
+/* mct_BeforeTrainDQSRdWrPos_D
+ * Function is inline.
+ */
+u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       u8 _DisableDramECC = 0;
+       u32 val;
+       u32 reg;
+       u32 dev;
+
+       /*Disable ECC correction of reads on the dram bus. */
+
+       dev = pDCTstat->dev_dct;
+       reg = 0x90;
+       val = Get_NB32(dev, reg);
+       if (val & (1<<DimmEcEn)) {
+               _DisableDramECC |= 0x01;
+               val &= ~(1<<DimmEcEn);
+               Set_NB32(dev, reg, val);
+       }
+       if (!pDCTstat->GangedMode) {
+               reg = 0x190;
+               val = Get_NB32(dev, reg);
+               if (val & (1<<DimmEcEn)) {
+                       _DisableDramECC |= 0x02;
+                       val &= ~(1<<DimmEcEn);
+                       Set_NB32(dev, reg, val);
+               }
+       }
+       return _DisableDramECC;
+}
+
+void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 _DisableDramECC)
+{
+       u32 val;
+       u32 reg;
+       u32 dev;
+
+       /* Enable ECC correction if it was previously disabled */
+
+       dev = pDCTstat->dev_dct;
+
+       if ((_DisableDramECC & 0x01) == 0x01) {
+               reg = 0x90;
+               val = Get_NB32(dev, reg);
+               val |= (1<<DimmEcEn);
+               Set_NB32(dev, reg, val);
+       }
+       if ((_DisableDramECC & 0x02) == 0x02) {
+               reg = 0x190;
+               val = Get_NB32(dev, reg);
+               val |= (1<<DimmEcEn);
+               Set_NB32(dev, reg, val);
+       }
+}
+
+static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 ChipSel)
+{
+       u8 ByteLane;
+       u32 val;
+       u32 index_reg = 0x98 + 0x100 * pDCTstat->Channel;
+       u8 shift;
+       u32 dqs_delay = (u32)pDCTstat->DQSDelay;
+       u32 dev = pDCTstat->dev_dct;
+       u32 index;
+
+       ByteLane = pDCTstat->ByteLane;
+
+       if (!(pDCTstat->DqsRdWrPos_Saved & (1 << ByteLane))) {
+               /* Channel is offset */
+               if (ByteLane < 4) {
+                       index = 1;
+               } else if (ByteLane <8) {
+                       index = 2;
+               } else {
+                       index = 3;
+               }
+
+               if (pDCTstat->Direction == DQS_READDIR) {
+                       index += 4;
+               }
+
+               /* get the proper register index */
+               shift = ByteLane%4;
+               shift <<= 3; /* get bit position of bytelane, 8 bit */
+
+               index += (ChipSel>>1) << 8;
+
+               val = Get_NB32_index_wait(dev, index_reg, index);
+               if (ByteLane < 8) {
+                       if (pDCTstat->Direction == DQS_WRITEDIR) {
+                               dqs_delay += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][ChipSel>>1][ByteLane];
+                       } else {
+                               dqs_delay <<= 1;
+                       }
+               }
+               val &= ~(0x7f << shift);
+               val |= (dqs_delay << shift);
+               Set_NB32_index_wait(dev, index_reg, index, val);
+       }
+}
+
+static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u8 cs_start)
+{
+       u8 ByteLane;
+       u8 ChipSel = cs_start;
+
+       for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) {
+               if ( mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel)) {
+                       for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+                               pDCTstat->ByteLane = ByteLane;
+                               mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, ChipSel);
+                       }
+               }
+       }
+}
+
+u8 mct_RcvrRankEnabled_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 Channel, u8 ChipSel)
+{
+       u8 ret;
+
+       ret = ChipSelPresent_D(pMCTstat, pDCTstat, Channel, ChipSel);
+       return ret;
+}
+
+u32 mct_GetRcvrSysAddr_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 channel, u8 receiver, u8 *valid)
+{
+       return mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, channel, receiver, valid);
+}
+
+u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 Channel, u8 receiver, u8 *valid)
+{
+       u32 val;
+       u32 reg_off = 0;
+       u32 reg;
+       u32 dword;
+       u32 dev = pDCTstat->dev_dct;
+
+       *valid = 0;
+
+
+       if (!pDCTstat->GangedMode)  {   /* FIXME: not used. */
+               reg_off = 0x100 * Channel;
+       }
+
+       /* get the local base addr of the chipselect */
+       reg = 0x40 + (receiver << 2);
+       val = Get_NB32(dev, reg);
+
+       val &= ~0x0F;
+
+       /* unganged mode DCT0+DCT1, sys addr of DCT1=node
+        * base+DctSelBaseAddr+local ca base*/
+       if ((Channel) && (pDCTstat->GangedMode == 0) && ( pDCTstat->DIMMValidDCT[0] > 0)) {
+               reg = 0x110;
+               dword = Get_NB32(dev, reg);
+               dword &= 0xfffff800;
+               dword <<= 8;    /* scale [47:27] of F2x110[31:11] to [39:8]*/
+               val += dword;
+
+               /* if DCTSelBaseAddr < Hole, and eax > HoleBase, then add Hole size to test address */
+               if ((val >= pDCTstat->DCTHoleBase) && (pDCTstat->DCTHoleBase > dword)) {
+                       dword = (~(pDCTstat->DCTHoleBase >> (24 - 8)) + 1) & 0xFF;
+                       dword <<= (24 - 8);
+                       val += dword;
+               }
+       } else {
+               /* sys addr=node base+local cs base */
+               val += pDCTstat->DCTSysBase;
+
+               /* New stuff */
+               if (pDCTstat->DCTHoleBase && (val >= pDCTstat->DCTHoleBase)) {
+                       val -= pDCTstat->DCTSysBase;
+                       dword = Get_NB32(pDCTstat->dev_map, 0xF0); /* get Hole Offset */
+                       val += (dword & 0x0000ff00) << (24-8-8);
+               }
+       }
+
+       /* New stuff */
+       val += ((1 << 21) >> 8);        /* Add 2MB offset to avoid compat area */
+       if (val >= MCT_TRNG_KEEPOUT_START) {
+               while(val < MCT_TRNG_KEEPOUT_END)
+                       val += (1 << (15-8));   /* add 32K */
+       }
+
+       /* Add a node seed */
+       val += (((1 * pDCTstat->Node_ID) << 20) >> 8);  /* Add 1MB per node to avoid aliases */
+
+       /* HW remap disabled? */
+       if (!(pDCTstat->Status & (1 << SB_HWHole))) {
+               if (!(pDCTstat->Status & (1 << SB_SWNodeHole))) {
+                       /* SW memhole disabled */
+                       u32 lo, hi;
+                       _RDMSR(TOP_MEM, &lo, &hi);
+                       lo >>= 8;
+                       if ((val >= lo) && (val < _4GB_RJ8)) {
+                               val = 0;
+                               *valid = 0;
+                               goto exitGetAddr;
+                       } else {
+                               *valid = 1;
+                               goto exitGetAddrWNoError;
+                       }
+               } else {
+                       *valid = 1;
+                       goto exitGetAddrWNoError;
+               }
+       } else {
+               *valid = 1;
+               goto exitGetAddrWNoError;
+       }
+
+exitGetAddrWNoError:
+
+       /* Skip if Address is in UMA region */
+       dword = pMCTstat->Sub4GCacheTop;
+       dword >>= 8;
+       if (dword != 0) {
+               if ((val >= dword) && (val < _4GB_RJ8)) {
+                       val = 0;
+                       *valid = 0;
+               } else {
+                       *valid = 1;
+               }
+       }
+       print_debug_dqs("mct_GetMCTSysAddr_D: receiver ", receiver, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: Channel ", Channel, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: base_addr ", val, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: valid ", *valid, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: status ", pDCTstat->Status, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: HoleBase ", pDCTstat->DCTHoleBase, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: Cachetop ", pMCTstat->Sub4GCacheTop, 2);
+
+exitGetAddr:
+       return val;
+}
+
+static void mct_Write1LTestPattern_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u32 TestAddr, u8 pattern)
+{
+
+       u8 *buf;
+
+       /* Issue the stream of writes. When F2x11C[MctWrLimit] is reached
+        * (or when F2x11C[FlushWr] is set again), all the writes are written
+        * to DRAM.
+        */
+
+       SetUpperFSbase(TestAddr);
+
+       if (pattern)
+               buf = (u8 *)pDCTstat->PtrPatternBufB;
+       else
+               buf = (u8 *)pDCTstat->PtrPatternBufA;
+
+       WriteLNTestPattern(TestAddr << 8, buf, 1);
+}
+
+void mct_Read1LTestPattern_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 addr)
+{
+       u32 value;
+
+       /* BIOS issues the remaining (Ntrain - 2) reads after checking that
+        * F2x11C[PrefDramTrainMode] is cleared. These reads must be to
+        * consecutive cache lines (i.e., 64 bytes apart) and must not cross
+        * a naturally aligned 4KB boundary. These reads hit the prefetches and
+        * read the data from the prefetch buffer.
+        */
+
+       /* get data from DIMM */
+       SetUpperFSbase(addr);
+
+       /* 1st move causes read fill (to exclusive or shared)*/
+       value = read32_fs(addr<<8);
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
new file mode 100644 (file)
index 0000000..288093c
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "mct_d.h"
+
+static void setSyncOnUnEccEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat);
+
+/* Initialize ECC modes of Integrated Dram+Memory Controllers of a network of
+ * Hammer processors.  Use Dram background scrubber to fast initialize ECC bits
+ * of all dram.
+ *
+ * Notes:
+ *
+ * Order that items are set:
+ *  1. eccen bit in NB
+ *  2. Scrub Base
+ *  3. Temp Node Base
+ *  4. Temp Node Limit
+ *  5. Redir bit in NB
+ *  6. Scrub CTL
+ *
+ * Conditions for setting background scrubber.
+ *  1. node is present
+ *  2. node has dram functioning (WE=RE=1)
+ *  3. all eccdimms (or bit 17 of offset 90,fn 2)
+ *  4. no chip-select gap exists
+ *
+ * The dram background scrubber is used under very controlled circumstances to
+ * initialize all the ECC bits on the DIMMs of the entire dram address map
+ * (including hidden or lost dram and dram above 4GB). We will turn the scrub
+ * rate up to maximum, which should clear 4GB of dram in about 2.7 seconds.
+ * We will activate the scrubbers of all nodes with ecc dram and let them run in
+ * parallel, thereby reducing even further the time required to condition dram.
+ * Finally, we will go through each node and either disable background scrubber,
+ *  or set the scrub rate to the user setup specified rate.
+ *
+ * To allow the NB to scrub, we need to wait a time period long enough to
+ * guarantee that the NB scrubs the entire dram on its node. Do do this, we
+ * simply sample the scrub ADDR once, for an initial value, then we sample and poll until the polled value of scrub ADDR
+ * has wrapped around at least once: Scrub ADDRi+1 < Scrub ADDRi. Since we let all
+ * Nodes run in parallel, we need to gaurantee that all nodes have wrapped. To do
+ * this efficiently, we need only to sample one of the nodes, the node with the
+ * largest ammount of dram populated is the one which will take the longest amount
+ * of time (the scrub rate is set to max, the same rate, on all nodes).  So,
+ * during setup of scrub Base, we determine how much memory and which node has
+ * the largest memory installed.
+ *
+ * Scrubbing should not ordinarily be enabled on a Node with a chip-select gap
+ * (aka SW memhole, cs hoisting, etc..).To init ECC memory on this node, the
+ * scrubber is used in two steps.  First, the Dram Limit for the node is adjusted
+ * down to the bottom of the gap, and that ECC dram is initialized.  Second, the
+ * orignal Limit is restored, the Scrub base is set to 4GB, and scrubber is
+ * allowed to run until the Scrub Addr wraps around to zero.
+ */
+u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+       u8 AllECC;
+       u16 OB_NBECC;
+       u32 curBase;
+       u16 OB_ECCRedir;
+       u32 LDramECC;
+       u32 OF_ScrubCTL;
+       u16 OB_ChipKill;
+       u8 MemClrECC;
+
+       u32 dev;
+       u32 reg;
+       u32 val;
+       u16 nvbits;
+
+       mctHookBeforeECC();
+
+       /* Construct these booleans, based on setup options, for easy handling
+       later in this procedure */
+       OB_NBECC = mctGet_NVbits(NV_NBECC);     /* MCA ECC (MCE) enable bit */
+
+       OB_ECCRedir =  mctGet_NVbits(NV_ECCRedir);      /* ECC Redirection */
+
+       OB_ChipKill = mctGet_NVbits(NV_ChipKill);       /* ECC Chip-kill mode */
+
+       OF_ScrubCTL = 0;                /* Scrub CTL for Dcache, L2, and dram */
+       nvbits = mctGet_NVbits(NV_DCBKScrub);
+       /* mct_AdjustScrub_D(pDCTstatA, &nvbits); */ /* Need not adjust */
+       OF_ScrubCTL |= (u32) nvbits << 16;
+
+       nvbits = mctGet_NVbits(NV_L2BKScrub);
+       OF_ScrubCTL |= (u32) nvbits << 8;
+
+       nvbits = mctGet_NVbits(NV_DramBKScrub);
+       OF_ScrubCTL |= nvbits;
+
+       AllECC = 1;
+       MemClrECC = 0;
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               LDramECC = 0;
+               if (NodePresent_D(Node)) {      /*If Node is present */
+                       dev = pDCTstat->dev_map;
+                       reg = 0x40+(Node << 3); /* Dram Base Node 0 + index */
+                       val = Get_NB32(dev, reg);
+
+                       /* WE/RE is checked */
+                       if((val & 3)==3) {      /* Node has dram populated */
+                               /* Negate 'all nodes/dimms ECC' flag if non ecc
+                                  memory populated */
+                               if( pDCTstat->Status & (1<<SB_ECCDIMMs)) {
+                                       LDramECC = isDramECCEn_D(pDCTstat);
+                                       if(pDCTstat->ErrCode != SC_RunningOK) {
+                                               pDCTstat->Status &=  ~(1 << SB_ECCDIMMs);
+                                               if (OB_NBECC) {
+                                                       pDCTstat->ErrStatus |= (1 << SB_DramECCDis);
+                                               }
+                                               AllECC = 0;
+                                               LDramECC =0;
+                                       }
+                               } else {
+                                       AllECC = 0;
+                               }
+                               if(LDramECC) {  /* if ECC is enabled on this dram */
+                                       if (OB_NBECC) {
+                                               mct_EnableDatIntlv_D(pMCTstat, pDCTstat);
+                                               dev = pDCTstat->dev_nbmisc;
+                                               reg =0x44;      /* MCA NB Configuration */
+                                               val = Get_NB32(dev, reg);
+                                               val |= 1 << 22; /* EccEn */
+                                               Set_NB32(dev, reg, val);
+                                               DCTMemClr_Init_D(pMCTstat, pDCTstat);
+                                               MemClrECC = 1;
+                                       }
+                               }       /* this node has ECC enabled dram */
+                       } else {
+                               LDramECC = 0;
+                       }       /* Node has Dram */
+
+                       if (MemClrECC) {
+                               MCTMemClrSync_D(pMCTstat, pDCTstatA);
+                       }
+               }       /* if Node present */
+       }
+
+       if(AllECC)
+               pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
+       else
+               pMCTstat->GStatus &= ~(1<<GSB_ECCDIMMs);
+
+       /* Program the Dram BKScrub CTL to the proper (user selected) value.*/
+       /* Reset MC4_STS. */
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               LDramECC = 0;
+               if (NodePresent_D(Node)) {      /* If Node is present */
+                       reg = 0x40+(Node<<3);   /* Dram Base Node 0 + index */
+                       val = Get_NB32(pDCTstat->dev_map, reg);
+                       curBase = val & 0xffff0000;
+                       /*WE/RE is checked because memory config may have been */
+                       if((val & 3)==3) {      /* Node has dram populated */
+                               if (isDramECCEn_D(pDCTstat)) {  /* if ECC is enabled on this dram */
+                                       dev = pDCTstat->dev_nbmisc;
+                                       val = curBase << 8;
+                                       if(OB_ECCRedir) {
+                                               val |= (1<<0); /* enable redirection */
+                                       }
+                                       Set_NB32(dev, 0x5C, val); /* Dram Scrub Addr Low */
+                                       val = curBase>>24;
+                                       Set_NB32(dev, 0x60, val); /* Dram Scrub Addr High */
+                                       Set_NB32(dev, 0x58, OF_ScrubCTL);       /*Scrub Control */
+
+                                       /* Divisor should not be set deeper than
+                                        * divide by 16 when Dcache scrubber or
+                                        * L2 scrubber is enabled.
+                                        */
+                                       if ((OF_ScrubCTL & (0x1F << 16)) || (OF_ScrubCTL & (0x1F << 8))) {
+                                               val = Get_NB32(dev, 0x84);
+                                               if ((val & 0xE0000000) > 0x80000000) {  /* Get F3x84h[31:29]ClkDivisor for C1 */
+                                                       val &= 0x1FFFFFFF;      /* If ClkDivisor is deeper than divide-by-16 */
+                                                       val |= 0x80000000;      /* set it to divide-by-16 */
+                                                       Set_NB32(dev, 0x84, val);
+                                               }
+                                       }
+                               }       /* this node has ECC enabled dram */
+                       }       /*Node has Dram */
+               }       /*if Node present */
+       }
+
+       if(mctGet_NVbits(NV_SyncOnUnEccEn))
+               setSyncOnUnEccEn_D(pMCTstat, pDCTstatA);
+
+       mctHookAfterECC();
+       return MemClrECC;
+}
+
+static void setSyncOnUnEccEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       u32 Node;
+       u32 reg;
+       u32 dev;
+       u32 val;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               if (NodePresent_D(Node)) {      /* If Node is present*/
+                       reg = 0x40+(Node<<3);   /* Dram Base Node 0 + index*/
+                       val = Get_NB32(pDCTstat->dev_map, reg);
+                       /*WE/RE is checked because memory config may have been*/
+                       if((val & 3)==3) {      /* Node has dram populated*/
+                               if( isDramECCEn_D(pDCTstat)) {
+                                       /*if ECC is enabled on this dram*/
+                                       dev = pDCTstat->dev_nbmisc;
+                                       reg = 0x44;     /* MCA NB Configuration*/
+                                       val = Get_NB32(dev, reg);
+                                       val |= (1<<SyncOnUcEccEn);
+                                       Set_NB32(dev, reg, val);
+                               }
+                       }       /* Node has Dram*/
+               }       /* if Node present*/
+       }
+}
+
+static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat)
+{
+       u32 reg;
+       u32 val;
+       u8 i;
+       u32 dev = pDCTstat->dev_dct;
+       u8 ch_end;
+       u8 isDimmECCEn = 0;
+
+       if(pDCTstat->GangedMode) {
+               ch_end = 1;
+       } else {
+               ch_end = 2;
+       }
+       for(i=0; i<ch_end; i++) {
+               if(pDCTstat->DIMMValidDCT[i] > 0){
+                       reg = 0x90 + i * 0x100;         /* Dram Config Low */
+                       val = Get_NB32(dev, reg);
+                       if(val & (1<<DimmEcEn)) {
+                               /* set local flag 'dram ecc capable' */
+                               isDimmECCEn = 1;
+                               break;
+                       }
+               }
+       }
+       return isDimmECCEn;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
new file mode 100644 (file)
index 0000000..9b03b75
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 val;
+       u32 reg;
+       u32 dev = pDCTstat->dev_dct;
+
+       /*flag for selecting HW/SW DRAM Init HW DRAM Init */
+       reg = 0x90 + 0x100 * dct; /*DRAM Configuration Low */
+       val = Get_NB32(dev, reg);
+       val |= (1<<InitDram);
+       Set_NB32(dev, reg, val);
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
new file mode 100644 (file)
index 0000000..bf92223
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat);
+static void AgesaHwWlPhase1(sMCTStruct *pMCTData,
+                                       sDCTStruct *pDCTData, u8 dimm, u8 pass);
+static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+static void PrepareC_DCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
+static void MultiplyDelay(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
+static void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+static void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+
+static void SetEccWrDQS_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
+{
+       u8 ByteLane, DimmNum, OddByte, Addl_Index, Channel;
+       u8 EccRef1, EccRef2, EccDQSScale;
+       u32 val;
+       u16 word;
+
+       for (Channel = 0; Channel < 2; Channel ++) {
+               for (DimmNum = 0; DimmNum < C_MAX_DIMMS; DimmNum ++) { /* we use DimmNum instead of DimmNumx3 */
+                       for (ByteLane = 0; ByteLane < 9; ByteLane ++) {
+                               /* Get RxEn initial value from WrDqs */
+                               if (ByteLane & 1)
+                                       OddByte = 1;
+                               else
+                                       OddByte = 0;
+                               if (ByteLane < 2)
+                                       Addl_Index = 0x30;
+                               else if (ByteLane < 4)
+                                       Addl_Index = 0x31;
+                               else if (ByteLane < 6)
+                                       Addl_Index = 0x40;
+                               else if (ByteLane < 8)
+                                       Addl_Index = 0x41;
+                               else
+                                       Addl_Index = 0x32;
+                               Addl_Index += DimmNum * 3;
+
+                               val = Get_NB32_index_wait(pDCTstat->dev_dct, Channel * 0x100 + 0x98, Addl_Index);
+                               if (OddByte)
+                                       val >>= 16;
+                               /* Save WrDqs to stack for later usage */
+                               pDCTstat->CH_D_B_TxDqs[Channel][DimmNum][ByteLane] = val & 0xFF;
+                               EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
+                               word = pDCTstat->CH_EccDQSLike[Channel];
+                               if ((word & 0xFF) == ByteLane) EccRef1 = val & 0xFF;
+                               if (((word >> 8) & 0xFF) == ByteLane) EccRef2 = val & 0xFF;
+                       }
+               }
+       }
+}
+
+static void EnableAutoRefresh_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x8C);
+       val &= ~(1 << DisAutoRefresh);
+       Set_NB32(pDCTstat->dev_dct, 0x8C, val);
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
+       val &= ~(1 << DisAutoRefresh);
+       Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
+}
+
+static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x8C);
+       val |= 1 << DisAutoRefresh;
+       Set_NB32(pDCTstat->dev_dct, 0x8C, val);
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
+       val |= 1 << DisAutoRefresh;
+       Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
+}
+
+
+static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 dimm;
+       u16 DIMMValid;
+       void *DCTPtr;
+
+       dct &= 1;
+
+       DCTPtr = (void *)(pDCTstat->C_DCTPtr[dct]);
+       pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
+       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
+
+       if (pDCTstat->GangedMode & 1)
+               pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
+
+       if (pDCTstat->DIMMValid) {
+               DIMMValid = pDCTstat->DIMMValid;
+               PrepareC_DCT(pMCTstat, pDCTstat, dct);
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
+                       if (DIMMValid & (1 << (dimm << 1)))
+                               AgesaHwWlPhase1(pDCTstat->C_MCTPtr, DCTPtr, dimm, FirstPass);
+               }
+       }
+}
+
+static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 dimm;
+       u16 DIMMValid;
+       void *DCTPtr;
+
+       dct &= 1;
+
+       DCTPtr = (void *)&(pDCTstat->C_DCTPtr[dct]); /* todo: */
+       pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
+       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
+
+       if (pDCTstat->GangedMode & 1)
+               pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
+
+       if (pDCTstat->DIMMValid) {
+               DIMMValid = pDCTstat->DIMMValid;
+               PrepareC_DCT(pMCTstat, pDCTstat, dct);
+               pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
+               pDCTstat->CASL = pDCTstat->DIMMCASL = pDCTstat->TargetCASL;
+               SPD2ndTiming(pMCTstat, pDCTstat, dct);
+               ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
+               PlatformSpec_D(pMCTstat, pDCTstat, dct);
+               fenceDynTraining_D(pMCTstat, pDCTstat, dct);
+               Restore_OnDimmMirror(pMCTstat, pDCTstat);
+               StartupDCT_D(pMCTstat, pDCTstat, dct);
+               Clear_OnDimmMirror(pMCTstat, pDCTstat);
+               SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
+               DisableAutoRefresh_D(pMCTstat, pDCTstat);
+               MultiplyDelay(pMCTstat, pDCTstat, dct);
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
+                       if (DIMMValid & (1 << (dimm << 1)))
+                               AgesaHwWlPhase1(pDCTstat->C_MCTPtr, pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
+               }
+       }
+}
+
+static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
+       pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
+       pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
+
+       /* Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1 */
+       DisableAutoRefresh_D(pMCTstat, pDCTstat);
+
+       /* Disable ZQ calibration short command by F2x[1,0]94[ZqcsInterval]=00b */
+       DisableZQcalibration(pMCTstat, pDCTstat);
+       PrepareC_MCT(pMCTstat, pDCTstat);
+
+       if (pDCTstat->GangedMode & (1 << 0)) {
+               pDCTstat->DIMMValidDCT[1] = pDCTstat->DIMMValidDCT[0];
+       }
+
+       PhyWLPass1(pMCTstat, pDCTstat, 0);
+       PhyWLPass1(pMCTstat, pDCTstat, 1);
+
+       if (pDCTstat->TargetFreq > 4) {
+               /* 8.Prepare the memory subsystem for the target MEMCLK frequency.
+                * Note: BIOS must program both DCTs to the same frequency.
+                */
+               SetTargetFreq(pMCTstat, pDCTstat);
+               PhyWLPass2(pMCTstat, pDCTstat, 0);
+               PhyWLPass2(pMCTstat, pDCTstat, 1);
+
+       }
+
+       SetEccWrDQS_D(pMCTstat, pDCTstat);
+       EnableAutoRefresh_D(pMCTstat, pDCTstat);
+       EnableZQcalibration(pMCTstat, pDCTstat);
+}
+
+void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+
+               if (pDCTstat->NodePresent) {
+                       mctSMBhub_Init(Node);
+                       Clear_OnDimmMirror(pMCTstat, pDCTstat);
+                       WriteLevelization_HW(pMCTstat, pDCTstat);
+                       Restore_OnDimmMirror(pMCTstat, pDCTstat);
+               }
+       }
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
new file mode 100644 (file)
index 0000000..947da43
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "mct_d.h"
+
+static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr);
+static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType);
+
+void CPUMemTyping_D(struct MCTStatStruc *pMCTstat,
+                        struct DCTStatStruc *pDCTstatA)
+{
+       /* BSP only.  Set the fixed MTRRs for common legacy ranges.
+        * Set TOP_MEM and TOM2.
+        * Set some variable MTRRs with WB Uncacheable type.
+        */
+
+       u32 Bottom32bIO, Bottom40bIO, Cache32bTOP;
+       u32 val;
+       u32 addr;
+       u32 lo, hi;
+
+       /* Set temporary top of memory from Node structure data.
+        * Adjust temp top of memory down to accomodate 32-bit IO space.
+        * Bottom40bIO=top of memory, right justified 8 bits
+        *      (defines dram versus IO space type)
+        * Bottom32bIO=sub 4GB top of memory, right justified 8 bits
+        *      (defines dram versus IO space type)
+        * Cache32bTOP=sub 4GB top of WB cacheable memory,
+        *      right justified 8 bits
+        */
+
+       val = mctGet_NVbits(NV_BottomIO);
+       if(val == 0)
+               val++;
+
+       Bottom32bIO = val << (24-8);
+
+       val = pMCTstat->SysLimit + 1;
+       if(val <= _4GB_RJ8) {
+               Bottom40bIO = 0;
+               if(Bottom32bIO >= val)
+                       Bottom32bIO = val;
+       } else {
+               Bottom40bIO = val;
+       }
+
+       Cache32bTOP = Bottom32bIO;
+
+       /*======================================================================
+        Set default values for CPU registers
+       ======================================================================*/
+
+       /* NOTE : For coreboot, we don't need to set mtrr enables here because
+       they are still enable from cache_as_ram.inc */
+
+       addr = 0x250;
+       lo = 0x1E1E1E1E;
+       hi = lo;
+       _WRMSR(addr, lo, hi);           /* 0 - 512K = WB Mem */
+       addr = 0x258;
+       _WRMSR(addr, lo, hi);           /* 512K - 640K = WB Mem */
+
+       /*======================================================================
+         Set variable MTRR values
+        ======================================================================*/
+       /* NOTE: for coreboot change from 0x200 to 0x204: coreboot is using
+               0x200, 0x201 for [1M, CONFIG_TOP_MEM)
+               0x202, 0x203 for ROM Caching
+                */
+       addr = 0x204;   /* MTRR phys base 2*/
+                       /* use TOP_MEM as limit*/
+                       /* Limit=TOP_MEM|TOM2*/
+                       /* Base=0*/
+       printk(BIOS_DEBUG, "\t CPUMemTyping: Cache32bTOP:%x\n", Cache32bTOP);
+       SetMTRRrangeWB_D(0, &Cache32bTOP, &addr);
+                               /* Base */
+                               /* Limit */
+                               /* MtrrAddr */
+       if(addr == -1)          /* ran out of MTRRs?*/
+               pMCTstat->GStatus |= 1<<GSB_MTRRshort;
+
+       pMCTstat->Sub4GCacheTop = Cache32bTOP<<8;
+
+       /*======================================================================
+        Set TOP_MEM and TOM2 CPU registers
+       ======================================================================*/
+       addr = TOP_MEM;
+       lo = Bottom32bIO<<8;
+       hi = Bottom32bIO>>24;
+       _WRMSR(addr, lo, hi);
+       printk(BIOS_DEBUG, "\t CPUMemTyping: Bottom32bIO:%x\n", Bottom32bIO);
+       printk(BIOS_DEBUG, "\t CPUMemTyping: Bottom40bIO:%x\n", Bottom40bIO);
+       if(Bottom40bIO) {
+               hi = Bottom40bIO >> 24;
+               lo = Bottom40bIO << 8;
+               addr += 3;              /* TOM2 */
+               _WRMSR(addr, lo, hi);
+       }
+       addr = 0xC0010010;              /* SYS_CFG */
+       _RDMSR(addr, &lo, &hi);
+       if(Bottom40bIO) {
+               lo |= (1<<21);          /* MtrrTom2En=1 */
+               lo |= (1<<22);          /* Tom2ForceMemTypeWB */
+       } else {
+               lo &= ~(1<<21);         /* MtrrTom2En=0 */
+               lo &= ~(1<<22);         /* Tom2ForceMemTypeWB */
+       }
+       _WRMSR(addr, lo, hi);
+}
+
+static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr)
+{
+       /*set WB type*/
+       SetMTRRrange_D(Base, pLimit, pMtrrAddr, 6);
+}
+
+static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType)
+{
+       /* Program MTRRs to describe given range as given cache type.
+        * Use MTRR pairs starting with the given MTRRphys Base address,
+        * and use as many as is required up to (excluding) MSR 020C, which
+        * is reserved for OS.
+        *
+        * "Limit" in the context of this procedure is not the numerically
+        * correct limit, but rather the Last address+1, for purposes of coding
+        * efficiency and readability.  Size of a region is then Limit-Base.
+        *
+        * 1. Size of each range must be a power of two
+        * 2. Each range must be naturally aligned (Base is same as size)
+        *
+        * There are two code paths: the ascending path and descending path
+        * (analogous to bsf and bsr), where the next limit is a funtion of the
+        * next set bit in a forward or backward sequence of bits (as a function
+        * of the Limit). We start with the ascending path, to ensure that
+        * regions are naturally aligned, then we switch to the descending path
+        * to maximize MTRR usage efficiency. Base=0 is a special case where we
+        * start with the descending path. Correct Mask for region is
+        * 2comp(Size-1)-1, which is 2comp(Limit-Base-1)-1
+        */
+
+       u32 curBase, curLimit, curSize;
+       u32 val, valx;
+       u32 addr;
+
+       val = curBase = Base;
+       curLimit = *pLimit;
+       addr = *pMtrrAddr;
+       while((addr >= 0x200) && (addr < 0x20C) && (val < *pLimit)) {
+               /* start with "ascending" code path */
+               /* alignment (largest block size)*/
+               valx = 1 << bsf(curBase);
+               curSize = valx;
+
+               /* largest legal limit, given current non-zero range Base*/
+               valx += curBase;
+               if((curBase == 0) || (*pLimit < valx)) {
+                       /* flop direction to "descending" code path*/
+                       valx = 1<<bsr(*pLimit - curBase);
+                       curSize = valx;
+                       valx += curBase;
+               }
+               curLimit = valx;                /*eax=curBase, edx=curLimit*/
+               valx = val>>24;
+               val <<= 8;
+
+               /* now program the MTRR */
+               val |= MtrrType;                /* set cache type (UC or WB)*/
+               _WRMSR(addr, val, valx);        /* prog. MTRR with current region Base*/
+               val = ((~(curSize - 1))+1) - 1; /* Size-1*/ /*Mask=2comp(Size-1)-1*/
+               valx = (val >> 24) | (0xff00);  /* GH have 48 bits addr */
+               val <<= 8;
+               val |= ( 1 << 11);                      /* set MTRR valid*/
+               addr++;
+               _WRMSR(addr, val, valx);        /* prog. MTRR with current region Mask*/
+               val = curLimit;
+               curBase = val;                  /* next Base = current Limit (loop exit)*/
+               addr++;                         /* next MTRR pair addr */
+       }
+       if(val < *pLimit) {
+               *pLimit = val;
+               addr = -1;
+       }
+       *pMtrrAddr = addr;
+}
+
+void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
+{
+/* UMA memory size may need splitting the MTRR configuration into two
+  Before training use NB_BottomIO or the physical memory size to set the MTRRs.
+  After training, add UMAMemTyping function to reconfigure the MTRRs based on
+  NV_BottomUMA (for UMA systems only).
+  This two-step process allows all memory to be cached for training
+*/
+       u32 Bottom32bIO, Cache32bTOP;
+       u32 val;
+       u32 addr;
+       u32 lo, hi;
+
+       /*======================================================================
+        * Adjust temp top of memory down to accomodate UMA memory start
+        *======================================================================*/
+       /* Bottom32bIO=sub 4GB top of memory, right justified 8 bits
+        * (defines dram versus IO space type)
+        * Cache32bTOP=sub 4GB top of WB cacheable memory, right justified 8 bits */
+
+       Bottom32bIO = pMCTstat->Sub4GCacheTop >> 8;
+
+       val = mctGet_NVbits(NV_BottomUMA);
+       if (val == 0)
+               val++;
+
+       val <<= (24-8);
+       if (val < Bottom32bIO) {
+               Cache32bTOP = val;
+               pMCTstat->Sub4GCacheTop = val;
+
+       /*======================================================================
+        * Clear variable MTRR values
+        *======================================================================*/
+               addr = 0x200;
+               lo = 0;
+               hi = lo;
+               while( addr < 0x20C) {
+                       _WRMSR(addr, lo, hi);           /* prog. MTRR with current region Mask */
+                       addr++;                                         /* next MTRR pair addr */
+               }
+
+               /*======================================================================
+                * Set variable MTRR values
+                *======================================================================*/
+               printk(BIOS_DEBUG, "\t UMAMemTyping_D: Cache32bTOP:%x\n", Cache32bTOP);
+               SetMTRRrangeWB_D(0, &Cache32bTOP, &addr);
+               if(addr == -1)          /* ran out of MTRRs?*/
+                       pMCTstat->GStatus |= 1<<GSB_MTRRshort;
+       }
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
new file mode 100644 (file)
index 0000000..cc59561
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+void InterleaveNodes_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+{
+       /* Applies Node memory interleaving if enabled and if all criteria are met. */
+       u8 Node;
+       u32 Base;
+       u32 MemSize, MemSize0 = 0;
+       u32 Dct0MemSize = 0, DctSelBase, DctSelBaseOffset;
+       u8 Nodes;
+       u8 NodesWmem;
+       u8 DoIntlv;
+       u8 _NdIntCap;
+       u8 _SWHole;
+       u32 HWHoleSz;
+       u32 DramHoleAddrReg;
+       u32 HoleBase;
+       u32 dev0;
+       u32 reg0;
+       u32 val;
+       u8 i;
+       struct DCTStatStruc *pDCTstat;
+
+       DoIntlv = mctGet_NVbits(NV_NodeIntlv);
+
+       _NdIntCap = 0;
+       HWHoleSz = 0;   /*For HW remapping, NOT Node hoisting. */
+
+       pDCTstat = pDCTstatA + 0;
+       dev0 = pDCTstat->dev_host;
+       Nodes = ((Get_NB32(dev0, 0x60) >> 4) & 0x7) + 1;
+
+       dev0 = pDCTstat->dev_map;
+       reg0 = 0x40;
+
+       NodesWmem = 0;
+       Node = 0;
+
+       while (DoIntlv && (Node < Nodes)) {
+               pDCTstat = pDCTstatA + Node;
+               if (pMCTstat->GStatus & (1 << GSB_SpIntRemapHole)) {
+                       pMCTstat->GStatus |= 1 << GSB_HWHole;
+                       _SWHole = 0;
+               } else if (pDCTstat->Status & (1 << SB_SWNodeHole)) {
+                       _SWHole = 1;
+               } else {
+                       _SWHole = 0;
+               }
+
+               if(!_SWHole) {
+                       Base = Get_NB32(dev0, reg0);
+                       if (Base & 1) {
+                               NodesWmem++;
+                               Base &= 0xFFFF0000;     /* Base[39:8] */
+
+                               if (pDCTstat->Status & (1 << SB_HWHole )) {
+
+                                       /* to get true amount of dram,
+                                        * subtract out memory hole if HW dram remapping */
+                                       DramHoleAddrReg = Get_NB32(pDCTstat->dev_map, 0xF0);
+                                       HWHoleSz = DramHoleAddrReg >> 16;
+                                       HWHoleSz = (((~HWHoleSz) + 1) & 0xFF);
+                                       HWHoleSz <<= 24-8;
+                               }
+                               /* check to see if the amount of memory on each channel
+                                * are the same on all nodes */
+
+                               DctSelBase = Get_NB32(pDCTstat->dev_dct, 0x114);
+                               if(DctSelBase) {
+                                       DctSelBase <<= 8;
+                                       if ( pDCTstat->Status & (1 << SB_HWHole)) {
+                                               if (DctSelBase >= 0x1000000) {
+                                                       DctSelBase -= HWHoleSz;
+                                               }
+                                       }
+                                       DctSelBaseOffset -= Base;
+                                       if (Node == 0) {
+                                               Dct0MemSize = DctSelBase;
+                                       } else if (DctSelBase != Dct0MemSize) {
+                                               break;
+                                       }
+                               }
+
+                               MemSize = Get_NB32(dev0, reg0 + 4);
+                               MemSize &= 0xFFFF0000;
+                               MemSize += 0x00010000;
+                               MemSize -= Base;
+                               if ( pDCTstat->Status & (1 << SB_HWHole)) {
+                                       MemSize -= HWHoleSz;
+                               }
+                               if (Node == 0) {
+                                       MemSize0 = MemSize;
+                               } else if (MemSize0 != MemSize) {
+                                       break;
+                               }
+                       } else {
+                               break;
+                       }
+               } else {
+                       break;
+               }
+       Node++;
+       reg0 += 8;
+       }
+
+       if (Node == Nodes) {
+               /* if all nodes have memory and no Node had SW memhole */
+               if (Nodes == 2 || Nodes == 4 || Nodes == 8)
+                       _NdIntCap = 1;
+       }
+
+       if (!_NdIntCap)
+               DoIntlv = 0;
+
+       if (pMCTstat->GStatus & 1 << (GSB_SpIntRemapHole)) {
+               HWHoleSz = pMCTstat->HoleBase;
+               if (HWHoleSz == 0) {
+                       HWHoleSz = mctGet_NVbits(NV_BottomIO) & 0xFF;
+                       HWHoleSz <<= 24-8;
+               }
+               HWHoleSz = ((~HWHoleSz) + 1) & 0x00FF0000;
+       }
+
+       if (DoIntlv) {
+               MCTMemClr_D(pMCTstat,pDCTstatA);
+               /* Program Interleaving enabled on Node 0 map only.*/
+               MemSize0 <<= bsf(Nodes);        /* MemSize=MemSize*2 (or 4, or 8) */
+               Dct0MemSize <<= bsf(Nodes);
+               MemSize0 += HWHoleSz;
+               Base = ((Nodes - 1) << 8) | 3;
+               reg0 = 0x40;
+               Node = 0;
+               while(Node < Nodes) {
+                       Set_NB32(dev0, reg0, Base);
+                       MemSize = MemSize0;
+                       MemSize--;
+                       MemSize &= 0xFFFF0000;
+                       MemSize |= Node << 8;   /* set IntlvSel[2:0] field */
+                       MemSize |= Node;        /* set DstNode[2:0] field */
+                       Set_NB32(dev0, reg0 + 4, MemSize0);
+                       reg0 += 8;
+                       Node++;
+               }
+
+               /*  set base/limit to F1x120/124 per Node */
+               Node = 0;
+               while(Node < Nodes) {
+                       pDCTstat = pDCTstatA + Node;
+                       pDCTstat->NodeSysBase = 0;
+                       MemSize = MemSize0;
+                       MemSize -= HWHoleSz;
+                       MemSize--;
+                       pDCTstat->NodeSysLimit = MemSize;
+                       Set_NB32(pDCTstat->dev_map, 0x120, Node << 21);
+                       MemSize = MemSize0;
+                       MemSize--;
+                       MemSize >>= 19;
+                       val = Base;
+                       val &= 0x700;
+                       val <<= 13;
+                       val |= MemSize;
+                       Set_NB32(pDCTstat->dev_map, 0x124, val);
+
+                       if (pMCTstat->GStatus & (1 << GSB_HWHole)) {
+                               HoleBase = pMCTstat->HoleBase;
+                               if (Dct0MemSize >= HoleBase) {
+                                       val = HWHoleSz;
+                                       if( Node == 0) {
+                                               val += Dct0MemSize;
+                                       }
+                               } else {
+                                       val = HWHoleSz + Dct0MemSize;
+                               }
+
+                               val >>= 8;              /* DramHoleOffset */
+                               HoleBase <<= 8;         /* DramHoleBase */
+                               val |= HoleBase;
+                               val |= 1 << DramMemHoistValid;
+                               val |= 1 << DramHoleValid;
+                               Set_NB32(pDCTstat->dev_map, 0xF0, val);
+                       }
+
+                       Set_NB32(pDCTstat->dev_dct, 0x114, Dct0MemSize >> 8);   /* DctSelBaseOffset */
+                       val = Get_NB32(pDCTstat->dev_dct, 0x110);
+                       val &= 0x7FF;
+                       val |= Dct0MemSize >> 8;
+                       Set_NB32(pDCTstat->dev_dct, 0x110, val);        /* DctSelBaseAddr */
+                       printk(BIOS_DEBUG, "InterleaveNodes: DRAM Controller Select Low Register = %x\n", val);
+                       Node++;
+               }
+
+               /* Copy Node 0 into other Nodes' CSRs */
+               Node = 1;
+               while (Node < Nodes) {
+                       pDCTstat = pDCTstatA + Node;
+
+                       for (i = 0x40; i <= 0x80; i++) {
+                               val = Get_NB32(dev0, i);
+                               Set_NB32(pDCTstat->dev_map, i, val);
+                       }
+
+                       val = Get_NB32(dev0, 0xF0);
+                       Set_NB32(pDCTstat->dev_map, 0xF0, val);
+                       Node++;
+               }
+               pMCTstat->GStatus = (1 << GSB_NodeIntlv);
+       }
+       printk(BIOS_DEBUG, "InterleaveNodes_D: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "InterleaveNodes_D: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "InterleaveNodes_D: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "InterleaveNodes_D: Done\n\n");
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctprob.c b/src/northbridge/amd/amdmct/mct_ddr3/mctprob.c
new file mode 100644 (file)
index 0000000..cfd4adf
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+
+       if (pDCTstat->LogicalCPUID & AMD_DR_Bx) {
+               Set_NB32(pDCTstat->dev_dct, 0x98, 0x0D004007);
+               val = Get_NB32(pDCTstat->dev_dct, 0x9C);
+               val |= 0x3FF;
+               Set_NB32(pDCTstat->dev_dct, 0x9C, val);
+               Set_NB32(pDCTstat->dev_dct, 0x98, 0x4D0F4F07);
+
+               Set_NB32(pDCTstat->dev_dct, 0x198, 0x0D004007);
+               val = Get_NB32(pDCTstat->dev_dct, 0x19C);
+               val |= 0x3FF;
+               Set_NB32(pDCTstat->dev_dct, 0x19C, val);
+               Set_NB32(pDCTstat->dev_dct, 0x198, 0x4D0F4F07);
+       }
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
new file mode 100644 (file)
index 0000000..a40dda4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2)
+{
+       u32 val;
+
+       if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
+               if (pDCTstat->Status & (1 << SB_Registered)) {
+                       misc2 |= 1 << SubMemclkRegDly;
+                       if (mctGet_NVbits(NV_MAX_DIMMS) == 8)
+                               misc2 |= 1 << Ddr3FourSocketCh;
+                       else
+                               misc2 &= ~(1 << Ddr3FourSocketCh);
+               }
+
+               if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
+                       misc2 |= 1 << OdtSwizzle;
+               val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78);
+
+               val &= 7;
+               val = ((~val) & 0xFF) + 1;
+               val += 6;
+               val &= 0xFF;
+               misc2 &= 0xFFF8FFFF;
+               misc2 |= val << 16;     /* DataTxFifoWrDly */
+       }
+       return misc2;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
new file mode 100644 (file)
index 0000000..647e637
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum)
+{
+       u8 Dimms, DimmNum, MaxDimm, Speed;
+       u32 val;
+
+       DimmNum = MrsChipSel >> 20;
+
+       /* assume dct=0; */
+       /* if (dct == 1) */
+       /* DimmNum ++; */
+       /* cl +=8; */
+
+       MaxDimm = mctGet_NVbits(NV_MAX_DIMMS);
+       Speed = pDCTstat->DIMMAutoSpeed;
+       /* if (dct == 0) */
+       Dimms = pDCTstat->MAdimms[0];
+
+       val = 0;
+       if (CtrlWordNum == 0)
+               val |= 1 << 1;
+       else if (CtrlWordNum == 1) {
+               if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 << DimmNum)))
+                       val |= 0xC; /* if single rank, set DBA1 and DBA0 */
+       }
+       else if (CtrlWordNum == 2) {
+               if (MaxDimm == 4) {
+                       if (Speed == 4) {
+                               if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) && (Dimms == 1)) || Dimms == 2)
+                                       if (!(pDCTstat->MirrPresU_NumRegR & (1 << DimmNum)))
+                                               val |= 1 << 2;
+                       } else {
+                               if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
+                                       val |= 2;
+                       }
+               } else {
+                       if (Dimms > 1)
+                               val |= 2;
+               }
+       } else if (CtrlWordNum == 3) {
+               val = pDCTstat->CtrlWrd3 >> (DimmNum << 2);
+       } else if (CtrlWordNum == 4) {
+               val = pDCTstat->CtrlWrd4 >> (DimmNum << 2);
+       } else if (CtrlWordNum == 5) {
+               val = pDCTstat->CtrlWrd5 >> (DimmNum << 2);
+       } else if (CtrlWordNum == 8) {
+               if (MaxDimm == 4)
+                       if (Speed == 4)
+                               if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
+                                       val |= 1 << 2;
+       } else if (CtrlWordNum == 9) {
+               val |= 0xD;     /* DBA1, DBA0, DA3 = 0 */
+       }
+       val &= 0xf;
+
+       val = MrsChipSel | ((val >> 2) & 3) << 16 | MrsChipSel | ((val >> 2) & 3);
+
+       /* transfer Control word number to address [BA2,A2,A1,A0] */
+       if (CtrlWordNum > 7) {
+               val |= 1 << 18;
+               CtrlWordNum &= 7;
+       }
+       val |= CtrlWordNum;
+
+       return val;
+}
+
+static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u32 val)
+{
+       u32 dev = pDCTstat->dev_dct;
+
+       val |= Get_NB32(dev, 0x7C) & ~0xFFFFFF;
+       val |= 1 << SendControlWord;
+       Set_NB32(dev, 0x7C, val);
+
+       do {
+               val = Get_NB32(dev, 0x7C);
+       } while (val & (1 << SendControlWord));
+}
+
+void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 MrsChipSel;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val, cw;
+
+       mct_Wait(1600);
+
+       mct_Wait(1200);
+
+       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       val = Get_NB32(dev, 0xA8);
+                       val &= ~(0xF << 8);
+
+                       switch (MrsChipSel) {
+                       case 0:
+                       case 1:
+                               val |= 3 << 8;
+                       case 2:
+                       case 3:
+                               val |= (3 << 2) << 8;
+                       case 4:
+                       case 5:
+                               val |= (3 << 4) << 8;
+                       case 6:
+                       case 7:
+                               val |= (3 << 6) << 8;
+                       }
+                       Set_NB32(dev, 0xA8, val);
+
+                       for (cw=0; cw <=15; cw ++) {
+                               mct_Wait(1600);
+                               if (!(cw==6 || cw==7)) {
+                                       val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, cw);
+                                       mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
+                               }
+                       }
+               }
+       }
+
+       mct_Wait(1200);
+}
+
+void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat)
+{
+       u32 SaveSpeed = pDCTstat->DIMMAutoSpeed;
+       u32 MrsChipSel;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+
+       pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
+       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       val = Get_NB32(dev, 0xA8);
+                       val &= ~(0xFF << 8);
+                       val |= (0x3 << MrsChipSel) << 8;
+                       Set_NB32(dev, 0xA8, val);
+
+                       mct_Wait(1600);
+                       switch (pDCTstat->TargetFreq) {
+                       case 6:
+                               mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4000A);
+                               break;
+                       case 5:
+                               mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40012);
+                               break;
+                       case 7:
+                               mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4001A);
+                               break;
+                       }
+
+                       mct_Wait(1600);
+
+                       val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 2);
+                       mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
+
+                       mct_Wait(1600);
+
+                       /* Resend control word 8 */
+                       val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 8);
+                       mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
+
+                       mct_Wait(1600);
+               }
+       }
+       pDCTstat->DIMMAutoSpeed = SaveSpeed;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
new file mode 100644 (file)
index 0000000..18ef477
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+
+static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+
+       do {
+               val = Get_NB32(dev, reg_off + 0x98);
+       } while (!(val & (1 << DctAccessDone)));
+}
+
+static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting, u8 MrsChipSel, u8 dct)
+{
+       u16 word;
+       u32 ret;
+
+       if (!(pDCTstat->Status & (1 << SB_Registered))) {
+               word = pDCTstat->MirrPresU_NumRegR;
+               if (dct == 0) {
+                       word &= 0x55;
+                       word <<= 1;
+               } else
+                       word &= 0xAA;
+
+               if (word & (1 << MrsChipSel)) {
+                       /* A3<->A4,A5<->A6,A7<->A8,BA0<->BA1 */
+                       ret = 0;
+                       if (MR_register_setting & (1 << 3)) ret |= 1 << 4;
+                       if (MR_register_setting & (1 << 4)) ret |= 1 << 3;
+                       if (MR_register_setting & (1 << 5)) ret |= 1 << 6;
+                       if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
+                       if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
+                       if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
+                       if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
+                       if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
+                       MR_register_setting &= ~0x301f8;
+                       MR_register_setting |= ret;
+               }
+       }
+       return MR_register_setting;
+}
+
+static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+
+       val = Get_NB32(dev, reg_off + 0x7C);
+       val &= ~0xFFFFFF;
+       val |= EMRS;
+       val |= 1 << SendMrsCmd;
+       Set_NB32(dev, reg_off + 0x7C, val);
+
+       do {
+               val = Get_NB32(dev, reg_off + 0x7C);
+       } while (val & (1 << SendMrsCmd));
+}
+
+static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+
+       ret = 0x20000;
+       ret |= MrsChipSel;
+
+       /* program MrsAddress[5:3]=CAS write latency (CWL):
+        * based on F2x[1,0]84[Tcwl] */
+       dword = Get_NB32(dev, reg_off + 0x84);
+       dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
+
+       ret |= ((dword >> 20) & 7) << 3;
+
+       /* program MrsAddress[6]=auto self refresh method (ASR):
+          based on F2x[1,0]84[ASR]
+          program MrsAddress[7]=self refresh temperature range (SRT):
+          based on F2x[1,0]84[ASR and SRT] */
+       ret |= ((dword >> 18) & 3) << 6;
+
+       /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
+          based on F2x[1,0]84[DramTermDyn] */
+       ret |= ((dword >> 10) & 3) << 9;
+
+       return ret;
+}
+
+static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+
+       ret = 0x30000;
+       ret |= MrsChipSel;
+
+       /* 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]
+       */
+       dword = Get_NB32(dev, reg_off + 0x84);
+       ret |= (dword >> 24) & 7;
+
+       return ret;
+}
+
+static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+
+       ret = 0x10000;
+       ret |= MrsChipSel;
+
+       /* program MrsAddress[5,1]=output driver impedance control (DIC):
+        * based on F2x[1,0]84[DrvImpCtrl] */
+       dword = Get_NB32(dev, reg_off + 0x84);
+       if (dword & (1 << 3))
+               ret |= 1 << 5;
+       if (dword & (1 << 2))
+               ret |= 1 << 1;
+
+       /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
+          based on F2x[1,0]84[DramTerm] */
+       if (!(pDCTstat->Status & (1 << SB_Registered))) {
+               if (dword & (1 << 9))
+                       ret |= 1 << 9;
+               if (dword & (1 << 8))
+                       ret |= 1 << 6;
+               if (dword & (1 << 7))
+                       ret |= 1 << 2;
+       } else {
+               /* TODO: mct_MR1Odt_RDimm */
+       }
+
+       /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
+       if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
+               u8 bit;
+               /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
+               bit = (ret >> 21) << 1;
+               if ((dct & 1) != 0)
+                       bit ++;
+               if (pDCTstat->Dimmx8Present & (1 << bit))
+                       ret |= 1 << 11;
+       }
+
+       if (dword & (1 << 13))
+               ret |= 1 << 12;
+
+       return ret;
+}
+
+static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret, dword2;
+
+       ret = 0x00000;
+       ret |= MrsChipSel;
+
+       /* program MrsAddress[1:0]=burst length and control method
+          (BL):based on F2x[1,0]84[BurstCtrl] */
+       dword = Get_NB32(dev, reg_off + 0x84);
+       ret |= dword & 3;
+
+       /* program MrsAddress[3]=1 (BT):interleaved */
+       ret |= 1 << 3;
+
+       /* program MrsAddress[6:4,2]=read CAS latency
+          (CL):based on F2x[1,0]88[Tcl] */
+       dword2 = Get_NB32(dev, reg_off + 0x88);
+       ret |= (dword2 & 0xF) << 4; /* F2x88[3:0] to MrsAddress[6:4,2]=xxx0b */
+
+       /* program MrsAddress[12]=0 (PPD):slow exit */
+       if (dword & (1 << 23))
+               ret |= 1 << 12;
+
+       /* program MrsAddress[11:9]=write recovery for auto-precharge
+          (WR):based on F2x[1,0]84[Twr] */
+       ret |= ((dword >> 4) & 7) << 9;
+
+       /* program MrsAddress[8]=1 (DLL):DLL reset
+          just issue DLL reset at first time */
+       ret |= 1 << 8;
+
+       return ret;
+}
+
+static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword;
+
+       /*1.Program MrsAddress[10]=1
+         2.Set SendZQCmd=1
+        */
+       dword = Get_NB32(dev, reg_off + 0x7C);
+       dword &= ~0xFFFFFF;
+       dword |= 1 << 10;
+       dword |= 1 << SendZQCmd;
+       Set_NB32(dev, reg_off + 0x7C, dword);
+
+       /* Wait for SendZQCmd=0 */
+       do {
+               dword = Get_NB32(dev, reg_off + 0x7C);
+       } while (dword & (1 << SendZQCmd));
+
+       /* 4.Wait 512 MEMCLKs */
+       mct_Wait(300);
+}
+
+void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 MrsChipSel;
+       u32 dword;
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+
+       if (pDCTstat->DIMMAutoSpeed == 4) {
+               /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
+               dword = Get_NB32(dev, reg_off + 0x7C);
+               dword |= 1 << EnDramInit;
+               Set_NB32(dev, reg_off + 0x7C, dword);
+               mct_DCTAccessDone(pDCTstat, dct);
+
+               /* 4.wait 200us */
+               mct_Wait(40000);
+
+               /* 5.On revision C processors, program F2x[1, 0]7C[DeassertMemRstX] = 1. */
+               dword = Get_NB32(dev, reg_off + 0x7C);
+               dword |= 1 << DeassertMemRstX;
+               Set_NB32(dev, reg_off + 0x7C, dword);
+
+               /* 6.wait 500us */
+               mct_Wait(200000);
+
+               /* 7.Program F2x[1,0]7C[AssertCke]=1 */
+               dword = Get_NB32(dev, reg_off + 0x7C);
+               dword |= 1 << AssertCke;
+               Set_NB32(dev, reg_off + 0x7C, dword);
+
+               /* 8.wait 360ns */
+               mct_Wait(80);
+
+               /* The following steps are performed with registered DIMMs only and
+                * must be done for each chip select pair */
+               if (pDCTstat->Status & (1 << SB_Registered))
+                       mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
+       }
+
+       /* The following steps are performed once for unbuffered DIMMs and once for each
+        * chip select on registered DIMMs: */
+       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       u32 EMRS;
+                       /* 13.Send EMRS(2) */
+                       EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+                       /* 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b */
+                       EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+                       /* 15.Send EMRS(1) */
+                       EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+                       /* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
+                       EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+
+                       if (pDCTstat->DIMMAutoSpeed == 4)
+                               if (!(pDCTstat->Status & (1 << SB_Registered)))
+                                       break; /* For UDIMM, only send MR commands once per channel */
+               }
+               if (pDCTstat->LogicalCPUID & (AMD_DR_Cx/* | AMD_RB_C0 */)) /* We dont support RB_C0 now. need to be added and tested. */
+                       if (!(pDCTstat->Status & (1 << SB_Registered)))
+                               MrsChipSel ++;
+       }
+
+       mct_Wait(100000);
+
+       if (pDCTstat->DIMMAutoSpeed == 4) {
+               /* 17.Send two ZQCL commands */
+               mct_SendZQCmd(pDCTstat, dct);
+               mct_SendZQCmd(pDCTstat, dct);
+               /* 18.Program F2x[1,0]7C[EnDramInit]=0 */
+               dword = Get_NB32(dev, reg_off + 0x7C);
+               dword &= ~(1 << EnDramInit);
+               Set_NB32(dev, reg_off + 0x7C, dword);
+               mct_DCTAccessDone(pDCTstat, dct);
+       }
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
new file mode 100644 (file)
index 0000000..86d0742
--- /dev/null
@@ -0,0 +1,1056 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/******************************************************************************
+ Description: Receiver En and DQS Timing Training feature for DDR 3 MCT
+******************************************************************************/
+
+static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Pass);
+static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat,
+                                       u8 rcvrEnDly, u8 Channel,
+                                       u8 receiver, u8 Pass);
+static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 addr, u8 channel,
+                                       u8 pattern, u8 Pass);
+static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                                        struct DCTStatStruc *pDCTstat);
+static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel);
+static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel);
+static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat,
+                               u8 RcvrEnDly, u8 where,
+                               u8 Channel, u8 Receiver,
+                               u32 dev, u32 index_reg,
+                               u8 Addl_Index, u8 Pass);
+static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQSRcvEnDly);
+static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat);
+
+/* Warning:  These must be located so they do not cross a logical 16-bit
+   segment boundary! */
+const static u32 TestPattern0_D[] = {
+       0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+       0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+       0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+       0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+};
+const static u32 TestPattern1_D[] = {
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+};
+const static u32 TestPattern2_D[] = {
+       0x12345678, 0x87654321, 0x23456789, 0x98765432,
+       0x59385824, 0x30496724, 0x24490795, 0x99938733,
+       0x40385642, 0x38465245, 0x29432163, 0x05067894,
+       0x12349045, 0x98723467, 0x12387634, 0x34587623,
+};
+
+static void SetupRcvrPattern(struct MCTStatStruc *pMCTstat,
+               struct DCTStatStruc *pDCTstat, u32 *buffer, u8 pass)
+{
+       /*
+        * 1. Copy the alpha and Beta patterns from ROM to Cache,
+        *     aligning on 16 byte boundary
+        * 2. Set the ptr to DCTStatstruc.PtrPatternBufA for Alpha
+        * 3. Set the ptr to DCTStatstruc.PtrPatternBufB for Beta
+        */
+       u32 *buf_a;
+       u32 *buf_b;
+       u32 *p_A;
+       u32 *p_B;
+       u8 i;
+
+       buf_a = (u32 *)(((u32)buffer + 0x10) & (0xfffffff0));
+       buf_b = buf_a + 32; /* ?? */
+       p_A = (u32 *)SetupDqsPattern_1PassB(pass);
+       p_B = (u32 *)SetupDqsPattern_1PassA(pass);
+
+       for(i=0;i<16;i++) {
+               buf_a[i] = p_A[i];
+               buf_b[i] = p_B[i];
+       }
+
+       pDCTstat->PtrPatternBufA = (u32)buf_a;
+       pDCTstat->PtrPatternBufB = (u32)buf_b;
+}
+
+void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 Pass)
+{
+       if(mct_checkNumberOfDqsRcvEn_1Pass(Pass))
+               dqsTrainRcvrEn_SW(pMCTstat, pDCTstat, Pass);
+}
+
+static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Pass)
+{
+       u8 Channel, RcvrEnDly, RcvrEnDlyRmin;
+       u8 Test0, Test1, CurrTest, CurrTestSide0, CurrTestSide1;
+       u8 CTLRMaxDelay, _2Ranks, PatternA, PatternB;
+       u8 Addl_Index = 0;
+       u8 Receiver;
+       u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
+       u8 RcvrEnDlyLimit, Final_Value, MaxDelay_CH[2];
+       u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B;
+       u32 PatternBuffer[64+4]; /* FIXME: need increase 8? */
+       u32 Errors;
+
+       u32 val;
+       u32 reg;
+       u32 dev;
+       u32 index_reg;
+       u32 ch_start, ch_end, ch;
+       u32 msr;
+       u32 cr4;
+       u32 lo, hi;
+
+       u8 valid;
+       u32 tmp;
+       u8 LastTest;
+
+       print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
+       print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
+
+       dev = pDCTstat->dev_dct;
+       ch_start = 0;
+       if(!pDCTstat->GangedMode) {
+               ch_end = 2;
+       } else {
+               ch_end = 1;
+       }
+
+       for (ch = ch_start; ch < ch_end; ch++) {
+               reg = 0x78 + (0x100 * ch);
+               val = Get_NB32(dev, reg);
+               val &= ~(0x3ff << 22);
+               val |= (0x0c8 << 22);           /* Max Rd Lat */
+               Set_NB32(dev, reg, val);
+       }
+
+       Final_Value = 1;
+       if (Pass == FirstPass) {
+               mct_InitDQSPos4RcvrEn_D(pMCTstat, pDCTstat);
+       } else {
+               pDCTstat->DimmTrainFail = 0;
+               pDCTstat->CSTrainFail = ~pDCTstat->CSPresent;
+       }
+
+       cr4 = read_cr4();
+       if(cr4 & ( 1 << 9)) {   /* save the old value */
+               _SSE2 = 1;
+       }
+       cr4 |= (1 << 9);        /* OSFXSR enable SSE2 */
+       write_cr4(cr4);
+
+       msr = HWCR;
+       _RDMSR(msr, &lo, &hi);
+       /* FIXME: Why use SSEDIS */
+       if(lo & (1 << 17)) {    /* save the old value */
+               _Wrap32Dis = 1;
+       }
+       lo |= (1 << 17);        /* HWCR.wrap32dis */
+       lo &= ~(1 << 15);       /* SSEDIS */
+       _WRMSR(msr, lo, hi);    /* Setting wrap32dis allows 64-bit memory references in real mode */
+
+       _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
+
+       SetupRcvrPattern(pMCTstat, pDCTstat, PatternBuffer, Pass);
+
+       Errors = 0;
+       dev = pDCTstat->dev_dct;
+       CTLRMaxDelay = 0;
+
+       for (Channel = 0; Channel < 2; Channel++) {
+               print_debug_dqs("\tTrainRcvEn51: Node ", pDCTstat->Node_ID, 1);
+               print_debug_dqs("\tTrainRcvEn51: Channel ", Channel, 1);
+               pDCTstat->Channel = Channel;
+
+               MaxDelay_CH[Channel] = 0;
+               index_reg = 0x98 + 0x100 * Channel;
+
+               Receiver = mct_InitReceiver_D(pDCTstat, Channel);
+               /* There are four receiver pairs, loosely associated with chipselects. */
+               for (; Receiver < 8; Receiver += 2) {
+                       Addl_Index = (Receiver >> 1) * 3 + 0x10;
+                       LastTest = DQS_FAIL;
+
+                       /* mct_ModifyIndex_D */
+                       RcvrEnDlyRmin = RcvrEnDlyLimit = 0xff;
+
+                       print_debug_dqs("\t\tTrainRcvEnd52: index ", Addl_Index, 2);
+
+                       if(!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) {
+                               continue;
+                       }
+
+                       TestAddr0 = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, Channel, Receiver, &valid);
+                       if(!valid) {    /* Address not supported on current CS */
+                               continue;
+                       }
+
+                       TestAddr0B = TestAddr0 + (BigPagex8_RJ8 << 3);
+
+                       if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver+1)) {
+                               TestAddr1 = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, Channel, Receiver+1, &valid);
+                               if(!valid) {    /* Address not supported on current CS */
+                                       continue;
+                               }
+                               TestAddr1B = TestAddr1 + (BigPagex8_RJ8 << 3);
+                               _2Ranks = 1;
+                       } else {
+                               _2Ranks = TestAddr1 = TestAddr1B = 0;
+                       }
+
+                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr0 ", TestAddr0, 2);
+                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr0B ", TestAddr0B, 2);
+                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1 ", TestAddr1, 2);
+                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", TestAddr1B, 2);
+
+                       /*
+                        * Get starting RcvrEnDly value
+                        */
+                       RcvrEnDly = mct_Get_Start_RcvrEnDly_1Pass(Pass);
+
+                       /* mct_GetInitFlag_D*/
+                       if (Pass == FirstPass) {
+                               pDCTstat->DqsRcvEn_Pass = 0;
+                       } else {
+                               pDCTstat->DqsRcvEn_Pass=0xFF;
+                       }
+                       pDCTstat->DqsRcvEn_Saved = 0;
+
+
+                       while(RcvrEnDly < RcvrEnDlyLimit) {     /* sweep Delay value here */
+                               print_debug_dqs("\t\t\tTrainRcvEn541: RcvrEnDly ", RcvrEnDly, 3);
+
+                               /* callback not required
+                               if(mct_AdjustDelay_D(pDCTstat, RcvrEnDly))
+                                       goto skipDly;
+                               */
+
+                               /* Odd steps get another pattern such that even
+                                and odd steps alternate. The pointers to the
+                                patterns will be swaped at the end of the loop
+                                so that they correspond. */
+                               if(RcvrEnDly & 1) {
+                                       PatternA = 1;
+                                       PatternB = 0;
+                               } else {
+                                       /* Even step */
+                                       PatternA = 0;
+                                       PatternB = 1;
+                               }
+
+                               mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, PatternA); /* rank 0 of DIMM, testpattern 0 */
+                               mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0B, PatternB); /* rank 0 of DIMM, testpattern 1 */
+                               if(_2Ranks) {
+                                       mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1, PatternA); /*rank 1 of DIMM, testpattern 0 */
+                                       mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1B, PatternB); /*rank 1 of DIMM, testpattern 1 */
+                               }
+
+                               mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, 0, Channel, Receiver, dev, index_reg, Addl_Index, Pass);
+
+                               CurrTest = DQS_FAIL;
+                               CurrTestSide0 = DQS_FAIL;
+                               CurrTestSide1 = DQS_FAIL;
+
+                               mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0); /*cache fills */
+                               Test0 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr0, Channel, PatternA, Pass);/* ROM vs cache compare */
+                               proc_IOCLFLUSH_D(TestAddr0);
+                               ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
+
+                               print_debug_dqs("\t\t\tTrainRcvEn542: Test0 result ", Test0, 3);
+
+                               /* != 0x00 mean pass */
+
+                               if(Test0 == DQS_PASS) {
+                                       mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0B);        /*cache fills */
+                                       /* ROM vs cache compare */
+                                       Test1 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr0B, Channel, PatternB, Pass);
+                                       proc_IOCLFLUSH_D(TestAddr0B);
+                                       ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
+
+                                       print_debug_dqs("\t\t\tTrainRcvEn543: Test1 result ", Test1, 3);
+
+                                       if(Test1 == DQS_PASS) {
+                                               CurrTestSide0 = DQS_PASS;
+                                       }
+                               }
+                               if(_2Ranks) {
+                                       mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1); /*cache fills */
+                                       /* ROM vs cache compare */
+                                       Test0 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1, Channel, PatternA, Pass);
+                                       proc_IOCLFLUSH_D(TestAddr1);
+                                       ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
+
+                                       print_debug_dqs("\t\t\tTrainRcvEn544: Test0 result ", Test0, 3);
+
+                                       if(Test0 == DQS_PASS) {
+                                               mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1B);        /*cache fills */
+                                               /* ROM vs cache compare */
+                                               Test1 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1B, Channel, PatternB, Pass);
+                                               proc_IOCLFLUSH_D(TestAddr1B);
+                                               ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
+
+                                               print_debug_dqs("\t\t\tTrainRcvEn545: Test1 result ", Test1, 3);
+                                               if(Test1 == DQS_PASS) {
+                                                       CurrTestSide1 = DQS_PASS;
+                                               }
+                                       }
+                               }
+
+                               if(_2Ranks) {
+                                       if ((CurrTestSide0 == DQS_PASS) && (CurrTestSide1 == DQS_PASS)) {
+                                               CurrTest = DQS_PASS;
+                                       }
+                               } else if (CurrTestSide0 == DQS_PASS) {
+                                       CurrTest = DQS_PASS;
+                               }
+
+                               /* record first pass DqsRcvEn to stack */
+                               valid = mct_SavePassRcvEnDly_D(pDCTstat, RcvrEnDly, Channel, Receiver, Pass);
+
+                               /* Break(1:RevF,2:DR) or not(0) FIXME: This comment deosn't make sense */
+                               if(valid == 2 || (LastTest == DQS_FAIL && valid == 1)) {
+                                       RcvrEnDlyRmin = RcvrEnDly;
+                                       break;
+                               }
+
+                               LastTest = CurrTest;
+
+                               /* swap the rank 0 pointers */
+                               tmp = TestAddr0;
+                               TestAddr0 = TestAddr0B;
+                               TestAddr0B = tmp;
+
+                               /* swap the rank 1 pointers */
+                               tmp = TestAddr1;
+                               TestAddr1 = TestAddr1B;
+                               TestAddr1B = tmp;
+
+                               print_debug_dqs("\t\t\tTrainRcvEn56: RcvrEnDly ", RcvrEnDly, 3);
+
+                               RcvrEnDly++;
+
+                       }       /* while RcvrEnDly */
+
+                       print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDly ", RcvrEnDly, 2);
+                       print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyRmin ", RcvrEnDlyRmin, 3);
+                       print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyLimit ", RcvrEnDlyLimit, 3);
+                       if(RcvrEnDlyRmin == RcvrEnDlyLimit) {
+                               /* no passing window */
+                               pDCTstat->ErrStatus |= 1 << SB_NORCVREN;
+                               Errors |= 1 << SB_NORCVREN;
+                               pDCTstat->ErrCode = SC_FatalErr;
+                       }
+
+                       if(RcvrEnDly > (RcvrEnDlyLimit - 1)) {
+                               /* passing window too narrow, too far delayed*/
+                               pDCTstat->ErrStatus |= 1 << SB_SmallRCVR;
+                               Errors |= 1 << SB_SmallRCVR;
+                               pDCTstat->ErrCode = SC_FatalErr;
+                               RcvrEnDly = RcvrEnDlyLimit - 1;
+                               pDCTstat->CSTrainFail |= 1 << Receiver;
+                               pDCTstat->DimmTrainFail |= 1 << (Receiver + Channel);
+                       }
+
+                       /* CHB_D0_B0_RCVRDLY set in mct_Average_RcvrEnDly_Pass */
+                       mct_Average_RcvrEnDly_Pass(pDCTstat, RcvrEnDly, RcvrEnDlyLimit, Channel, Receiver, Pass);
+
+                       mct_SetFinalRcvrEnDly_D(pDCTstat, RcvrEnDly, Final_Value, Channel, Receiver, dev, index_reg, Addl_Index, Pass);
+
+                       if(pDCTstat->ErrStatus & (1 << SB_SmallRCVR)) {
+                               Errors |= 1 << SB_SmallRCVR;
+                       }
+
+                       RcvrEnDly += Pass1MemClkDly;
+                       if(RcvrEnDly > CTLRMaxDelay) {
+                               CTLRMaxDelay = RcvrEnDly;
+                       }
+
+               }       /* while Receiver */
+               MaxDelay_CH[Channel] = CTLRMaxDelay;
+       }       /* for Channel */
+
+       CTLRMaxDelay = MaxDelay_CH[0];
+       if (MaxDelay_CH[1] > CTLRMaxDelay)
+               CTLRMaxDelay = MaxDelay_CH[1];
+
+       for (Channel = 0; Channel < 2; Channel++) {
+               mct_SetMaxLatency_D(pDCTstat, Channel, CTLRMaxDelay); /* program Ch A/B MaxAsyncLat to correspond with max delay */
+       }
+
+       ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
+
+       if(_DisableDramECC) {
+               mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
+       }
+
+       if (Pass == FirstPass) {
+               /*Disable DQSRcvrEn training mode */
+               mct_DisableDQSRcvEn_D(pDCTstat);
+       }
+
+       if(!_Wrap32Dis) {
+               msr = HWCR;
+               _RDMSR(msr, &lo, &hi);
+               lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
+               _WRMSR(msr, lo, hi);
+       }
+       if(!_SSE2){
+               cr4 = read_cr4();
+               cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
+               write_cr4(cr4);
+       }
+
+#if DQS_TRAIN_DEBUG > 0
+       {
+               u8 Channel;
+               printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
+               for(Channel = 0; Channel<2; Channel++) {
+                       printk(BIOS_DEBUG, "Channel:%x: %x\n",
+                              Channel, pDCTstat->CH_MaxRdLat[Channel]);
+               }
+       }
+#endif
+
+#if DQS_TRAIN_DEBUG > 0
+       {
+               u8 val;
+               u8 Channel, Receiver;
+               u8 i;
+               u8 *p;
+
+               printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
+               for(Channel = 0; Channel < 2; Channel++) {
+                       printk(BIOS_DEBUG, "Channel:%x\n");
+                       for(Receiver = 0; Receiver<8; Receiver+=2) {
+                               printk(BIOS_DEBUG, "\t\tReceiver:%x:");
+                               p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
+                               for (i=0;i<8; i++) {
+                                       val  = p[i];
+                                       printk(BIOS_DEBUG, "%x ", val);
+                               }
+                               printk(BIOS_DEBUG, "\n");
+                       }
+               }
+       }
+#endif
+
+       printk(BIOS_DEBUG, "TrainRcvrEn: Status %x\n", pDCTstat->Status);
+       printk(BIOS_DEBUG, "TrainRcvrEn: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "TrainRcvrEn: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
+}
+
+u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       if (pDCTstat->DIMMValidDCT[dct] == 0 ) {
+               return 8;
+       } else {
+               return 0;
+       }
+}
+
+static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 where, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 Pass/*, u8 *p*/)
+{
+       /*
+        * Program final DqsRcvEnDly to additional index for DQS receiver
+        *  enabled delay
+        */
+       mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, where, Channel, Receiver, dev, index_reg, Addl_Index, Pass);
+}
+
+static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat)
+{
+       u8 ch_end, ch;
+       u32 reg;
+       u32 dev;
+       u32 val;
+
+       dev = pDCTstat->dev_dct;
+       if (pDCTstat->GangedMode) {
+               ch_end = 1;
+       } else {
+               ch_end = 2;
+       }
+
+       for (ch=0; ch<ch_end; ch++) {
+               reg = 0x78 + 0x100 * ch;
+               val = Get_NB32(dev, reg);
+               val &= ~(1 << DqsRcvEnTrain);
+               Set_NB32(dev, reg, val);
+       }
+}
+
+/* mct_ModifyIndex_D
+ * Function only used once so it was inlined.
+ */
+
+/* mct_GetInitFlag_D
+ * Function only used once so it was inlined.
+ */
+
+void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly,
+                       u8 FinalValue, u8 Channel, u8 Receiver, u32 dev,
+                       u32 index_reg, u8 Addl_Index, u8 Pass)
+{
+       u32 index;
+       u8 i;
+       u8 *p;
+       u32 val;
+
+       if(RcvrEnDly == 0xFE) {
+               /*set the boudary flag */
+               pDCTstat->Status |= 1 << SB_DQSRcvLimit;
+       }
+
+       /* DimmOffset not needed for CH_D_B_RCVRDLY array */
+       for(i=0; i < 8; i++) {
+               if(FinalValue) {
+                       /*calculate dimm offset */
+                       p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1];
+                       RcvrEnDly = p[i];
+               }
+
+               /* if flag=0, set DqsRcvEn value to reg. */
+               /* get the register index from table */
+               index = Table_DQSRcvEn_Offset[i >> 1];
+               index += Addl_Index;    /* DIMMx DqsRcvEn byte0 */
+               val = Get_NB32_index_wait(dev, index_reg, index);
+               if(i & 1) {
+                       /* odd byte lane */
+                       val &= ~(0xFF << 16);
+                       val |= (RcvrEnDly << 16);
+               } else {
+                       /* even byte lane */
+                       val &= ~0xFF;
+                       val |= RcvrEnDly;
+               }
+               Set_NB32_index_wait(dev, index_reg, index, val);
+       }
+
+}
+
+static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQSRcvEnDly)
+{
+       u32 dev;
+       u32 reg;
+       u16 SubTotal;
+       u32 index_reg;
+       u32 reg_off;
+       u32 val;
+       u32 valx;
+
+       if(pDCTstat->GangedMode)
+               Channel = 0;
+
+       dev = pDCTstat->dev_dct;
+       reg_off = 0x100 * Channel;
+       index_reg = 0x98 + reg_off;
+
+       /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
+       val = Get_NB32(dev, 0x88 + reg_off);
+       SubTotal = ((val & 0x0f) + 4) << 1;     /* SubTotal is 1/2 Memclk unit */
+
+       /* If registered DIMMs are being used then
+        *  add 1 MEMCLK to the sub-total.
+        */
+       val = Get_NB32(dev, 0x90 + reg_off);
+       if(!(val & (1 << UnBuffDimm)))
+               SubTotal += 2;
+
+       /* If the address prelaunch is setup for 1/2 MEMCLKs then
+        *  add 1, else add 2 to the sub-total.
+        *  if (AddrCmdSetup || CsOdtSetup || CkeSetup) then K := K + 2;
+        */
+       val = Get_NB32_index_wait(dev, index_reg, 0x04);
+       if(!(val & 0x00202020))
+               SubTotal += 1;
+       else
+               SubTotal += 2;
+
+       /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
+        * then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
+       val = Get_NB32(dev, 0x78 + reg_off);
+       SubTotal += 8 - (val & 0x0f);
+
+       /* Convert bits 7-5 (also referred to as the course delay) of
+        * the current (or worst case) DQS receiver enable delay to
+        * 1/2 MEMCLKs units, rounding up, and add this to the sub-total.
+        */
+       SubTotal += DQSRcvEnDly >> 5;   /*BOZO-no rounding up */
+
+       /* Add 5.5 to the sub-total. 5.5 represents part of the
+        * processor specific constant delay value in the DRAM
+        * clock domain.
+        */
+       SubTotal <<= 1;         /*scale 1/2 MemClk to 1/4 MemClk */
+       SubTotal += 11;         /*add 5.5 1/2MemClk */
+
+       /* Convert the sub-total (in 1/2 MEMCLKs) to northbridge
+        * clocks (NCLKs) as follows (assuming DDR400 and assuming
+        * that no P-state or link speed changes have occurred).
+        */
+
+       /* New formula:
+        * SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
+       val = Get_NB32(dev, 0x94 + reg_off);
+
+       /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
+       val &= 7;
+       if (val >= 3) {
+               val <<= 1;
+       } else
+               val += 3;
+       valx = val << 2;
+
+       val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4);
+       SubTotal *= ((val & 0x1f) + 4 ) * 3;
+
+       SubTotal /= valx;
+       if (SubTotal % valx) {  /* round up */
+               SubTotal++;
+       }
+
+       /* Add 5 NCLKs to the sub-total. 5 represents part of the
+        * processor specific constant value in the northbridge
+        * clock domain.
+        */
+       SubTotal += 5;
+
+       pDCTstat->CH_MaxRdLat[Channel] = SubTotal;
+       if(pDCTstat->GangedMode) {
+               pDCTstat->CH_MaxRdLat[1] = SubTotal;
+       }
+
+       /* Program the F2x[1, 0]78[MaxRdLatency] register with
+        * the total delay value (in NCLKs).
+        */
+       reg = 0x78 + reg_off;
+       val = Get_NB32(dev, reg);
+       val &= ~(0x3ff << 22);
+       val |= (SubTotal & 0x3ff) << 22;
+
+       /* program MaxRdLatency to correspond with current delay */
+       Set_NB32(dev, reg, val);
+}
+
+static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat,
+                       u8 rcvrEnDly, u8 Channel,
+                       u8 receiver, u8 Pass)
+{
+       u8 i;
+       u8 mask_Saved, mask_Pass;
+       u8 *p;
+
+       /* calculate dimm offset
+        * not needed for CH_D_B_RCVRDLY array
+        */
+
+       /* cmp if there has new DqsRcvEnDly to be recorded */
+       mask_Pass = pDCTstat->DqsRcvEn_Pass;
+
+       if(Pass == SecondPass) {
+               mask_Pass = ~mask_Pass;
+       }
+
+       mask_Saved = pDCTstat->DqsRcvEn_Saved;
+       if(mask_Pass != mask_Saved) {
+
+               /* find desired stack offset according to channel/dimm/byte */
+               if(Pass == SecondPass) {
+                       /* FIXME: SecondPass is never used for Barcelona p = pDCTstat->CH_D_B_RCVRDLY_1[Channel][receiver>>1]; */
+                       p = 0; /* Keep the compiler happy. */
+               } else {
+                       mask_Saved &= mask_Pass;
+                       p = pDCTstat->CH_D_B_RCVRDLY[Channel][receiver>>1];
+               }
+               for(i=0; i < 8; i++) {
+                       /* cmp per byte lane */
+                       if(mask_Pass & (1 << i)) {
+                               if(!(mask_Saved & (1 << i))) {
+                                       /* save RcvEnDly to stack, according to
+                                       the related Dimm/byte lane */
+                                       p[i] = (u8)rcvrEnDly;
+                                       mask_Saved |= 1 << i;
+                               }
+                       }
+               }
+               pDCTstat->DqsRcvEn_Saved = mask_Saved;
+       }
+       return mct_SaveRcvEnDly_D_1Pass(pDCTstat, Pass);
+}
+
+static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 addr, u8 channel,
+                                       u8 pattern, u8 Pass)
+{
+       /* Compare only the first beat of data.  Since target addrs are cache
+        * line aligned, the Channel parameter is used to determine which
+        * cache QW to compare.
+        */
+
+       u8 *test_buf;
+       u8 i;
+       u8 result;
+       u8 value;
+
+       if(Pass == FirstPass) {
+               if(pattern==1) {
+                       test_buf = (u8 *)TestPattern1_D;
+               } else {
+                       test_buf = (u8 *)TestPattern0_D;
+               }
+       } else {                /* Second Pass */
+               test_buf = (u8 *)TestPattern2_D;
+       }
+
+       SetUpperFSbase(addr);
+       addr <<= 8;
+
+       if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) {
+               addr += 8;      /* second channel */
+               test_buf += 8;
+       }
+
+       print_debug_dqs_pair("\t\t\t\t\t\t  test_buf = ", (u32)test_buf, "  |  addr_lo = ", addr,  4);
+       for (i=0; i<8; i++, addr ++) {
+               value = read32_fs(addr);
+               print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", test_buf[i], "  |  ", value, 4);
+
+               if (value == test_buf[i]) {
+                       pDCTstat->DqsRcvEn_Pass |= (1<<i);
+               } else {
+                       pDCTstat->DqsRcvEn_Pass &= ~(1<<i);
+               }
+       }
+
+       result = DQS_FAIL;
+
+       if (Pass == FirstPass) {
+               /* if first pass, at least one byte lane pass
+                * ,then DQS_PASS=1 and will set to related reg.
+                */
+               if(pDCTstat->DqsRcvEn_Pass != 0) {
+                       result = DQS_PASS;
+               } else {
+                       result = DQS_FAIL;
+               }
+
+       } else {
+               /* if second pass, at least one byte lane fail
+                * ,then DQS_FAIL=1 and will set to related reg.
+                */
+               if(pDCTstat->DqsRcvEn_Pass != 0xFF) {
+                       result = DQS_FAIL;
+               } else {
+                       result = DQS_PASS;
+               }
+       }
+
+       /* if second pass, we can't find the fail until FFh,
+        * then let it fail to save the final delay
+        */
+       if((Pass == SecondPass) && (pDCTstat->Status & (1 << SB_DQSRcvLimit))) {
+               result = DQS_FAIL;
+               pDCTstat->DqsRcvEn_Pass = 0;
+       }
+
+       /* second pass needs to be inverted
+        * FIXME? this could be inverted in the above code to start with...
+        */
+       if(Pass == SecondPass) {
+               if (result == DQS_PASS) {
+                       result = DQS_FAIL;
+               } else if (result == DQS_FAIL) { /* FIXME: doesn't need to be else if */
+                       result = DQS_PASS;
+               }
+       }
+
+
+       return result;
+}
+
+static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       /* Initialize the DQS Positions in preparation for
+        * Reciever Enable Training.
+        * Write Position is 1/2 Memclock Delay
+        * Read Position is 1/2 Memclock Delay
+        */
+       u8 i;
+       for(i=0;i<2; i++){
+               InitDQSPos4RcvrEn_D(pMCTstat, pDCTstat, i);
+       }
+}
+
+static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel)
+{
+       /* Initialize the DQS Positions in preparation for
+        * Reciever Enable Training.
+        * Write Position is no Delay
+        * Read Position is 1/2 Memclock Delay
+        */
+
+       u8 i, j;
+       u32 dword;
+       u8 dn = 4; /* TODO: Rev C could be 4 */
+       u32 dev = pDCTstat->dev_dct;
+       u32 index_reg = 0x98 + 0x100 * Channel;
+
+       /* FIXME: add Cx support */
+       dword = 0x00000000;
+       for(i=1; i<=3; i++) {
+               for(j=0; j<dn; j++)
+                       /* DIMM0 Write Data Timing Low */
+                       /* DIMM0 Write ECC Timing */
+                       Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, dword);
+       }
+
+       /* errata #180 */
+       dword = 0x2f2f2f2f;
+       for(i=5; i<=6; i++) {
+               for(j=0; j<dn; j++)
+                       /* DIMM0 Read DQS Timing Control Low */
+                       Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, dword);
+       }
+
+       dword = 0x0000002f;
+       for(j=0; j<dn; j++)
+               /* DIMM0 Read DQS ECC Timing Control */
+               Set_NB32_index_wait(dev, index_reg, 7 + 0x100 * j, dword);
+}
+
+void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel)
+{
+       u32 dev;
+       u32 index_reg;
+       u32 index;
+       u8 ChipSel;
+       u8 *p;
+       u32 val;
+
+       dev = pDCTstat->dev_dct;
+       index_reg = 0x98 + Channel * 0x100;
+       index = 0x12;
+       p = pDCTstat->CH_D_BC_RCVRDLY[Channel];
+       print_debug_dqs("\t\tSetEccDQSRcvrPos: Channel ", Channel,  2);
+       for(ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
+               val = p[ChipSel>>1];
+               Set_NB32_index_wait(dev, index_reg, index, val);
+               print_debug_dqs_pair("\t\tSetEccDQSRcvrPos: ChipSel ",
+                                       ChipSel, " rcvr_delay ",  val, 2);
+               index += 3;
+       }
+}
+
+static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel)
+{
+       u8 ChipSel;
+       u16 EccDQSLike;
+       u8 EccDQSScale;
+       u32 val, val0, val1;
+
+       EccDQSLike = pDCTstat->CH_EccDQSLike[Channel];
+       EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
+
+       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
+               if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, ChipSel)) {
+                       u8 *p;
+                       p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
+
+                       /* DQS Delay Value of Data Bytelane
+                        * most like ECC byte lane */
+                       val0 = p[EccDQSLike & 0x07];
+                       /* DQS Delay Value of Data Bytelane
+                        * 2nd most like ECC byte lane */
+                       val1 = p[(EccDQSLike>>8) & 0x07];
+
+                       if (!(pDCTstat->Status & (1 << SB_Registered))) {
+                               if(val0 > val1) {
+                                       val = val0 - val1;
+                               } else {
+                                       val = val1 - val0;
+                               }
+
+                               val *= ~EccDQSScale;
+                               val >>= 8; /* /256 */
+
+                               if(val0 > val1) {
+                                       val -= val1;
+                               } else {
+                                       val += val0;
+                               }
+                       } else {
+                               val = val1 - val0;
+                               val += val1;
+                       }
+
+               pDCTstat->CH_D_BC_RCVRDLY[Channel][ChipSel>>1] = val;
+               }
+       }
+       SetEccDQSRcvrEn_D(pDCTstat, Channel);
+}
+
+void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+       u8 i;
+
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               if (!pDCTstat->NodePresent)
+                       break;
+               if (pDCTstat->DCTSysLimit) {
+               for(i=0; i<2; i++)
+               CalcEccDQSRcvrEn_D(pMCTstat, pDCTstat, i);
+               }
+       }
+}
+
+void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node = 0;
+       struct DCTStatStruc *pDCTstat;
+
+       /* FIXME: skip for Ax */
+       while (Node < MAX_NODES_SUPPORTED) {
+               pDCTstat = pDCTstatA + Node;
+
+               if(pDCTstat->DCTSysLimit) {
+                       fenceDynTraining_D(pMCTstat, pDCTstat, 0);
+                       fenceDynTraining_D(pMCTstat, pDCTstat, 1);
+               }
+               Node++;
+       }
+}
+
+static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u16 avRecValue;
+       u32 val;
+       u32 dev;
+       u32 index_reg = 0x98 + 0x100 * dct;
+       u32 index;
+
+       /* BIOS first programs a seed value to the phase recovery engine
+        *  (recommended 19) registers.
+        * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
+        * F2x[1,0]9C_x52.) .
+        */
+       dev = pDCTstat->dev_dct;
+       for (index = 0x50; index <= 0x52; index ++) {
+               val = Get_NB32_index_wait(dev, index_reg, index) & ~0xFF;
+               val |= (FenceTrnFinDlySeed & 0x1F);
+               if (index != 0x52) {
+                       val &= ~(0xFF << 8);
+                       val |= (val & 0xFF) << 8;
+                       val &= 0xFFFF;
+                       val |= val << 16;
+               }
+               Set_NB32_index_wait(dev, index_reg, index, val);
+       }
+
+       /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
+       val = Get_NB32_index_wait(dev, index_reg, 0x08);
+       val |= 1 << PhyFenceTrEn;
+       Set_NB32_index_wait(dev, index_reg, 0x08, val);
+
+       /* Wait 200 MEMCLKs. */
+       mct_Wait(50000);                /* wait 200us */
+
+       /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
+       val = Get_NB32_index_wait(dev, index_reg, 0x08);
+       val &= ~(1 << PhyFenceTrEn);
+       Set_NB32_index_wait(dev, index_reg, 0x08, val);
+
+       /* BIOS reads the phase recovery engine registers
+        * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
+       avRecValue = 0;
+       for (index = 0x50; index <= 0x52; index ++) {
+               val = Get_NB32_index_wait(dev, index_reg, index);
+               avRecValue += val & 0x7F;
+               if (index != 0x52) {
+                       avRecValue += (val >> 8) & 0x7F;
+                       avRecValue += (val >> 16) & 0x7F;
+                       avRecValue += (val >> 24) & 0x7F;
+               }
+       }
+
+       val = avRecValue / 9;
+       if (avRecValue % 9)
+               val++;
+       avRecValue = val;
+
+       /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
+       /* inlined mct_AdjustFenceValue() */
+       /* The RBC0 is not supported. */
+       /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
+               avRecValue -= 3;
+       else
+       */
+       if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
+               avRecValue -= 8;
+       else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
+               avRecValue -= 8;
+
+       val = Get_NB32_index_wait(dev, index_reg, 0x0C);
+       val &= ~(0x1F << 16);
+       val |= (avRecValue & 0x1F) << 16;
+       Set_NB32_index_wait(dev, index_reg, 0x0C, val);
+
+       /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control Register
+        * delays (both channels). */
+       val = Get_NB32_index_wait(dev, index_reg, 0x04);
+       Set_NB32_index_wait(dev, index_reg, 0x04, val);
+}
+
+void mct_Wait(u32 cycles)
+{
+       u32 saved;
+       u32 hi, lo, msr;
+
+       /* Wait # of 50ns cycles
+          This seems like a hack to me...  */
+
+       cycles <<= 3;           /* x8 (number of 1.25ns ticks) */
+
+       msr = 0x10;                     /* TSC */
+       _RDMSR(msr, &lo, &hi);
+       saved = lo;
+       do {
+               _RDMSR(msr, &lo, &hi);
+       } while (lo - saved < cycles );
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
new file mode 100644 (file)
index 0000000..008705c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass)
+{
+       u8 ret = 1;
+       if (pass == SecondPass)
+               ret = 0;
+
+       return ret;
+}
+
+u32 SetupDqsPattern_1PassA(u8 pass)
+{
+       return (u32) TestPattern1_D;
+}
+
+u32 SetupDqsPattern_1PassB(u8 pass)
+{
+       return (u32) TestPattern0_D;
+}
+
+u8  mct_Get_Start_RcvrEnDly_1Pass(u8 pass)
+{
+       return 0;
+}
+
+static u8 mct_Average_RcvrEnDly_1Pass(struct DCTStatStruc *pDCTstat, u8 Channel, u8 Receiver,
+                                       u8 Pass)
+{
+       u8 i, MaxValue;
+       u8 *p;
+       u8 val;
+
+       MaxValue = 0;
+       p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1];
+
+       for(i=0; i < 8; i++) {
+               /* get left value from DCTStatStruc.CHA_D0_B0_RCVRDLY*/
+               val = p[i];
+               /* get right value from DCTStatStruc.CHA_D0_B0_RCVRDLY_1*/
+               val += Pass1MemClkDly;
+               /* write back the value to stack */
+               if (val > MaxValue)
+                       MaxValue = val;
+
+               p[i] = val;
+       }
+       /* pDCTstat->DimmTrainFail &= ~(1<<Receiver+Channel); */
+
+       return MaxValue;
+}
+
+u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass)
+{
+       u8 ret;
+       ret = 0;
+       if((pDCTstat->DqsRcvEn_Pass == 0xff) && (pass== FirstPass))
+               ret = 2;
+       return ret;
+}
+
+u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
+                               u8 RcvrEnDly, u8 RcvrEnDlyLimit,
+                               u8 Channel, u8 Receiver, u8 Pass)
+
+{
+       return mct_Average_RcvrEnDly_1Pass(pDCTstat, Channel, Receiver, Pass);
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
new file mode 100644 (file)
index 0000000..7fe6867
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+u8 mct_checkNumberOfDqsRcvEn_Pass(u8 pass)
+{
+       return 1;
+}
+
+u32 SetupDqsPattern_PassA(u8 Pass)
+{
+       u32 ret;
+       if(Pass == FirstPass)
+               ret = (u32) TestPattern1_D;
+       else
+               ret = (u32) TestPattern2_D;
+
+       return ret;
+}
+
+u32 SetupDqsPattern_PassB(u8 Pass)
+{
+       u32 ret;
+       if(Pass == FirstPass)
+               ret = (u32) TestPattern0_D;
+       else
+               ret = (u32) TestPattern2_D;
+
+       return ret;
+}
+
+u8 mct_Get_Start_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
+                                       u8 Channel, u8 Receiver,
+                                       u8 Pass)
+{
+       u8 RcvrEnDly;
+
+       if (Pass == FirstPass)
+               RcvrEnDly = 0;
+       else {
+               u8 max = 0;
+               u8 val;
+               u8 i;
+               u8 *p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
+               u8 bn;
+               bn = 8;
+
+               for ( i=0;i<bn; i++) {
+                       val  = p[i];
+
+                       if(val > max) {
+                               max = val;
+                       }
+               }
+               RcvrEnDly = max;
+       }
+
+       return RcvrEnDly;
+}
+
+u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
+                               u8 RcvrEnDly, u8 RcvrEnDlyLimit,
+                               u8 Channel, u8 Receiver, u8 Pass)
+{
+       u8 i;
+       u8 *p;
+       u8 *p_1;
+       u8 val;
+       u8 val_1;
+       u8 valid = 1;
+       u8 bn;
+
+       bn = 8;
+
+       p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
+
+       if (Pass == SecondPass) { /* second pass must average values */
+               /* FIXME: which byte? */
+               p_1 = pDCTstat->B_RCVRDLY_1;
+               /* p_1 = pDCTstat->CH_D_B_RCVRDLY_1[Channel][Receiver>>1]; */
+               for(i=0; i<bn; i++) {
+                       val = p[i];
+                       /* left edge */
+                       if (val != (RcvrEnDlyLimit - 1)) {
+                               val -= Pass1MemClkDly;
+                               val_1 = p_1[i];
+                               val += val_1;
+                               val >>= 1;
+                               p[i] = val;
+                       } else {
+                               valid = 0;
+                               break;
+                       }
+               }
+               if (!valid) {
+                       pDCTstat->ErrStatus |= 1<<SB_NORCVREN;
+               } else {
+                       pDCTstat->DimmTrainFail &= ~(1<<(Receiver + Channel));
+               }
+       } else {
+               for(i=0; i < bn; i++) {
+                       val = p[i];
+                       /* Add 1/2 Memlock delay */
+                       /* val += Pass1MemClkDly; */
+                       val += 0x5; /* NOTE: middle value with DQSRCVEN_SAVED_GOOD_TIMES */
+                       /* val += 0x02; */
+                       p[i] = val;
+                       pDCTstat->DimmTrainFail &= ~(1<<(Receiver + Channel));
+               }
+       }
+
+       return RcvrEnDly;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
new file mode 100644 (file)
index 0000000..355e926
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Description: Max Read Latency Training feature for DDR 3 MCT
+ */
+
+static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr);
+static u32 GetMaxRdLatTestAddr_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel,
+                               u8 *MaxRcvrEnDly, u8 *valid);
+u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel,
+                               u8 DQSRcvEnDly, u32 *Margin);
+static void maxRdLatencyTrain_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat, u8 Channel,
+                                       u16 MaxRdLatVal);
+
+/*Warning:  These must be located so they do not cross a logical 16-bit
+   segment boundary!*/
+static const u32 TestMaxRdLAtPattern_D[] = {
+       0x6E0E3FAC, 0x0C3CFF52,
+       0x4A688181, 0x49C5B613,
+       0x7C780BA6, 0x5C1650E3,
+       0x0C4F9D76, 0x0C6753E6,
+       0x205535A5, 0xBABFB6CA,
+       0x610E6E5F, 0x0C5F1C87,
+       0x488493CE, 0x14C9C383,
+       0xF5B9A5CD, 0x9CE8F615,
+
+       0xAAD714B5, 0xC38F1B4C,
+       0x72ED647C, 0x669F7562,
+       0x5233F802, 0x4A898B30,
+       0x10A40617, 0x3326B465,
+       0x55386E04, 0xC807E3D3,
+       0xAB49E193, 0x14B4E63A,
+       0x67DF2495, 0xEA517C45,
+       0x7624CE51, 0xF8140C51,
+
+       0x4824BD23, 0xB61DD0C9,
+       0x072BCFBE, 0xE8F3807D,
+       0x919EA373, 0x25E30C47,
+       0xFEB12958, 0x4DA80A5A,
+       0xE9A0DDF8, 0x792B0076,
+       0xE81C73DC, 0xF025B496,
+       0x1DB7E627, 0x808594FE,
+       0x82668268, 0x655C7783,
+};
+
+static u32 SetupMaxRdPattern(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 *buffer)
+{
+       /* 1. Copy the alpha and Beta patterns from ROM to Cache,
+        *    aligning on 16 byte boundary
+        * 2. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufA
+        *    for Alpha
+        * 3. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufB
+        *    for Beta
+        */
+       u32 *buf;
+       u8 i;
+
+       buf = (u32 *)(((u32)buffer + 0x10) & (0xfffffff0));
+
+       for(i = 0; i < (16 * 3); i++) {
+               buf[i] = TestMaxRdLAtPattern_D[i];
+       }
+
+       return (u32)buf;
+}
+
+void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+{
+       u8 Node;
+
+       for(Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+
+               if(!pDCTstat->NodePresent)
+                       break;
+
+               if(pDCTstat->DCTSysLimit)
+                       maxRdLatencyTrain_D(pMCTstat, pDCTstat);
+       }
+}
+
+static void maxRdLatencyTrain_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u8 Channel;
+       u32 TestAddr0;
+       u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
+       u16 MaxRdLatDly;
+       u8 RcvrEnDly = 0;
+       u32 PatternBuffer[60];  /* FIXME: why not 48 + 4 */
+       u32 Margin;
+       u32 addr;
+       u32 cr4;
+       u32 lo, hi;
+
+       u8 valid;
+       u32 pattern_buf;
+
+       cr4 = read_cr4();
+       if(cr4 & (1<<9)) {              /* save the old value */
+               _SSE2 = 1;
+       }
+       cr4 |= (1<<9);                  /* OSFXSR enable SSE2 */
+       write_cr4(cr4);
+
+       addr = HWCR;
+       _RDMSR(addr, &lo, &hi);
+       if(lo & (1<<17)) {              /* save the old value */
+               _Wrap32Dis = 1;
+       }
+       lo |= (1<<17);                  /* HWCR.wrap32dis */
+       lo &= ~(1<<15);                 /* SSEDIS */
+       /* Setting wrap32dis allows 64-bit memory references in
+          real mode */
+       _WRMSR(addr, lo, hi);
+
+       _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
+
+       pattern_buf = SetupMaxRdPattern(pMCTstat, pDCTstat, PatternBuffer);
+
+       for (Channel = 0; Channel < 2; Channel++) {
+               print_debug_dqs("\tMaxRdLatencyTrain51: Channel ",Channel, 1);
+               pDCTstat->Channel = Channel;
+
+               if( (pDCTstat->Status & (1 << SB_128bitmode)) && Channel)
+                       break;          /*if ganged mode, skip DCT 1 */
+
+               TestAddr0 = GetMaxRdLatTestAddr_D(pMCTstat, pDCTstat, Channel, &RcvrEnDly,       &valid);
+               if(!valid)      /* Address not supported on current CS */
+                       continue;
+               /* rank 1 of DIMM, testpattern 0 */
+               WriteMaxRdLat1CLTestPattern_D(pattern_buf, TestAddr0);
+
+               MaxRdLatDly = mct_GetStartMaxRdLat_D(pMCTstat, pDCTstat, Channel, RcvrEnDly, &Margin);
+               print_debug_dqs("\tMaxRdLatencyTrain52:  MaxRdLatDly start ", MaxRdLatDly, 2);
+               print_debug_dqs("\tMaxRdLatencyTrain52:  MaxRdLatDly Margin ", Margin, 2);
+               while(MaxRdLatDly < MAX_RD_LAT) {       /* sweep Delay value here */
+                       mct_setMaxRdLatTrnVal_D(pDCTstat, Channel, MaxRdLatDly);
+                       ReadMaxRdLat1CLTestPattern_D(TestAddr0);
+                       if( CompareMaxRdLatTestPattern_D(pattern_buf, TestAddr0) == DQS_PASS)
+                               break;
+                       SetTargetWTIO_D(TestAddr0);
+                       FlushMaxRdLatTestPattern_D(TestAddr0);
+                       ResetTargetWTIO_D();
+                       MaxRdLatDly++;
+               }
+               print_debug_dqs("\tMaxRdLatencyTrain53:  MaxRdLatDly end ", MaxRdLatDly, 2);
+               mct_setMaxRdLatTrnVal_D(pDCTstat, Channel, MaxRdLatDly + Margin);
+       }
+
+       if(_DisableDramECC) {
+               mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
+       }
+
+       if(!_Wrap32Dis) {
+               addr = HWCR;
+               _RDMSR(addr, &lo, &hi);
+               lo &= ~(1<<17); /* restore HWCR.wrap32dis */
+               _WRMSR(addr, lo, hi);
+       }
+       if(!_SSE2){
+               cr4 = read_cr4();
+               cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
+               write_cr4(cr4);
+       }
+
+#if DQS_TRAIN_DEBUG > 0
+       {
+               u8 Channel;
+               print_debug("maxRdLatencyTrain: CH_MaxRdLat:\n");
+               for(Channel = 0; Channel<2; Channel++) {
+                       print_debug("Channel:"); print_debug_hex8(Channel);
+                       print_debug(": ");
+                       print_debug_hex8( pDCTstat->CH_MaxRdLat[Channel] );
+                       print_debug("\n");
+               }
+       }
+#endif
+}
+
+static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat,
+                                       u8 Channel, u16 MaxRdLatVal)
+{
+       u8 i;
+       u32 reg;
+       u32 dev;
+       u32 val;
+
+       if (pDCTstat->GangedMode) {
+               Channel = 0; /* for safe */
+       for (i=0; i<2; i++)
+               pDCTstat->CH_MaxRdLat[i] = MaxRdLatVal;
+       } else {
+               pDCTstat->CH_MaxRdLat[Channel] = MaxRdLatVal;
+       }
+
+       dev = pDCTstat->dev_dct;
+       reg = 0x78 + Channel * 0x100;
+       val = Get_NB32(dev, reg);
+       val &= ~(0x3ff<<22);
+       val |= MaxRdLatVal<<22;
+       /* program MaxRdLatency to correspond with current delay */
+       Set_NB32(dev, reg, val);
+}
+
+static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr)
+{
+       /* Compare only the first beat of data.  Since target addrs are cache
+        * line aligned, the Channel parameter is used to determine which cache
+        * QW to compare.
+        */
+
+       u32 *test_buf = (u32 *)pattern_buf;
+       u32 addr_lo;
+       u32 val, val_test;
+       int i;
+       u8 ret = DQS_PASS;
+
+       SetUpperFSbase(addr);
+       addr_lo = addr<<8;
+
+       _EXECFENCE;
+       for (i=0; i<(16*3); i++) {
+               val = read32_fs(addr_lo);
+               val_test = test_buf[i];
+
+               print_debug_dqs_pair("\t\t\t\t\t\ttest_buf = ", (u32)test_buf, " value = ", val_test, 5);
+               print_debug_dqs_pair("\t\t\t\t\t\ttaddr_lo = ", addr_lo, " value = ", val, 5);
+               if(val != val_test) {
+                       ret = DQS_FAIL;
+                       break;
+               }
+               addr_lo += 4;
+       }
+
+       return ret;
+}
+
+static u32 GetMaxRdLatTestAddr_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u8 Channel, u8 *MaxRcvrEnDly,
+                                       u8 *valid)
+{
+       u8 Max = 0;
+
+       u8 Channel_Max = 0;
+       u8 d;
+       u8 d_Max = 0;
+
+       u8 Byte;
+       u32 TestAddr0 = 0;
+       u8 ch, ch_start, ch_end;
+       u8 bn;
+
+       bn = 8;
+
+       if(pDCTstat->Status & (1 << SB_128bitmode)) {
+               ch_start = 0;
+               ch_end = 2;
+       } else {
+               ch_start = Channel;
+               ch_end = Channel + 1;
+       }
+
+       *valid = 0;
+
+       for(ch = ch_start; ch < ch_end; ch++) {
+               for(d=0; d<4; d++) {
+                       for(Byte = 0; Byte<bn; Byte++) {
+                               u8 tmp;
+                               tmp = pDCTstat->CH_D_B_RCVRDLY[ch][d][Byte];
+                               if(tmp>Max) {
+                                       Max = tmp;
+                                       Channel_Max = Channel;
+                                       d_Max = d;
+                               }
+                       }
+               }
+       }
+
+       if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel_Max, d_Max << 1))  {
+               TestAddr0 = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, Channel_Max, d_Max << 1, valid);
+       }
+
+       if(*valid)
+               *MaxRcvrEnDly = Max;
+
+       return TestAddr0;
+}
+
+u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 Channel, u8 DQSRcvEnDly, u32 *Margin)
+{
+       u32 SubTotal;
+       u32 val;
+       u32 valx;
+       u32 valxx;
+       u32 index_reg;
+       u32 reg_off;
+       u32 dev;
+
+       if(pDCTstat->GangedMode)
+               Channel =  0;
+
+       index_reg = 0x98 + 0x100 * Channel;
+
+       reg_off = 0x100 * Channel;
+       dev = pDCTstat->dev_dct;
+
+       /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
+       val = Get_NB32(dev, 0x88 + reg_off);
+       SubTotal = ((val & 0x0f) + 1) << 1;     /* SubTotal is 1/2 Memclk unit */
+
+       /* If registered DIMMs are being used then add 1 MEMCLK to the sub-total*/
+       val = Get_NB32(dev, 0x90 + reg_off);
+       if(!(val & (1 << UnBuffDimm)))
+               SubTotal += 2;
+
+       /*If the address prelaunch is setup for 1/2 MEMCLKs then add 1,
+        *  else add 2 to the sub-total. if (AddrCmdSetup || CsOdtSetup
+        *  || CkeSetup) then K := K + 2; */
+       val = Get_NB32_index_wait(dev, index_reg, 0x04);
+       if(!(val & 0x00202020))
+               SubTotal += 1;
+       else
+               SubTotal += 2;
+
+       /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
+        *  then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
+       val = Get_NB32(dev, 0x78 + reg_off);
+       SubTotal += 8 - (val & 0x0f);
+
+       /* Convert bits 7-5 (also referred to as the course delay) of the current
+        * (or worst case) DQS receiver enable delay to 1/2 MEMCLKs units,
+        * rounding up, and add this to the sub-total. */
+       SubTotal += DQSRcvEnDly >> 5;   /*BOZO-no rounding up */
+
+       SubTotal <<= 1;                 /*scale 1/2 MemClk to 1/4 MemClk */
+
+       /* Convert the sub-total (in 1/2 MEMCLKs) to northbridge clocks (NCLKs)
+        * as follows (assuming DDR400 and assuming that no P-state or link speed
+        * changes have occurred). */
+
+       /*New formula:
+       SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
+       val = Get_NB32(dev, 0x94 + reg_off);
+       /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
+       val &= 7;
+       if (val >= 3) {
+               val <<= 1;
+       } else
+               val += 3;
+       valx = (val) << 2;      /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
+
+       val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4);
+       val = ((val & 0x1f) + 4 ) * 3;
+
+       /* Calculate 1 MemClk + 1 NCLK delay in NCLKs for margin */
+       valxx = val << 2;
+       valxx /= valx;
+       if (valxx % valx)
+               valxx++;        /* round up */
+       valxx++;                /* add 1NCLK */
+       *Margin = valxx;        /* one MemClk delay in NCLKs and one additional NCLK */
+
+       val *= SubTotal;
+
+       val /= valx;
+       if (val % valx)
+               val++;          /* round up */
+
+       return val;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
new file mode 100644 (file)
index 0000000..d14bc0d
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat);
+
+
+static void AgesaDelay(u32 msec)
+{
+       mct_Wait(msec*10);
+}
+
+void PrepareC_MCT(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       pDCTstat->C_MCTPtr->AgesaDelay = AgesaDelay;
+       pDCTstat->C_MCTPtr->PlatMaxTotalDimms = mctGet_NVbits(NV_MAX_DIMMS);
+       pDCTstat->C_MCTPtr->PlatMaxDimmsDct = pDCTstat->C_MCTPtr->PlatMaxTotalDimms >> 1;
+}
+
+void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u8 dimm;
+       u16 DimmValid;
+       u16 Dimmx8Present;
+
+       dct &= 1;
+
+       pDCTstat->C_DCTPtr[dct]->DctTrain = dct;
+
+       if (dct == 1) {
+               Dimmx8Present = pDCTstat->Dimmx8Present >> 1;
+       } else
+               Dimmx8Present = pDCTstat->Dimmx8Present;
+       Dimmx8Present &= 0x55;
+
+       pDCTstat->C_DCTPtr[dct]->MaxDimmsInstalled = pDCTstat->MAdimms[dct];
+       DimmValid = pDCTstat->DIMMValidDCT[dct];
+
+       pDCTstat->C_DCTPtr[dct]->NodeId = pDCTstat->Node_ID;
+       pDCTstat->C_DCTPtr[dct]->LogicalCPUID = pDCTstat->LogicalCPUID;
+
+       for (dimm = 0; dimm < MAX_DIMMS; dimm++) {
+               if (DimmValid & (1 << dimm))
+                       pDCTstat->C_DCTPtr[dct]->DimmPresent[dimm] = 1;
+               if (Dimmx8Present & (1 << dimm))
+                       pDCTstat->C_DCTPtr[dct]->DimmX8Present[dimm] = 1;
+       }
+
+       if (pDCTstat->GangedMode & (1 << 0))
+               pDCTstat->C_DCTPtr[dct]->CurrDct = 0;
+       else
+               pDCTstat->C_DCTPtr[dct]->CurrDct = dct;
+
+       pDCTstat->C_DCTPtr[dct]->DctCSPresent = pDCTstat->CSPresent_DCT[dct];
+       if (!(pDCTstat->GangedMode & (1 << 0)) && (dct == 1))
+               pDCTstat->C_DCTPtr[dct]->DctCSPresent = pDCTstat->CSPresent_DCT[0];
+
+       if (pDCTstat->Status & (1 << SB_Registered)) {
+               pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 1;
+               pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_OnDimmMirror] = 0;
+       } else {
+               if (pDCTstat->MirrPresU_NumRegR > 0)
+                       pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_OnDimmMirror] = 1;
+               pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 0;
+       }
+
+       pDCTstat->C_DCTPtr[dct]->RegMan1Present = pDCTstat->RegMan1Present;
+
+       for (dimm = 0; dimm < MAX_TOTAL_DIMMS; dimm++) {
+               u8  DimmRanks;
+               if (DimmValid & (1 << dimm)) {
+                       DimmRanks = 1;
+                       if (pDCTstat->DimmDRPresent & (1 << (dimm+dct)))
+                               DimmRanks = 2;
+                       else if (pDCTstat->DimmQRPresent & (1 << (dimm+dct)))
+                               DimmRanks = 4;
+               } else
+                       DimmRanks = 0;
+               pDCTstat->C_DCTPtr[dct]->DimmRanks[dimm] = DimmRanks;
+       }
+}
+
+void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x94);
+       val |= 1 << 11;
+       Set_NB32(pDCTstat->dev_dct, 0x94, val);
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+       val |= 1 << 11;
+       Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+}
+
+void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u32 val;
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x94);
+       val &= ~(1 << 11);
+       val &= ~(1 << 10);
+       Set_NB32(pDCTstat->dev_dct, 0x94, val);
+
+       val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+       val &= ~(1 << 11);
+       val &= ~(1 << 10);
+       Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+}
+
+static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u8 DCT0Present, DCT1Present;
+       u32 val;
+
+       DCT0Present = pDCTstat->DIMMValidDCT[0];
+       if (pDCTstat->GangedMode)
+               DCT1Present = 0;
+       else
+               DCT1Present = pDCTstat->DIMMValidDCT[1];
+
+       /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
+       if (DCT0Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x90);
+               val |= 1 << EnterSelfRef;
+               Set_NB32(pDCTstat->dev_dct, 0x90, val);
+       }
+       if (DCT1Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+               val |= 1 << EnterSelfRef;
+               Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
+       }
+       /* Wait until the hardware resets F2x[1, 0]90[EnterSelfRefresh]=0. */
+       if (DCT0Present)
+               do {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x90);
+               } while (val & (1 <<EnterSelfRef));
+       if (DCT1Present)
+               do {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+               } while (val & (1 <<EnterSelfRef));
+}
+
+/*
+ * Change memclk for write levelization pass 2
+ */
+static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u8 DCT0Present, DCT1Present;
+       u32 val;
+
+       DCT0Present = pDCTstat->DIMMValidDCT[0];
+       if (pDCTstat->GangedMode)
+               DCT1Present = 0;
+       else
+               DCT1Present = pDCTstat->DIMMValidDCT[1];
+
+       /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
+       if (DCT0Present) {
+               val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
+               val |= 1 << DisAutoComp;
+               Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
+       }
+       if (DCT1Present) {
+               val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
+               val |= 1 << DisAutoComp;
+               Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
+       }
+
+       /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
+       if (DCT0Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94);
+               val &= ~(1 << MemClkFreqVal);
+               Set_NB32(pDCTstat->dev_dct, 0x94, val);
+       }
+       if (DCT1Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+               val &= ~(1 << MemClkFreqVal);
+               Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+       }
+
+       /* Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency. */
+       if (DCT0Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94);
+               val &= 0xFFFFFFF8;
+               val |= pDCTstat->TargetFreq - 1;
+               Set_NB32(pDCTstat->dev_dct, 0x94, val);
+       }
+       if (DCT1Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+               val &= 0xFFFFFFF8;
+               val |= pDCTstat->TargetFreq - 1;
+               Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+       }
+
+       /* Program F2x[1, 0]94[MemClkFreqVal] = 1. */
+       if (DCT0Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94);
+               val |= 1 << MemClkFreqVal;
+               Set_NB32(pDCTstat->dev_dct, 0x94, val);
+       }
+       if (DCT1Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+               val |= 1 << MemClkFreqVal;
+               Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+       }
+
+       /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
+       if (DCT0Present)
+               do {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x94);
+               } while (val & (1 << FreqChgInProg));
+       if (DCT1Present)
+               do {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+               } while (val & (1 << FreqChgInProg));
+
+       /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
+       if (DCT0Present) {
+               val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
+               val &= ~(1 << DisAutoComp);
+               Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
+       }
+       if (DCT1Present) {
+               val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
+               val &= ~(1 << DisAutoComp);
+               Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
+       }
+}
+
+/* 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.
+ */
+void MultiplyDelay(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u16 index;
+       u8 Multiplier;
+       u8 gross, fine;
+       u16 total;
+
+       Multiplier = pDCTstat->TargetFreq;
+
+       for (index=0; index < MAX_BYTE_LANES*MAX_LDIMMS; index ++) {
+               gross = pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index];
+               fine = pDCTstat->C_DCTPtr[dct]->WLFineDelay[index];
+
+               total = gross << 5 | fine;
+               total *= Multiplier;
+               if (total % 3)
+                       total = total / 3 + 1;
+               else
+                       total = total / 3;
+               pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index] = (total & 0xFF) >> 5;
+               pDCTstat->C_DCTPtr[dct]->WLFineDelay[index] = total & 0x1F;
+       }
+}
+
+/*
+ * the DRAM controller to bring the DRAMs out of self refresh mode.
+ */
+static void ExitSelfRefresh(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       u8 DCT0Present, DCT1Present;
+       u32 val;
+
+       DCT0Present = pDCTstat->DIMMValidDCT[0];
+       if (pDCTstat->GangedMode)
+               DCT1Present = 0;
+       else
+               DCT1Present = pDCTstat->DIMMValidDCT[1];
+
+       /* Program F2x[1, 0]90[ExitSelfRef]=1 for both DCTs. */
+       if (DCT0Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x90);
+               val |= 1 << ExitSelfRef;
+               Set_NB32(pDCTstat->dev_dct, 0x90, val);
+       }
+       if (DCT1Present) {
+               val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+               val |= 1 << ExitSelfRef;
+               Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
+       }
+       /* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0. */
+       if (DCT0Present)
+               do {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x90);
+               } while (val & (1 << ExitSelfRef));
+       if (DCT1Present)
+               do {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
+               } while (val & (1 << ExitSelfRef));
+}
+
+void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+{
+       /* Program F2x[1,0]90[EnterSelfRefresh]=1.
+        * Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
+        */
+       EnterSelfRefresh(pMCTstat, pDCTstat);
+
+       /*
+        * Program F2x[1,0]9C_x08[DisAutoComp]=1
+        * Program F2x[1,0]94[MemClkFreqVal] = 0.
+        * Program F2x[1,0]94[MemClkFreq] to specify the target MEMCLK frequency.
+        * Program F2x[1,0]94[MemClkFreqVal] = 1.
+        * Wait until F2x[1,0]94[FreqChgInProg]=0.
+        * Program F2x[1,0]9C_x08[DisAutoComp]=0
+        */
+       ChangeMemClk(pMCTstat, pDCTstat);
+
+       /* Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
+        * Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
+        */
+       ExitSelfRefresh(pMCTstat, pDCTstat);
+
+       /* wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns */
+       mct_Wait(250);
+
+       if (pDCTstat->Status & (1 << SB_Registered)) {
+               /* TODO: Assuming the dct==0. The agesa here is confusing. */
+               FreqChgCtrlWrd(pMCTstat, pDCTstat);
+       }
+}
+
+static void Modify_OnDimmMirror(struct DCTStatStruc *pDCTstat, u8 dct, u8 set)
+{
+       u32 val;
+       u32 reg_off = dct * 0x100 + 0x44;
+       while (reg_off < 0x60) {
+               val = Get_NB32(pDCTstat->dev_dct, reg_off);
+               if (val & (1 << CSEnable))
+                       set ? (val |= 1 << onDimmMirror) : (val &= ~(1<<onDimmMirror));
+               Set_NB32(pDCTstat->dev_dct, reg_off, val);
+               reg_off += 8;
+       }
+}
+
+void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       if (pDCTstat->LogicalCPUID & (AMD_DR_Bx /* | AMD_RB_C0 */)) { /* We dont support RB-C0 now */
+               if (pDCTstat->MirrPresU_NumRegR & 0x55)
+                       Modify_OnDimmMirror(pDCTstat, 0, 1); /* dct=0, set */
+               if (pDCTstat->MirrPresU_NumRegR & 0xAA)
+                       Modify_OnDimmMirror(pDCTstat, 1, 1); /* dct=1, set */
+       }
+}
+void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+{
+       if (pDCTstat->LogicalCPUID & (AMD_DR_Bx /* | AMD_RB_C0 */)) { /* We dont support RB-C0 now */
+               if (pDCTstat->MirrPresU_NumRegR & 0x55)
+                       Modify_OnDimmMirror(pDCTstat, 0, 0); /* dct=0, clear */
+               if (pDCTstat->MirrPresU_NumRegR & 0xAA)
+                       Modify_OnDimmMirror(pDCTstat, 1, 0); /* dct=1, clear */
+       }
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
new file mode 100644 (file)
index 0000000..fdc35e3
--- /dev/null
@@ -0,0 +1,916 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *                     MODULES USED
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *                     PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue);
+u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue);
+void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl);
+void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm);
+void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass);
+void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr);
+void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm);
+/*
+ *-----------------------------------------------------------------------------
+ *             EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * void AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct *DCTData,
+ *                  u8 Dimm, u8 Pass)
+ *
+ *  Description:
+ *       This function initialized Hardware based write levelization phase 1
+ *
+ *   Parameters:
+ *       IN  OUT   *SPDData - Pointer to buffer with information about each DIMMs
+ *                            SPD information
+ *                 *MCTData - Pointer to buffer with runtime parameters,
+ *                 *DCTData - Pointer to buffer with information about each DCT
+ *
+ *       IN        DIMM - Logical DIMM number
+ *                 Pass - First or Second Pass
+ *       OUT
+ *-----------------------------------------------------------------------------
+ */
+void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
+               u8 dimm, u8 pass)
+{
+       u8 ByteLane;
+       u32 Value, Addr;
+       u16 Addl_Data_Offset, Addl_Data_Port;
+
+       pDCTData->WLPass = pass;
+       /* 1. Specify the target DIMM that is to be trained by programming
+        * F2x[1, 0]9C_x08[TrDimmSel].
+        */
+       set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
+                       TrDimmSelEnd,(u32)dimm);
+       /* 2. Prepare the DIMMs for write levelization using DDR3-defined
+        * MR commands. */
+       prepareDimms(pMCTData, pDCTData,dimm, TRUE);
+       /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
+        *    satisfy DDR3-defined internal DRAM timing.
+        */
+       pMCTData->AgesaDelay(40);
+       /* 4. Configure the processor's DDR phy for write levelization training: */
+       procConifg(pMCTData,pDCTData, dimm, pass);
+       /* 5. Begin write levelization training:
+        *  Program F2x[1, 0]9C_x08[WrtLevelTrEn]=1. */
+       if (pDCTData->LogicalCPUID & AMD_DR_Cx)
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 1);
+       else
+       {
+               /* Broadcast write to all D3Dbyte chiplet register offset 0xc
+                * Set bit 0 (wrTrain)
+                * Program bit 4 to nibble being trained (only matters for x4dimms)
+                * retain value of 3:2 (Trdimmsel)
+                * reset bit 5 (FrzPR)
+                */
+               if (pDCTData->DctTrain)
+               {
+                       Addl_Data_Offset=0x198;
+                       Addl_Data_Port=0x19C;
+               }
+               else
+               {
+                       Addl_Data_Offset=0x98;
+                       Addl_Data_Port=0x9C;
+               }
+               Addr=0x0D00000C;
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
+               while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
+                               DctAccessDone, DctAccessDone)) == 0);
+               AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
+               Value = bitTestSet(Value, 0);   /* enable WL training */
+               Value = bitTestReset(Value, 4); /* for x8 only */
+               Value = bitTestReset(Value, 5); /* for harward WL training */
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
+               Addr=0x4D030F0C;
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
+               while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
+                               DctAccessDone, DctAccessDone)) == 0);
+       }
+
+       /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
+       pMCTData->AgesaDelay(140);
+       /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
+       set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 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. */
+       ByteLane = 0;
+       while (ByteLane < MAX_BYTE_LANES)
+       {
+               getWLByteDelay(pDCTData,ByteLane, dimm);
+               setWLByteDelay(pDCTData,ByteLane, dimm, 1);
+               ByteLane++;
+       }
+
+       /* 6. Configure DRAM Phy Control Register so that the phy stops driving
+        *    write levelization ODT. */
+       set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, 0);
+
+       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
+       pMCTData->AgesaDelay(10);
+
+       /* 7. Program the target DIMM back to normal operation by configuring
+        * the following (See section 2.8.5.4.1.1
+        * [Phy Assisted Write Levelization] on page 97 pass 1, step #2):
+        * Configure all ranks of the target DIMM for normal operation.
+        * Enable the output drivers of all ranks of the target DIMM.
+        * For a two DIMM system, program the Rtt value for the target DIMM
+        * to the normal operating termination:
+        */
+       prepareDimms(pMCTData, pDCTData,dimm,FALSE);
+}
+
+/*----------------------------------------------------------------------------
+ *     LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ * u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
+ *
+ * Description:
+ *     This function swaps the bits in MSR register value
+ *
+ * Parameters:
+ *     IN  OUT   *DCTData - Pointer to buffer with information about each DCT
+ *     IN      u32: MRS value
+ *     OUT     u32: sWAPPED BANK BITS
+ *
+ * ----------------------------------------------------------------------------
+ */
+u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
+{
+       u32 tempW, tempW1;
+
+       tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                       FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
+       if (tempW1 & 1)
+       {
+               if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
+               {
+                       /* swap A3/A4,A5/A6,A7/A8 */
+                       tempW = MRSValue;
+                       tempW1 = MRSValue;
+                       tempW &= 0x0A8;
+                       tempW1 &= 0x0150;
+                       MRSValue &= 0xFE07;
+                       MRSValue |= (tempW<<1);
+                       MRSValue |= (tempW1>>1);
+               }
+       }
+       return MRSValue;
+}
+
+/*-----------------------------------------------------------------------------
+ *  u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
+ *
+ *  Description:
+ *       This function swaps the bits in MSR register value
+ *
+ *   Parameters:
+ *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
+ *       IN    u32: MRS value
+ *       OUT       u32: sWAPPED BANK BITS
+ *
+ * ----------------------------------------------------------------------------
+ */
+u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
+{
+       u32 tempW, tempW1;
+
+       tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                       FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
+       if (tempW1 & 1)
+       {
+               if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
+               {
+                       /* swap BA0/BA1 */
+                       tempW = MRSValue;
+                       tempW1 = MRSValue;
+                       tempW &= 0x01;
+                       tempW1 &= 0x02;
+                       MRSValue = 0;
+                       MRSValue |= (tempW<<1);
+                       MRSValue |= (tempW1>>1);
+               }
+       }
+       return MRSValue;
+}
+
+/*-----------------------------------------------------------------------------
+ *  void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *DCTData, u8 Dimm, BOOL WL)
+ *
+ *  Description:
+ *       This function prepares DIMMS for training
+ *
+ *   Parameters:
+ *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
+ *              *SPDData - Pointer to buffer with information about each DIMMs
+ *                         SPD information
+ *              *MCTData - Pointer to buffer with runtime parameters,
+ *       IN    Dimm - Logical DIMM number
+ *              WL - indicates if the routine is used for Write levelization
+ *                   training
+ *
+ *       OUT
+ *
+ * ----------------------------------------------------------------------------
+ */
+void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
+{
+       u32 tempW, tempW1, tempW2, MrsBank;
+       u8 rank, currDimm, MemClkFreq;
+
+       MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                       FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
+       /* Configure the DCT to send initialization MR commands to the target DIMM
+        * ;by programming the F2x[1,0]7C register using the following steps.
+        */
+       rank = 0;
+       while ((rank < pDCTData->DimmRanks[dimm]) && (rank < 2))
+       {
+               /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank to be trained. */
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, dimm*2+rank);
+               /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
+                * ;register that defines the required DDR3-defined function for write
+                * ; levelization.
+                */
+               MrsBank = swapBankBits(pDCTData,1);
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+               /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
+                * ; for write levelization.
+                */
+               tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0 */
+
+               /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
+               tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
+               if (tempW2)
+               {
+                       if (pDCTData->DimmX8Present[dimm])
+                               tempW |= 0x800;
+               }
+
+               /* determine Rtt_Nom for WL & Normal mode */
+               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+                       tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
+               } else {
+                       if (wl)
+                       {
+                               if (pDCTData->MaxDimmsInstalled == 1)
+                               {
+                                       if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 0))
+                                       {
+                                               tempW1 = 0x00;  /* Rtt_Nom=OFF */
+                                       }
+                                       else
+                                       {
+                                               tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
+                                       }
+                               }
+                               else    /* 2 Dimms or more per channel */
+                               {
+                                       if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 1))
+                                       {
+                                               tempW1 = 0x00;  /* Rtt_Nom=OFF */
+                                       }
+                                       else
+                                       {
+                                               if (MemClkFreq == 6) {
+                                                       tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
+                                               } else {
+                                                       tempW1 = 0x40;/* Rtt_Nom=RZQ/2=120 Ohm */
+                                               }
+                                       }
+                               }
+                       }
+                       else {  /* 1 or 4 Dimms per channel */
+                               if ((pDCTData->MaxDimmsInstalled == 1) || (pDCTData->MaxDimmsInstalled == 4))
+                               {
+                                       tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
+                               }
+                               else    /* 2 or 3 Dimms per channel */
+                               {
+                                       if (MemClkFreq < 5) {
+                                               tempW1 = 0x0044;        /* Rtt_Nom=RZQ/6=40 Ohm */
+                                       } else {
+                                               tempW1 = 0x0204;        /* Rtt_Nom=RZQ/8=30 Ohm */
+                                       }
+                               }
+                       }
+               }
+               tempW=tempW|tempW1;
+
+               /* All ranks of the target DIMM are set to write levelization mode. */
+               if (wl)
+               {
+                       tempW1 = bitTestSet(tempW, MRS_Level);
+                       if (rank == 0)
+                       {
+                               /* ?Enable the output driver of the first rank of the target DIMM. */
+                               tempW = tempW1;
+                       }
+                       else
+                       {
+                               /* Disable the output drivers of all other ranks for
+                                * the target DIMM. */
+                               tempW = bitTestSet(tempW1, Qoff);
+                       }
+               }
+               /* program MrsAddress[5,1]=output driver impedance control (DIC):
+                * based on F2x[1,0]84[DrvImpCtrl] */
+               tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
+               if (bitTest(tempW1,1))
+               {tempW = bitTestSet(tempW, 5);}
+               if (bitTest(tempW1,0))
+               {tempW = bitTestSet(tempW, 1);}
+
+               tempW = swapAddrBits_wl(pDCTData,tempW);
+
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+               /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
+                * ;the specified DIMM.
+                */
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+               /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
+               while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
+               {
+               }
+               /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
+                * ;register that defines the required DDR3-defined function for Rtt_WR.
+                */
+               MrsBank = swapBankBits(pDCTData,2);
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+               /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
+                * ; for Rtt_WR (DRAMTermDyn).
+                */
+               tempW = 0;/* PASR = 0,*/
+               /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
+                * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
+               tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
+               if (bitTest(tempW1,19))
+               {tempW = bitTestSet(tempW, 7);}
+               if (bitTest(tempW1,18))
+               {tempW = bitTestSet(tempW, 6);}
+               /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
+               tempW=tempW|((tempW1&0x00700000)>>17);
+               /* workaround for DR-B0 */
+               if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
+                       tempW+=0x8;
+               /* determine Rtt_WR for WL & Normal mode */
+               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+                       tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
+               } else {
+                       if (wl)
+                       {
+                               tempW1 = 0x00;  /* Rtt_WR=off */
+                       }
+                       else
+                       {
+                               if (pDCTData->MaxDimmsInstalled == 1)
+                               {
+                                       tempW1 = 0x00;  /* Rtt_WR=off */
+                               }
+                               else
+                               {
+                                       if (MemClkFreq == 6) {
+                                               tempW1 = 0x200; /* Rtt_WR=RZQ/4=60 Ohm */
+                                       } else {
+                                               tempW1 = 0x400; /* Rtt_WR=RZQ/2 */
+                                       }
+                               }
+                       }
+               }
+               tempW=tempW|tempW1;
+               tempW = swapAddrBits_wl(pDCTData,tempW);
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+               /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
+                  the specified DIMM.*/
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+               /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
+               while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
+               {
+               }
+
+               rank++;
+       }
+
+       /* Configure the non-target DIMM normally. */
+       currDimm = 0;
+       while (currDimm < MAX_LDIMMS)
+       {
+               if (pDCTData->DimmPresent[currDimm])
+               {
+                       if (currDimm != dimm)
+                       {
+                               rank = 0;
+                               while ((rank < pDCTData->DimmRanks[currDimm]) && (rank < 2))
+                               {
+
+                                       /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank
+                                        * ;to be trained.
+                                        */
+                                       set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                               FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, currDimm*2+rank);
+                                       /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal
+                                        * ;DRAM register that defines the required DDR3-defined function
+                                        * ; for write levelization.
+                                        */
+                                       MrsBank = swapBankBits(pDCTData,1);
+                                       set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                               FUN_DCT, DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+                                       /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required
+                                        * ;DDR3-defined function for write levelization.
+                                        */
+                                       tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0, Level=0, Qoff=0 */
+
+                                       /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
+                                       tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                                       FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
+                                       if (tempW2)
+                                       {
+                                               if (pDCTData->DimmX8Present[currDimm])
+                                                       tempW |= 0x800;
+                                       }
+
+                                       /* determine Rtt_Nom for WL & Normal mode */
+                                       if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+                                               tempW1 = RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
+                                       } else {
+                                               if (wl)
+                                               {
+                                                       if ((pDCTData->DimmRanks[currDimm] == 2) && (rank == 1))
+                                                       {
+                                                               tempW1 = 0x00;  /* Rtt_Nom=OFF */
+                                                       }
+                                                       else
+                                                       {
+                                                               if (MemClkFreq < 5) {
+                                                                       tempW1 = 0x0044;/* Rtt_Nom=RZQ/6=40 Ohm */
+                                                               } else {
+                                                                       tempW1 = 0x0204;/* Rtt_Nom=RZQ/8=30 Ohm */
+                                                               }
+                                                       }
+                                               }
+                                               else {  /* 1 or 4 Dimms per channel */
+                                                       if ((pDCTData->MaxDimmsInstalled == 4))
+                                                       {
+                                                               tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
+                                                       }
+                                                       else {  /* 2 or 3 Dimms per channel */
+                                                               if (MemClkFreq < 5) {
+                                                                       tempW1 = 0x0044;        /* Rtt_Nom=RZQ/6=40 Ohm */
+                                                               } else {
+                                                                       tempW1 = 0x0204;        /* Rtt_Nom=RZQ/8=30 Ohm */
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       tempW=tempW|tempW1;
+                                       /* program MrsAddress[5,1]=output driver impedance control (DIC):
+                                        * based on F2x[1,0]84[DrvImpCtrl] */
+                                       tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                                       FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
+                                       if (bitTest(tempW1,1))
+                                       {tempW = bitTestSet(tempW, 5);}
+                                       if (bitTest(tempW1,0))
+                                       {tempW = bitTestSet(tempW, 1);}
+                                       tempW = swapAddrBits_wl(pDCTData,tempW);
+                                       set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                               FUN_DCT, DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+                                       /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command
+                                        * ; to the specified DIMM.
+                                        */
+                                       set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                               FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+                                       /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
+                                       while ((get_Bits(pDCTData, pDCTData->CurrDct,
+                                                       pDCTData->NodeId, FUN_DCT, DRAM_INIT,
+                                                       SendMrsCmd, SendMrsCmd)) == 1);
+                                       /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
+                                        * ;register that defines the required DDR3-defined function for Rtt_WR.
+                                        */
+                                       MrsBank = swapBankBits(pDCTData,2);
+                                       set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                                               DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
+                                       /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
+                                        * ; for Rtt_WR (DRAMTermDyn).
+                                        */
+                                       tempW = 0;/* PASR = 0,*/
+                                       /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
+                                        * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
+                                       tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                                       FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
+                                       if (bitTest(tempW1,19))
+                                       {tempW = bitTestSet(tempW, 7);}
+                                       if (bitTest(tempW1,18))
+                                       {tempW = bitTestSet(tempW, 6);}
+                                       /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
+                                       tempW=tempW|((tempW1&0x00700000)>>17);
+                                       /* workaround for DR-B0 */
+                                       if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
+                                               tempW+=0x8;
+                                       /* determine Rtt_WR for WL & Normal mode */
+                                       if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+                                               tempW1 = RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
+                                       } else {
+                                               if (wl)
+                                               {
+                                                       tempW1 = 0x00;  /* Rtt_WR=off */
+                                               }
+                                               else
+                                               {
+                                                       if (MemClkFreq == 6) {
+                                                               tempW1 = 0x200; /* Rtt_WR=RZQ/4=60 Ohm */
+                                                       } else {
+                                                               tempW1 = 0x400; /* Rtt_WR=RZQ/2 */
+                                                       }
+                                               }
+                                       }
+                                       tempW=tempW|tempW1;
+                                       tempW = swapAddrBits_wl(pDCTData,tempW);
+                                       set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                                               DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+                                       /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
+                                          the specified DIMM.*/
+                                       set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                                               DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+                                       /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
+                                       while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                                                       FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
+                                       {
+                                       }
+                                       rank++;
+                               }
+                       }
+               }
+               currDimm++;
+       }
+}
+
+/*-----------------------------------------------------------------------------
+ * void programODT(sMCTStruct *pMCTData, DCTStruct *DCTData, u8 dimm)
+ *
+ *  Description:
+ *       This function programs the ODT values for the NB
+ *
+ *   Parameters:
+ *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
+ *       IN
+ *       OUT
+ * ----------------------------------------------------------------------------
+ */
+void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
+{
+       u8 WrLvOdt1=0;
+
+       if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
+               if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
+                       WrLvOdt1 = 0x03;
+               } else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
+                       WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
+               } else {
+                       WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
+               }
+       } else {
+               WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
+       }
+
+       set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
+
+}
+
+/*-----------------------------------------------------------------------------
+ * void procConifg(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
+ *
+ *  Description:
+ *       This function programs the ODT values for the NB
+ *
+ *   Parameters:
+ *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
+ *              *MCTData - Pointer to buffer with runtime parameters,
+ *       IN    Dimm - Logical DIMM
+ *              Pass - First of Second Pass
+ *       OUT
+ * ----------------------------------------------------------------------------
+ */
+void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
+{
+       u8 ByteLane, Seed_Gross, Seed_Fine;
+       u32 Value, Addr;
+       u16 Addl_Data_Offset, Addl_Data_Port;
+
+       /* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for the
+        * ;current memory subsystem configuration.
+        */
+       programODT(pMCTData, pDCTData, dimm);
+
+       /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
+       if (pDCTData->LogicalCPUID & AMD_DR_Cx)
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn,(u32) 1);
+       else
+       {
+               /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 0 for Rev.B*/
+               if (pDCTData->DctTrain)
+               {
+                       Addl_Data_Offset=0x198;
+                       Addl_Data_Port=0x19C;
+               }
+               else
+               {
+                       Addl_Data_Offset=0x98;
+                       Addl_Data_Port=0x9C;
+               }
+               Addr=0x0D008000;
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
+               while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
+                               DctAccessDone, DctAccessDone)) == 0);
+               AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
+               Value = bitTestSet(Value, 12);
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
+               Addr=0x4D088F00;
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
+               while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
+                               DctAccessDone, DctAccessDone)) == 0);
+       }
+
+       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
+       pMCTData->AgesaDelay(10);
+       ByteLane = 0;
+       if (pass == 1)
+       {
+               if (pDCTData->Status[DCT_STATUS_REGISTERED])
+               {
+                       if(pDCTData->RegMan1Present & ((1<<(dimm*2+pDCTData->DctTrain))))
+                       {
+                               Seed_Gross = 0x02;
+                               Seed_Fine = 0x16;
+                       }
+                       else
+                       {
+                               Seed_Gross = 0x02;
+                               Seed_Fine = 0x00;
+                       }
+               }
+               else
+               {
+                       Seed_Gross = 0x00;
+                       Seed_Fine = 0x1A;
+               }
+               while(ByteLane < MAX_BYTE_LANES)
+               {
+                       /* 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
+                        * ; of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined
+                        * ;by design.
+                        */
+                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
+                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
+                       ByteLane++;
+               }
+       }
+       setWLByteDelay(pDCTData, ByteLane, dimm, 0);
+}
+
+/*-----------------------------------------------------------------------------
+ *  void setWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm){
+ *
+ *  Description:
+ *       This function writes the write levelization byte delay for the Phase
+ *       Recovery control registers
+ *
+ *   Parameters:
+ *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
+ *       IN    Dimm - Dimm Number
+ *              DCTData->WLGrossDelay[index+ByteLane] - gross write delay for each
+ *                                                  logical DIMM
+ *              DCTData->WLFineDelay[index+ByteLane] - fine write delay for each
+ *                                                 logical DIMM
+ *              ByteLane - target byte lane to write
+ *       targetAddr -    0: write to DRAM phase recovery control register
+ *                       1: write to DQS write register
+ *       OUT
+ *
+ *-----------------------------------------------------------------------------
+ */
+void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
+{
+       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr;
+       u32 addr, fineDelayValue, grossDelayValue, ValueLow, ValueHigh, EccValue, tempW;
+
+       if (targetAddr == 0)
+       {
+               index = (u8)(MAX_BYTE_LANES * dimm);
+               ValueLow = 0;
+               ValueHigh = 0;
+               ByteLane = 0;
+               EccValue = 0;
+               while (ByteLane < MAX_BYTE_LANES)
+               {
+                       /* This subtract 0xC workaround might be temporary. */
+                       if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+pDCTData->DctTrain))))
+                       {
+                               tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
+                               tempW -= 0xC;
+                               pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
+                               pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
+                       }
+                       grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
+                       /* Adjust seed gross delay overflow (greater than 3):
+                        *      - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
+                        *      - Keep original seed gross delay for later reference.
+                        */
+                       if(grossDelayValue >= 3)
+                       {
+                               grossDelayValue = (grossDelayValue&1)? 1 : 2;
+                       }
+                       fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
+                       if (ByteLane < 4)
+                               ValueLow |= ((grossDelayValue << 5) | fineDelayValue) << 8*ByteLane;
+                       else if(ByteLane < 8)
+                               ValueHigh |= ((grossDelayValue << 5) | fineDelayValue) << 8*(ByteLane-4);
+                       else
+                               EccValue = ((grossDelayValue << 5) | fineDelayValue);
+                       ByteLane++;
+               }
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                               DRAM_CONT_ADD_PHASE_REC_CTRL_LOW, 0, 31, (u32)ValueLow);
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                               DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH, 0, 31, (u32)ValueHigh);
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                               DRAM_CONT_ADD_ECC_PHASE_REC_CTRL, 0, 31, (u32)EccValue);
+       }
+       else
+       {
+               index = (u8)(MAX_BYTE_LANES * dimm);
+               grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
+               fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
+
+               tempB = 0;
+               offsetAddr = (u8)(3 * dimm);
+               if (ByteLane < 2)
+               {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01;
+               }
+               else if (ByteLane <4)
+               {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 1;
+               }
+               else if (ByteLane <6)
+               {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45;
+               }
+               else if (ByteLane <8)
+               {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 + 1;
+               }
+               else
+               {
+                       tempB = 0;
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 2;
+               }
+               addr += offsetAddr;
+
+               fineStartLoc = (u8)(tempB % 32);
+               fineEndLoc = (u8)(fineStartLoc + 4);
+               grossStartLoc = (u8)(fineEndLoc + 1);
+               grossEndLoc = (u8)(grossStartLoc + 1);
+
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                               (u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
+                               (u16)addr, grossStartLoc, grossEndLoc, (u32)grossDelayValue);
+       }
+
+}
+
+/*-----------------------------------------------------------------------------
+ *  void getWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm)
+ *
+ *  Description:
+ *       This function reads the write levelization byte delay from the Phase
+ *       Recovery control registers
+ *
+ *   Parameters:
+ *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
+ *       IN    Dimm - Dimm Number
+ *              ByteLane - target byte lane to read
+ *       OUT
+ *              DCTData->WLGrossDelay[index+ByteLane] - gross write delay for current
+ *                                                  byte for logical DIMM
+ *              DCTData->WLFineDelay[index+ByteLane] - fine write delay for current
+ *                                                 byte for logical DIMM
+ *
+ *-----------------------------------------------------------------------------
+ */
+void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm)
+{
+       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index;
+       u32 addr, fine, gross;
+       tempB = 0;
+       index = (u8)(MAX_BYTE_LANES*dimm);
+       if (ByteLane < 4)
+       {
+               tempB = (u8)(8 * ByteLane);
+               addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;
+       }
+       else if (ByteLane < 8)
+       {
+               tempB1 = (u8)(ByteLane - 4);
+               tempB = (u8)(8 * tempB1);
+               addr = DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH;
+       }
+       else
+       {
+               tempB = 0;
+               addr = DRAM_CONT_ADD_ECC_PHASE_REC_CTRL;
+       }
+       fineStartLoc = tempB;
+       fineEndLoc = (u8)(fineStartLoc + 4);
+       grossStartLoc = (u8)(fineEndLoc + 1);
+       grossEndLoc = (u8)(grossStartLoc + 1);
+
+       fine = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
+                               FUN_DCT, (u16)addr, fineStartLoc, fineEndLoc);
+       gross = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
+                               FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
+       /* Adjust seed gross delay overflow (greater than 3):
+        * - Adjust the trained gross delay to the original seed gross delay.
+        */
+       if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
+       {
+               gross += pDCTData->WLGrossDelay[index+ByteLane];
+               if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
+                       gross -= 1;
+               else
+                       gross -= 2;
+       }
+       else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
+       {
+               /* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
+                * We will then round the negative number to 0.
+                */
+               gross = 0;
+               fine = 0;
+       }
+       pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
+       pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c b/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
new file mode 100644 (file)
index 0000000..e75b549
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* This file contains functions for odt setting on registered DDR3 dimms */
+
+/*
+ *-----------------------------------------------------------------------------
+ *                                  MODULES USED
+ *
+ *-----------------------------------------------------------------------------
+ */
+/*----------------------------------------------------------------------------
+ *                        PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *                                EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ *   This function set Rtt_Nom for registered DDR3 dimms on targeted dimm.
+ *
+ *     @param[in]  *pDCTData - Pointer to buffer with information about each DCT
+ *                 dimm - targeted dimm
+ *                 wl - current mode, either write levelization mode or normal mode
+ *                 MemClkFreq - current frequency
+ *
+ *      @return    tempW1 - Rtt_Nom
+ */
+static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
+{
+       u32 tempW1;
+       tempW1 = 0;
+       if (wl) {
+               switch (pMCTData->PlatMaxDimmsDct) {
+               case 2:
+                       /* 2 dimms per channel */
+                       if (pDCTData->MaxDimmsInstalled == 1) {
+                               if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 0)) {
+                                       tempW1 = 0x00;  /* Rtt_Nom = OFF */
+                               } else if (pDCTData->DimmRanks[dimm] == 4) {
+                                       if (rank == 1) {
+                                               tempW1 = 0x00;  /* Rtt_Nom = OFF on second and forth rank of QR dimm */
+                                       } else {
+                                               if (MemClkFreq == 6) {
+                                                       tempW1 = 0x04;  /* Rtt_Nom = 60 ohms */
+                                               } else {
+                                                       tempW1 = 0x40;  /* Rtt_Nom = 120 ohms */
+                                               }
+                                       }
+                               } else {
+                                       tempW1 = 0x04;  /* Rtt_Nom = 60 ohms */
+                               }
+                       } else if (pDCTData->MaxDimmsInstalled == 2) {
+                               if (((pDCTData->DimmRanks[dimm] == 2) || (pDCTData->DimmRanks[dimm] == 4)) && (rank == 1)) {
+                                       tempW1 = 0x00;  /* Rtt_Nom = OFF */
+                               } else if ((pDCTData->DimmRanks[dimm] == 4) || (pDCTData->DctCSPresent & 0xF0)) {
+                                       if (MemClkFreq == 3) {
+                                               tempW1 = 0x40;  /* Rtt_Nom = 120 ohms */
+                                       } else {
+                                               tempW1 = 0x04;  /* Rtt_Nom = 60 ohms */
+                                       }
+                               } else {
+                                       if (MemClkFreq == 6) {
+                                               tempW1 = 0x04;  /* Rtt_Nom = 60 ohms */
+                                       } else {
+                                               tempW1 = 0x40;  /* Rtt_Nom = 120 ohms */
+                                       }
+                               }
+                       }
+                       break;
+               case 3:
+                       /* 3 dimms per channel */
+                       /* QR not supported in this case on L1 package. */
+                       if (pDCTData->MaxDimmsInstalled == 1) {
+                               if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
+                                       tempW1 = 0x00;  /* Rtt_Nom = OFF */
+                               } else {
+                                       tempW1 = 0x04;  /* Rtt_Nom = 60 ohms */
+                               }
+                       } else {
+                               tempW1 = 0x40;  /* Rtt_Nom = 120 ohms */
+                       }
+                       break;
+               default:
+                       ASSERT (FALSE);
+               }
+       } else {
+               switch (pMCTData->PlatMaxDimmsDct) {
+               case 2:
+                       /* 2 dimms per channel */
+                       if ((pDCTData->DimmRanks[dimm] == 4) && (rank == 1)) {
+                               tempW1 = 0x00;  /* Rtt_Nom = OFF */
+                       } else if ((pDCTData->MaxDimmsInstalled == 1) || (pDCTData->DimmRanks[dimm] == 4)) {
+                               tempW1 = 0x04;  /* Rtt_Nom = 60 ohms */
+                       } else {
+                               if (pDCTData->DctCSPresent & 0xF0) {
+                                       tempW1 = 0x0204;        /* Rtt_Nom = 30 ohms */
+                               } else {
+                                       if (MemClkFreq < 5) {
+                                               tempW1 = 0x44;  /* Rtt_Nom = 40 ohms */
+                                       } else {
+                                               tempW1 = 0x0204;        /* Rtt_Nom = 30 ohms */
+                                       }
+                               }
+                       }
+                       break;
+               case 3:
+                       /* 3 dimms per channel */
+                       /* L1 package does not support QR dimms this case. */
+                       if (rank == 1) {
+                               tempW1 = 0x00;  /* Rtt_Nom = OFF */
+                       } else if (pDCTData->MaxDimmsInstalled == 1) {
+                               tempW1 = 0x04;  /* Rtt_Nom = 60 ohms */
+                       } else if ((MemClkFreq < 5) || (pDCTData->MaxDimmsInstalled == 3)) {
+                               tempW1 = 0x44;  /* Rtt_Nom = 40 ohms */
+                       } else {
+                               tempW1 = 0x0204;        /* Rtt_Nom = 30 ohms */
+                       }
+                       break;
+               default:
+                       ASSERT (FALSE);
+               }
+       }
+       return tempW1;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ *   This function set Rtt_Nom for registered DDR3 dimms on non-targeted dimm.
+ *
+ *     @param[in]  *pDCTData - Pointer to buffer with information about each DCT
+ *                 dimm - non-targeted dimm
+ *                 wl - current mode, either write levelization mode or normal mode
+ *                 MemClkFreq - current frequency
+ *
+ *      @return    tempW1 - Rtt_Nom
+ */
+static u32 RttNomNonTargetRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
+{
+       if ((wl) && (pMCTData->PlatMaxDimmsDct == 2) && (pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
+               return 0x00;    /* for non-target dimm during WL, the second rank of a DR dimm need to have Rtt_Nom = OFF */
+       } else {
+               return RttNomTargetRegDimm (pMCTData, pDCTData, dimm, FALSE, MemClkFreq, rank); /* otherwise, the same as target dimm in normal mode. */
+       }
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ *   This function set Rtt_Wr for registered DDR3 dimms.
+ *
+ *     @param[in]  *pDCTData - Pointer to buffer with information about each DCT
+ *                 dimm - targeted dimm
+ *                 wl - current mode, either write levelization mode or normal mode
+ *                 MemClkFreq - current frequency
+ *
+ *      @return    tempW1 - Rtt_Wr
+ */
+static u32 RttWrRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
+{
+       u32 tempW1;
+       tempW1 = 0;
+       if (wl) {
+               tempW1 = 0x00;  /* Rtt_WR = OFF */
+       } else {
+               switch (pMCTData->PlatMaxDimmsDct) {
+               case 2:
+                       if (pDCTData->MaxDimmsInstalled == 1) {
+                               if (pDCTData->DimmRanks[dimm] != 4) {
+                                       tempW1 = 0x00;
+                               } else {
+                                       if (MemClkFreq == 6) {
+                                               tempW1 = 0x200; /* Rtt_WR = 60 ohms */
+                                       } else {
+                                               tempW1 = 0x400; /* Rtt_WR = 120 ohms */
+                                       }
+                               }
+                       } else {
+                               if ((pDCTData->DimmRanks[dimm] == 4) || (pDCTData->DctCSPresent & 0xF0)) {
+                                       if (MemClkFreq == 3) {
+                                               tempW1 = 0x400; /* Rtt_WR = 120 ohms */
+                                       } else {
+                                               tempW1 = 0x200; /* Rtt_WR = 60 ohms */
+                                       }
+                               } else {
+                                       if (MemClkFreq == 6) {
+                                               tempW1 = 0x200; /* Rtt_WR = 60 ohms */
+                                       } else {
+                                               tempW1 = 0x400; /* Rtt_Nom = 120 ohms */
+                                       }
+                               }
+                       }
+                       break;
+               case 3:
+                       if (pDCTData->MaxDimmsInstalled == 1) {
+                               tempW1 = 0x00;  /* Rtt_WR = OFF */
+                       } else {
+                               tempW1 = 0x400; /* Rtt_Nom = 120 ohms */
+                       }
+                       break;
+               default:
+                       ASSERT (FALSE);
+               }
+       }
+       return tempW1;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ *   This function set WrLvOdt for registered DDR3 dimms.
+ *
+ *     @param[in]  *pDCTData - Pointer to buffer with information about each DCT
+ *                 dimm - targeted dimm
+ *
+ *      @return    WrLvOdt
+ */
+static u8 WrLvOdtRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
+{
+       u8 WrLvOdt1, i;
+       WrLvOdt1 = 0;
+       i = 0;
+       while (i < 8) {
+               if (pDCTData->DctCSPresent & (1 << i)) {
+                       WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, i/2);
+               }
+               i += 2;
+       }
+       if (pMCTData->PlatMaxDimmsDct == 2) {
+               if ((pDCTData->DimmRanks[dimm] == 4) && (pDCTData->MaxDimmsInstalled != 1)) {
+                       if (dimm >= 2) {
+                               WrLvOdt1 = (u8)bitTestReset (WrLvOdt1, (dimm - 2));
+                       } else {
+                               WrLvOdt1 = (u8)bitTestReset (WrLvOdt1, (dimm + 2));
+                       }
+               } else if ((pDCTData->DimmRanks[dimm] == 2) && (pDCTData->MaxDimmsInstalled == 1)) {
+                       /* the case for one DR on a 2 dimms per channel is special */
+                       WrLvOdt1 = 0x8;
+               }
+       }
+       return WrLvOdt1;
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mport_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mport_d.c
new file mode 100644 (file)
index 0000000..a1132ff
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+static void AmdMemPCIRead(SBDFO loc, u32 *Value)
+{
+       /* Convert SBDFO into a CF8 Address */
+       loc = (loc >> 4 & 0xFFFFFF00) | (loc & 0xFF) | ((loc & 0xF00) << 16) ;
+       loc |= 0x80000000;
+
+       outl(loc, 0xCF8);
+
+       *Value = inl(0xCFC);
+}
+
+static void AmdMemPCIWrite(SBDFO loc, u32 *Value)
+{
+       /* Convert SBDFO into a CF8 Address */
+       loc = (loc >> 4 & 0xFFFFFF00) | (loc & 0xFF) | ((loc & 0xF00) << 16) ;
+       loc |= 0x80000000;
+
+       outl(loc, 0xCF8);
+       outl(*Value, 0xCFC);
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
new file mode 100644 (file)
index 0000000..b153eef
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* This file contains functions for common utility functions */
+
+/*
+ *-----------------------------------------------------------------------------
+ *             MODULES USED
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *             EXPORTED FUNCTIONS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void AmdMemPCIReadBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
+{
+       /* ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0); */
+
+       AmdMemPCIRead(loc, pValue);
+       *pValue = *pValue >> lowbit;  /* Shift */
+
+       /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
+       if ((highbit-lowbit) != 31)
+               *pValue &= (((u32)1 << (highbit-lowbit+1))-1);
+}
+
+static void AmdMemPCIWriteBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
+{
+       u32 temp, mask;
+
+       /* ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0); */
+
+       /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
+       if ((highbit-lowbit) != 31)
+               mask = (((u32)1 << (highbit-lowbit+1))-1);
+       else
+               mask = (u32)0xFFFFFFFF;
+
+       AmdMemPCIRead(loc, &temp);
+       temp &= ~(mask << lowbit);
+       temp |= (*pValue & mask) << lowbit;
+       AmdMemPCIWrite(loc, &temp);
+}
+
+/*-----------------------------------------------------------------------------
+ * uint 32
+ * u32 bitTestSet(u32 csMask,u32 tempD)
+ *
+ * Description:
+ *     This routine sets a bit in a u32
+ *
+ * Parameters:
+ *     IN        csMask = Target value in which the bit will be set
+ *     IN        tempD     =  Bit that will be set
+ *     OUT    value     =  Target value with the bit set
+ *-----------------------------------------------------------------------------
+ */
+static u32 bitTestSet(u32 csMask,u32 tempD)
+{
+       u32 localTemp;
+       /* ASSERT(tempD < 32); */
+       localTemp = 1;
+       csMask |= localTemp << tempD;
+       return csMask;
+}
+
+/*-----------------------------------------------------------------------------
+ * uint 32
+ * u32 bitTestReset(u32 csMask,u32 tempD)
+ *
+ * Description:
+ *     This routine re-sets a bit in a u32
+ *
+ * Parameters:
+ *     IN        csMask = Target value in which the bit will be re-set
+ *     IN        tempD     =  Bit that will be re-set
+ *     OUT    value     =  Target value with the bit re-set
+ *-----------------------------------------------------------------------------
+ */
+static u32 bitTestReset(u32 csMask,u32 tempD)
+{
+       u32 temp, localTemp;
+       /* ASSERT(tempD < 32); */
+       localTemp = 1;
+       temp = localTemp << tempD;
+       temp = ~temp;
+       csMask &= temp;
+       return csMask;
+}
+
+/*-----------------------------------------------------------------------------
+ * uint 32
+ *  u32 get_Bits(DCTStruct *DCTData, u8 DCT, u8 Node, u8 func, u16 offset,
+ *                 u8 low, u8 high)
+ *
+ * Description:
+ *     This routine Gets the PCT bits from the specidfied Node, DCT and PCI address
+ *
+ * Parameters:
+ *   IN  OUT *DCTData - Pointer to buffer with information about each DCT
+ *     IN        DCT - DCT number
+ *              - 1 indicates DCT 1
+ *              - 0 indicates DCT 0
+ *              - 2 both DCTs
+ *          Node - Node number
+ *          Func - PCI Function number
+ *          Offset - PCI register number
+ *          Low - Low bit of the bit field
+ *          High - High bit of the bit field
+ *
+ *     OUT    value     =  Value read from PCI space
+ *-----------------------------------------------------------------------------
+ */
+static u32 get_Bits(sDCTStruct *pDCTData,
+               u8 dct, u8 node, u8 func,
+               u16 offset, u8 low, u8 high)
+{
+       u32 temp;
+       /* ASSERT(node < MAX_NODES); */
+       if (dct == BOTH_DCTS)
+       {
+               /* Registers exist on DCT0 only */
+               AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+       }
+       else
+       {
+               if (dct == 1)
+               {
+                       /* Write to dct 1 */
+                       offset += 0x100;
+                       AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+               }
+               else
+               {
+                       /* Write to dct 0 */
+                       AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+               }
+       }
+       return temp;
+}
+
+/*-----------------------------------------------------------------------------
+ * uint 32
+ *  void set_Bits(DCTStruct *DCTData,u8 DCT,u8 Node,u8 func, u16 offset,
+ *                u8 low, u8 high, u32 value)
+ *
+ * Description:
+ *     This routine Sets the PCT bits from the specidfied Node, DCT and PCI address
+ *
+ * Parameters:
+ *   IN  OUT *DCTData - Pointer to buffer with information about each DCT
+ *     IN        DCT - DCT number
+ *              - 1 indicates DCT 1
+ *              - 0 indicates DCT 0
+ *              - 2 both DCTs
+ *          Node - Node number
+ *          Func - PCI Function number
+ *          Offset - PCI register number
+ *          Low - Low bit of the bit field
+ *          High - High bit of the bit field
+ *
+ *     OUT
+ *-----------------------------------------------------------------------------
+ */
+static void set_Bits(sDCTStruct *pDCTData,
+               u8 dct, u8 node, u8 func,
+               u16 offset, u8 low, u8 high, u32 value)
+{
+       u32 temp;
+       temp = value;
+
+       if (dct == BOTH_DCTS)
+       {
+               /* Registers exist on DCT0 only */
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+       }
+       else
+       {
+               if (dct == 1)
+               {
+                       /* Write to dct 1 */
+                       offset += 0x100;
+                       AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+               }
+               else
+               {
+                       /* Write to dct 0 */
+                       AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
+               }
+       }
+}
+
+/*-------------------------------------------------
+ * uint 32
+ *  u32 get_ADD_DCT_Bits(DCTStruct *DCTData,u8 DCT,u8 Node,u8 func,
+ *                         u16 offset,u8 low, u8 high)
+ *
+ * Description:
+ *     This routine gets the Additional PCT register from Function 2 by specidfied
+ *   Node, DCT and PCI address
+ *
+ * Parameters:
+ *   IN  OUT *DCTData - Pointer to buffer with information about each DCT
+ *     IN        DCT - DCT number
+ *              - 1 indicates DCT 1
+ *              - 0 indicates DCT 0
+ *              - 2 both DCTs
+ *          Node - Node number
+ *          Func - PCI Function number
+ *          Offset - Additional PCI register number
+ *          Low - Low bit of the bit field
+ *          High - High bit of the bit field
+ *
+ *     OUT
+ *-------------------------------------------------
+ */
+static u32 get_ADD_DCT_Bits(sDCTStruct *pDCTData,
+               u8 dct, u8 node, u8 func,
+               u16 offset, u8 low, u8 high)
+{
+       u32 tempD;
+       tempD = offset;
+       tempD = bitTestReset(tempD,DctAccessWrite);
+       set_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
+               PCI_MIN_LOW, PCI_MAX_HIGH, offset);
+       while ((get_Bits(pDCTData,dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
+                       DctAccessDone, DctAccessDone)) == 0);
+       return (get_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_PORT_REG,
+                       low, high));
+}
+
+/*-------------------------------------------------
+ * uint 32
+ *  void set_DCT_ADDR_Bits(DCTStruct *DCTData, u8 DCT,u8 Node,u8 func,
+ *                         u16 offset,u8 low, u8 high, u32 value)
+ *
+ * Description:
+ *     This routine sets the Additional PCT register from Function 2 by specidfied
+ *   Node, DCT and PCI address
+ *
+ * Parameters:
+ *   IN  OUT *DCTData - Pointer to buffer with information about each DCT
+ *     IN        DCT - DCT number
+ *              - 1 indicates DCT 1
+ *              - 0 indicates DCT 0
+ *              - 2 both DCTs
+ *          Node - Node number
+ *          Func - PCI Function number
+ *          Offset - Additional PCI register number
+ *          Low - Low bit of the bit field
+ *          High - High bit of the bit field
+ *
+ *     OUT
+ *-------------------------------------------------
+ */
+static void set_DCT_ADDR_Bits(sDCTStruct *pDCTData,
+               u8 dct, u8 node, u8 func,
+               u16 offset, u8 low, u8 high, u32 value)
+{
+       u32 tempD;
+
+       set_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
+               PCI_MIN_LOW, PCI_MAX_HIGH, offset);
+       while ((get_Bits(pDCTData,dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
+                       DctAccessDone, DctAccessDone)) == 0);
+
+       set_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_PORT_REG,
+               low, high, value);
+       tempD = offset;
+       tempD = bitTestSet(tempD,DctAccessWrite);
+       set_Bits(pDCTData, dct, node, FUN_DCT,DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
+               PCI_MIN_LOW, PCI_MAX_HIGH, tempD);
+       while ((get_Bits(pDCTData,dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_CONTROLLER_ADD_DATA_OFFSET_REG, DctAccessDone,
+                       DctAccessDone)) == 0);
+}
+
+/*-------------------------------------------------
+ * uint 32
+ * BOOL bitTest(u32 value, u8 bitLoc)
+ *
+ * Description:
+ *     This routine tests the value to determine if the bitLoc is set
+ *
+ * Parameters:
+ *     IN        Value - value to be tested
+ *          bitLoc - bit location to be tested
+ *     OUT    TRUE - bit is set
+ *          FALSE - bit is clear
+ *-------------------------------------------------
+ */
+static BOOL bitTest(u32 value, u8 bitLoc)
+{
+       u32 tempD, compD;
+       tempD = value;
+       compD = 0;
+       compD = bitTestSet(compD,bitLoc);
+       tempD &= compD;
+       if (compD == tempD)
+       {
+               return TRUE;
+       }
+       else
+       {
+               return FALSE;
+       }
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
new file mode 100644 (file)
index 0000000..9b20699
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+/* IBV defined Structure */ /* IBV Specific Options */
+#ifndef MWLC_D_H
+#define MWLC_D_H
+
+#define MAX_TOTAL_DIMMS 8      /* Maximum Number of DIMMs in systems */
+                               /* (DCT0 + DCT1) */
+#define MAX_DIMMS 4            /* Maximum Number of DIMMs on each DCT */
+#define MAX_LDIMMS 4           /* Maximum number of Logial DIMMs per DCT */
+
+/*MCT Max variables */
+#define MAX_ERRORS 32          /* Maximum number of Errors Reported */
+#define MAX_STATUS 32          /* Maximum number of Status variables*/
+#define MAX_BYTE_LANES (8+1)   /* Maximum number of Byte Lanes - include ECC */
+
+#define C_MAX_DIMMS 4          /* Maximum Number of DIMMs on each DCT */
+
+/* STATUS Definition */
+#define DCT_STATUS_REGISTERED 3        /* Registered DIMMs support */
+#define DCT_STATUS_OnDimmMirror 24     /* OnDimmMirror support */
+
+/* PCI Defintions */
+#define FUN_HT 0         /* Funtion 0 Access */
+#define FUN_MAP 1        /* Funtion 1 Access */
+#define FUN_DCT 2        /* Funtion 2 Access */
+#define FUN_MISC 3       /* Funtion 3 Access */
+#define FUN_ADD_DCT 0xF          /* Funtion 2 Additional Register Access */
+#define BOTH_DCTS 2      /* The access is independent of DCTs */
+#define PCI_MIN_LOW 0    /* Lowest possible PCI register location */
+#define PCI_MAX_HIGH 31          /* Highest possible PCI register location */
+
+/*Function 2 */
+/* #define DRAM_INIT 0x7C */
+#define DRAM_MRS_REGISTER 0x84
+#define DRAM_CONFIG_HIGH 0x94
+#define DRAM_CONTROLLER_ADD_DATA_OFFSET_REG 0x98
+#define DRAM_CONTROLLER_ADD_DATA_PORT_REG 0x9C
+
+/*Function 2 Additional DRAM control registers */
+#define DRAM_ADD_DCT_PHY_CONTROL_REG 0x8
+#define DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 0x30
+#define DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 0x40
+#define DRAM_CONT_ADD_PHASE_REC_CTRL_LOW 0x50
+#define DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH 0x51
+#define DRAM_CONT_ADD_ECC_PHASE_REC_CTRL 0x52
+#define DRAM_CONT_ADD_WRITE_LEV_ERROR_REG 0x53
+
+/* CPU Register defintions */
+
+/* Register Bit Location */
+#define DctAccessDone 31
+#define DctAccessWrite 30
+#define RDqsEn 12
+#define TrDimmSelStart 4
+#define TrDimmSelEnd 5
+#define WrLvTrMode 1
+#define TrNibbleSel 2
+#define WrLvOdtEn 12
+#define WrLvErrStart 0
+#define WrLvErrEnd 8
+#define SendMrsCmd 26
+#define Qoff 12
+#define MRS_Level 7
+#define MrsAddressStart 0
+#define MrsAddressEnd 15
+#define MrsBankStart 16
+#define MrsBankEnd 18
+#define MrsChipSelStart 20
+#define MrsChipSelEnd 22
+#define ASR 18
+#define SRT 19
+#define DramTermDynStart 10
+#define DramTermDynEnd 11
+#define WrtLvTrMode 1
+#define TrNibbleSel 2
+#define TrDimmSelStart 4
+#define TrDimmSelEnd 5
+#define WrtLvTrEn 0
+#define DrvImpCtrlStart 2
+#define DrvImpCtrlEnd 3
+#define DramTermNbStart 7
+#define DramTermNbEnd 9
+#define onDimmMirror 3
+
+typedef struct _sMCTStruct
+{
+       u8 PlatMaxTotalDimms;                   /* IBV defined total number of DIMMs */
+                                               /* on a particular node */
+       u8 PlatMaxDimmsDct;                     /* IBV defined maximum number of */
+                                               /* DIMMs on a DCT */
+       void (*AgesaDelay)(u32 delayval);       /* IBV defined Delay Function */
+} sMCTStruct;
+
+/* DCT 0 and DCT 1 Data structure */
+typedef struct _sDCTStruct
+{
+       u8 NodeId;                      /* Node ID */
+       u8 DctTrain;                    /* Current DCT being trained */
+       u8 CurrDct;                     /* Current DCT number (0 or 1) */
+       u8 DctCSPresent;                /* Current DCT CS mapping */
+       u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write Levelization Gross Delay */
+                                                       /* per byte Lane Per Logical DIMM*/
+       u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];      /* Write Levelization Fine Delay */
+                                                       /* per byte Lane Per Logical DIMM*/
+       u16 RegMan1Present;
+       u8 DimmPresent[MAX_TOTAL_DIMMS];/* Indicates which DIMMs are present */
+                                       /* from Total Number of DIMMs(per Node)*/
+       u8 DimmX8Present[MAX_TOTAL_DIMMS];      /* Which DIMMs x8 devices */
+       u8 Status[MAX_STATUS];          /* Status for DCT0 and 1 */
+       u8 ErrCode[MAX_ERRORS];         /* Major Error codes for DCT0 and 1 */
+       u8 ErrStatus[MAX_ERRORS];       /* Minor Error codes for DCT0 and 1 */
+       u8 DimmValid[MAX_TOTAL_DIMMS];  /* Indicates which DIMMs are valid for */
+                                       /* Total Number of DIMMs(per Node) */
+       u8 WLTotalDelay[MAX_BYTE_LANES];/* Write Levelization Toral Delay */
+                                       /* per byte lane */
+       u8 MaxDimmsInstalled;           /* Max Dimms Installed for current DCT */
+       u8 DimmRanks[MAX_TOTAL_DIMMS];  /* Total Number of Ranks(per Dimm) */
+       u32 LogicalCPUID;
+       u8 WLPass;
+} sDCTStruct;
+
+#endif
index 632b581289c7bed1c80202eee9e065a16772f565..a4a87fca01dc7cdacd2ae9f30147411d0ea58c40 100644 (file)
@@ -27,8 +27,10 @@ static u16 mctGet_NVbits(u8 index)
        case NV_PACK_TYPE:
 #if CONFIG_CPU_SOCKET_TYPE == 0x10     /* Socket F */
                val = 0;
-#elif CONFIG_CPU_SOCKET_TYPE == 0x11   /* AM2r2 */
+#elif CONFIG_CPU_SOCKET_TYPE == 0x11   /* AM3 */
                val = 1;
+#elif CONFIG_CPU_SOCKET_TYPE == 0x13   /* ASB2 */
+               val = 4;
 //#elif SYSTEM_TYPE == MOBILE
 //             val = 2;
 #endif
@@ -400,9 +402,21 @@ static void vErrata350(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTs
 
 static void mctHookBeforeAnyTraining(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 {
-       if (pDCTstatA->LogicalCPUID & (AMD_RB_C2 | AMD_DA_C2)) {
+#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+       if (pDCTstatA->LogicalCPUID & (AMD_RB_C2 | AMD_DA_C2 | AMD_DA_C3)) {
                vErrata350(pMCTstat, pDCTstatA);
        }
+#endif
+}
+
+static u32 mct_AdjustSPDTimings(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u32 val)
+{
+       if (pDCTstatA->LogicalCPUID & AMD_DR_Bx) {
+               if (pDCTstatA->Status & (1 << SB_Registered)) {
+                       val ++;
+               }
+       }
+       return val;
 }
 
 static void mctHookAfterAnyTraining(void)
@@ -418,3 +432,4 @@ static u8 mctSetNodeBoundary_D(void)
 {
        return 0;
 }
+