Index: src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c	(revision 0)
@@ -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);
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c	(revision 0)
@@ -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);
+		}
+	}
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c	(revision 0)
@@ -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;
+	}
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mport_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mport_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mport_d.c	(revision 0)
@@ -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);
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctprob.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctprob.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctprob.c	(revision 0)
@@ -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);
+	}
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctproc.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c	(revision 0)
@@ -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);
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c	(revision 0)
@@ -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;
+	}
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h	(revision 0)
@@ -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: src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c	(revision 0)
@@ -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");
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c	(revision 0)
@@ -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;
+	}
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c	(revision 0)
@@ -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");
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctrci.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctrci.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c	(revision 0)
@@ -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);
+	}
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c	(revision 0)
@@ -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");
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctwl.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctwl.c	(revision 0)
@@ -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 */
+	}
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c	(revision 0)
@@ -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));
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c	(revision 0)
@@ -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 );
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h	(revision 0)
@@ -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
Index: src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c	(revision 0)
@@ -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);
+}
Index: src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
===================================================================
--- src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c	(revision 0)
+++ src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c	(revision 0)
@@ -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;
+}
Index: src/northbridge/amd/amdmct/wrappers/mcti_d.c
===================================================================
--- src/northbridge/amd/amdmct/wrappers/mcti_d.c	(revision 5474)
+++ src/northbridge/amd/amdmct/wrappers/mcti_d.c	(working copy)
@@ -27,8 +27,10 @@
 	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,11 +402,23 @@
 
 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 @@
 {
 	return 0;
 }
+
Index: src/northbridge/amd/amdmct/amddefs.h
===================================================================
--- src/northbridge/amd/amdmct/amddefs.h	(revision 5474)
+++ src/northbridge/amd/amdmct/amddefs.h	(working copy)
@@ -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
@@ -60,9 +62,12 @@
 #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
  */
Index: src/northbridge/amd/amdfam10/raminit_amdmct.c
===================================================================
--- src/northbridge/amd/amdfam10/raminit_amdmct.c	(revision 5474)
+++ src/northbridge/amd/amdfam10/raminit_amdmct.c	(working copy)
@@ -30,9 +30,57 @@
 	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"
 #include "../amdmct/mct/mct_d.h"
 #include "../amdmct/mct/mct_d_gcc.h"
 
@@ -65,6 +113,8 @@
 
 #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 @@
 	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: src/northbridge/amd/amdfam10/amdfam10.h
===================================================================
--- src/northbridge/amd/amdfam10/amdfam10.h	(revision 5474)
+++ src/northbridge/amd/amdfam10/amdfam10.h	(working copy)
@@ -996,7 +996,11 @@
 	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 {
