Initial AMD Barcelona support for rev Bx.
These are the core files for HyperTransport, DDR2 Memory, and multi-core initialization.

Signed-off-by: Marc Jones <marc.jones@amd.com>
Reviewed-by: Jordan Crouse <jordan.crouse@amd.com>

Index: LinuxBIOSv2/src/northbridge/amd/amdmct/amddefs.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/amddefs.h	2007-12-12 11:55:52.000000000 -0700
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+/* Public Revisions - USE THESE VERSIONS TO MAKE COMPARE WITH CPULOGICALID RETURN VALUE*/
+#define	AMD_SAFEMODE	0x80000000	/* Unknown future revision - SAFE MODE */
+#define	AMD_NPT_F0	0x00000001	/* F0 stepping */
+#define	AMD_NPT_F1	0x00000002	/* F1 stepping */
+#define	AMD_NPT_F2C	0x00000004
+#define	AMD_NPT_F2D	0x00000008
+#define	AMD_NPT_F2E	0x00000010	/* F2 stepping E */
+#define	AMD_NPT_F2G	0x00000020	/* F2 stepping G */
+#define	AMD_NPT_F2J	0x00000040
+#define	AMD_NPT_F2K	0x00000080
+#define	AMD_NPT_F3L	0x00000100	/* F3 Stepping */
+#define	AMD_NPT_G0A	0x00000200	/* G0 stepping */
+#define	AMD_NPT_G1B	0x00000400	/* G1 stepping */
+#define	AMD_DR_A0A	0x00010000	/* Barcelona A0 */
+#define	AMD_DR_A1B	0x00020000	/* Barcelona A1 */
+#define	AMD_DR_A2	0x00040000	/* Barcelona A2 */
+#define	AMD_DR_B0	0x00080000	/* Barcelona B0 */
+#define	AMD_DR_B1	0x00100000	/* Barcelona B1 */
+#define	AMD_DR_B2	0x00200000	/* Barcelona B2 */
+#define	AMD_DR_BA	0x00400000	/* Barcelona BA */
+
+/*
+ Groups - Create as many as you wish, from the above public values
+*/
+#define	AMD_NPT_F2	(AMD_NPT_F2C + AMD_NPT_F2D + AMD_NPT_F2E + AMD_NPT_F2G + AMD_NPT_F2J + AMD_NPT_F2K)
+#define	AMD_NPT_F3	(AMD_NPT_F3L)
+#define	AMD_NPT_Fx	(AMD_NPT_F0 + AMD_NPT_F1 + AMD_NPT_F2 + AMD_NPT_F3)
+#define	AMD_NPT_Gx	(AMD_NPT_G0A + AMD_NPT_G1B)
+#define	AMD_NPT_ALL	(AMD_NPT_Fx + AMD_NPT_Gx)
+#define	AMD_DR_Ax	(AMD_DR_A0A + AMD_DR_A1B + AMD_DR_A2)
+#define	AMD_FINEDELAY	(AMD_NPT_F0 + AMD_NPT_F1 + AMD_NPT_F2)
+#define	AMD_GT_F0	(AMD_NPT_ALL AND NOT AMD_NPT_F0)
+
+
+#define CPUID_EXT_PM		0x80000007
+
+#define CPUID_MODEL		1
+
+
+#define HWCR			0xC0010015
+
+
+#define FidVidStatus		0xC0010042
+
+
+#define FS_Base		0xC0000100
+
+
+#define BU_CFG			0xC0011023
+#define BU_CFG2		0xC001102A
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_d.c	2007-12-12 14:39:29.000000000 -0700
@@ -0,0 +1,3862 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 2 */
+
+
+/* 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 ResetNBECCstat_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 u8 Get_DefTrc_k_D(u8 k);
+static u16 Get_40Tk_D(u8 k);
+static u16 Get_Fk_D(u8 k);
+static u8 Dimm_Supports_D(struct DCTStatStruc *pDCTstat, u8 i, u8 j, u8 k);
+static u8 Sys_Capability_D(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstat, int j, int 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 u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat, u8 dct,
+				u32 dev, u32 index_reg, u32 index);
+static u8 Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
+					u32 dev, u32 index_reg);
+static u8 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 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 WaitRoutine_D(u32 time);
+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);
+
+
+/*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 Table_T_k[]	= {0x00,0x50,0x3D,0x30,0x25, 0x18 };
+static const u8 Table_CL2_j[]	= {0x04,0x08,0x10,0x20,0x40, 0x80 };
+static const u8 Tab_defTrc_k[]	= {0x0,0x41,0x3C,0x3C,0x3A, 0x3A };
+static const u16 Tab_40T_k[]	= {00,200,150,120,100,75 };
+static const u8 Tab_TrefT_k[]	= {00,0,1,1,2,2,3,4,5,6,0,0};
+static const u8 Tab_BankAddr[]	= {0x0,0x08,0x09,0x10,0x0C,0x0D,0x11,0x0E,0x15,0x16,0x0F,0x17};
+static const u8 Tab_tCL_j[]	= {0,2,3,4,5};
+static const u8 Tab_1KTfawT_k[] = {00,8,10,13,14,20};
+static const u8 Tab_2KTfawT_k[] = {00,10,14,17,18,24};
+static const u8 Tab_L1CLKDis[]	= {8,8,6,4,2,0,8,8};
+static const u8 Tab_M2CLKDis[]	= {2,0,8,8,2,0,2,0};
+static const u8 Tab_S1CLKDis[]	= {8,0,8,8,8,0,8,0};
+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};
+
+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 toaccessing 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.
+	 *
+	 * Run-Time Requirements:
+	 * 1. Complete Hypertransport Bus Configuration
+	 * 2. SMBus Controller Initialized
+	 * 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:
+	 * 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
+	 */
+	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;
+
+		print_tx("mctAutoInitMCT_D: mct_init Node ", Node);
+		mct_init(pMCTstat, pDCTstat);
+		mctNodeIDDebugPort_D();
+		pDCTstat->NodePresent = NodePresent_D(Node);
+		if (pDCTstat->NodePresent) {		/* See if Node is there*/
+			print_t("mctAutoInitMCT_D: clear_legacy_Mode\n");
+			clear_legacy_Mode(pMCTstat, pDCTstat);
+			pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
+
+			print_t("mctAutoInitMCT_D: mct_InitialMCT_D\n");
+			mct_InitialMCT_D(pMCTstat, pDCTstat);
+
+			print_t("mctAutoInitMCT_D: mctSMBhub_Init\n");
+			mctSMBhub_Init(Node);		/* Switch SMBUS crossbar to proper node*/
+
+			print_t("mctAutoInitMCT_D: mct_initDCT\n");
+			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) {
+		print_debug("No Nodes?!\n");
+		goto fatalexit;
+	}
+
+	print_t("mctAutoInitMCT_D: SyncDCTsReady_D\n");
+	SyncDCTsReady_D(pMCTstat, pDCTstatA);	/* Make sure DCTs are ready for accesses.*/
+
+	print_t("mctAutoInitMCT_D: HTMemMapInit_D\n");
+	HTMemMapInit_D(pMCTstat, pDCTstatA);	/* Map local memory into system address space.*/
+	mctHookAfterHTMap();
+
+	print_t("mctAutoInitMCT_D: CPUMemTyping_D\n");
+	CPUMemTyping_D(pMCTstat, pDCTstatA);	/* Map dram into WB/UC CPU cacheability */
+	mctHookAfterCPU();			/* Setup external northbridge(s) */
+
+	print_t("mctAutoInitMCT_D: DQSTiming_D\n");
+	DQSTiming_D(pMCTstat, pDCTstatA);	/* Get Receiver Enable and DQS signal timing*/
+
+	print_t("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);
+
+	print_t("mctAutoInitMCT_D: ECCInit_D\n");
+	if (ECCInit_D(pMCTstat, pDCTstatA)) {		/* Setup ECC control and ECC check-bits*/
+		print_t("mctAutoInitMCT_D: MCTMemClr_D\n");
+		MCTMemClr_D(pMCTstat,pDCTstatA);
+	}
+
+	mct_FinalMCT_D(pMCTstat, (pDCTstatA + 0) );	// Node 0
+	print_t("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;
+
+	if (nv_DQSTrainCTL) {
+		print_t("DQSTiming_D: mct_BeforeDQSTrain_D:\n");
+		mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);;
+		phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
+		mctHookBeforeAnyTraining();
+
+		print_t("DQSTiming_D: TrainReceiverEn_D FirstPass:\n");
+		TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
+
+		print_t("DQSTiming_D: mct_TrainDQSPos_D\n");
+		mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
+
+		// Second Pass never used for Barcelona!
+		//print_t("DQSTiming_D: TrainReceiverEn_D SecondPass:\n");
+		//TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass);
+
+		print_t("DQSTiming_D: mctSetEccDQSRcvrEn_D\n");
+		mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
+
+		print_t("DQSTiming_D: TrainMaxReadLatency_D\n");
+//FIXME - currently uses calculated value		TrainMaxReadLatency_D(pMCTstat, pDCTstatA);
+		mctHookAfterAnyTraining();
+		mctSaveDQSSigTmg_D();
+
+		print_t("DQSTiming_D: mct_EndDQSTraining_D\n");
+		mct_EndDQSTraining_D(pMCTstat, pDCTstatA);
+
+		print_t("DQSTiming_D: MCTMemClr_D\n");
+		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;
+
+
+	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 ? */
+
+				}
+			}
+			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 < 2; 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 ResetNBECCstat_D(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstatA)
+{
+	/* Clear MC4_STS for all Nodes in the system.  This is required in some
+	 * circumstances to clear left over garbage from cold reset, shutdown,
+	 * or normal ECC memory conditioning.
+	 */
+
+	//FIXME: this function depends on pDCTstat Array ( with Node id ) - Is this really a problem?
+
+	u32 dev;
+	u8 Node;
+
+	for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+		struct DCTStatStruc *pDCTstat;
+		pDCTstat = pDCTstatA + Node;
+
+		if (pDCTstat->NodePresent) {
+			dev = pDCTstat->dev_nbmisc;
+			/*MCA NB Status Low (alias to MC4_STS[31:0] */
+			Set_NB32(dev, 0x48, 0);
+			/* MCA NB Status High (alias to MC4_STS[63:32] */
+			Set_NB32(dev, 0x4C, 0);
+		}
+	}
+}
+
+
+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;
+	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++) {
+		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_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(dev, 0xF0, val); /*Dram Hole Address Register*/
+					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 DstNode*/
+		Set_NB32(dev, 0x44 + (Node << 3), val);	/* set DstNode */
+
+		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++) {
+		pDCTstat = pDCTstatA + Node;
+		u32 reg;
+		u32 devx = pDCTstat->dev_map;
+
+		if (pDCTstat->NodePresent) {
+		printk_debug(" Copy dram map from Node 0 to Node %02x \n", Node);
+			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' */
+	if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
+		print_t("\t\tDCTInit_D: mct_DIMMPresence Done\n");
+		if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
+			print_t("\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
+			if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+				print_t("\t\tDCTInit_D: AutoCycTiming_D Done\n");
+				if (AutoConfig_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+					print_t("\t\tDCTInit_D: AutoConfig_D Done\n");
+					if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+						print_t("\t\tDCTInit_D: PlatformSpec_D Done\n");
+						stopDCTflag = 0;
+						if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
+							print_t("\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);
+	}
+}
+
+
+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;
+
+	for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+		struct DCTStatStruc *pDCTstat;
+		pDCTstat = pDCTstatA + Node;
+		mct_SyncDCTsReady(pDCTstat);
+	}
+}
+
+
+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;
+	u8 byte;
+	u32 reg;
+	u32 reg_off = dct * 0x100;
+
+	dev = pDCTstat->dev_dct;
+	val = Get_NB32(dev, 0x94 + reg_off);
+	if (val & (1<<MemClkFreqVal)) {
+		print_t("\t\t\tStartupDCT_D: MemClkFreqVal\n");
+		byte = mctGet_NVbits(NV_DQSTrainCTL);
+		if (byte == 1) {
+			/* Enable DQSRcvEn training mode */
+			print_t("\t\t\tStartupDCT_D: DqsRcvEnTrain set \n");
+			reg = 0x78 + reg_off;
+			val = Get_NB32(dev, reg);
+			/* Setting this bit forces a 1T window with hard left
+			 * pass/fail edge and a probabalistic right pass/fail
+			 * edge.  LEFT edge is referenced for final
+			 * receiver enable position.*/
+			val |= 1 << DqsRcvEnTrain;
+			Set_NB32(dev, reg, val);
+		}
+		mctHookBeforeDramInit();	/* generalized Hook */
+		print_t("\t\t\tStartupDCT_D: DramInit \n");
+		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 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'.
+	 */
+
+	u8 i;
+	u8 Twr, Trtp;
+	u8 Trp, Trrd, Trcd, Tras, Trc, Trfc[4], Rows;
+	u32 DramTimingLo, DramTimingHi;
+	u16 Tk10, Tk40;
+	u8 Twtr;
+	u8 LDIMM;
+	u8 DDR2_1066;
+	u8 byte;
+	u32 dword;
+	u32 dev;
+	u32 reg;
+	u32 reg_off;
+	u32 val;
+	u16 smbaddr;
+
+	/* 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;
+
+		/* if "manual" memclock mode */
+		if ( mctGet_NVbits(NV_MCTUSRTMGMODE) == 2)
+			pDCTstat->Speed = mctGet_NVbits(NV_MemCkVal) + 1;
+
+		mct_AfterGetCLT(pMCTstat, pDCTstat, dct);
+	}
+
+	/* Gather all DIMM mini-max values for cycle timing data */
+	Rows = 0;
+	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;
+
+	for ( i = 0; i< MAX_DIMMS_SUPPORTED; i++) {
+		LDIMM = i >> 1;
+		if (pDCTstat->DIMMValid & (1 << i)) {
+			smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+			byte = mctRead_SPD(smbaddr, SPD_ROWSZ);
+			if (Rows < byte)
+				Rows = byte;	/* keep track of largest row sz */
+
+			byte = mctRead_SPD(smbaddr, SPD_TRP);
+			if (Trp < byte)
+				Trp = byte;
+
+			byte = mctRead_SPD(smbaddr, SPD_TRRD);
+			if (Trrd < byte)
+				Trrd = byte;
+
+			byte = mctRead_SPD(smbaddr, SPD_TRCD);
+			if (Trcd < byte)
+				Trcd = byte;
+
+			byte = mctRead_SPD(smbaddr, SPD_TRTP);
+			if (Trtp < byte)
+				Trtp = byte;
+
+			byte = mctRead_SPD(smbaddr, SPD_TWR);
+			if (Twr < byte)
+				Twr = byte;
+
+			byte = mctRead_SPD(smbaddr, SPD_TWTR);
+			if (Twtr < byte)
+				Twtr = byte;
+
+			val = mctRead_SPD(smbaddr, SPD_TRC);
+			if ((val == 0) || (val == 0xFF)) {
+				pDCTstat->ErrStatus |= 1<<SB_NoTrcTrfc;
+				pDCTstat->ErrCode = SC_VarianceErr;
+				val = Get_DefTrc_k_D(pDCTstat->DIMMAutoSpeed);
+			} else {
+				byte = mctRead_SPD(smbaddr, SPD_TRCRFC);
+				if (byte & 0xF0) {
+					val++;	/* round up in case fractional extention is non-zero.*/
+				}
+		}
+		if (Trc < val)
+			Trc = val;
+
+		/* dev density=rank size/#devs per rank */
+		byte = mctRead_SPD(smbaddr, SPD_BANKSZ);
+
+		val = ((byte >> 5) | (byte << 3)) & 0xFF;
+		val <<= 2;
+
+		byte = mctRead_SPD(smbaddr, SPD_DEVWIDTH) & 0xFE;     /* dev density=2^(rows+columns+banks) */
+		if (byte == 4) {
+			val >>= 4;
+		} else if (byte == 8) {
+			val >>= 3;
+		} else if (byte == 16) {
+			val >>= 2;
+		}
+
+		byte = bsr(val);
+
+		if (Trfc[LDIMM] < byte)
+			Trfc[LDIMM] = byte;
+
+		byte = mctRead_SPD(smbaddr, SPD_TRAS);
+		if (Tras < byte)
+			Tras = byte;
+		}	/* Dimm Present */
+	}
+
+	/* Convert  DRAM CycleTiming values and store into DCT structure */
+	DDR2_1066 = 0;
+	byte = pDCTstat->DIMMAutoSpeed;
+	if (byte == 5)
+		DDR2_1066 = 1;
+	Tk40 = Get_40Tk_D(byte);
+	Tk10 = Tk40>>2;
+
+	/* Notes:
+	 1. All secondary time values given in SPDs are in binary with units of ns.
+	 2. Some time values are scaled by four, in order to have least count of 0.25 ns
+	    (more accuracy).  JEDEC SPD spec. shows which ones are x1 and x4.
+	 3. Internally to this SW, cycle time, Tk, is scaled by 10 to affect a
+	    least count of 0.1 ns (more accuracy).
+	 4. SPD values not scaled are multiplied by 10 and then divided by 10T to find
+	    equivalent minimum number of bus clocks (a remainder causes round-up of clocks).
+	 5. SPD values that are prescaled by 4 are multiplied by 10 and then divided by 40T to find
+	    equivalent minimum number of bus clocks (a remainder causes round-up of clocks).*/
+
+	/* Tras */
+	dword = Tras * 40;
+	pDCTstat->DIMMTras = (u16)dword;
+	val = dword / Tk40;
+	if (dword % Tk40) {	/* round up number of busclocks */
+		val++;
+	}
+	if (DDR2_1066) {
+		if (val < Min_TrasT_1066)
+			val = Min_TrasT_1066;
+		else if (val > Max_TrasT_1066)
+			val = Max_TrasT_1066;
+	} else {
+		if (val < Min_TrasT)
+			val = Min_TrasT;
+		else if (val > Max_TrasT)
+			val = Max_TrasT;
+	}
+	pDCTstat->Tras = val;
+
+	/* Trp */
+	dword = Trp * 10;
+	pDCTstat->DIMMTrp = dword;
+	val = dword / Tk40;
+	if (dword % Tk40) {	/* round up number of busclocks */
+		val++;
+	}
+	if (DDR2_1066) {
+		if (val < Min_TrasT_1066)
+			val = Min_TrpT_1066;
+		else if (val > Max_TrpT_1066)
+			val = Max_TrpT_1066;
+	} else {
+		if (val < Min_TrpT)
+			val = Min_TrpT;
+		else if (val > Max_TrpT)
+			val = Max_TrpT;
+	}
+	pDCTstat->Trp = val;
+
+	 /*Trrd*/
+	dword = Trrd * 10;
+	pDCTstat->DIMMTrrd = dword;
+	val = dword / Tk40;
+	if (dword % Tk40) {	/* round up number of busclocks */
+		val++;
+	}
+	if (DDR2_1066) {
+		if (val < Min_TrrdT_1066)
+			val = Min_TrrdT_1066;
+		else if (val > Max_TrrdT_1066)
+			val = Max_TrrdT_1066;
+	} else {
+		if (val < Min_TrrdT)
+			val = Min_TrrdT;
+		else if (val > Max_TrrdT)
+			val = Max_TrrdT;
+	}
+	pDCTstat->Trrd = val;
+
+	/* Trcd */
+	dword = Trcd * 10;
+	pDCTstat->DIMMTrcd = dword;
+	val = dword / Tk40;
+	if (dword % Tk40) {	/* round up number of busclocks */
+		val++;
+	}
+	if (DDR2_1066) {
+		if (val < Min_TrcdT_1066)
+			val = Min_TrcdT_1066;
+		else if (val > Max_TrcdT_1066)
+			val = Max_TrcdT_1066;
+	} else {
+		if (val < Min_TrcdT)
+			val = Min_TrcdT;
+		else if (val > Max_TrcdT)
+			val = Max_TrcdT;
+	}
+	pDCTstat->Trcd = val;
+
+	/* Trc */
+	dword = Trc * 40;
+	pDCTstat->DIMMTrc = dword;
+	val = dword / Tk40;
+	if (dword % Tk40) {	/* round up number of busclocks */
+		val++;
+	}
+	if (DDR2_1066) {
+		if (val < Min_TrcT_1066)
+			val = Min_TrcT_1066;
+		else if (val > Max_TrcT_1066)
+			val = Max_TrcT_1066;
+	} else {
+		if (val < Min_TrcT)
+			val = Min_TrcT;
+		else if (val > Max_TrcT)
+			val = Max_TrcT;
+	}
+	pDCTstat->Trc = val;
+
+	/* Trtp */
+	dword = Trtp * 10;
+	pDCTstat->DIMMTrtp = dword;
+	val = pDCTstat->Speed;
+	if (val <= 2) {
+		val = 2;	/* Calculate by 7.75ns / Speed in ns to get clock # */
+	} else if (val == 4) {	/* Note a speed of 3 will be a Trtp of 3 */
+		val = 3;
+	} else if (val == 5){
+		val = 2;
+	}
+	pDCTstat->Trtp = val;
+
+	/* Twr */
+	dword = Twr * 10;
+	pDCTstat->DIMMTwr = dword;
+	val = dword / Tk40;
+	if (dword % Tk40) {	/* round up number of busclocks */
+		val++;
+	}
+	if (DDR2_1066) {
+		if (val < Min_TwrT_1066)
+			val = Min_TwrT_1066;
+		else if (val > Max_TwrT_1066)
+			val = Max_TwrT_1066;
+	} else {
+		if (val < Min_TwrT)
+			val = Min_TwrT;
+		else if (val > Max_TwrT)
+			val = Max_TwrT;
+	}
+	pDCTstat->Twr = val;
+
+	/* Twtr */
+	dword = Twtr * 10;
+	pDCTstat->DIMMTwtr = dword;
+	val = dword / Tk40;
+	if (dword % Tk40) {	/* round up number of busclocks */
+		val++;
+	}
+	if (DDR2_1066) {
+		if (val < Min_TwrT_1066)
+			val = Min_TwtrT_1066;
+		else if (val > Max_TwtrT_1066)
+			val = Max_TwtrT_1066;
+	} else {
+		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];
+
+	mctAdjustAutoCycTmg_D();
+
+	/* Program DRAM Timing values */
+	DramTimingLo = 0;	/* Dram Timing Low init */
+	val = pDCTstat->CASL;
+	val = Tab_tCL_j[val];
+	DramTimingLo |= val;
+
+	val = pDCTstat->Trcd;
+	if (DDR2_1066)
+		val -= Bias_TrcdT_1066;
+	else
+		val -= Bias_TrcdT;
+
+	DramTimingLo |= val<<4;
+
+	val = pDCTstat->Trp;
+	if (DDR2_1066)
+		val -= Bias_TrpT_1066;
+	else {
+		val -= Bias_TrpT;
+		val <<= 1;
+	}
+	DramTimingLo |= val<<7;
+
+	val = pDCTstat->Trtp;
+	val -= Bias_TrtpT;
+	DramTimingLo |= val<<11;
+
+	val = pDCTstat->Tras;
+	if (DDR2_1066)
+		val -= Bias_TrasT_1066;
+	else
+		val -= Bias_TrasT;
+	DramTimingLo |= val<<12;
+
+	val = pDCTstat->Trc;
+	val -= Bias_TrcT;
+	DramTimingLo |= val<<16;
+
+	if (!DDR2_1066) {
+		val = pDCTstat->Twr;
+		val -= Bias_TwrT;
+		DramTimingLo |= val<<20;
+	}
+
+	val = pDCTstat->Trrd;
+	if (DDR2_1066)
+		val -= Bias_TrrdT_1066;
+	else
+		val -= Bias_TrrdT;
+	DramTimingLo |= val<<22;
+
+
+	DramTimingHi = 0;	/* Dram Timing Low init */
+	val = pDCTstat->Twtr;
+	if (DDR2_1066)
+		val -= Bias_TwtrT_1066;
+	else
+		val -= 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;
+	print_tx("AutoCycTiming: DramTimingLo ", DramTimingLo);
+	print_tx("AutoCycTiming: DramTimingHi ", DramTimingHi);
+
+	Set_NB32(dev, 0x88 + reg_off, DramTimingLo);	/*DCT Timing Low*/
+	DramTimingHi |=0x0000FC77;
+	Set_NB32(dev, 0x8c + reg_off, DramTimingHi);	/*DCT Timing Hi*/
+
+	if (DDR2_1066) {
+		/* Twr */
+		dword = pDCTstat->Twr;
+		dword -= Bias_TwrT_1066;
+		dword <<= 4;
+		reg = 0x84 + reg_off;
+		val = Get_NB32(dev, reg);
+		val &= 0x8F;
+		val |= dword;
+		Set_NB32(dev, reg, val);
+	}
+//	dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2));
+
+	print_tx("AutoCycTiming: Status ", pDCTstat->Status);
+	print_tx("AutoCycTiming: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("AutoCycTiming: ErrCode ", pDCTstat->ErrCode);
+	print_t("AutoCycTiming: Done\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;
+	}
+}
+
+
+
+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).
+	 */
+	int i, j, k;
+	u8 T1min, CL1min;
+
+	/* i={0..7} (std. physical DIMM number)
+	 * j is an integer which enumerates increasing CAS latency.
+	 * k is an integer which enumerates decreasing cycle time.
+	 * CL no. {0,1,2} corresponds to CL X, CL X-.5, or CL X-1 (per individual DIMM)
+	 * Max timing values are per parameter, of all DIMMs, spec'd in ns like the SPD.
+	 */
+
+	CL1min = 0xFF;
+	T1min = 0xFF;
+	for (k=K_MAX; k >= K_MIN; k--) {
+		for (j = J_MIN; j <= J_MAX; j++) {
+			if (Sys_Capability_D(pMCTstat, pDCTstat, j, k) ) {
+				/* 1. check to see if DIMMi is populated.
+				   2. check if DIMMi supports CLj and Tjk */
+				for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
+					if (pDCTstat->DIMMValid & (1 << i)) {
+						if (Dimm_Supports_D(pDCTstat, i, j, k))
+							break;
+					}
+				}	/* while ++i */
+				if (i == MAX_DIMMS_SUPPORTED) {
+					T1min = k;
+					CL1min = j;
+					goto got_TCL;
+				}
+			}
+		}	/* while ++j */
+	}	/* while --k */
+
+got_TCL:
+	if (T1min != 0xFF) {
+		pDCTstat->DIMMCASL = CL1min;	/*mfg. optimized */
+		pDCTstat->DIMMAutoSpeed = T1min;
+		print_tx("SPDGetTCL_D: DIMMCASL ", pDCTstat->DIMMCASL);
+		print_tx("SPDGetTCL_D: DIMMAutoSpeed ", pDCTstat->DIMMAutoSpeed);
+
+	} else {
+		pDCTstat->DIMMCASL = CL_DEF;	/* failsafe values (running in min. mode) */
+		pDCTstat->DIMMAutoSpeed = T_DEF;
+		pDCTstat->ErrStatus |= 1 << SB_DimmMismatchT;
+		pDCTstat->ErrStatus |= 1 << SB_MinimumMode;
+		pDCTstat->ErrCode = SC_VarianceErr;
+	}
+	print_tx("SPDGetTCL_D: Status ", pDCTstat->Status);
+	print_tx("SPDGetTCL_D: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("SPDGetTCL_D: ErrCode ", pDCTstat->ErrCode);
+	print_t("SPDGetTCL_D: Done\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) {
+		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);
+	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;
+
+	print_tx("AutoConfig_D: DCT: ", dct);
+
+	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*/
+
+	if (mctGet_NVbits(NV_CLKHZAltVidC3))
+		DramControl |= 1<<16;
+
+	// FIXME: Add support(skip) for Ax and Cx versions
+	DramControl |= 5;	/* RdPtrInit */
+
+
+	/* Build Dram Config Lo Register Value */
+	DramConfigLo |= 1 << 4;					/* 75 Ohms ODT */
+	if (mctGet_NVbits(NV_MAX_DIMMS) == 8) {
+		if (pDCTstat->Speed == 3) {
+			if ((pDCTstat->MAdimms[dct] == 4))
+				DramConfigLo |= 1 << 5;		/* 50 Ohms ODT */
+		} else if (pDCTstat->Speed == 4){
+			if ((pDCTstat->MAdimms[dct] != 1))
+				DramConfigLo |= 1 << 5;		/* 50 Ohms ODT */
+		}
+	} else {
+		// FIXME: Skip for Ax versions
+		if ((pDCTstat->MAdimms[dct] == 4)) {
+			if ( pDCTstat->DimmQRPresent != 0) {
+				if ((pDCTstat->Speed == 3) || (pDCTstat->Speed == 4)) {
+					DramConfigLo |= 1 << 5;	/* 50 Ohms ODT */
+				}
+			} else if ((pDCTstat->MAdimms[dct] == 4)) {
+				if (pDCTstat->Speed == 4) {
+					if ( pDCTstat->DimmQRPresent != 0) {
+						DramConfigLo |= 1 << 5;	/* 50 Ohms ODT */
+					}
+				}
+			}
+		} else if ((pDCTstat->MAdimms[dct] == 2)) {
+			DramConfigLo |= 1 << 5;		/* 50 Ohms ODT */
+		}
+
+	}
+
+	// FIXME: Skip for Ax versions
+	/* callback not required - if (!mctParityControl_D()) */
+	if (Status & (1 << SB_PARDIMMs)) {
+		DramConfigLo |= 1 << ParEn;
+		DramConfigMisc2 |= 1 << ActiveCmdAtRst;
+	} else {
+		DramConfigLo  &= ~(1 << ParEn);
+		DramConfigMisc2 &= ~(1 << ActiveCmdAtRst);
+	}
+
+	if (mctGet_NVbits(NV_BurstLen32)) {
+		if (!pDCTstat->GangedMode)
+			DramConfigLo |= 1 << BurstLength32;
+	}
+
+	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;
+
+
+
+	/* 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_PDEN)) {
+		DramConfigHi |= 1 << 15;		/* PowerDownEn */
+		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;
+
+	val = pDCTstat->DIMM2Kpage;
+	if (pDCTstat->GangedMode != 0) {
+		if (dct != 0) {
+			val &= 0x55;
+		} else {
+			val &= 0xAA;
+		}
+	}
+	if (val)
+		val = Tab_2KTfawT_k[pDCTstat->Speed];
+	else
+		val = Tab_1KTfawT_k[pDCTstat->Speed];
+
+	if (pDCTstat->Speed == 5)
+		val >>= 1;
+
+	val -= Bias_TfawT;
+	val <<= 28;
+	DramConfigHi |= val;	/* Tfaw for 1K or 2K paged drams */
+
+	// FIXME: Skip for Ax versions
+	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;
+			byte = mctGet_NVbits(NV_PACK_TYPE);
+			if (byte == PT_L1)
+				p = Tab_L1CLKDis;
+			else if (byte == PT_M2)
+				p = Tab_M2CLKDis;
+			else
+				p = Tab_S1CLKDis;
+
+			dword = 0;
+			while(dword < MAX_DIMMS_SUPPORTED) {
+				val = p[dword];
+				print_tx("DramTimingLo: val=", val);
+				if (!(pDCTstat->DIMMValid & (1<<val)))
+					/*disable memclk*/
+					DramTimingLo |= 1<<(dword+24);
+				dword++ ;
+			}
+		}
+	}
+
+	print_tx("AutoConfig_D: DramControl: ", DramControl);
+	print_tx("AutoConfig_D: DramTimingLo: ", DramTimingLo);
+	print_tx("AutoConfig_D: DramConfigMisc: ", DramConfigMisc);
+	print_tx("AutoConfig_D: DramConfigMisc2: ", DramConfigMisc2);
+	print_tx("AutoConfig_D: DramConfigLo: ", DramConfigLo);
+	print_tx("AutoConfig_D: DramConfigHi: ", 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);
+	Set_NB32(dev, 0xA8 + reg_off, DramConfigMisc2);
+	Set_NB32(dev, 0x90 + reg_off, DramConfigLo);
+	mct_SetDramConfigHi_D(pDCTstat, dct, DramConfigHi);
+	mct_ForceAutoPrecharge_D(pDCTstat, dct);
+	mct_EarlyArbEn_D(pMCTstat, pDCTstat);
+	mctHookAfterAutoCfg();
+
+//	dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2));
+
+	print_tx("AutoConfig: Status ", pDCTstat->Status);
+	print_tx("AutoConfig: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("AutoConfig: ErrCode ", pDCTstat->ErrCode);
+	print_t("AutoConfig: Done\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, DevWidth;
+	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_ROWSZ);
+			Rows = byte & 0x1f;
+
+			byte = mctRead_SPD(smbaddr, SPD_COLSZ);
+			Cols = byte & 0x1f;
+
+			Banks = mctRead_SPD(smbaddr, SPD_LBANKS);
+
+			byte = mctRead_SPD(smbaddr, SPD_DEVWIDTH);
+			DevWidth = byte & 0x7f; /* bits 0-6 = bank 0 width */
+
+			byte = mctRead_SPD(smbaddr, SPD_DMBANKS);
+			Ranks = (byte & 7) + 1;
+
+			/* Configure Bank encoding
+			 * Use a 6-bit key into a lookup table.
+			 * Key (index) = CCCBRR, where CCC is the number of
+			 * Columns minus 9,RR is the number of Rows minus 13,
+			 * and B is the number of banks minus 2.
+			 * See "6-bit Bank Addressing Table" at the end of
+			 * this file.*/
+			byte = Cols - 9;	/* 9 Cols is smallest dev size */
+			byte <<= 3;		/* make room for row and bank bits*/
+			if (Banks == 8)
+				byte |= 4;
+
+			/* 13 Rows is smallest dev size */
+			byte |= Rows - 13;	/* CCCBRR internal encode */
+
+			for (dword=0; dword < 12; dword++) {
+				if (byte == Tab_BankAddr[dword])
+					break;
+			}
+
+			if (dword < 12) {
+
+				/* 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*/
+				if (Banks == 8)
+					byte -= 2;		/* 3 banks - 5 */
+				else
+					byte -= 3;		/* 2 banks - 5 */
+								/* mask size (64-bit rank only) */
+
+				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 */
+	SetODTTriState(pMCTstat, pDCTstat, dct);
+
+	if ( pDCTstat->Status & 1<<SB_128bitmode) {
+		SetCSTriState(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);
+
+//	dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2));
+
+	print_tx("SPDSetBanks: Status ", pDCTstat->Status);
+	print_tx("SPDSetBanks: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("SPDSetBanks: ErrCode ", pDCTstat->ErrCode);
+	print_t("SPDSetBanks: Done\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_ROWSZ) & 0x1f;
+			byte1 = mctRead_SPD(smbaddr1, SPD_ROWSZ) & 0x1f;
+			if (byte != byte1) {
+				pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+				break;
+			}
+
+			byte =	 mctRead_SPD(smbaddr, SPD_COLSZ) & 0x1f;
+			byte1 =	 mctRead_SPD(smbaddr1, SPD_COLSZ) & 0x1f;
+			if (byte != byte1) {
+				pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+				break;
+			}
+
+			byte = mctRead_SPD(smbaddr, SPD_BANKSZ);
+			byte1 = mctRead_SPD(smbaddr1, SPD_BANKSZ);
+			if (byte != byte1) {
+				pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+				break;
+			}
+
+			byte = mctRead_SPD(smbaddr, SPD_DEVWIDTH) & 0x7f;
+			byte1 = mctRead_SPD(smbaddr1, SPD_DEVWIDTH) & 0x7f;
+			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 */
+			}
+			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));
+
+	print_tx("StitchMemory: Status ", pDCTstat->Status);
+	print_tx("StitchMemory: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("StitchMemory: ErrCode ", pDCTstat->ErrCode);
+	print_t("StitchMemory: Done\n");
+}
+
+
+static u8 Get_Tk_D(u8 k)
+{
+	return Table_T_k[k];
+}
+
+
+static u8 Get_CLj_D(u8 j)
+{
+	return Table_CL2_j[j];
+}
+
+static u8 Get_DefTrc_k_D(u8 k)
+{
+	return Tab_defTrc_k[k];
+}
+
+
+static u16 Get_40Tk_D(u8 k)
+{
+	return Tab_40T_k[k]; /* FIXME: k or k<<1 ?*/
+}
+
+
+static u16 Get_Fk_D(u8 k)
+{
+	return Table_F_k[k]; /* FIXME: k or k<<1 ? */
+}
+
+
+static u8 Dimm_Supports_D(struct DCTStatStruc *pDCTstat,
+				u8 i, u8 j, u8 k)
+{
+	u8 Tk, CLj, CL_i;
+	u8 ret = 0;
+
+	u32 DIMMi;
+	u8 byte;
+	u16 word, wordx;
+
+	DIMMi = Get_DIMMAddress_D(pDCTstat, i);
+
+	CLj = Get_CLj_D(j);
+
+	/* check if DIMMi supports CLj */
+	CL_i = mctRead_SPD(DIMMi, SPD_CASLAT);
+	byte = CL_i & CLj;
+	if (byte) {
+		/*find out if its CL X, CLX-1, or CLX-2 */
+		word = bsr(byte);	/* bit position of CLj */
+		wordx = bsr(CL_i);	/* bit position of CLX of CLi */
+		wordx -= word;		/* CL number (CL no. = 0,1, 2, or 3) */
+		wordx <<= 3;		/* 8 bits per SPD byte index */
+		/*get T from SPD byte 9, 23, 25*/
+		word = (EncodedTSPD >> wordx) & 0xFF;
+		Tk = Get_Tk_D(k);
+		byte = mctRead_SPD(DIMMi, word);	/* DIMMi speed */
+		if (Tk < byte) {
+			ret = 1;
+		} else if (byte == 0){
+			pDCTstat->ErrStatus |= 1<<SB_NoCycTime;
+			ret = 1;
+		} else {
+			ret = 0;	/* DIMM is capable! */
+		}
+	} else {
+		ret = 1;
+	}
+	return ret;
+}
+
+
+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, Index;
+	u16 Checksum;
+	u8 SPDCtrl;
+	u16 RegDIMMPresent, MaxDimms;
+	u8 devwidth;
+	u16 DimmSlots;
+	u8 byte = 0, bytex;
+	u16 word;
+
+	/* 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)) {
+			print_tx("\t DIMMPresence: i=", i);
+			smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+			print_tx("\t DIMMPresence: smbaddr=", smbaddr);
+			if (smbaddr) {
+				Checksum = 0;
+				for (Index=0; Index < 64; Index++){
+					int status;
+					status = mctRead_SPD(smbaddr, Index);
+					if (status < 0)
+						break;
+					byte = status & 0xFF;
+					if (Index < 63)
+						Checksum += byte;
+				}
+
+				if (Index == 64) {
+					pDCTstat->DIMMPresent |= 1 << i;
+					if ((Checksum & 0xFF) == byte) {
+						byte = mctRead_SPD(smbaddr, SPD_TYPE);
+						if (byte == JED_DDR2SDRAM) {
+							/*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_DDR2SDRAM)
+								pDCTstat->DIMMValid |= 1 << i;
+						}
+					}
+					/* Check module type */
+					byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE);
+					if (byte & JED_REGADCMSK)
+						RegDIMMPresent |= 1 << i;
+					/* Check ECC capable */
+					byte = mctRead_SPD(smbaddr, SPD_EDCTYPE);
+					if (byte & JED_ECC) {
+						/* DIMM is ECC capable */
+						pDCTstat->DimmECCPresent |= 1 << i;
+					}
+					if (byte & JED_ADRCPAR) {
+					/* DIMM is ECC capable */
+					pDCTstat->DimmPARPresent |= 1 << i;
+					}
+					/* Check if x4 device */
+					devwidth = mctRead_SPD(smbaddr, SPD_DEVWIDTH) & 0xFE;
+					if (devwidth == 4) {
+						/* DIMM is made with x4 or x16 drams */
+						pDCTstat->Dimmx4Present |= 1 << i;
+					} else if (devwidth == 8) {
+						pDCTstat->Dimmx8Present |= 1 << i;
+					} else if (devwidth == 16) {
+						pDCTstat->Dimmx16Present |= 1 << i;
+					}
+					/* check page size */
+					byte = mctRead_SPD(smbaddr, SPD_COLSZ);
+					byte &= 0x0F;
+					word = 1 << byte;
+					word >>= 3;
+					word *= devwidth;	/* (((2^COLBITS) / 8) * ORG) / 2048 */
+					word >>= 11;
+					if (word)
+						pDCTstat->DIMM2Kpage |= 1 << i;
+
+					/*Check if SPD diag bit 'analysis probe installed' is set */
+					byte = mctRead_SPD(smbaddr, SPD_ATTRIB);
+					if ( byte & JED_PROBEMSK )
+						pDCTstat->Status |= 1<<SB_DiagClks;
+
+					byte = mctRead_SPD(smbaddr, SPD_DMBANKS);
+					if (!(byte & (1<< SPDPLBit)))
+						pDCTstat->DimmPlPresent |= 1 << i;
+					byte &= 7;
+					byte++;		 /* ranks */
+					if (byte > 2) {
+						/* 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));
+						}
+						byte = 2;	/* upper two ranks of QR DIMM will be counted on another DIMM number iteration*/
+					} else if (byte == 2) {
+						pDCTstat->DimmDRPresent |= 1 << i;
+					}
+					bytex = devwidth;
+					if (devwidth == 16)
+						bytex = 4;
+					else if (devwidth == 4)
+						bytex=16;
+
+					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 for DRAM package Year <= 06*/
+					byte = mctRead_SPD(smbaddr, SPD_MANDATEYR);
+					if (byte < MYEAR06) {
+						/*Year < 06 and hence Week < 24 of 06 */
+						pDCTstat->DimmYr06 |= 1 << i;
+						pDCTstat->DimmWk2406 |= 1 << i;
+					} else if (byte == MYEAR06) {
+						/*Year = 06, check if Week <= 24 */
+						pDCTstat->DimmYr06 |= 1 << i;
+						byte = mctRead_SPD(smbaddr, SPD_MANDATEWK);
+						if (byte <= MWEEK24)
+							pDCTstat->DimmWk2406 |= 1 << i;
+					}
+				}
+			}
+		}
+	}
+	print_tx("\t DIMMPresence: DIMMValid=", pDCTstat->DIMMValid);
+	print_tx("\t DIMMPresence: DIMMPresent=", pDCTstat->DIMMPresent);
+	print_tx("\t DIMMPresence: RegDIMMPresent=", RegDIMMPresent);
+	print_tx("\t DIMMPresence: DimmECCPresent=", pDCTstat->DimmECCPresent);
+	print_tx("\t DIMMPresence: DimmPARPresent=", pDCTstat->DimmPARPresent);
+	print_tx("\t DIMMPresence: Dimmx4Present=", pDCTstat->Dimmx4Present);
+	print_tx("\t DIMMPresence: Dimmx8Present=", pDCTstat->Dimmx8Present);
+	print_tx("\t DIMMPresence: Dimmx16Present=", pDCTstat->Dimmx16Present);
+	print_tx("\t DIMMPresence: DimmPlPresent=", pDCTstat->DimmPlPresent);
+	print_tx("\t DIMMPresence: DimmDRPresent=", pDCTstat->DimmDRPresent);
+	print_tx("\t DIMMPresence: DimmQRPresent=", pDCTstat->DimmQRPresent);
+	print_tx("\t DIMMPresence: DATAload[0]=", pDCTstat->DATAload[0]);
+	print_tx("\t DIMMPresence: MAload[0]=", pDCTstat->MAload[0]);
+	print_tx("\t DIMMPresence: MAdimms[0]=", pDCTstat->MAdimms[0]);
+	print_tx("\t DIMMPresence: DATAload[1]=", pDCTstat->DATAload[1]);
+	print_tx("\t DIMMPresence: MAload[1]=", pDCTstat->MAload[1]);
+	print_tx("\t DIMMPresence: MAdimms[1]=", 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;
+	}
+
+	print_tx("\t DIMMPresence: Status ", pDCTstat->Status);
+	print_tx("\t DIMMPresence: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("\t DIMMPresence: ErrCode ", pDCTstat->ErrCode);
+	print_t("\t DIMMPresence: Done\n");
+
+	mctHookAfterDIMMpre();
+
+	return pDCTstat->ErrCode;
+}
+
+
+static u8 Sys_Capability_D(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstat, int j, int k)
+{
+	/* Determine if system is capable of operating at given input
+	 * parameters for CL, and T.  There are three components to
+	 * determining "maximum frequency" in AUTO mode: SPD component,
+	 * Bus load component, and "Preset" max frequency component.
+	 * This procedure is used to help find the SPD component and relies
+	 * on pre-determination of the bus load component and the Preset
+	 * components.  The generalized algorithm for finding maximum
+	 * frequency is structured this way so as to optimize for CAS
+	 * latency (which might get better as a result of reduced frequency).
+	 * See "Global relationship between index values and item values"
+	 * for definition of CAS latency index (j) and Frequency index (k).
+	 */
+	u8 freqOK, ClOK;
+	u8 ret = 0;
+
+	if (Get_Fk_D(k) > pDCTstat->PresetmaxFreq)
+		freqOK = 0;
+	else
+		freqOK = 1;
+
+	/* compare proposed CAS latency with AMD Si capabilities */
+	if ((j < J_MIN) || (j > J_MAX))
+		ClOK = 0;
+	else
+		ClOK = 1;
+
+	if (freqOK && ClOK)
+		ret = 1;
+
+	return ret;
+}
+
+
+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 */
+	print_t("\tmct_initDCT: DCTInit_D 0\n");
+	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) {
+				print_t("\tmct_initDCT: DCTInit_D 1\n");
+				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)
+{
+	u32 val;
+
+	mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat);
+	// FIXME: for rev A: mct_BeforeDramInit_D(pDCTstat, dct);
+
+	/* Disable auto refresh before Dram init when in ganged mode */
+	if (pDCTstat->GangedMode) {
+		val = Get_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct));
+		val |= 1 << DisAutoRefresh;
+		Set_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct), val);
+	}
+
+	mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct);
+
+	/* Re-enable auto refresh after Dram init when in ganged mode
+	 * to ensure both DCTs are in sync
+	 */
+
+	if (pDCTstat->GangedMode) {
+		do {
+			val = Get_NB32(pDCTstat->dev_dct, 0x90 + (0x100 * dct));
+		} while (!(val & (1 << InitDram)));
+
+		WaitRoutine_D(50);
+
+		val = Get_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct));
+		val &= ~(1 << DisAutoRefresh);
+		val |= 1 << DisAutoRefresh;
+		val &= ~(1 << DisAutoRefresh);
+	}
+}
+
+
+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 {
+	if ( mctGet_NVbits(NV_Unganged) )
+		pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO);
+
+		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);
+			print_tx("setMode: DRAM Controller Select Low Register = ", val);
+		}
+	}
+	return pDCTstat->ErrCode;
+}
+
+
+u32 Get_NB32(u32 dev, u32 reg)
+{
+	u32 addr;
+
+	addr = (dev>>4) | (reg & 0xFF) | ((reg & 0xf00)<<16);
+	outl((1<<31) | (addr & ~3), 0xcf8);
+
+	return inl(0xcfc);
+}
+
+
+void Set_NB32(u32 dev, u32 reg, u32 val)
+{
+	u32 addr;
+
+	addr = (dev>>4) | (reg & 0xFF) | ((reg & 0xf00)<<16);
+	outl((1<<31) | (addr & ~3), 0xcf8);
+	outl(val, 0xcfc);
+}
+
+
+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);
+		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) {
+		print_tx("mct_SyncDCTsReady: Node ", pDCTstat->Node_ID);
+		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)));
+			print_t("mct_SyncDCTsReady: DramEnabled\n");
+		}
+	}	/* 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;
+
+	if ( dct == 0) {
+		SPDCalcWidth_D(pMCTstat, pDCTstat);
+		ret = mct_setMode(pMCTstat, pDCTstat);
+	} else {
+		ret = pDCTstat->ErrCode;
+	}
+
+	print_tx("SPDCalcWidth: Status ", pDCTstat->Status);
+	print_tx("SPDCalcWidth: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("SPDCalcWidth: ErrCode ", pDCTstat->ErrCode);
+	print_t("SPDCalcWidth: Done\n");
+
+	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 exist both, set DctSelBaseAddr[47:27] */
+		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 &= ~(0xFF);
+					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);
+				print_tx("AfterStitch DCT0 and DCT1: DRAM Controller Select Low Register = ", 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) {
+					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);
+				print_tx("AfterStitch DCT1 only: DRAM Controller Select Low Register = ", val);
+			}
+		}
+	} else {
+		pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit;
+	}
+	print_tx("AfterStitch pDCTstat->NodeSysBase = ", pDCTstat->NodeSysBase);
+	print_tx("mct_AfterStitchMemory: pDCTstat->NodeSysLimit ", 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_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; //0x07
+	val |= dword << 4;
+	dword = pDCTstat->Twrrd; //0x03
+	val |= dword << 10;
+	dword = pDCTstat->Twrwr; //0x03
+	val |= dword << 12;
+	dword = pDCTstat->Trdrd; //0x03
+	val |= dword << 14;
+	dword = pDCTstat->TrwtWB; //0x07
+	val |= dword;
+	val = OtherTiming_A_D(pDCTstat, val);
+	Set_NB32(dev, reg, val);
+
+}
+
+
+static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+			struct DCTStatStruc *pDCTstat, u8 dct)
+{
+	u8 Trdrd;
+	u8 byte;
+	u32 dword;
+	u32 val;
+	u32 index_reg = 0x98 + 0x100 * dct;
+	u32 dev = pDCTstat->dev_dct;
+
+	if ((pDCTstat->Dimmx4Present != 0) && (pDCTstat->Dimmx8Present != 0)) {
+		/* mixed (x4 or x8) DIMM types
+		  the largest DqsRcvEnGrossDelay of any DIMM minus the DqsRcvEnGrossDelay
+		  of any other DIMM is equal to the Critical Gross Delay Difference (CGDD) for Trdrd.*/
+		byte = Get_DqsRcvEnGross_Diff(pDCTstat, dev, index_reg);
+		if (byte == 0)
+			Trdrd = 1;
+		else
+			Trdrd = 2;
+
+	} else {
+		/*
+		 Trdrd with non-mixed DIMM types
+		 RdDqsTime are the same for all DIMMs and DqsRcvEn difference between
+		 any two DIMMs is less than half of a MEMCLK, BIOS should program Trdrd to 0000b,
+		 else BIOS should program Trdrd to 0001b.
+
+		 RdDqsTime are the same for all DIMMs
+		 DDR400~DDR667 only use one set register
+		 DDR800 have two set register for DIMM0 and DIMM1 */
+		Trdrd = 1;
+		if (pDCTstat->Speed > 3) {
+			/* DIMM0+DIMM1 exist */ //NOTE it should be 5
+			val = bsf(pDCTstat->DIMMValid);
+			dword = bsr(pDCTstat->DIMMValid);
+			if (dword != val && dword != 0)  {
+				/* DCT Read DQS Timing Control - DIMM0 - Low */
+				dword = Get_NB32_index_wait(dev, index_reg, 0x05);
+				/* DCT Read DQS Timing Control - DIMM1 - Low */
+				val = Get_NB32_index_wait(dev, index_reg, 0x105);
+				if (val != dword)
+					goto Trdrd_1;
+
+				/* DCT Read DQS Timing Control - DIMM0 - High */
+				dword = Get_NB32_index_wait(dev, index_reg, 0x06);
+				/* DCT Read DQS Timing Control - DIMM1 - High */
+				val = Get_NB32_index_wait(dev, index_reg, 0x106);
+				if (val != dword)
+					goto Trdrd_1;
+			}
+		}
+
+		/* DqsRcvEn difference between any two DIMMs is
+		   less than half of a MEMCLK */
+		/* DqsRcvEn byte 1,0*/
+		if (Check_DqsRcvEn_Diff(pDCTstat, dct, dev, index_reg, 0x10))
+			goto Trdrd_1;
+		/* DqsRcvEn byte 3,2*/
+		if (Check_DqsRcvEn_Diff(pDCTstat, dct, dev, index_reg, 0x11))
+			goto Trdrd_1;
+		/* DqsRcvEn byte 5,4*/
+		if (Check_DqsRcvEn_Diff(pDCTstat, dct, dev, index_reg, 0x20))
+			goto Trdrd_1;
+		/* DqsRcvEn byte 7,6*/
+		if (Check_DqsRcvEn_Diff(pDCTstat, dct, dev, index_reg, 0x21))
+			goto Trdrd_1;
+		/* DqsRcvEn ECC*/
+		if (Check_DqsRcvEn_Diff(pDCTstat, dct, dev, index_reg, 0x12))
+			goto Trdrd_1;
+		Trdrd = 0;
+	Trdrd_1:
+		;
+	}
+	pDCTstat->Trdrd = Trdrd;
+
+}
+
+
+static void Get_Twrwr(struct MCTStatStruc *pMCTstat,
+			struct DCTStatStruc *pDCTstat, u8 dct)
+{
+	u8 Twrwr = 0;
+	u32 index_reg = 0x98 + 0x100 * dct;
+	u32 dev = pDCTstat->dev_dct;
+	u32 val;
+	u32 dword;
+
+	/* WrDatGrossDlyByte only use one set register when DDR400~DDR667
+	   DDR800 have two set register for DIMM0 and DIMM1 */
+	if (pDCTstat->Speed > 3) {
+		val = bsf(pDCTstat->DIMMValid);
+		dword = bsr(pDCTstat->DIMMValid);
+		if (dword != val && dword != 0)  {
+			/*the largest WrDatGrossDlyByte of any DIMM minus the
+			WrDatGrossDlyByte of any other DIMM is equal to CGDD */
+			val = Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg);
+		}
+		if (val == 0)
+			Twrwr = 2;
+		else
+			Twrwr = 3;
+	}
+	pDCTstat->Twrwr = Twrwr;
+}
+
+
+static void Get_Twrrd(struct MCTStatStruc *pMCTstat,
+			struct DCTStatStruc *pDCTstat, u8 dct)
+{
+	u8 byte, bytex;
+	u32 index_reg = 0x98 + 0x100 * dct;
+	u32 dev = pDCTstat->dev_dct;
+
+	/* On any given byte lane, the largest WrDatGrossDlyByte delay of
+	   any DIMM minus the DqsRcvEnGrossDelay delay of any other DIMM is
+	   equal to the Critical Gross Delay Difference (CGDD) for Twrrd.*/
+	pDCTstat->Twrrd = 0;
+	Get_DqsRcvEnGross_Diff(pDCTstat, dev, index_reg);
+	Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg);
+	bytex = pDCTstat->DqsRcvEnGrossL;
+	byte = pDCTstat->WrDatGrossH;
+	if (byte > bytex) {
+		byte -= bytex;
+		if (byte == 1)
+			bytex = 1;
+		else
+			bytex = 2;
+	} else {
+		bytex = 0;
+	}
+	pDCTstat->Twrrd = bytex;
+}
+
+
+static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
+			struct DCTStatStruc *pDCTstat, u8 dct)
+{
+	u8 byte, bytex;
+	u32 index_reg = 0x98 + 0x100 * dct;
+	u32 dev = pDCTstat->dev_dct;
+
+	/* On any given byte lane, the largest WrDatGrossDlyByte delay of
+	   any DIMM minus the DqsRcvEnGrossDelay delay of any other DIMM is
+	   equal to the Critical Gross Delay Difference (CGDD) for TrwtTO. */
+	Get_DqsRcvEnGross_Diff(pDCTstat, dev, index_reg);
+	Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg);
+	bytex = pDCTstat->DqsRcvEnGrossL;
+	byte = pDCTstat->WrDatGrossH;
+	if (bytex > byte) {
+		bytex -= byte;
+		if ((bytex == 1) || (bytex == 2))
+			bytex = 3;
+		else
+			bytex = 4;
+	} else {
+		byte -= bytex;
+		if ((byte == 0) || (byte == 1))
+			bytex = 2;
+		else
+			bytex = 1;
+	}
+
+	pDCTstat->TrwtTO = bytex;
+}
+
+
+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 + 1;
+}
+
+
+static u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat,
+					u8 dct, u32 dev, u32 index_reg,
+					u32 index)
+{
+	u8 Smallest_0, Largest_0, Smallest_1, Largest_1;
+	u8 i;
+	u32 val;
+	u8 byte;
+
+	Smallest_0 = 0xFF;
+	Smallest_1 = 0xFF;
+	Largest_0 = 0;
+	Largest_1 = 0;
+
+	for (i=0; i < 8; i+=2) {
+		if ( pDCTstat->DIMMValid & (1 << i)) {
+			val = Get_NB32_index_wait(dev, index_reg, index);
+			byte = val & 0xFF;
+			if (byte < Smallest_0)
+				Smallest_0 = byte;
+			if (byte > Largest_0)
+				Largest_0 = byte;
+			byte = (val >> 16) & 0xFF;
+			if (byte < Smallest_1)
+				Smallest_1 = byte;
+			if (byte > Largest_1)
+				Largest_1 = byte;
+		}
+		index += 3;
+	}	/* while ++i */
+
+	/* check if total DqsRcvEn delay difference between any
+	   two DIMMs is less than half of a MEMCLK */
+	if ((Largest_0 - Smallest_0) > 31)
+		return 1;
+	if ((Largest_1 - Smallest_1) > 31)
+		return 1;
+	return 0;
+}
+
+
+static u8 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->DqsRcvEnGrossL = Largest;
+	return Largest - Smallest;
+}
+
+
+static u8 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 */
+	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;
+	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;
+
+	// FIXME: Add Cx support.
+
+	pDCTstat->WrDatGrossH = Largest;
+	return Largest - 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;
+
+	Smallest = 7;
+	Largest = 0;
+
+	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;
+			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)
+{
+	print_t("\tmct_FinalMCT_D: Clr Cl, Wb\n");
+
+
+	mct_ClrClToNB_D(pMCTstat, pDCTstat);
+	mct_ClrWbEnhWsbDis_D(pMCTstat, pDCTstat);
+}
+
+
+static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
+{
+	print_t("\tmct_InitialMCT_D: Set Cl, Wb\n");
+	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);
+}
+
+
+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;
+	u8 cs;
+	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)) {
+		for (cs = 0; cs < 8; cs++) {
+			if (word & (1 << cs)) {
+				if (!(cs & 1))
+					word |= 1 << (cs + 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;
+	u8 cs;
+	u32 index;
+	u16 word;
+
+	/* Tri-state unused CKEs when motherboard termination is available */
+
+	// FIXME: skip for Ax
+
+	dev = pDCTstat->dev_dct;
+	word = 0x101;
+	for (cs = 0; cs < 8; cs++) {
+		if (pDCTstat->CSPresent & (1 << cs)) {
+			if (!(cs & 1))
+				word &= 0xFF00;
+			else
+				word &= 0x00FF;
+		}
+	}
+
+	index  = 0x0c;
+	val = Get_NB32_index_wait(dev, index_reg, index);
+	if ((word & 0x00FF) == 1)
+		val |= 1 << 12;
+	else
+		val &= ~(1 << 12);
+
+	if ((word >> 8) == 1)
+		val |= 1 << 13;
+	else
+		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;
+	u16 word;
+
+	/* Tri-state unused ODTs when motherboard termination is available */
+
+	// FIXME: skip for Ax
+
+	dev = pDCTstat->dev_dct;
+	word = 0;
+	for (cs = 0; cs < 8; cs += 2) {
+		if (!(pDCTstat->CSPresent & (1 << cs))) {
+			if (!(pDCTstat->CSPresent & (1 << (cs + 1))))
+				word |= (1 << (cs >> 1));
+		}
+	}
+
+	index  = 0x0C;
+	val = Get_NB32_index_wait(dev, index_reg, index);
+	val |= (word << 8);
+	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->Speed == 2) && (pDCTstat->MAdimms[dct] == 4))
+		dword &= 0xF18FFF18;
+
+	Set_NB32_index_wait(dev, index_reg, 0x0a, dword);
+}
+
+
+static void WaitRoutine_D(u32 time)
+{
+	while(time) {
+		_EXECFENCE;
+		time--;
+	}
+}
+
+
+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);
+
+	//FIXME: check for Cx
+	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;
+	u16 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 = ((u16) &((struct DCTStatStruc *)0)->CH_MaxRdLat[2]);
+		for (i = start; i < stop ; i++) {
+			p[i] = 0;
+		}
+
+		start = ((u16) &((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;
+	u32 dev = pDCTstat->dev_dct;
+
+	// FIXME: skip for Ax
+	if ((pDCTstat->Speed == 3) || ( pDCTstat->Speed == 2)) { // MemClkFreq = 667MHz or 533Mhz
+		for (i=0; i < 2; i++) {
+			reg_off = 0x100 * i;
+			Set_NB32(dev,  0x98 + reg_off, 0x0D000030);
+			Set_NB32(dev,  0x9C + reg_off, 0x00000806);
+			Set_NB32(dev,  0x98 + reg_off, 0x4D040F30);
+		}
+	}
+}
+
+
+void mct_AdjustDelayRange_D(struct MCTStatStruc *pMCTstat,
+			struct DCTStatStruc *pDCTstat, u8 *dqs_pos)
+{
+	// FIXME: Skip for Ax
+	if ((pDCTstat->Speed == 3) || ( pDCTstat->Speed == 2)) { // MemClkFreq = 667MHz or 533Mhz
+		*dqs_pos = 32;
+	}
+}
+
+
+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);
+}
+
+
+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);
+	Set_NB32_index_wait(dev, index_reg, index, val | (1 << DisAutoComp));
+
+	//FIXME: check for Bx Cx CPU
+	  // if Ax mct_SetDramConfigHi_Samp_D
+
+	/* errata#177 */
+	index = 0x4D014F00;	/* F2x[1, 0]9C_x[D0FFFFF:D000000] DRAM Phy Debug Registers */
+	index |= 1 << DctAccessWrite;
+	val = 0;
+	Set_NB32_index_wait(dev, index_reg, index, val);
+
+	Set_NB32(dev, 0x94 + 0x100 * dct, DramConfigHi);
+
+	index = 0x08;
+	val = Get_NB32_index_wait(dev, index_reg, index);
+	Set_NB32_index_wait(dev, index_reg, index, val & (~(1 << DisAutoComp)));
+}
+
+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 DDR2 training.
+	 */
+
+	for (Node = 0; Node < 8; Node++) {
+		pDCTstat = pDCTstatA + Node;
+
+		if (pDCTstat->NodePresent)
+			mct_BeforeDQSTrain_Samp_D(pMCTstat, pDCTstat);
+			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 val;
+	u32 dev = pDCTstat->dev_dct;
+	u32 reg_off = 0x100 * dct;
+	u32 addr;
+	u8 valid = 0;
+
+	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 */
+				Set_NB32(dev, 0x98 + reg_off, 0x0D00000C);
+				val = Get_NB32(dev, 0x9C + reg_off);
+				val |= 1 << 15;
+				Set_NB32(dev, 0x9C + reg_off, val);
+				Set_NB32(dev, 0x98 + reg_off, 0x4D0F0F0C);
+				mct_Wait_10ns(60); /* wait >= 300ns */
+
+				Set_NB32(dev, 0x98 + reg_off, 0x0D00000C);
+				val = Get_NB32(dev, 0x9C + reg_off);
+				val &= ~(1 << 15);
+				Set_NB32(dev, 0x9C + reg_off, val);
+				Set_NB32(dev, 0x98 + reg_off, 0x4D0F0F0C);
+				mct_Wait_10ns(400); /* wait >= 2us */
+				break;
+			}
+		}
+	}
+}
+
+
+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 |= 36-32;			// DisDatMask
+		Set_NB32(dev, 0x8C, val);
+	}
+}
+
+
+static void mct_SetupSync_D(struct MCTStatStruc *pMCTstat,
+					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 |= 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) {
+		mct_Wait_10ns(5000);	/* 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
+ */
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_d.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_d.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,737 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 2 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 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	3		/* bias to convert bus clocks to bit field value*/
+#define Bias_TrrdT	2
+#define Bias_TrcdT	3
+#define Bias_TrasT	3
+#define Bias_TrcT	11
+#define Bias_TrtpT	2
+#define Bias_TwrT	3
+#define Bias_TwtrT	0
+#define Bias_TfawT	7
+
+#define Min_TrpT	3		/* min programmable value in busclocks*/
+#define Max_TrpT	6		/* max programmable value in busclocks*/
+#define Min_TrrdT	2
+#define Max_TrrdT	5
+#define Min_TrcdT	3
+#define Max_TrcdT	6
+#define Min_TrasT	5
+#define Max_TrasT	18
+#define Min_TrcT	11
+#define Max_TrcT	26
+#define Min_TrtpT	2
+#define Max_TrtpT	3
+#define Min_TwrT	3
+#define Max_TwrT	6
+#define Min_TwtrT	1
+#define Max_TwtrT	3
+
+/*DDR2-1066 support*/
+#define Bias_TrcdT_1066	5
+#define Bias_TrasT_1066	15
+#define Bias_TrrdT_1066	4
+#define Bias_TwrT_1066		4
+#define Bias_TrpT_1066		5
+#define Bias_TwtrT_1066	4
+#define Bias_TfawT_1066	15
+
+#define Min_TrcdT_1066		5
+#define Max_TrcdT_1066		12
+#define Min_TrasT_1066		15
+#define Max_TrasT_1066		30
+#define Min_TrcT_1066		11
+#define Max_TrcT_1066		42
+#define Min_TrrdT_1066		4
+#define Max_TrrdT_1066		7
+#define Min_TwrT_1066		5
+#define Max_TwrT_1066		8
+#define Min_TrpT_1066		5
+#define Max_TrpT_1066		12
+#define Min_TwtrT_1066		4
+#define Max_TwtrT_1066		7
+
+/*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 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 */
+
+
+
+/*=============================================================================
+	SW Initialization
+============================================================================*/
+#define DLL_Enable	1
+#define OCD_Default	2
+#define OCD_Exit	3
+
+
+
+/*=============================================================================
+	Jedec DDR II
+=============================================================================*/
+#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 SPD_DIMMTYPE	20
+#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 SPD_DEVATTRIB	22
+#define SPD_EDCTYPE	11
+	#define JED_ECC		0x02
+	#define JED_ADRCPAR	0x04
+#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)
+===============================================================================*/
+
+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][4][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 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_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*/
+	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;
+};
+
+/*===============================================================================
+	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);
+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 SyncSetting(struct DCTStatStruc *pDCTstat);
+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);
+static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 ChipSel);
+void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass);
+static void mct_AdjustScrub_D(struct DCTStatStruc *pDCTstat, u16 *scrub_request);
+static u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_Wait_10ns (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: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_d_gcc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_d_gcc.h	2007-12-12 12:00:52.000000000 -0700
@@ -0,0 +1,388 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 inline 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 inline 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)
+	);
+
+}
+
+
+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;
+}
+
+
+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;
+}
+
+
+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)
+	);
+
+}
+
+
+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)
+	);
+}
+
+
+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;
+}
+
+
+void oemSet_NB32(u32 addr, u32 val, u8 *valid)
+{
+}
+
+
+u32 oemGet_NB32(u32 addr,  u8 *valid)
+{
+	*valid = 0;
+	return 0xffffffff;
+}
+
+
+u8 oemNodePresent_D(u8 Node, u8 *ret)
+{
+	*ret = 0;
+	return 0;
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_fd.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct_fd.c	2007-12-12 12:00:14.000000000 -0700
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 amd_FD_support(void)
+{
+	return 1;
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctardk3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctardk3.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,206 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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  021100xFF301 USA
+ */
+
+
+static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
+				u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL);
+
+
+void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+			 struct DCTStatStruc *pDCTstat, u32 dct)
+{
+	u16 val, valx;
+
+	print_tx("dct: ", dct);
+	print_tx("Speed: ", pDCTstat->Speed);
+
+	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]));
+
+
+	if(pDCTstat->MAdimms[dct] == 1)
+		pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;	/* 75ohms */
+	else
+		pDCTstat->CH_ODC_CTL[dct] |= 0x10000000;	/* 150ohms */
+
+	pDCTstat->_2Tmode = 1;
+
+	/* use byte lane 4 delay for ECC lane */
+	pDCTstat->CH_EccDQSLike[0] = 0x0504;
+	pDCTstat->CH_EccDQSScale[0] = 0;	/* 100% byte lane 4 */
+	pDCTstat->CH_EccDQSLike[1] = 0x0504;
+	pDCTstat->CH_EccDQSScale[1] = 0;	/* 100% byte lane 4 */
+
+
+	/*
+	 Overrides and/or exceptions
+	*/
+
+	/* 1) QRx4 needs to adjust CS/ODT setup time */
+	// FIXME: Add Ax support?
+	if (mctGet_NVbits(NV_MAX_DIMMS) == 4) {
+		if (pDCTstat->DimmQRPresent != 0) {
+			pDCTstat->CH_ADDR_TMG[dct] &= 0xFF00FFFF;
+			pDCTstat->CH_ADDR_TMG[dct] |= 0x00000000;
+			if (pDCTstat->MAdimms[dct] == 4) {
+				pDCTstat->CH_ADDR_TMG[dct] &= 0xFF00FFFF;
+				pDCTstat->CH_ADDR_TMG[dct] |= 0x002F0000;
+				if (pDCTstat->Speed == 3 || pDCTstat->Speed == 4) {
+					pDCTstat->CH_ADDR_TMG[dct] &= 0xFF00FFFF;
+					pDCTstat->CH_ADDR_TMG[dct] |= 0x00002F00;
+					if (pDCTstat->MAdimms[dct] == 4)
+						pDCTstat->CH_ODC_CTL[dct] = 0x00331222;
+				}
+			}
+		}
+	}
+
+
+	/* 2) DRx4 (R/C-J) @ DDR667 needs to adjust CS/ODT setup time */
+	if (pDCTstat->Speed == 3 || pDCTstat->Speed == 4) {
+		val = pDCTstat->Dimmx4Present;
+		if (dct == 0) {
+			val &= 0x55;
+		} else {
+			val &= 0xAA;
+			val >>= 1;
+		}
+		val &= pDCTstat->DIMMValid;
+		if (val) {
+			//FIXME: skip for Ax
+			valx = pDCTstat->DimmDRPresent;
+			if (dct == 0) {
+				valx &= 0x55;
+			} else {
+				valx &= 0xAA;
+				valx >>= 1;
+			}
+			if (mctGet_NVbits(NV_MAX_DIMMS) == 8) {
+				val &= valx;
+				if (val != 0) {
+					pDCTstat->CH_ADDR_TMG[dct] &= 0xFFFF00FF;
+					pDCTstat->CH_ADDR_TMG[dct] |= 0x00002F00;
+				}
+			} else {
+				val &= valx;
+				if (val != 0) {
+					if (pDCTstat->Speed == 3 || pDCTstat->Speed == 3) {
+						pDCTstat->CH_ADDR_TMG[dct] &= 0xFFFF00FF;
+						pDCTstat->CH_ADDR_TMG[dct] |= 0x00002F00;
+					}
+				}
+
+			}
+		}
+	}
+
+
+	pDCTstat->CH_ODC_CTL[dct] = procOdtWorkaround(pDCTstat, dct, pDCTstat->CH_ODC_CTL[dct]);
+
+	print_tx("CH_ODC_CTL: ", pDCTstat->CH_ODC_CTL[dct]);
+	print_tx("CH_ADDR_TMG: ", pDCTstat->CH_ADDR_TMG[dct]);
+
+
+}
+
+
+/*===============================================================================
+ * Vendor is responsible for correct settings.
+ * M2/Unbuffered 4 Slot - AMD Design Guideline.
+ *===============================================================================
+ * #1, BYTE, Speed (DCTStatstruc.Speed) (Secondary Key)
+ * #2, BYTE, number of Address bus loads on the Channel. (Tershery Key)
+ *           These must be listed in ascending order.
+ *           FFh (0xFE) has special meanying of 'any', and must be listed first for each speed grade.
+ * #3, DWORD, Address Timing Control Register Value
+ * #4, DWORD, Output Driver Compensation Control Register Value
+ * #5, BYTE, Number of DIMMs (Primary Key)
+ */
+static const u8 Table_ATC_ODC_8D_D[] = {
+	0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x11, 0x00, 1,
+	0xFE, 0xFF, 0x00, 0x00, 0x37, 0x00, 0x22, 0x12, 0x11, 0x00, 2,
+	   1, 0xFF, 0x00, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x11, 0x00, 3,
+	   2, 0xFF, 0x00, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x11, 0x00, 3,
+	   3, 0xFF, 0x2F, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x11, 0x00, 3,
+	   4, 0xFF, 0x2F, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x33, 0x00, 3,
+	   1, 0xFF, 0x00, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x11, 0x00, 4,
+	   2, 0xFF, 0x00, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x11, 0x00, 4,
+	   3, 0xFF, 0x2F, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x33, 0x00, 4,
+	   4, 0xFF, 0x2F, 0x00, 0x2F, 0x00, 0x22, 0x12, 0x33, 0x00, 4,
+	0xFF
+};
+
+static const u8 Table_ATC_ODC_4D_D[] = {
+	0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x11, 0x00, 1,
+	0xFE, 0xFF, 0x00, 0x00, 0x37, 0x00, 0x22, 0x12, 0x11, 0x00, 2,
+	0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x11, 0x00, 3,
+	0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x11, 0x00, 4,
+	0xFF
+};
+
+static const u8 Table_ATC_ODC_8D_D_Ax[] = {
+	1,0xff,0x00,0x00,0x2F,0x0,0x22,0x12,0x11,0x00, 0xFE,
+	2,0xff,0x00,0x00,0x2C,0x0,0x22,0x12,0x11,0x00, 0xFE,
+	3,0xff,0x00,0x00,0x2C,0x0,0x22,0x12,0x11,0x00, 0xFE,
+	4,0xff,0x00,0x33,0x2F,0x0,0x22,0x12,0x11,0x00, 0xFE,
+	0xFF
+};
+
+static const u8 Table_ATC_ODC_4D_D_Ax[] = {
+	1,0xff,0x00,0x00,0x2F,0x00,0x22,0x12,0x11,0x00, 0xFE,
+	2,0xff,0x00,0x2C,0x2C,0x00,0x22,0x12,0x11,0x00, 0xFE,
+	3,0xff,0x00,0x00,0x2C,0x00,0x22,0x12,0x11,0x00, 0xFE,
+	4,0xff,0x00,0x33,0x2F,0x00,0x22,0x12,0x11,0x00, 0xFE,
+	0xFF
+};
+
+
+static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
+				u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL)
+{
+	const u8 *p;
+
+	*AddrTmgCTL = 0;
+	*ODC_CTL = 0;
+
+	if(mctGet_NVbits(NV_MAX_DIMMS) == 8) {
+		/* 8 DIMM Table */
+		p = Table_ATC_ODC_8D_D;
+		//FIXME Add Ax support
+	} else {
+		/* 4 DIMM Table*/
+		p = Table_ATC_ODC_4D_D;
+		//FIXME Add Ax support
+	}
+
+	while (*p != 0xFF) {
+		if ((MAAdimms == *(p+10)) || (*(p+10 ) == 0xFE)) {
+			if((*p == Speed) || (*p == 0xFE)) {
+				if(MAAload <= *(p+1)) {
+					*AddrTmgCTL = stream_to_int((u8*)(p+2));
+					*ODC_CTL = stream_to_int((u8*)(p+6));
+					break;
+				}
+			}
+		}
+	p+=11;
+	}
+}
+
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctardk4.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctardk4.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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,
+				u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL,
+				u32 *CMDmode);
+
+
+void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+			 struct DCTStatStruc *pDCTstat, u32 dct)
+
+	print_tx("dct: ", dct);
+	print_tx("Speed: ", pDCTstat->Speed);
+
+	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);
+
+//	print_tx("1 CH_ODC_CTL: ", pDCTstat->CH_ODC_CTL[dct]);
+//	print_tx("1 CH_ADDR_TMG: ", pDCTstat->CH_ADDR_TMG[dct]);
+
+	if(pDCTstat->MAdimms[dct] == 1)
+		pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;	/* 75ohms */
+	else
+		pDCTstat->CH_ODC_CTL[dct] |= 0x10000000;	/* 150ohms */
+
+
+	/*
+	 * Overrides and/or workarounds
+	 */
+	pDCTstat->CH_ODC_CTL[dct] = procOdtWorkaround(pDCTstat, dct, pDCTstat->CH_ODC_CTL[dct]);
+
+	print_tx("4 CH_ODC_CTL: ", pDCTstat->CH_ODC_CTL[dct]);
+	print_tx("4 CH_ADDR_TMG: ", pDCTstat->CH_ADDR_TMG[dct]);
+}
+
+/*=============================================================================
+ * Vendor is responsible for correct settings.
+ * M2/Unbuffered 4 Slot - AMD Design Guideline.
+ *=============================================================================
+ * #1, BYTE, Speed (DCTStatstruc.Speed)
+ * #2, BYTE, number of Address bus loads on the Channel.
+ *     These must be listed in ascending order.
+ *     FFh (-1) has special meanying of 'any', and must be listed first for
+ *     each speed grade.
+ * #3, DWORD, Address Timing Control Register Value
+ * #4, DWORD, Output Driver Compensation Control Register Value
+ */
+
+static const u8 Table_ATC_ODC_D_Bx[] = {
+	1, 0xFF, 0x00, 0x2F, 0x2F, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   12, 0x00, 0x2F, 0x2F, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   16, 0x00, 0x2F, 0x00, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   20, 0x00, 0x2F, 0x38, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   24, 0x00, 0x2F, 0x37, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   32, 0x00, 0x2F, 0x34, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   12, 0x20, 0x22, 0x20, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   16, 0x20, 0x22, 0x30, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   20, 0x20, 0x22, 0x2C, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   24, 0x20, 0x22, 0x2A, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   32, 0x20, 0x22, 0x2B, 0x0, 0x22, 0x13, 0x11, 0x0
+	4, 0xFF, 0x20, 0x25, 0x20, 0x0, 0x22, 0x33, 0x11, 0x0
+	5, 0xFF, 0x20, 0x20, 0x2F, 0x0, 0x22, 0x32, 0x11, 0x0
+	0FFh
+
+static const u8 Table_ATC_ODC_D_Ax[] = {
+	1, 0xFF, 0x00, 0x2F, 0x2F, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   12, 0x00, 0x2F, 0x2F, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   16, 0x00, 0x2F, 0x00, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   20, 0x00, 0x2F, 0x38, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   24, 0x00, 0x2F, 0x37, 0x0, 0x22, 0x13, 0x11, 0x0
+	2,   32, 0x00, 0x2F, 0x34, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   12, 0x20, 0x22, 0x20, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   16, 0x20, 0x22, 0x30, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   20, 0x20, 0x22, 0x2C, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   24, 0x20, 0x22, 0x2A, 0x0, 0x22, 0x13, 0x11, 0x0
+	3,   32, 0x20, 0x22, 0x2B, 0x0, 0x22, 0x13, 0x11, 0x0
+	4, 0xFF, 0x20, 0x25, 0x20, 0x0, 0x22, 0x33, 0x11, 0x0
+	5, 0xFF, 0x20, 0x20, 0x2F, 0x0, 0x22, 0x32, 0x11, 0x0
+	0xFF
+};
+
+
+static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
+				u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL,
+				u32 *CMDmode);
+{
+	u8 *p;
+
+	*AddrTmgCTL = 0;
+	*ODC_CTL = 0;
+	*CMDmode = 1;
+
+	// FIXME: add Ax support
+	if(MAAdimms == 0) {
+		*ODC_CTL = 0x00111222;
+		if(Speed == 3)
+			*AddrTmgCTL = 0x00202220;
+		else if (Speed == 2)
+			*AddrTmgCTL = 0x002F2F00;
+		else if (Speed == 1)
+			*AddrTmgCTL = 0x002F2F00;
+		else if (Speed == 4)
+			*AddrTmgCTL = 0x00202520;
+		else if (Speed == 4)
+			*AddrTmgCTL = 0x002F2020;
+		else
+			*AddrTmgCTL = 0x002F2F2F;
+	} else if(MAAdimms == 1) {
+		if(Speed == 4) {
+			*CMDmode = 2;
+			*AddrTmgCTL = 0x00202520;
+			*ODC_CTL = 0x00113222;
+		} else if(Speed == 4) {
+			*CMDmode = 2;
+			*AddrTmgCTL = 0x002F2020;
+			*ODC_CTL = 0x00113222;
+		} else {
+			*CMDmode = 1;
+			*ODC_CTL = 0x00111222;
+			if(Speed == 3) {
+				*AddrTmgCTL = 0x00202220;
+			} else if(Speed == 2) {
+				if (MAAload == 4)
+					*AddrTmgCTL = 0x002B2F00;
+				else if (MAAload == 16)
+					*AddrTmgCTL = 0x002B2F00;
+				else if (MAAload == 8)
+					*AddrTmgCTL = 0x002F2F00;
+				else
+					*AddrTmgCTL = 0x002F2F00;
+			} else if(Speed == 1) {
+				*AddrTmgCTL = 0x002F2F00;
+			} else if(Speed == 5) {
+				*AddrTmgCTL = 0x002F2020;
+			} else {
+				*AddrTmgCTL = 0x002F2F2F;
+			}
+		}
+	} else {
+		*CMDmode = 2;
+		p = Table_ATC_ODC_D_Bx;
+	do {
+		if(Speed == *p) {
+			if(MAAload <= *(p+1)) {
+				*AddrTmgCTL = stream_to_int(p+2);
+				*ODC_CTL = stream_to_int(p+6);
+				break;
+			}
+		}
+		p+=10;
+	} while (0xFF == *p);
+
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctchi_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctchi_d.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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;
+	u8 enabled;
+	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 */
+	// FIXME: Check for Cx
+	DctSelIntLvAddr = 5;	/* use default: Enable channel interleave */
+	enabled = 1;		/* with Hash*: exclusive OR of address bits[20:16, 6]. */
+	beforeInterleaveChannels_D(pDCTstatA, &enabled);
+
+	if (enabled) {
+		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 += HoleBase;
+				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);
+				print_tx("InterleaveChannels: DRAM Controller Select Low Register = ", 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 &= 0x7F;
+					val |= (tmp & 0xFF);
+					Set_NB32(pDCTstat->dev_map, 0xF0, val);
+print_tx("InterleaveChannels:0xF0 = ", val);
+
+				}
+			}
+			print_tx("InterleaveChannels_D: Node ", Node);
+			print_tx("InterleaveChannels_D: Status ", pDCTstat->Status);
+			print_tx("InterleaveChannels_D: ErrStatus ", pDCTstat->ErrStatus);
+			print_tx("InterleaveChannels_D: ErrCode ", pDCTstat->ErrCode);
+			Node++;
+		}
+	}
+	print_t("InterleaveChannels_D: Done\n");
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctcsi_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctcsi_d.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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);
+			}
+		}
+		print_t("InterleaveBanks_D: Banks Interleaved ");
+	}	/* DoIntlv */
+
+//	dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2));
+
+	print_tx("InterleaveBanks_D: Status ", pDCTstat->Status);
+	print_tx("InterleaveBanks_D: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("InterleaveBanks_D: ErrCode ", pDCTstat->ErrCode);
+	print_t("InterleaveBanks_D: Done\n");
+}
+
+
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctdqs_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctdqs_d.c	2007-12-12 11:58:51.000000000 -0700
@@ -0,0 +1,1216 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 u8 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);
+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);
+
+#define DQS_TRAIN_DEBUG 0
+
+static inline void print_debug_dqs(const char *str, u32 val, u8 level)
+{
+#if DQS_TRAIN_DEBUG > 0
+	if (DQS_TRAIN_DEBUG >= level) {
+		printk_debug("%s%x\n", str, val);
+	}
+#endif
+}
+
+static inline 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_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 */
+};
+
+const u8 Table_DQSRcvEn_Offset[] = {0x00,0x01,0x10,0x11};
+
+
+void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
+			struct DCTStatStruc *pDCTstatA, u8 Pass)
+{
+	u8 Node;
+	struct DCTStatStruc *pDCTstat;
+
+	for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+		pDCTstat = pDCTstatA + Node;
+
+/*FIXME: needed?		if (!pDCTstat->NodePresent)
+			break;
+*/
+		if (pDCTstat->DCTSysLimit) {
+			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;
+
+	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;
+
+		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: 22 TrainErrors ",pDCTstat->TrainErrors, 2);
+			if (pDCTstat->TrainErrors == 0) {
+					break;
+			}
+			Errors |= pDCTstat->TrainErrors;
+		}
+		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 == 0) {
+				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);
+	}
+
+	print_tx("TrainDQSRdWrPos: Status ", pDCTstat->Status);
+	print_tx("TrainDQSRdWrPos: TrainErrors ", pDCTstat->TrainErrors);
+	print_tx("TrainDQSRdWrPos: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("TrainDQSRdWrPos: ErrCode ", pDCTstat->ErrCode);
+	print_t("TrainDQSRdWrPos: Done\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,RnkDlySeqPassMax, RnkDlyFilterMin, RnkDlyFilterMax;
+	u8 LastTest;
+	u32 TestAddr;
+	u8 ByteLane;
+	u8 MutualCSPassW[64];
+	u8 BanksPresent;
+	u8 dqsDelay_end;
+	u8 tmp, valid;
+
+//	print_tx("TrainDQSPos: Node_ID", pDCTstat->Node_ID);
+//	print_tx("TrainDQSPos: Direction", pDCTstat->Direction);
+
+	/* 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;
+
+	if (pDCTstat->Direction == DQS_READDIR) {
+		dqsDelay_end = 64;
+		mct_AdjustDelayRange_D(pMCTstat, pDCTstat, &dqsDelay_end);
+	} else {
+		dqsDelay_end = 32;
+	}
+
+	/* Bitmapped status per delay setting, 0xff=All positions
+	 * passing (1= PASS). Set the entire array.
+	 */
+	for (DQSDelay=0; DQSDelay<64; 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);
+			if (MutualCSPassW[DQSDelay] == 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);
+			tmp = CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); /* 0=fail, 1=pass */
+
+			if (mct_checkFenceHoleAdjust_D(pMCTstat, pDCTstat, DQSDelay, ChipSel, &tmp)) {
+				goto skipLocMiddle;
+			}
+
+			MutualCSPassW[DQSDelay] &= tmp;
+			print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 \tMutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+
+			SetTargetWTIO_D(TestAddr);
+			FlushDQSTestPattern_D(pDCTstat, TestAddr<<8);
+			ResetTargetWTIO_D();
+		}
+
+	}
+
+	if (BanksPresent) {
+		u8 mask_pass = 0;
+		for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+			print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane ",ByteLane, 4);
+			pDCTstat->ByteLane = ByteLane;
+			LastTest = DQS_FAIL;		/* Analyze the results */
+			RnkDlySeqPassMin = 0;
+			RnkDlySeqPassMax = 0;
+			RnkDlyFilterMax = 0;
+			RnkDlyFilterMin = 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);
+
+					RnkDlySeqPassMax = DQSDelay;
+					if (LastTest == DQS_FAIL) {
+						RnkDlySeqPassMin = DQSDelay; //start sequential run
+					}
+					if ((RnkDlySeqPassMax - RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)){
+						RnkDlyFilterMin = RnkDlySeqPassMin;
+						RnkDlyFilterMax = RnkDlySeqPassMax;
+					}
+					LastTest = DQS_PASS;
+				} else {
+					LastTest = 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 */
+					middle_dqs = MiddleDQS_D(RnkDlyFilterMin, RnkDlyFilterMax);
+					pDCTstat->DQSDelay = middle_dqs;
+					mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, cs_start);  /* load the register with the value */
+					StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start); /* store the value into the data structure */
+					print_debug_dqs("\t\t\t\tTrainDQSPos: 42 middle_dqs : ",middle_dqs, 4);
+				}
+			}
+		}
+		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 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;
+
+	if (pDCTstat->Status & (1 << SB_Over400MHz))
+		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 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 */
+	if (pDCTstat->Status & (1<<SB_Over400MHz))
+		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 u8 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;
+	u8 bitmap;
+	u8 bytelane;
+	u8 i;
+	u32 value;
+	u8 j;
+	u32 value_test;
+	u8 pattern, channel;
+
+	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 = 0xFF;
+	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);
+
+		for (j = 0; j < (4 * 8); j += 8) {
+			if (((value >> j) & 0xff) != ((value_test >> j) & 0xff)) {
+				bitmap &= ~(1 << bytelane);
+			}
+
+			bytelane++;
+			bytelane &= 0x7;
+		}
+
+		print_debug_dqs("\t\t\t\t\t\tbitmap = ", bitmap, 7);
+
+		if (!bitmap)
+			break;
+
+		if (bytelane == 0){
+			if (pattern == 1) { //dual channel
+				addr_lo += 8; //skip over other channel's data
+				test_buf += 2;
+			}
+		}
+		addr_lo += 4;
+		test_buf += 1;
+	}
+
+	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) {
+			/* when DCT speed >= 400MHz, we only support 2 DIMMs
+			 * and we have two sets registers for DIMM0 and DIMM1 so
+			 * here we must traning DQSRd/WrPos for DIMM0 and DIMM1
+			 */
+			if (pDCTstat->Speed >= 4) {
+				pDCTstat->Status |= (1 << SB_Over400MHz);
+			}
+			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;
+
+	/* 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 */
+
+	if (pDCTstat->Status & (1 << SB_Over400MHz)) {
+		index += (ChipSel >> 1) * 0x100;	/* if logical DIMM1/DIMM3 */
+	}
+
+	val = Get_NB32_index_wait(dev, index_reg, index);
+	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 */
+	}
+
+	/* 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;
+		}
+	}
+
+exitGetAddr:
+	return val;
+}
+
+
+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: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctecc_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctecc_d.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,296 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 u32 GetScrubAddr_D(u32 Node);
+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;
+
+	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 */
+	val = mctGet_NVbits(NV_DCBKScrub);
+	mct_AdjustScrub_D(pDCTstatA, val);
+	OF_ScrubCTL |= val << 16;
+	val = mctGet_NVbits(NV_L2BKScrub);
+	OF_ScrubCTL |= val << 8;
+
+	val = mctGet_NVbits(NV_DramBKScrub);
+	OF_ScrubCTL |= val;
+
+	AllECC = 1;
+	MemClrECC = 0;
+	print_t(" ECCInit 0 \n");
+	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;
+						print_tx("  ECC enabled on node: ", Node);
+					}
+				}	/* this node has ECC enabled dram */
+			} else {
+				LDramECC = 0;
+			}	/* Node has Dram */
+
+			if (MemClrECC) {
+				MCTMemClrSync_D(pMCTstat, pDCTstatA);
+			}
+		}	/* if Node present */
+	}
+	print_t(" ECCInit 1 \n");
+
+	if(AllECC)
+		pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
+	else
+		pMCTstat->GStatus &= ~(1<<GSB_ECCDIMMs);
+
+	print_t(" ECCInit 2 \n");
+
+	/* 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 */    /*set dram background scrubbing to setup value */
+				}	/* this node has ECC enabled dram */
+			}	/*Node has Dram */
+		}	/*if Node present */
+	}
+	print_t(" ECCInit 3 \n");
+
+	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 u32 GetScrubAddr_D(u32 Node)
+{
+	/* Get the current 40-bit Scrub ADDR address, scaled to 32-bits,
+	 * of the specified Node.
+	 */
+
+	u32 reg;
+	u32 regx;
+	u32 lo, hi;
+	u32 val;
+	u32 dev = PA_NBMISC(Node);
+
+
+	reg = 0x60;		/* Scrub Addr High */
+	hi = Get_NB32(dev, reg);
+
+	regx = 0x5C;		/* Scrub Addr Low */
+	lo = Get_NB32(dev, regx);
+				/* Scrub Addr High again, detect 32-bit wrap */
+	val = Get_NB32(dev, reg);
+	if(val != hi) {
+		hi = val;	/* Scrub Addr Low again, if wrap occured */
+		lo = Get_NB32(dev, regx);
+	}
+
+	val = hi << 24;
+	val |= lo >> 8;
+
+	return val;		/* ScrubAddr[39:8] */
+}
+
+
+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: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctgr.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctgr.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 const u8 Tab_GRCLKDis[] = {	8,0,8,8,0,0,8,0 };
+
+
+u32 mct_AdjustMemClkDis_GR(struct DCTStatStruc *pDCTstat, u32 dct,
+				u32 DramTimingLo)
+{
+	/* Greayhound format -> Griffin format */
+	u32 NewDramTimingLo;
+	u32 dev = pDCTstat->dev_dct;
+	u32 reg;
+	u32 reg_off = 0x100 * dct;
+	u32 val;
+	int i;
+
+	DramTimingLo = val;
+	/* Dram Timing Low (owns Clock Enable bits) */
+	NewDramTimingLo = 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))) {
+			for(i=0; i<MAX_DIMMS_SUPPORTED; i++) {
+				val = Tab_GRCLKDis[i];
+				if(val<8) {
+					if(!(pDCTstat->DIMMValidDCT[dct] & (1<<val))) {
+						/* disable memclk */
+						NewDramTimingLo |= (1<<(i+1));
+					}
+				}
+			}
+		}
+	}
+	DramTimingLo &= ~(0xff<<24);
+	DramTimingLo |= NewDramTimingLo & (0xff<<24);
+	DramTimingLo &= (0x4d<<24); /* FIXME - enable all MemClks for now */
+
+	return DramTimingLo;
+}
+
+
+u32 mct_AdjustDramConfigLo_GR(struct DCTStatStruc *pDCTstat, u32 dct, u32 val)
+{
+	/* Greayhound format -> Griffin format */
+	/*FIXME - BurstLength32 must be 0 when F3x44[DramEccEn]=1. */
+/*
+			; mov	cx,PA_NBMISC+44h	;MCA NB Configuration
+			; call Get_NB32n_D
+			; bt eax,22				;EccEn
+			; .if(CARRY?)
+				; btr eax,BurstLength32
+			; .endif
+*/
+	return val;
+}
+
+
+void mct_AdjustMemHoist_GR(struct DCTStatStruc *pDCTstat, u32 base, u32 HoleSize)
+{
+	u32 val;
+	if(base >= pDCTstat->DCTHoleBase) {
+		u32 dev = pDCTstat->dev_dct;
+		base += HoleSize;
+		base >>= 27 - 8;
+		val = Get_NB32(dev, 0x110);
+		val &= ~(0xfff<<11);
+		val |= (base & 0xfff)<<11;
+		Set_NB32(dev, 0x110, val);
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mcthdi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mcthdi.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctmtr_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctmtr_d.c	2007-12-12 11:58:49.000000000 -0700
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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;
+	}
+
+	val = mctGet_NVbits(NV_BottomUMA);
+	if(val == 0)
+		val++;
+
+	val <<= (24-8);
+	if(val >  Bottom32bIO)
+		val = Bottom32bIO;
+
+	Cache32bTOP = val;
+
+	/*======================================================================
+	 Set default values for CPU registers
+	======================================================================*/
+
+	/* NOTE : For LinuxBIOS, 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 LinuxBIOS change from 0x200 to 0x204: LinuxBIOS 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*/
+	print_tx("\t CPUMemTyping: Cache32bTOP:", 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);
+	print_tx("\t CPUMemTyping: Bottom32bIO:", Bottom32bIO);
+	print_tx("\t CPUMemTyping: Bottom40bIO:", 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;
+}
+
+
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctndi_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctndi_d.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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;
+	u8 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 */
+			print_tx("InterleaveNodes: DRAM Controller Select Low Register = ", 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);
+	}
+	print_tx("InterleaveNodes_D: Status ", pDCTstat->Status);
+	print_tx("InterleaveNodes_D: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("InterleaveNodes_D: ErrCode ", pDCTstat->ErrCode);
+	print_t("InterleaveNodes_D: Done\n");
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctpro_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctpro_d.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,406 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 CheckNBCOFAutoPrechg(struct DCTStatStruc *pDCTstat, u32 dct);
+static u8 mct_AdjustDQSPosDelay_D(struct DCTStatStruc *pDCTstat, u8 dly);
+
+void EarlySampleSupport_D(void)
+{
+}
+
+
+u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val)
+{
+	u32 tmp;
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		val &= 0x0FFFFFFF;
+		if(pDCTstat->MAdimms[dct] > 1)
+			val |= 0x10000000;
+	}
+
+	return val;
+}
+
+
+u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val)
+{
+	/* Bug#10695:One MEMCLK Bubble Writes Don't Do X4 X8 Switching Correctly
+	 * Solution: BIOS should set DRAM Timing High[Twrwr] > 00b
+	 * ( F2x[1, 0]8C[1:0] > 00b).  Silicon Status: Fixed in Rev B
+	 * FIXME: check if this is still required.
+	 */
+	u32 tmp;
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		if(!(val & (3<<12) ))
+			val |= 1<<12;
+	}
+	return val;
+}
+
+
+void mct_ForceAutoPrecharge_D(struct DCTStatStruc *pDCTstat, u32 dct)
+{
+	u32 tmp;
+	u32 reg;
+	u32 reg_off;
+	u32 dev;
+	u32 val;
+
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		if(CheckNBCOFAutoPrechg(pDCTstat, dct)) {
+			dev = pDCTstat->dev_dct;
+			reg_off = 0x100 * dct;
+			reg = 0x90 + reg_off;	/* Dram Configuration Lo */
+			val = Get_NB32(dev, reg);
+			val |= 1<<ForceAutoPchg;
+			if(!pDCTstat->GangedMode)
+				val |= 1<<BurstLength32;
+			Set_NB32(dev, reg, val);
+
+			reg = 0x88 + reg_off;	/* cx=Dram Timing Lo */
+			val = Get_NB32(dev, reg);
+			val |= 0x000F0000;	/* Trc = 0Fh */
+			Set_NB32(dev, reg, val);
+		}
+	}
+}
+
+
+void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstatA)
+{
+	/* Bug#13341: Prefetch is getting killed when the limit is reached in
+	 * PrefDramTrainMode
+	 * Solution: Explicitly clear the PrefDramTrainMode bit after training
+	 * sequence in order to ensure resumption of normal HW prefetch
+	 * behavior.
+	 * NOTE -- this has been documented with a note at the end of this
+	 * section in the  BKDG (although, admittedly, the note does not really
+	 * stand out).
+	 * Silicon Status: Fixed in Rev B ( confirm)
+	 * FIXME: check this.
+	 */
+
+	u32 tmp;
+	u32 dev;
+	u32 reg;
+	u32 val;
+	u32 Node;
+
+	for(Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+		struct DCTStatStruc *pDCTstat;
+		pDCTstat = pDCTstatA + Node;
+
+		if(!pDCTstat->NodePresent) break;
+
+		tmp = pDCTstat->LogicalCPUID;
+		if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+			dev = pDCTstat->dev_dct;
+			reg = 0x11c;
+			val = Get_NB32(dev, reg);
+			val &= ~(1<<PrefDramTrainMode);
+			Set_NB32(dev, reg, val);
+		}
+	}
+}
+
+
+
+
+void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstat)
+{
+	/* 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
+	 *   regi..
+	 * Solutiuon: At least, set WrDqs fine delay to be 0 for DDR2 training.
+	 */
+
+	u32 dev;
+	u32 reg_off;
+	u32 index_reg;
+	u32 index;
+	u32 reg;
+	u32 val;
+	u32 tmp;
+	u32 Channel;
+
+
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+
+		dev = pDCTstat->dev_dct;
+		index = 0;
+
+		for(Channel = 0; Channel<2; Channel++) {
+			index_reg = 0x98 + 0x100 * Channel;
+			val = Get_NB32_index_wait(dev, index_reg, 0x0d004007);
+			val |= 0x3ff;
+			Set_NB32_index_wait(dev, index_reg, 0x0d0f4f07, val);
+		}
+
+		for(Channel = 0; Channel<2; Channel++) {
+			if(pDCTstat->GangedMode && Channel)
+				break;
+			reg_off = 0x100 * Channel;
+			reg = 0x78 + reg_off;
+			val = Get_NB32(dev, reg);
+			val &= ~(0x07);
+			val |= 5;
+			Set_NB32(dev, reg, val);
+		}
+
+		for(Channel = 0; Channel<2; Channel++) {
+			reg_off = 0x100 * Channel;
+			val = 0;
+			index_reg = 0x98 + reg_off;
+			for( index = 0x30; index < (0x45 + 1); index++) {
+				Set_NB32_index_wait(dev, index_reg, index, val);
+			}
+		}
+
+	}
+}
+
+
+u32 Modify_D3CMP(struct DCTStatStruc *pDCTstat, u32 dct, u32 value)
+{
+	/* Errata#189: Reads To Phy Driver Calibration Register and Phy
+	 *  Predriver Calibration Register Do Not Return Bit 27.
+	 * Solution: See #41322 for details.
+	 * BIOS can modify bit 27 of the Phy Driver Calibration register
+	 * as follows:
+	 *  1. Read F2x[1, 0]9C_x09
+	 *  2. Read F2x[1, 0]9C_x0D004201
+	 *  3. Set F2x[1, 0]9C_x09[27] = F2x[1, 0]9C_x0D004201[10]
+	 * BIOS can modify bit 27 of the Phy Predriver Calibration register
+	 * as follows:
+	 *  1. Read F2x[1, 0]9C_x0A
+	 *  2. Read F2x[1, 0]9C_x0D004209
+	 *  3. Set F2x[1, 0]9C_x0A[27] = F2x[1, 0]9C_x0D004209[10]
+	 * Silicon Status: Fixed planned for DR-B0
+	 */
+
+	u32 dev;
+	u32 index_reg;
+	u32 index;
+	u32 val;
+	u32 tmp;
+
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		dev = pDCTstat->dev_dct;
+		index_reg = 0x98 + 0x100 * dct;
+		index = 0x0D004201;
+		val = Get_NB32_index_wait(dev, index_reg, index);
+		value &= ~(1<<27);
+		value |= ((val>>10) & 1) << 27;
+	}
+	return value;
+}
+
+
+void SyncSetting(struct DCTStatStruc *pDCTstat)
+{
+	/* Errata#198: AddrCmdSetup, CsOdtSetup, and CkeSetup Require Identical
+	 * Programming For Both Channels in Ganged Mode
+	 * Solution: The BIOS must program the following DRAM timing parameters
+	 * the same for both channels:
+	 *  1. F2x[1, 0]9C_x04[21] (AddrCmdSetup)
+	 *  2. F2x[1, 0]9C_x04[15] (CsOdtSetup)
+	 *  3. F2x[1, 0]9C_x04[5]) (CkeSetup)
+	 * That is, if the AddrCmdSetup, CsOdtSetup, or CkeSetup is
+	 * set to 1'b1 for one of the controllers, then the corresponding
+	 * AddrCmdSetup, CsOdtSetup, or CkeSetup must be set to 1'b1 for the
+	 * other controller.
+	 * Silicon Status: Fix TBD
+	 */
+
+	u32 tmp;
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		pDCTstat->CH_ODC_CTL[1] = pDCTstat->CH_ODC_CTL[0];
+		pDCTstat->CH_ADDR_TMG[1] = pDCTstat->CH_ADDR_TMG[0];
+	}
+}
+
+
+static u32 CheckNBCOFAutoPrechg(struct DCTStatStruc *pDCTstat, u32 dct)
+{
+	u32 ret = 0;
+	u32 lo, hi;
+	u32 msr;
+	u32 val;
+	u32 valx, valy;
+	u32 NbDid;
+
+	/* 3 * (Fn2xD4[NBFid]+4)/(2^NbDid)/(3+Fn2x94[MemClkFreq]) */
+	msr = 0xC0010071;
+	_RDMSR(msr, &lo, &hi);
+	NbDid = (lo>>22) & 1;
+
+	val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100 * dct);
+	valx = ((val & 0x07) + 3)<<NbDid;
+	print_tx("MemClk:", valx >> NbDid);
+
+	val = Get_NB32(pDCTstat->dev_nbmisc, 0xd4);
+	valy = ((val & 0x1f) + 4) * 3;
+	print_tx("NB COF:", valy >> NbDid);
+
+	val = valy/valx;
+	if((val==3) && (valy%valx))  /* 3 < NClk/MemClk < 4 */
+		ret = 1;
+
+	return ret;
+}
+
+
+void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct)
+{
+	u32 tmp;
+	u32 Speed;
+	u32 ch, ch_start, ch_end;
+	u32 index_reg;
+	u32 index;
+	u32 dev;
+	u32 val;
+
+
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		Speed = pDCTstat->Speed;
+		/* MemClkFreq = 333MHz or 533Mhz */
+		if((Speed == 3) || (Speed == 2)) {
+			if(pDCTstat->GangedMode) {
+				ch_start = 0;
+				ch_end = 2;
+			} else {
+				ch_start = dct;
+				ch_end = dct+1;
+			}
+			dev = pDCTstat->dev_dct;
+			index = 0x0D00E001;
+			for(ch=ch_start; ch<ch_end; ch++) {
+				index_reg = 0x98 + 0x100 * ch;
+				val = Get_NB32_index(dev, index_reg, 0x0D00E001);
+				val &= ~(0xf0);
+				val |= 0x80;
+				Set_NB32_index(dev, index_reg, 0x0D01E001, val);
+			}
+		}
+
+	}
+}
+
+
+static u8 mct_AdjustDelay_D(struct DCTStatStruc *pDCTstat, u8 dly)
+{
+	u8 skip = 0;
+	dly &= 0x1f;
+	if ((dly >= MIN_FENCE) && (dly <= MAX_FENCE))
+		skip = 1;
+
+	return skip;
+}
+
+
+static u8 mct_checkFenceHoleAdjust_D(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstat, u8 DQSDelay,
+				u8 ChipSel,  u8 *result)
+{
+	u8 ByteLane;
+	u32 tmp;
+
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		if (pDCTstat->Direction == DQS_WRITEDIR) {
+			if ((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) {
+				if(DQSDelay == 13) {
+					if (*result == 0xFF) {
+						for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+							pDCTstat->DQSDelay = 13;
+							pDCTstat->ByteLane = ByteLane;
+							/* store the value into the data structure */
+							StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+						}
+						return 1;
+					}
+				}
+			}
+			if (mct_AdjustDQSPosDelay_D(pDCTstat, DQSDelay)) {
+				*result = 0;
+			}
+		}
+	}
+	return 0;
+}
+
+
+static u8 mct_AdjustDQSPosDelay_D(struct DCTStatStruc *pDCTstat, u8 dly)
+{
+	u8 skip = 0;
+
+	dly &= 0x1f;
+	if ((dly >= MIN_DQS_WR_FENCE) && (dly <= MAX_DQS_WR_FENCE))
+		skip = 1;
+
+	return skip;
+
+}
+
+static void beforeInterleaveChannels_D(struct DCTStatStruc *pDCTstatA, u8 *enabled) {
+
+	if (pDCTstatA->LogicalCPUID & (AMD_DR_Ax))
+		*enabled = 0;
+}
+
+
+static u8 mctDoAxRdPtrInit_D(struct DCTStatStruc *pDCTstat, u8 *Rdtr)
+{
+	u32 tmp;
+
+	tmp = pDCTstat->LogicalCPUID;
+	if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+		*Rdtr = 5;
+		return 1;
+	}
+	return 0;
+}
+
+
+static void mct_AdjustScrub_D(struct DCTStatStruc *pDCTstat, u16 *scrub_request) {
+
+	/* Erratum #202: disable DCache scrubber for Ax parts */
+
+	if (pDCTstat->LogicalCPUID & (AMD_DR_Ax)) {
+		*scrub_request = 0;
+		pDCTstat->ErrStatus |= 1 << SB_DCBKScrubDis;
+	}
+}
+
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctsrc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctsrc.c	2007-12-12 12:12:47.000000000 -0700
@@ -0,0 +1,1121 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 2 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 CalcMaxLatency_D(struct DCTStatStruc *pDCTstat,
+				u8 DQSRcvrEnDly, u8 Channel);
+static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQSRcvEnDly);
+static void mct_SetDQSRcvEn_D(struct DCTStatStruc *pDCTstat, u32 val);
+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;
+	}
+	print_t("TrainRcvrEn: 1\n");
+
+	cr4 = read_cr4();
+	if(cr4 & ( 1 << 9)) {	/* save the old value */
+		_SSE2 = 1;
+	}
+	cr4 |= (1 << 9);	/* OSFXSR enable SSE2 */
+	write_cr4(cr4);
+	print_t("TrainRcvrEn: 2\n");
+
+	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 */
+	print_t("TrainRcvrEn: 3\n");
+
+	_DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
+
+
+	if(pDCTstat->Speed == 1) {
+		pDCTstat->T1000 = 5000;	/* get the T1000 figure (cycle time (ns)*1K */
+	} else if(pDCTstat->Speed == 2) {
+		pDCTstat->T1000 = 3759;
+	} else if(pDCTstat->Speed == 3) {
+		pDCTstat->T1000 = 3003;
+	} else if(pDCTstat->Speed == 4) {
+		pDCTstat->T1000 = 2500;
+	} else if(pDCTstat->Speed  == 5) {
+		pDCTstat->T1000 = 1876;
+	} else {
+		pDCTstat->T1000 = 0;
+	}
+
+	SetupRcvrPattern(pMCTstat, pDCTstat, PatternBuffer, Pass);
+	print_t("TrainRcvrEn: 4\n");
+
+	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)) {
+				print_t("\t\t\tRank not enabled_D\n");
+				continue;
+			}
+
+			TestAddr0 = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, Channel, Receiver, &valid);
+			if(!valid) {	/* Address not supported on current CS */
+				print_t("\t\t\tAddress not supported on current CS\n");
+				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 */
+					print_t("\t\t\tAddress not supported on current CS+1\n");
+					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 */
+		print_t("TrainRcvrEn: mct_DisableDQSRcvEn_D\n");
+		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;
+		print_debug("TrainRcvrEn: 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
+
+#if DQS_TRAIN_DEBUG > 0
+	{
+		u8 val;
+		u8 Channel, Receiver;
+		u8 i;
+		u8 *p;
+
+		print_debug("TrainRcvrEn: CH_D_B_RCVRDLY:\n");
+		for(Channel = 0; Channel < 2; Channel++) {
+			print_debug("Channel:"); print_debug_hex8(Channel); print_debug("\n");
+			for(Receiver = 0; Receiver<8; Receiver+=2) {
+				print_debug("\t\tReceiver:");
+				print_debug_hex8(Receiver);
+				p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
+				print_debug(": ");
+				for (i=0;i<8; i++) {
+					val  = p[i];
+					print_debug_hex8(val);
+					print_debug(" ");
+				}
+			print_debug("\n");
+			}
+		}
+	}
+#endif
+
+	print_tx("TrainRcvrEn: Status ", pDCTstat->Status);
+	print_tx("TrainRcvrEn: ErrStatus ", pDCTstat->ErrStatus);
+	print_tx("TrainRcvrEn: ErrCode ", pDCTstat->ErrCode);
+	print_t("TrainRcvrEn: Done\n");
+}
+
+
+static 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) + 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 */
+
+	/* 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 == 4) {
+		val++;		/* adjust for DDR2-1066 */
+	}
+	valx = (val + 3) << 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 *addr_lo_buf;
+
+	SetUpperFSbase(addr);	// needed?
+
+	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;
+	}
+
+	addr_lo_buf = (u8 *) (addr << 8);
+	result = DQS_FAIL;
+
+	if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) {
+		addr_lo_buf += 8;	/* second channel */
+		test_buf += 8;
+	}
+
+
+#if DQS_TRAIN_DEBUG > 4
+	print_debug("\t\t\t\t\t\tQW0 :   test_buf  = ");
+	print_debug_hex32((unsigned)test_buf);
+	print_debug(": ");
+	for (i=0; i<8; i++) {
+		print_debug_hex8(test_buf[i]); print_debug(" ");
+	}
+	print_debug("\n");
+
+	print_debug("\t\t\t\t\t\tQW0 : addr_lo_buf = ");
+	print_debug_hex32((unsigned)addr_lo_buf);
+	print_debug(": ");
+	for (i=0; i<8; i++) {
+		print_debug_hex8(addr_lo_buf[i]); print_debug(" ");
+	}
+	print_debug("\n");
+#endif
+
+	/* prevent speculative execution of following instructions */
+	_EXECFENCE;
+
+	for (i=0; i<8; i++) {
+		if(addr_lo_buf[i] == test_buf[i]) {
+			pDCTstat->DqsRcvEn_Pass |= (1<<i);
+		} else {
+			pDCTstat->DqsRcvEn_Pass &= ~(1<<i);
+		}
+	}
+
+
+	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 = 2; // 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(val0 > val1) {
+				val = val0 - val1;
+			} else {
+				val = val1 - val0;
+			}
+
+			val *= ~EccDQSScale;
+			val >>= 8; // /256
+
+			if(val0 > val1) {
+				val -= val1;
+			} else {
+				val += val0;
+			}
+
+		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);
+		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_10ns (20000);		/* 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]. */
+	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);
+}
+
+
+static void mct_Wait_10ns (u32 cycles)
+{
+	u32 saved, i;
+	u32 hi, lo, msr;
+
+	/* cycles = number of 10ns cycles(or longer) to delay */
+	/* FIXME: Need to calibrate to CPU/NCLK speed? */
+
+	msr = 0x10;				/* TSC */
+	for (i = 0; i < cycles; i++) {
+		_RDMSR(msr, &lo, &hi);
+		saved = lo;
+
+		do {
+			_RDMSR(msr, &lo, &hi);
+		} while (lo - saved < 8);	/* 8 x 1.25 ns as NCLK is  at 1.25ns */
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctsrc1p.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctsrc1p.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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;
+}
+
+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_AdjustFinalDQSRcvValue_1Pass(u8 val_1p, u8 val_2p)
+{
+	return (val_1p & 0xff) + ((val_2p & 0xff)<<8);
+}
+
+
+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: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctsrc2p.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mctsrc2p.c	2007-12-12 12:00:14.000000000 -0700
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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;
+//		print_tx("mct_Get_Start_RcvrEnDly_Pass: Channel:", Channel);
+//		print_tx("mct_Get_Start_RcvrEnDly_Pass: Receiver:", Receiver);
+		for ( i=0;i<bn; i++) {
+			val  = p[i];
+//			print_tx("mct_Get_Start_RcvrEnDly_Pass: i:", i);
+//			print_tx("mct_Get_Start_RcvrEnDly_Pass: val:", val);
+			if(val > max) {
+				max = val;
+			}
+		}
+		RcvrEnDly = max;
+//		while(1) {; }
+//		RcvrEnDly += secPassOffset; //FIXME Why
+	}
+
+	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: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mcttmrl.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mcttmrl.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 2 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 == 4) {
+		val++;		/* adjust for DDR2-1066 */
+	}
+	valx = (val + 3) << 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: LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/mct/mct.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,552 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef MCT_H
+#define MCT_H
+/*===========================================================================
+	CPU - K8/FAM10
+===========================================================================*/
+#define PT_L1		0		/* CPU Package Type*/
+#define PT_M2		1
+#define PT_S1		2
+
+#define J_MIN		0		/* j loop constraint. 1=CL 2.0 T*/
+#define J_MAX		4		/* j loop constraint. 4=CL 6.0 T*/
+#define K_MIN		1		/* k loop constraint. 1=200 Mhz*/
+#define K_MAX		4		/* k loop constraint. 9=400 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_3	60	/* Max Async Latency Control value (This value will be divided by 20)*/
+#define DQS_FAIL	1
+#define DQS_PASS	0
+#define DQS_WRITEDIR	0
+#define DQS_READDIR	1
+#define MIN_DQS_WNDW	3
+#define secPassOffset	6
+
+#define PA_HOST	(((24 << 3)+0) << 8)	/* Node 0 Host Bus function PCI Address bits [15:0] */
+#define PA_MAP		(((24 << 3)+1) << 8)	/* Node 0 MAP function PCI Address bits [15:0] */
+#define PA_DCT		(((24 << 3)+2) << 8)	/* Node 0 DCT function PCI Address bits [15:0] */
+#define PA_DCTADDL	(((00 << 3)+2) << 8)	/* Node x DCT function, Additional Registers PCI Address bits [15:0] */
+#define PA_NBMISC	(((24 << 3)+3) << 8)	/* 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	3		/* bias to convert bus clocks to bit field value*/
+#define Bias_TrrdT	2
+#define Bias_TrcdT	3
+#define Bias_TrasT	3
+#define Bias_TrcT	11
+#define Bias_TrtpT	4
+#define Bias_TwrT	3
+#define Bias_TwtrT	0
+
+#define Min_TrpT	3		/* min programmable value in busclocks*/
+#define Max_TrpT	6		/* max programmable value in busclocks*/
+#define Min_TrrdT	2
+#define Max_TrrdT	5
+#define Min_TrcdT	3
+#define Max_TrcdT	6
+#define Min_TrasT	5
+#define Max_TrasT	18
+#define Min_TrcT	11
+#define Max_TrcT	26
+#define Min_TrtpT	4
+#define Max_TrtpT	5
+#define Min_TwrT	3
+#define Max_TwrT	6
+#define Min_TwtrT	1
+#define Max_TwtrT	3
+
+/* common register bit names */
+#define DramHoleValid	0		/* func 1, offset F0h, bit 0 */
+#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 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 DramEnabled	9		/* func 2, offset A0h, bit 9 */
+#define SyncOnUcEccEn	2		/* fun 3, offset 44h, bit 2 */
+
+/*=============================================================================
+	Jedec DDR II
+=============================================================================*/
+#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 SPD_DIMMTYPE	20
+#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 SPD_DEVATTRIB	22
+#define SPD_EDCTYPE	11
+	#define JED_ECC		0x02
+	#define JED_ADRCPAR	0x04
+#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) */
+
+/*--------------------------------------
+	Jedec 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*/
+
+
+/*===============================================================================
+	Local DCT Status structure (a structure for each DCT)
+===============================================================================*/
+
+struct DCTStatStruc {		/* A per Node structure*/
+	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 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 DIMM1Kpage;		/* 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 */
+	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*/
+//	u8 reserved_b_1;	/* Reserved*/
+				/* CHB DQS ECC byte like...*/
+				/* CHB DQS ECC byte scale*/
+//	u8 reserved_b_2;	/*Reserved*/
+	u8 MaxAsyncLat;	/* Max Asynchronous Latency (ns)*/
+	u8 CH_B_DQS[2][2][9];	/* CHA Byte 0 - 7 and Check Write DQS Delay*/
+				/* Reserved*/
+				/* CHA Byte 0 - 7 and Check Read DQS Delay*/
+				/* Reserved*/
+				/* CHB Byte 0 - 7 and Check Write DQS Delay*/
+				/* Reserved*/
+				/* CHB Byte 0 - 7 and Check Read DQS Delay*/
+				/* Reserved*/
+	u8 CH_D_RCVRDLY[2][4];	/* CHA DIMM 0 - 3 Receiver Enable Delay*/
+					/* CHB DIMM 0 - 3 Receiver Enable 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*/
+//	u8 reserved_b_3;	/* RSVD */
+	u32 AMC_TSC_DeltaLo;	/* Time Stamp Counter measurement of AMC, Low dword*/
+	u32 AMC_TSC_DeltaHi;	/* Time Stamp Counter measurement of AMC, High dword*/
+	u8 CH_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 ChannelTrainFail;	/* 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*/
+};
+
+/*===============================================================================
+	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*/
+
+/*===============================================================================
+	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.*/
+
+
+
+/*===============================================================================
+	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_Parity		60	/* Parity Enable*/
+#define NV_SyncOnUnEccEn	61	/* SyncOnUnEccEn control
+					   0=disable
+					   1=enable*/
+
+#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
+
+
+// global function
+u32 NodePresent(u32 Node);
+u32 Get_NB32n(struct DCTStatStruc *pDCTstat, u32 addrx);
+u32 Get_NB32(u32 addr); /* NOTE: extend addr to 32 bit for bus > 0 */
+u32 mctGetLogicalCPUID(u32 Node);
+
+void K8FInterleaveBanks(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+
+void mctInitWithWritetoCS(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+
+void mctGet_PS_Cfg(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+void Get_ChannelPS_Cfg0( unsigned MAAdimms, unsigned Speed, unsigned MAAload, unsigned DATAAload,
+		unsigned *AddrTmgCTL, unsigned *ODC_CTL);
+void Get_ChannelPS_Cfg1( unsigned MAAdimms, unsigned Speed, unsigned MAAload,
+		unsigned *AddrTmgCTL, unsigned *ODC_CTL, unsigned *val);
+void Get_ChannelPS_Cfg2( unsigned MAAdimms, unsigned Speed, unsigned MAAload,
+		unsigned *AddrTmgCTL, unsigned *ODC_CTL, unsigned *val);
+
+u8 MCTDefRet(void);
+
+u32 Get_RcvrSysAddr(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 channel, u8 receiver, u8 *valid);
+u32 Get_MCTSysAddr(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 channel, u8 chipsel, u8 *valid);
+void K8FTrainReceiverEn(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u8 pass);
+void K8FTrainDQSPos(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+u32 SetUpperFSbase(u32 addr_hi);
+
+
+void K8FECCInit(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+
+unsigned amd_FD_support(void);
+void amd_MCTInit(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+
+void K8FCPUMemTyping(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+void K8FCPUMemTyping_clear(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+
+void K8FWaitMemClrDelay(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
+unsigned K8FCalcFinalDQSRcvValue(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, unsigned LeftRcvEn, unsigned RightRcvEn, unsigned *valid);
+
+void K8FGetDeltaTSCPart1(struct DCTStatStruc *pDCTstat);
+void K8FGetDeltaTSCPart2(struct DCTStatStruc *pDCTstat);
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/wrappers/mcti.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/wrappers/mcti.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#define SERVER		0
+#define DESKTOP	1
+//#define MOBILE	2
+#define REV_F		0
+#define REV_DR		1
+#define REV_FDR	2
+
+
+/*----------------------------------------------------------------------------
+COMMENT OUT ALL BUT 1
+----------------------------------------------------------------------------*/
+//#define    BUILD_VERSION   REV_F	  /*BIOS supports rev F only*/
+//#define    BUILD_VERSION   REV_DR	  /*BIOS supports rev 10 only*/
+//#define    BUILD_VERSION   REV_FDR	  /*BIOS supports both rev F and 10*/
+
+/*----------------------------------------------------------------------------
+COMMENT OUT ALL BUT 1
+----------------------------------------------------------------------------*/
+#ifndef SYSTEM_TYPE
+#define    SYSTEM_TYPE	    SERVER
+//#define    SYSTEM_TYPE     DESKTOP
+//#define    SYSTEM_TYPE     MOBILE
+#endif
+
+/*----------------------------------------------------------------------------
+COMMENT OUT ALL BUT 1
+----------------------------------------------------------------------------*/
+#define UMA_SUPPORT	0	/*Not supported */
+//#define UMA_SUPPORT	1	/*Supported */
+
+/*----------------------------------------------------------------------------
+UPDATE AS NEEDED
+----------------------------------------------------------------------------*/
+#define MAX_NODES_SUPPORTED		8
+#define MAX_DIMMS_SUPPORTED		8
+#define MAX_CS_SUPPORTED		8
+#define MCT_TRNG_KEEPOUT_START		0x00000C00
+#define MCT_TRNG_KEEPOUT_END		0x00000CFF
+
Index: LinuxBIOSv2/src/northbridge/amd/amdmct/wrappers/mcti_d.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdmct/wrappers/mcti_d.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,338 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+/* Call-backs */
+
+u16 mctGet_NVbits(u8 index)
+{
+	u16 val = 0;
+
+	switch (index) {
+	case NV_PACK_TYPE:
+#if SYSTEM_TYPE == SERVER
+		val = 0;
+#elif SYSTEM_TYPE == DESKTOP
+		val = 1;
+//#elif SYSTEM_TYPE == MOBILE
+//		val = 2;
+#endif
+		break;
+	case NV_MAX_NODES:
+		val = MAX_NODES_SUPPORTED;
+		break;
+	case NV_MAX_DIMMS:
+		//val = MAX_DIMMS_SUPPORTED;
+		val = 8;
+		break;
+	case NV_MAX_MEMCLK:
+		/* Maximum platform supported memclk */
+		//val =  200;	/* 200MHz(DDR400) */
+		//val =  266;	/* 266MHz(DDR533) */
+		//val =  333;	/* 333MHz(DDR667) */
+		val =  400;	/* 400MHz(DDR800) */
+		break;
+	case NV_ECC_CAP:
+#if SYSTEM_TYPE == SERVER
+		val = 1;	/* memory bus ECC capable */
+#else
+		val = 0;	/* memory bus ECC not capable */
+#endif
+		break;
+	case NV_4RANKType:
+		/* Quad Rank DIMM slot type */
+		val = 0;	/* normal */
+		//val = 1;	/* R4 (registered DIMMs in AMD server configuration) */
+		//val = 2;	/* S4 (Unbuffered SO-DIMMS) */
+		break;
+	case NV_BYPMAX:
+#if   (UMA_SUPPORT == 0)
+		val = 4;
+#elif  (UMA_SUPPORT == 1)
+		val = 7;
+#endif
+		break;
+	case NV_RDWRQBYP:
+#if  (UMA_SUPPORT == 0)
+		val = 2;
+#elif (UMA_SUPPORT == 1)
+		val = 3;
+#endif
+		break;
+	case NV_MCTUSRTMGMODE:
+		val = 0;	/* Automatic (recommended) */
+		//val = 1;	/* Limited */
+		//val = 2;	/* Manual */
+		break;
+	case NV_MemCkVal:
+		//val = 0;	/* 200MHz */
+		//val = 1;	/* 266MHz */
+		val = 2;	/* 333MHz */
+		break;
+	case NV_BankIntlv:
+		/* Bank (chip select) interleaving */
+		//val = 0;	/* disabled */
+		val = 1;	/* enabled (recommended) */
+		break;
+	case NV_MemHole:
+		//val = 0;	/* Disabled */
+		val = 1;	/* Enabled (recommended) */
+		break;
+	case NV_AllMemClks:
+		val = 0;	/* Normal (only to slots that have enabled DIMMs) */
+		//val = 1;	/* Enable all memclocks */
+		break;
+	case NV_SPDCHK_RESTRT:
+		val = 0;	/* Exit current node initialization if any DIMM has SPD checksum error */
+		//val = 1;	/* Ignore faulty SPD checksum (DIMM will still be disabled), continue current node intialization */
+		break;
+	case NV_DQSTrainCTL:
+		//val = 0;	/*Skip dqs training */
+		val = 1;	/* Perform dqs training */
+		break;
+	case NV_NodeIntlv:
+		val = 0;	/* Disabled (recommended) */
+		//val = 1;	/* Enable */
+		break;
+	case NV_BurstLen32:
+#if (UMA_SUPPORT == 0)
+		val = 0;	/* 64 byte mode */
+#elif (UMA_SUPPORT == 1)
+		val = 1;	/* 32 byte mode */
+#endif
+		break;
+	case NV_CKE_PDEN:
+		//val = 0;	/* Disable */
+		val = 1;	/* Enable */
+		break;
+	case NV_CKE_CTL:
+		val = 0;	/* per channel control */
+		//val = 1;	/* per chip select control */
+		break;
+	case NV_CLKHZAltVidC3:
+		val = 0;	/* disable */
+		//val = 1;	/* enable */
+		break;
+	case NV_BottomIO:
+		val = 0xC0;	/* address bits [31:24] */
+		break;
+	case NV_BottomUMA:
+#if (UMA_SUPPORT == 0)
+		val = 0xC0;	/* address bits [31:24] */
+#elif (UMA_SUPPORT == 1)
+		val = 0xB0;	/* address bits [31:24] */
+#endif
+		break;
+	case NV_ECC:
+#if (SYSTEM_TYPE == SERVER)
+		val = 1;	/* Enable */
+#else
+		val = 0;	/* Disable */
+#endif
+		break;
+	case NV_NBECC:
+#if (SYSTEM_TYPE == SERVER)
+		val = 1;	/* Enable */
+#else
+		val = 0;	/* Disable */
+#endif
+		break;
+	case NV_ChipKill:
+#if (SYSTEM_TYPE == SERVER)
+		val = 1;	/* Enable */
+#else
+		val = 0;	/* Disable */
+#endif
+		break;
+	case NV_ECCRedir:
+		val = 0;	/* Disable */
+		//val = 1;	/* Enable */
+		break;
+	case NV_DramBKScrub:
+		val = 0x00;	/* Disabled */
+		//val = 0x01;	/* 40ns */
+		//val = 0x02;	/* 80ns */
+		//val = 0x03;	/* 160ns */
+		//val = 0x04;	/* 320ns */
+		//val = 0x05;	/* 640ns */
+		//val = 0x06;	/* 1.28us */
+		//val = 0x07;	/* 2.56us */
+		//val = 0x08;	/* 5.12us */
+		//val = 0x09;	/* 10.2us */
+		//val = 0x0a;	/* 20.5us */
+		//val = 0x0b;	/* 41us */
+		//val = 0x0c;	/* 81.9us */
+		//val = 0x0d;	/* 163.8us */
+		//val = 0x0e;	/* 327.7us */
+		//val = 0x0f;	/* 655.4us */
+		//val = 0x10;	/* 1.31ms */
+		//val = 0x11;	/* 2.62ms */
+		//val = 0x12;	/* 5.24ms */
+		//val = 0x13;	/* 10.49ms */
+		//val = 0x14;	/* 20.97sms */
+		//val = 0x15;	/* 42ms */
+		//val = 0x16;	/* 84ms */
+		break;
+	case NV_L2BKScrub:
+		val = 0;	/* Disabled - See L2Scrub in BKDG */
+		break;
+	case NV_DCBKScrub:
+		val = 0;	/* Disabled - See DcacheScrub in BKDG */
+		break;
+	case NV_CS_SpareCTL:
+		val = 0;	/* Disabled */
+		//val = 1;	/* Enabled */
+	case NV_SyncOnUnEccEn:
+		val = 0;	/* Disabled */
+		//val = 1;	/* Enabled */
+	case NV_Unganged:
+		/* channel interleave is better performance than ganged mode at this time */
+		val = 1;		/* Enabled */
+		//val = 0;	/* Disabled */
+	case NV_ChannelIntlv:
+		val = 5;	/* Disabled */ /* Not currently checked in mctchi_d.c */
+	/* Bit 0 =     0 - Disable
+	 *             1 - Enable
+	 * Bits[2:1] = 00b - Address bits 6
+	 *             01b - Address bits 1
+	 *             10b - Hash*, XOR of address bits [20:16, 6]
+	 *             11b - Hash*, XOR of address bits [20:16, 9]
+	 */
+
+	}
+
+	return val;
+}
+
+
+void mctHookAfterDIMMpre(void)
+{
+}
+
+
+void mctGet_MaxLoadFreq(struct DCTStatStruc *pDCTstat)
+{
+	pDCTstat->PresetmaxFreq = 400;
+}
+
+
+void mctAdjustAutoCycTmg(void)
+{
+}
+
+void mctAdjustAutoCycTmg_D(void)
+{
+}
+
+
+void mctHookAfterAutoCycTmg(void)
+{
+}
+
+
+void mctGetCS_ExcludeMap(void)
+{
+}
+
+
+void mctHookAfterAutoCfg(void)
+{
+}
+
+
+void mctHookAfterPSCfg(void)
+{
+}
+
+
+void mctHookAfterHTMap(void)
+{
+}
+
+
+void mctHookAfterCPU(void)
+{
+}
+
+
+void mctSaveDQSSigTmg_D(void)
+{
+}
+
+
+void mctGetDQSSigTmg_D(void)
+{
+}
+
+
+void mctHookBeforeECC(void)
+{
+}
+
+
+void mctHookAfterECC(void)
+{
+}
+
+
+void mctInitMemGPIOs_A(void)
+{
+}
+
+
+void mctInitMemGPIOs_A_D(void)
+{
+}
+
+
+void mctNodeIDDebugPort_D(void)
+{
+}
+
+
+void mctWarmReset(void)
+{
+}
+
+void mctWarmReset_D(void)
+{
+}
+
+
+void mctHookBeforeDramInit(void)
+{
+}
+
+
+void mctHookAfterDramInit(void)
+{
+}
+
+
+void mctHookBeforeAnyTraining(void)
+{
+}
+
+void mctHookAfterAnyTraining(void)
+{
+}
+
+u32 mctGetLogicalCPUID_D(u8 node)
+{
+	return mctGetLogicalCPUID(node);
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/Config.lb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/Config.lb	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,79 @@
+#
+# This file is part of the LinuxBIOS project.
+#
+# Copyright (C) 2007 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
+#
+
+uses CONFIG_CHIP_NAME
+uses AGP_APERTURE_SIZE
+uses HAVE_ACPI_TABLES
+
+default AGP_APERTURE_SIZE=0x4000000
+
+if CONFIG_CHIP_NAME
+	config chip.h
+end
+
+object northbridge.o
+driver misc_control.o
+
+if HAVE_ACPI_TABLES
+	object amdfam10_acpi.o
+	makerule ssdt.c
+		depends "$(TOP)/src/northbridge/amd/amdfam10/ssdt.dsl"
+		action	 "iasl -tc $(TOP)/src/northbridge/amd/amdfam10/ssdt.dsl"
+		action	 "perl -pi -e 's/AmlCode/AmlCode_ssdt/g' ssdt.hex"
+		action	 "mv ssdt.hex ssdt.c"
+	end
+	object ./ssdt.o
+	makerule sspr1.c
+		depends "$(TOP)/src/northbridge/amd/amdfam10/sspr1.dsl"
+		action	 "iasl -tc $(TOP)/src/northbridge/amd/amdfam10/sspr1.dsl"
+		action	 "perl -pi -e 's/AmlCode/AmlCode_sspr1/g' sspr1.hex"
+		action	 "mv sspr1.hex sspr1.c"
+	end
+	object ./sspr1.o
+	makerule sspr2.c
+		depends "$(TOP)/src/northbridge/amd/amdfam10/sspr2.dsl"
+		action	 "iasl -tc $(TOP)/src/northbridge/amd/amdfam10/sspr2.dsl"
+		action	 "perl -pi -e 's/AmlCode/AmlCode_sspr2/g' sspr2.hex"
+		action	 "mv sspr2.hex sspr2.c"
+	end
+	object ./sspr2.o
+	makerule sspr3.c
+		depends "$(TOP)/src/northbridge/amd/amdfam10/sspr3.dsl"
+		action	 "iasl -tc $(TOP)/src/northbridge/amd/amdfam10/sspr3.dsl"
+		action	 "perl -pi -e 's/AmlCode/AmlCode_sspr3/g' sspr3.hex"
+		action	 "mv sspr3.hex sspr3.c"
+	end
+	object ./sspr3.o
+	makerule sspr4.c
+		depends "$(TOP)/src/northbridge/amd/amdfam10/sspr4.dsl"
+		action	 "iasl -tc $(TOP)/src/northbridge/amd/amdfam10/sspr4.dsl"
+		action	 "perl -pi -e 's/AmlCode/AmlCode_sspr4/g' sspr4.hex"
+		action	 "mv sspr4.hex sspr4.c"
+	end
+	object ./sspr4.o
+	makerule sspr5.c
+		depends "$(TOP)/src/northbridge/amd/amdfam10/sspr5.dsl"
+		action	 "iasl -tc $(TOP)/src/northbridge/amd/amdfam10/sspr5.dsl"
+		action	 "perl -pi -e 's/AmlCode/AmlCode_sspr5/g' sspr5.hex"
+		action	 "mv sspr5.hex sspr5.c"
+	end
+	object ./sspr5.o
+end
+
+object get_pci1234.o
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,1164 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef AMDFAM10_H
+
+#define AMDFAM10_H
+/* Definitions of various FAM10 registers */
+/* Function 0 */
+#define HT_TRANSACTION_CONTROL 0x68
+#define  HTTC_DIS_RD_B_P		(1 << 0)
+#define  HTTC_DIS_RD_DW_P		(1 << 1)
+#define  HTTC_DIS_WR_B_P		(1 << 2)
+#define  HTTC_DIS_WR_DW_P		(1 << 3)
+#define  HTTC_DIS_MTS			(1 << 4)
+#define  HTTC_CPU1_EN			(1 << 5)
+#define  HTTC_CPU_REQ_PASS_PW		(1 << 6)
+#define  HTTC_CPU_RD_RSP_PASS_PW	(1 << 7)
+#define  HTTC_DIS_P_MEM_C		(1 << 8)
+#define  HTTC_DIS_RMT_MEM_C		(1 << 9)
+#define  HTTC_DIS_FILL_P		(1 << 10)
+#define  HTTC_RSP_PASS_PW		(1 << 11)
+#define  HTTC_BUF_REL_PRI_SHIFT	13
+#define  HTTC_BUF_REL_PRI_MASK		3
+#define   HTTC_BUF_REL_PRI_64		0
+#define   HTTC_BUF_REL_PRI_16		1
+#define   HTTC_BUF_REL_PRI_8		2
+#define   HTTC_BUF_REL_PRI_2		3
+#define  HTTC_LIMIT_CLDT_CFG		(1 << 15)
+#define  HTTC_LINT_EN			(1 << 16)
+#define  HTTC_APIC_EXT_BRD_CST		(1 << 17)
+#define  HTTC_APIC_EXT_ID		(1 << 18)
+#define  HTTC_APIC_EXT_SPUR		(1 << 19)
+#define  HTTC_SEQ_ID_SRC_NODE_EN	(1 << 20)
+#define  HTTC_DS_NP_REQ_LIMIT_SHIFT	21
+#define  HTTC_DS_NP_REQ_LIMIT_MASK	3
+#define   HTTC_DS_NP_REQ_LIMIT_NONE	0
+#define   HTTC_DS_NP_REQ_LIMIT_1	1
+#define   HTTC_DS_NP_REQ_LIMIT_4	2
+#define   HTTC_DS_NP_REQ_LIMIT_8	3
+
+
+/* Function 1 */
+#define PCI_IO_BASE0	0xc0
+#define PCI_IO_BASE1	0xc8
+#define PCI_IO_BASE2	0xd0
+#define PCI_IO_BASE3	0xd8
+#define PCI_IO_BASE_VGA_EN	(1 << 4)
+#define PCI_IO_BASE_NO_ISA	(1 << 5)
+
+/* Function 2 */
+// 0x1xx is for DCT1
+#define DRAM_CSBASE	0x40
+#define DRAM_CSMASK	0x60
+#define DRAM_BANK_ADDR_MAP 0x80
+
+#define DRAM_CTRL	0x78
+#define  DC_RdPtrInit_SHIFT 0
+#define  DC_RdPrtInit_MASK  0xf
+#define  DC_Twrrd3_2_SHIFT 8  /*DDR3 */
+#define  DC_Twrrd3_2_MASK 3
+#define  DC_Twrwr3_2_SHIFT 10 /*DDR3 */
+#define  DC_Twrwr3_2_MASK 3
+#define  DC_Trdrd3_2_SHIFT 12 /*DDR3 */
+#define  DC_Trdrd3_2_MASK 3
+#define  DC_AltVidC3MemClkTriEn (1<<16)
+#define  DC_DqsRcvEnTrain (1<<18)
+#define  DC_MaxRdLatency_SHIFT 22
+#define  DC_MaxRdLatency_MASK 0x3ff
+
+#define DRAM_INIT	0x7c
+#define  DI_MrsAddress_SHIFT 0
+#define  DI_MrsAddress_MASK 0xffff
+#define  DI_MrsBank_SHIFT 16
+#define  DI_MrsBank_MASK 7
+#define  DI_MrsChipSel_SHIFT 20
+#define  DI_MrsChipSel_MASK 7
+#define  DI_SendRchgAll (1<<24)
+#define  DI_SendAutoRefresh (1<<25)
+#define  DI_SendMrsCmd	  (1<<26)
+#define  DI_DeassertMemRstX (1<<27)
+#define  DI_AssertCke	 (1<<28)
+#define  DI_SendZQCmd	(1<<29) /*DDR3 */
+#define  DI_EnMrsCmd	(1<<30)
+#define  DI_EnDramInit	 (1<<31)
+
+#define DRAM_MRS	0x84
+#define  DM_BurstCtrl_SHIFT 0
+#define  DM_BurstCtrl_MASK 3
+#define  DM_DrvImpCtrl_SHIFT 2 /* DDR3 */
+#define  DM_DrvImpCtrl_MASK 3
+#define  DM_Twr_SHIFT 4 /* DDR3 */
+#define  DM_Twr_MASK 7
+#define  DM_Twr_BASE 4
+#define  DM_Twr_MIN  5
+#define  DM_Twr_MAX  12
+#define  DM_DramTerm_SHIFT 7 /*DDR3 */
+#define  DM_DramTerm_MASK 7
+#define  DM_DramTermDyn_SHIFT 10 /* DDR3 */
+#define  DM_DramTermDyn_MASK 3
+#define  DM_Ooff (1<<13)
+#define  DM_ASR (1<<18)
+#define  DM_SRT (1<<19)
+#define  DM_Tcwl_SHIFT 20
+#define  DM_Tcwl_MASK 7
+#define  DM_PchgPDModeSel (1<<23) /* DDR3 */
+#define  DM_MPrLoc_SHIFT 24 /* DDR3 */
+#define  DM_MPrLoc_MASK 3
+#define  DM_MprEn (1<<26) /* DDR3 */
+
+#define DRAM_TIMING_LOW	   0x88
+#define	 DTL_TCL_SHIFT	   0
+#define	 DTL_TCL_MASK	   0xf
+#define	  DTL_TCL_BASE	   1 /* DDR3 =4 */
+#define	  DTL_TCL_MIN	   3 /* DDR3 =4 */
+#define	  DTL_TCL_MAX	   6 /* DDR3 =12 */
+#define	 DTL_TRCD_SHIFT	   4
+#define	 DTL_TRCD_MASK	   3 /* DDR3 =7 */
+#define	  DTL_TRCD_BASE	   3 /* DDR3 =5 */
+#define	  DTL_TRCD_MIN	   3 /* DDR3 =5 */
+#define   DTL_TRCD_MAX	    6 /* DDR3 =12 */
+#define	 DTL_TRP_SHIFT	   8 /* DDR3 =7 */
+#define	 DTL_TRP_MASK	   3 /* DDR3 =7 */
+#define	  DTL_TRP_BASE	   3 /* DDR3 =5 */
+#define	  DTL_TRP_MIN	   3 /* DDR3 =5 */
+#define   DTL_TRP_MAX	    6 /* DDR3 =12 */
+#define	 DTL_TRTP_SHIFT	   11 /*DDR3 =10 */
+#define	 DTL_TRTP_MASK	   1  /*DDR3 =3 */
+#define	  DTL_TRTP_BASE	   2  /* DDR3 =4 */
+#define	  DTL_TRTP_MIN	   2  /* 4 for 64 bytes*/  /* DDR3 =4 for 32bytes or 64bytes */
+#define   DTL_TRTP_MAX	    3  /* 5 for 64 bytes */ /* DDR3 =7 for 32Bytes or 64bytes */
+#define	 DTL_TRAS_SHIFT	   12
+#define	 DTL_TRAS_MASK	   0xf
+#define	  DTL_TRAS_BASE	   3 /* DDR3 =15 */
+#define	  DTL_TRAS_MIN	   5 /* DDR3 =15 */
+#define	  DTL_TRAS_MAX	   18 /*DDR3 =30 */
+#define	 DTL_TRC_SHIFT	   16
+#define	 DTL_TRC_MASK	   0xf /* DDR3 =0x1f */
+#define	  DTL_TRC_BASE	   11
+#define	  DTL_TRC_MIN	   11
+#define	  DTL_TRC_MAX	   26  /* DDR3 =43 */
+#define	 DTL_TWR_SHIFT	   20 /* only for DDR2, DDR3's is on DC */
+#define	 DTL_TWR_MASK	   3
+#define	  DTL_TWR_BASE	   3
+#define	  DTL_TWR_MIN	   3
+#define	  DTL_TWR_MAX	   6
+#define  DTL_TRRD_SHIFT    22
+#define   DTL_TRRD_MASK    3
+#define   DTL_TRRD_BASE    2 /* DDR3 =4 */
+#define   DTL_TRRD_MIN	   2 /* DDR3 =4 */
+#define   DTL_TRRD_MAX	    5 /* DDR3 =7 */
+#define  DTL_MemClkDis_SHIFT 24    /* Channel A */
+#define  DTL_MemClkDis3       (1 << 26)
+#define  DTL_MemClkDis2       (1 << 27)
+#define  DTL_MemClkDis1       (1 << 28)
+#define  DTL_MemClkDis0       (1 << 29)
+/* DTL_MemClkDis for m2 and s1g1 is different */
+
+#define DRAM_TIMING_HIGH   0x8c
+#define  DTH_TRWTWB_SHIFT 0
+#define  DTH_TRWTWB_MASK 3
+#define   DTH_TRWTWB_BASE 3  /* DDR3 =4 */
+#define   DTH_TRWTWB_MIN  3  /* DDR3 =5 */
+#define   DTH_TRWTWB_MAX  10 /* DDR3 =11 */
+#define  DTH_TRWTTO_SHIFT  4
+#define  DTH_TRWTTO_MASK   7
+#define   DTH_TRWTTO_BASE   2 /* DDR3 =3 */
+#define   DTH_TRWTTO_MIN    2 /* DDR3 =3 */
+#define   DTH_TRWTTO_MAX    9 /* DDR3 =10 */
+#define	 DTH_TWTR_SHIFT	   8
+#define	 DTH_TWTR_MASK	   3
+#define	  DTH_TWTR_BASE	   0  /* DDR3 =4 */
+#define	  DTH_TWTR_MIN	   1  /* DDR3 =4 */
+#define	  DTH_TWTR_MAX	   3  /* DDR3 =7 */
+#define	 DTH_TWRRD_SHIFT   10
+#define	 DTH_TWRRD_MASK	   3	/* For DDR3 3_2 is at 0x78 DC */
+#define	  DTH_TWRRD_BASE   0  /* DDR3 =0 */
+#define	  DTH_TWRRD_MIN	   0  /* DDR3 =2 */
+#define	  DTH_TWRRD_MAX	   3  /* DDR3 =12 */
+#define  DTH_TWRWR_SHIFT   12
+#define  DTH_TWRWR_MASK    3	/* For DDR3 3_2 is at 0x78 DC */
+#define   DTH_TWRWR_BASE   1
+#define   DTH_TWRWR_MIN    1	/* DDR3 =3 */
+#define   DTH_TWRWR_MAX    3	/* DDR3 =12 */
+#define  DTH_TRDRD_SHIFT   14
+#define  DTH_TRDRD_MASK    3  /* For DDR3 3_2 is at 0x78 DC */
+#define   DTH_TRDRD_BASE   2
+#define   DTH_TRDRD_MIN    2
+#define   DTH_TRDRD_MAX    5	/* DDR3 =10 */
+#define	 DTH_TREF_SHIFT	   16
+#define	 DTH_TREF_MASK	   3
+#define	  DTH_TREF_7_8_US  2
+#define	  DTH_TREF_3_9_US  3
+#define  DTH_DisAutoRefresh (1<<18)
+#define  DTH_TRFC0_SHIFT   20 /* for Logical DIMM0 */
+#define  DTH_TRFC_MASK	     7
+#define	  DTH_TRFC_75_256M   0
+#define	  DTH_TRFC_105_512M  1
+#define   DTH_TRFC_127_5_1G  2
+#define   DTH_TRFC_195_2G    3
+#define   DTH_TRFC_327_5_4G  4
+#if 0
+//DDR3
+#define   DTH_TRFC_90_512M   1
+#define   DTH_TRFC_110_5_1G  2
+#define   DTH_TRFC_160_2G    3
+#define   DTH_TRFC_300_4G    4
+#define   DTH_TRFC_UNDEFINED_8G   5
+#endif
+#define  DTH_TRFC1_SHIFT   23 /*for Logical DIMM1 */
+#define  DTH_TRFC2_SHIFT   26 /*for Logical DIMM2 */
+#define  DTH_TRFC3_SHIFT   29 /*for Logical DIMM3 */
+
+#define DRAM_CONFIG_LOW	   0x90
+#define	 DCL_InitDram	   (1<<0)
+#define	 DCL_ExitSelfRef   (1<<1)
+#define  DCL_PllLockTime_SHIFT 2
+#define  DCL_PllLockTime_MASK 3
+#define   DCL_PllLockTime_15US 0
+#define   DCL_PllLockTime_6US 1
+#define  DCL_DramTerm_SHIFT 4
+#define  DCL_DramTerm_MASK  3
+#define   DCL_DramTerm_No   0
+#define   DCL_DramTerm_75_OH 1
+#define   DCL_DramTerm_150_OH 2
+#define   DCL_DramTerm_50_OH 3
+#define  DCL_DisDqsBar	    (1<<6) /* only for DDR2 */
+#define  DCL_DramDrvWeak   (1<<7) /* only for DDR2 */
+#define  DCL_ParEn	   (1<<8)
+#define  DCL_SelfRefRateEn (1<<9) /* only for DDR2 */
+#define  DCL_BurstLength32 (1<<10) /* only for DDR3 */
+#define  DCL_Width128	   (1<<11)
+#define  DCL_X4Dimm_SHIFT  12
+#define  DCL_X4Dimm_MASK   0xf
+#define  DCL_UnBuffDimm    (1<<16)
+#define  DCL_EnPhyDqsRcvEnTr (1<<18)
+#define	 DCL_DimmEccEn	   (1<<19)
+#define  DCL_DynPageCloseEn (1<<20)
+#define  DCL_IdleCycInit_SHIFT 21
+#define  DCL_IdleCycInit_MASK	3
+#define   DCL_IdleCycInit_16CLK 0
+#define   DCL_IdleCycInit_32CLK 1
+#define   DCL_IdleCycInit_64CLK 2
+#define   DCL_IdleCycInit_96CLK 3
+#define  DCL_ForceAutoPchg   (1<<23)
+
+#define DRAM_CONFIG_HIGH   0x94
+#define  DCH_MemClkFreq_SHIFT 0
+#define  DCH_MemClkFreq_MASK  7
+#define   DCH_MemClkFreq_200MHz 0  /* DDR2 */
+#define   DCH_MemClkFreq_266MHz 1  /* DDR2 */
+#define   DCH_MemClkFreq_333MHz 2  /* DDR2 */
+#define	  DCH_MemClkFreq_400MHz 3  /* DDR2 and DDR 3*/
+#define	  DCH_MemClkFreq_533MHz 4  /* DDR 3 */
+#define	  DCH_MemClkFreq_667MHz 5  /* DDR 3 */
+#define	  DCH_MemClkFreq_800MHz 6  /* DDR 3 */
+#define  DCH_MemClkFreqVal	(1<<3)
+#define  DCH_Ddr3Mode		(1<<8)
+#define  DCH_LegacyBiosMode	(1<<9)
+#define  DCH_ZqcsInterval_SHIFT 10
+#define  DCH_ZqcsInterval_MASK	3
+#define  DCH_ZqcsInterval_DIS	0
+#define  DCH_ZqcsInterval_64MS	 1
+#define  DCH_ZqcsInterval_128MS  2
+#define  DCH_ZqcsInterval_256MS  3
+#define  DCH_RDqsEn	      (1<<12) /* only for DDR2 */
+#define  DCH_DisSimulRdWr	(1<<13)
+#define  DCH_DisDramInterface (1<<14)
+#define  DCH_PowerDownEn      (1<<15)
+#define  DCH_PowerDownMode_SHIFT 16
+#define  DCH_PowerDownMode_MASK 1
+#define   DCH_PowerDownMode_Channel_CKE 0
+#define   DCH_PowerDownMode_ChipSelect_CKE 1
+#define  DCH_FourRankSODimm	(1<<17)
+#define  DCH_FourRankRDimm	(1<<18)
+#define  DCH_SlowAccessMode	(1<<20)
+#define  DCH_BankSwizzleMode	 (1<<22)
+#define  DCH_DcqBypassMax_SHIFT 24
+#define  DCH_DcqBypassMax_MASK	 0xf
+#define   DCH_DcqBypassMax_BASE 0
+#define   DCH_DcqBypassMax_MIN	 0
+#define   DCH_DcqBypassMax_MAX	 15
+#define  DCH_FourActWindow_SHIFT 28
+#define  DCH_FourActWindow_MASK 0xf
+#define   DCH_FourActWindow_BASE 7 /* DDR3 15 */
+#define   DCH_FourActWindow_MIN 8  /* DDR3 16 */
+#define   DCH_FourActWindow_MAX 20 /* DDR3 30 */
+
+
+// for 0x98 index and 0x9c data for DCT0
+// for 0x198 index and 0x19c data for DCT1
+// even at ganged mode, 0x198/0x19c will be used for channnel B
+
+#define DRAM_CTRL_ADDI_DATA_OFFSET	0x98
+#define  DCAO_DctOffset_SHIFT	0
+#define  DCAO_DctOffset_MASK	0x3fffffff
+#define  DCAO_DctAccessWrite	(1<<30)
+#define  DCAO_DctAccessDone	(1<<31)
+
+#define DRAM_CTRL_ADDI_DATA_PORT	 0x9c
+
+#define DRAM_OUTPUT_DRV_COMP_CTRL	0x00
+#define  DODCC_CkeDrvStren_SHIFT 0
+#define  DODCC_CkeDrvStren_MASK  3
+#define   DODCC_CkeDrvStren_1_0X  0
+#define   DODCC_CkeDrvStren_1_25X 1
+#define   DODCC_CkeDrvStren_1_5X  2
+#define   DODCC_CkeDrvStren_2_0X  3
+#define  DODCC_CsOdtDrvStren_SHIFT 4
+#define  DODCC_CsOdtDrvStren_MASK  3
+#define   DODCC_CsOdtDrvStren_1_0X  0
+#define   DODCC_CsOdtDrvStren_1_25X 1
+#define   DODCC_CsOdtDrvStren_1_5X  2
+#define   DODCC_CsOdtDrvStren_2_0X  3
+#define  DODCC_AddrCmdDrvStren_SHIFT 8
+#define  DODCC_AddrCmdDrvStren_MASK  3
+#define   DODCC_AddrCmdDrvStren_1_0X  0
+#define   DODCC_AddrCmdDrvStren_1_25X 1
+#define   DODCC_AddrCmdDrvStren_1_5X  2
+#define   DODCC_AddrCmdDrvStren_2_0X  3
+#define  DODCC_ClkDrvStren_SHIFT 12
+#define  DODCC_ClkDrvStren_MASK  3
+#define   DODCC_ClkDrvStren_0_75X  0
+#define   DODCC_ClkDrvStren_1_0X 1
+#define   DODCC_ClkDrvStren_1_25X  2
+#define   DODCC_ClkDrvStren_1_5X  3
+#define  DODCC_DataDrvStren_SHIFT 16
+#define  DODCC_DataDrvStren_MASK  3
+#define   DODCC_DataDrvStren_0_75X  0
+#define   DODCC_DataDrvStren_1_0X 1
+#define   DODCC_DataDrvStren_1_25X  2
+#define   DODCC_DataDrvStren_1_5X  3
+#define  DODCC_DqsDrvStren_SHIFT 20
+#define  DODCC_DqsDrvStren_MASK  3
+#define   DODCC_DqsDrvStren_0_75X  0
+#define   DODCC_DqsDrvStren_1_0X 1
+#define   DODCC_DqsDrvStren_1_25X  2
+#define   DODCC_DqsDrvStren_1_5X  3
+#define  DODCC_ProcOdt_SHIFT 28
+#define  DODCC_ProcOdt_MASK  3
+#define   DODCC_ProcOdt_300_OHMS  0
+#define   DODCC_ProcOdt_150_OHMS 1
+#define   DODCC_ProcOdt_75_OHMS  2
+#if 0
+//DDR3
+#define   DODCC_ProcOdt_240_OHMS  0
+#define   DODCC_ProcOdt_120_OHMS 1
+#define   DODCC_ProcOdt_60_OHMS  2
+#endif
+
+/*
+   for DDR2 400, 533, 667, F2x[1,0]9C_x[02:01], [03], [06:05], [07] controll timing of all DIMMs
+   for DDR2 800, DDR3 800, 1067, 1333, 1600, F2x[1,0]9C_x[02:01], [03], [06:05], [07] controll timing of DIMM0
+					     F2x[1,0]9C_x[102:101], [103], [106:105], [107] controll timing of DIMM1
+	So Socket F with Four Logical DIMM will only support DDR2 800  ?
+*/
+/* there are index	   +100	   ===> for DIMM1
+that are corresponding to 0x01, 0x02, 0x03, 0x05, 0x06, 0x07
+*/
+//02/15/2006 18:37
+#define DRAM_WRITE_DATA_TIMING_CTRL_LOW 0x01
+#define  DWDTC_WrDatFineDlyByte0_SHIFT 0
+#define  DWDTC_WrDatFineDlyByte_MASK  0x1f
+#define   DWDTC_WrDatFineDlyByte_BASE 0
+#define   DWDTC_WrDatFineDlyByte_MIN  0
+#define   DWDTC_WrDatFineDlyByte_MAX  31 // 1/64 MEMCLK
+#define  DWDTC_WrDatGrossDlyByte0_SHIFT 5
+#define  DWDTC_WrDatGrossDlyByte_MASK	0x3
+#define   DWDTC_WrDatGrossDlyByte_NO_DELAY 0
+#define   DWDTC_WrDatGrossDlyByte_0_5_	 1
+#define   DWDTC_WrDatGrossDlyByte_1  2
+#define  DWDTC_WrDatFineDlyByte1_SHIFT 8
+#define  DWDTC_WrDatGrossDlyByte1_SHIFT 13
+#define  DWDTC_WrDatFineDlyByte2_SHIFT 16
+#define  DWDTC_WrDatGrossDlyByte2_SHIFT 21
+#define  DWDTC_WrDatFineDlyByte3_SHIFT 24
+#define  DWDTC_WrDatGrossDlyByte3_SHIFT 29
+
+#define DRAM_WRITE_DATA_TIMING_CTRL_HIGH 0x02
+#define  DWDTC_WrDatFineDlyByte4_SHIFT 0
+#define  DWDTC_WrDatGrossDlyByte4_SHIFT 5
+#define  DWDTC_WrDatFineDlyByte5_SHIFT 8
+#define  DWDTC_WrDatGrossDlyByte5_SHIFT 13
+#define  DWDTC_WrDatFineDlyByte6_SHIFT 16
+#define  DWDTC_WrDatGrossDlyByte6_SHIFT 21
+#define  DWDTC_WrDatFineDlyByte7_SHIFT 24
+#define  DWDTC_WrDatGrossDlyByte7_SHIFT 29
+
+#define DRAM_WRITE_ECC_TIMING_CTRL 0x03
+#define  DWETC_WrChkFinDly_SHIFT 0
+#define  DWETC_WrChkGrossDly_SHIFT 5
+
+#define DRAM_ADDR_CMD_TIMING_CTRL 0x04
+#define  DACTC_CkeFineDelay_SHIFT 0
+#define  DACTC_CkeFineDelay_MASK  0x1f
+#define   DACTC_CkeFineDelay_BASE 0
+#define   DACTC_CkeFineDelay_MIN  0
+#define   DACTC_CkeFineDelay_MAX 31
+#define  DACTC_CkeSetup	(1<<5)
+#define  DACTC_CsOdtFineDelay_SHIFT 8
+#define  DACTC_CsOdtFineDelay_MASK  0x1f
+#define   DACTC_CsOdtFineDelay_BASE 0
+#define   DACTC_CsOdtFineDelay_MIN  0
+#define   DACTC_CsOdtFineDelay_MAX 31
+#define  DACTC_CsOdtSetup   (1<<13)
+#define  DACTC_AddrCmdFineDelay_SHIFT 16
+#define  DACTC_AddrCmdFineDelay_MASK  0x1f
+#define   DACTC_AddrCmdFineDelay_BASE 0
+#define   DACTC_AddrCmdFineDelay_MIN  0
+#define   DACTC_AddrCmdFineDelay_MAX 31
+#define  DACTC_AddrCmdSetup   (1<<21)
+
+#define DRAM_READ_DQS_TIMING_CTRL_LOW 0x05
+#define  DRDTC_RdDqsTimeByte0_SHIFT 0
+#define  DRDTC_RdDqsTimeByte_MASK  0x3f
+#define   DRDTC_RdDqsTimeByte_BASE 0
+#define   DRDTC_RdDqsTimeByte_MIN  0
+#define   DRDTC_RdDqsTimeByte_MAX  63 // 1/128 MEMCLK
+#define  DRDTC_RdDqsTimeByte1_SHIFT 8
+#define  DRDTC_RdDqsTimeByte2_SHIFT 16
+#define  DRDTC_RdDqsTimeByte3_SHIFT 24
+
+#define DRAM_READ_DQS_TIMING_CTRL_HIGH 0x06
+#define  DRDTC_RdDqsTimeByte4_SHIFT 0
+#define  DRDTC_RdDqsTimeByte5_SHIFT 8
+#define  DRDTC_RdDqsTimeByte6_SHIFT 16
+#define  DRDTC_RdDqsTimeByte7_SHIFT 24
+
+#define DRAM_READ_DQS_ECC_TIMING_CTRL 0x07
+#define  DRDETC_RdDqsTimeCheck_SHIFT 0
+
+#define DRAM_PHY_CTRL 0x08
+#define  DPC_WrtLvTrEn	(1<<0)
+#define  DPC_WrtLvTrMode (1<<1)
+#define  DPC_TrNibbleSel (1<<2)
+#define  DPC_TrDimmSel_SHIFT 4
+#define   DPC_TrDimmSel_MASK 3 /* 0-->dimm0, 1-->dimm1, 2--->dimm2, 3--->dimm3 */
+#define  DPC_WrLvOdt_SHIFT 8
+#define   DPC_WrLvOdt_MASK 0xf /* bit 0-->odt 0, ...*/
+#define  DPC_WrLvODtEn (1<<12)
+#define  DPC_DqsRcvTrEn (1<<13)
+#define  DPC_DisAutoComp (1<<30)
+#define  DPC_AsyncCompUpdate (1<<31)
+
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_0_0 0x10 //DIMM0 Channel A
+#define  DDRETC_DqsRcvEnFineDelayByte0_SHIFT 0
+#define   DDRETC_DqsRcvEnFineDelayByte0_MASK 0x1f
+#define  DDRETC_DqsRcvEnGrossDelayByte0_SHIFT 5
+#define   DDRETC_DqsRcvEnGrossDelayByte0_MASK 0x3
+#define  DDRETC_DqsRcvEnFineDelayByte1_SHIFT 8
+#define  DDRETC_DqsRcvEnGrossDelayByte1_SHIFT 13
+#define  DDRETC_DqsRcvEnFineDelayByte2_SHIFT 16
+#define  DDRETC_DqsRcvEnGrossDelayByte2_SHIFT 21
+#define  DDRETC_DqsRcvEnFineDelayByte3_SHIFT 24
+#define  DDRETC_DqsRcvEnGrossDelayByte3_SHIFT 29
+
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_0_1 0x11 //DIMM0 Channel A
+#define  DDRETC_DqsRcvEnFineDelayByte4_SHIFT 0
+#define  DDRETC_DqsRcvEnGrossDelayByte4_SHIFT 5
+#define  DDRETC_DqsRcvEnFineDelayByte5_SHIFT 8
+#define  DDRETC_DqsRcvEnGrossDelayByte5_SHIFT 13
+#define  DDRETC_DqsRcvEnFineDelayByte6_SHIFT 16
+#define  DDRETC_DqsRcvEnGrossDelayByte6_SHIFT 21
+#define  DDRETC_DqsRcvEnFineDelayByte7_SHIFT 24
+#define  DDRETC_DqsRcvEnGrossDelayByte7_SHIFT 29
+
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_0_0 0x12
+#define  DDRETCE_WrChkFineDlyByte0_SHIFT 0
+#define  DDRETCE_WrChkGrossDlyByte0_SHIFT 5
+
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_0_2 0x20   //DIMM0 channel B
+#define  DDRETC_DqsRcvEnFineDelayByte8_SHIFT 0
+#define  DDRETC_DqsRcvEnGrossDelayByte8_SHIFT 5
+#define  DDRETC_DqsRcvEnFineDelayByte9_SHIFT 8
+#define  DDRETC_DqsRcvEnGrossDelayByte9_SHIFT 13
+#define  DDRETC_DqsRcvEnFineDelayByte10_SHIFT 16
+#define  DDRETC_DqsRcvEnGrossDelayByte10_SHIFT 21
+#define  DDRETC_DqsRcvEnFineDelayByte11_SHIFT 24
+#define  DDRETC_DqsRcvEnGrossDelayByte11_SHIFT 29
+
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_0_3 0x21  // DIMM0 Channel B
+#define  DDRETC_DqsRcvEnFineDelayByte12_SHIFT 0
+#define  DDRETC_DqsRcvEnGrossDelayByte12_SHIFT 5
+#define  DDRETC_DqsRcvEnFineDelayByte13_SHIFT 8
+#define  DDRETC_DqsRcvEnGrossDelayByte13_SHIFT 13
+#define  DDRETC_DqsRcvEnFineDelayByte14_SHIFT 16
+#define  DDRETC_DqsRcvEnGrossDelayByte14_SHIFT 21
+#define  DDRETC_DqsRcvEnFineDelayByte15_SHIFT 24
+#define  DDRETC_DqsRcvEnGrossDelayByte15_SHIFT 29
+
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_0_1 0x22
+#define  DDRETCE_WrChkFineDlyByte1_SHIFT 0
+#define  DDRETCE_WrChkGrossDlyByte1_SHIFT 5
+
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_1_0 0x13  //DIMM1
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_1_1 0x14
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_1_0 0x15
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_1_2 0x23
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_1_3 0x24
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_1_1 0x25
+
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_2_0 0x16   // DIMM2
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_2_1 0x17
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_2_0 0x18
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_2_2 0x26
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_2_3 0x27
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_2_1 0x28
+
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_3_0 0x19   // DIMM3
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_3_1 0x1a
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_3_0 0x1b
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_3_2 0x29
+#define DRAM_DQS_RECV_ENABLE_TIME_CTRL_3_3 0x2a
+#define DRAM_DQS_RECV_ENABLE_TIMING_CTRL_ECC_3_1 0x2b
+
+/* 04.06.2006 19:12 */
+
+#if 0
+//DDR3
+#define DRAM_DQS_WRITE_TIME_CTRL_0_0 0x30 //DIMM0 Channel A
+#define  DDWTC_WrDqsFineDlyByte0_SHIFT 0
+#define   DDWTC_WrDqsFineDlyByte0_MASK 0x1f
+#define  DDWTC_WrDqsGrossDlyByte0_SHIFT 5
+#define   DDWTC_WrDqsGrossDlyByte0_MASK 0x3
+#define  DDWTC_WrDqsFineDlyByte1_SHIFT 8
+#define  DDWTC_WrDqsGrossDlyByte1_SHIFT 13
+#define  DDWTC_WrDqsFineDlyByte2_SHIFT 16
+#define  DDWTC_WrDqsGrossDlyByte2_SHIFT 21
+#define  DDWTC_WrDqsFineDlyByte3_SHIFT 24
+#define  DDWTC_WrDqsGrossDlyByte3_SHIFT 29
+
+#define DRAM_DQS_WRTIE_TIME_CTRL_0_1 0x31 //DIMM0 Channel A
+#define  DDWTC_WrDqsFineDlyByte4_SHIFT 0
+#define  DDWTC_WrDqsGrossDlyByte4_SHIFT 5
+#define  DDWTC_WrDqsFineDlyByte5_SHIFT 8
+#define  DDWTC_WrDqsGrossDlyByte5_SHIFT 13
+#define  DDWTC_WrDqsFineDlyByte6_SHIFT 16
+#define  DDWTC_WrDqsGrossDlyByte6_SHIFT 21
+#define  DDWTC_WrDqsFineDlyByte7_SHIFT 24
+#define  DDWTC_WrDqsGrossDlyByte7_SHIFT 29
+
+#define DRAM_DQS_WRITE_TIMING_CTRL_ECC_0_0 0x32
+#define  DDWTCE_WrDqsChkFineDlyByte0_SHIFT 0
+#define  DDWTCE_WrDqsChkGrossDlyByte0_SHIFT 5
+
+#define DRAM_DQS_WRITE_TIME_CTRL_0_2 0x40 //DIMM0 Channel B
+#define  DDWTC_WrDqsFineDlyByte8_SHIFT 0
+#define  DDWTC_WrDqsGrossDlyByte8_SHIFT 5
+#define  DDWTC_WrDqsFineDlyByte9_SHIFT 8
+#define  DDWTC_WrDqsGrossDlyByte9_SHIFT 13
+#define  DDWTC_WrDqsFineDlyByte10_SHIFT 16
+#define  DDWTC_WrDqsGrossDlyByte10_SHIFT 21
+#define  DDWTC_WrDqsFineDlyByte11_SHIFT 24
+#define  DDWTC_WrDqsGrossDlyByte11_SHIFT 29
+
+#define DRAM_DQS_WRTIE_TIME_CTRL_0_3 0x41 //DIMM0 Channel B
+#define  DDWTC_WrDqsFineDlyByte12_SHIFT 0
+#define  DDWTC_WrDqsGrossDlyByte12_SHIFT 5
+#define  DDWTC_WrDqsFineDlyByte13_SHIFT 8
+#define  DDWTC_WrDqsGrossDlyByte13_SHIFT 13
+#define  DDWTC_WrDqsFineDlyByte14_SHIFT 16
+#define  DDWTC_WrDqsGrossDlyByte14_SHIFT 21
+#define  DDWTC_WrDqsFineDlyByte15_SHIFT 24
+#define  DDWTC_WrDqsGrossDlyByte15_SHIFT 29
+
+#define DRAM_DQS_WRITE_TIMING_CTRL_ECC_0_1 0x42
+#define  DDWTCE_WrDqsChkFineDlyByte1_SHIFT 0
+#define  DDWTCE_WrDqsChkGrossDlyByte1_SHIFT 5
+
+#define DRAM_DQS_WRITE_TIME_CTRL_1_0 0x33 //DIMM1 Channel A
+#define DRAM_DQS_WRTIE_TIME_CTRL_1_1 0x34 //DIMM1 Channel A
+#define DRAM_DQS_WRITE_TIMING_CTRL_ECC_1_0 0x35
+#define DRAM_DQS_WRITE_TIME_CTRL_1_2 0x43 //DIMM1 Channel B
+#define DRAM_DQS_WRTIE_TIME_CTRL_1_3 0x44 //DIMM1 Channel B
+#define DRAM_DQS_WRITE_TIMING_CTRL_ECC_1_1 0x45
+#endif
+
+#define DRAM_PHASE_RECOVERY_CTRL_0 0x50
+#define  DPRC_PhRecFineDlyByte0_SHIFT 0
+#define   DDWTC_PhRecFineDlyByte0_MASK 0x1f
+#define  DDWTC_PhRecGrossDlyByte0_SHIFT 5
+#define   DDWTC_PhRecGrossDlyByte0_MASK 0x3
+#define  DDWTC_PhRecFineDlyByte1_SHIFT 8
+#define  DDWTC_PhRecGrossDlyByte1_SHIFT 13
+#define  DDWTC_PhRecFineDlyByte2_SHIFT 16
+#define  DDWTC_PhRecGrossDlyByte2_SHIFT 21
+#define  DDWTC_PhRecFineDlyByte3_SHIFT 24
+#define  DDWTC_PhRecGrossDlyByte3_SHIFT 29
+
+#define DRAM_PHASE_RECOVERY_CTRL_1 0x51
+#define  DPRC_PhRecFineDlyByte4_SHIFT 0
+#define  DDWTC_PhRecGrossDlyByte4_SHIFT 5
+#define  DDWTC_PhRecFineDlyByte5_SHIFT 8
+#define  DDWTC_PhRecGrossDlyByte5_SHIFT 13
+#define  DDWTC_PhRecFineDlyByte6_SHIFT 16
+#define  DDWTC_PhRecGrossDlyByte6_SHIFT 21
+#define  DDWTC_PhRecFineDlyByte7_SHIFT 24
+#define  DDWTC_PhRecGrossDlyByte7_SHIFT 29
+
+#define DRAM_ECC_PHASE_RECOVERY_CTRL 0x52
+#define  DEPRC_PhRecEccDlyByte0_SHIFT 0
+#define  DEPRC_PhRecEccGrossDlyByte0_SHIFT 5
+
+#define DRAM_WRITE_LEVEL_ERROR 0x53 /* read only */
+#define  DWLE_WrLvErr_SHIFT 0
+#define   DWLE_WrLvErr_MASK 0xff
+
+#define DRAM_CTRL_MISC 0xa0
+#define  DCM_MemCleared (1<<0) /* RD  == F2x110 [MemCleared] */
+#define  DCM_DramEnabled (1<<9) /* RD == F2x110 [DramEnabled] */
+
+#define NB_TIME_STAMP_COUNT_LOW 0xb0
+#define  TscLow_SHIFT 0
+#define  TscLow_MASK 0xffffffff
+
+#define NB_TIME_STAMP_COUNT_HIGH 0xb4
+#define  TscHigh_SHIFT 0
+#define  TscHigh_Mask 0xff
+
+#define DCT_DEBUG_CTRL 0xf0 /* 0xf0 for DCT0,	0x1f0 is for DCT1*/
+#define  DDC_DllAdjust_SHIFT 0
+#define   DDC_DllAdjust_MASK 0xff
+#define  DDC_DllSlower (1<<8)
+#define  DDC_DllFaster (1<<9)
+#define  DDC_WrtDqsAdjust_SHIFT 16
+#define   DDC_WrtDqsAdjust_MASK 0x7
+#define  DDC_WrtDqsAdjustEn (1<<19)
+
+#define DRAM_CTRL_SEL_LOW 0x110
+#define  DCSL_DctSelHiRngEn (1<<0)
+#define  DCSL_DctSelHi (1<<1)
+#define  DCSL_DctSelIntLvEn (1<<2)
+#define  DCSL_MemClrInit (1<<3) /* WR only */
+#define  DCSL_DctGangEn (1<<4)
+#define  DCSL_DctDataIntLv (1<<5)
+#define  DCSL_DctSelIntLvAddr_SHIFT
+#define   DCSL_DctSelIntLvAddr_MASK 3
+#define  DCSL_DramEnable (1<<8)  /* RD only */
+#define  DCSL_MemClrBusy (1<<9)  /* RD only */
+#define  DCSL_MemCleared (1<<10) /* RD only */
+#define  DCSL_DctSelBaseAddr_47_27_SHIFT 11
+#define   DCSL_DctSelBaseAddr_47_27_MASK 0x1fffff
+
+#define DRAM_CTRL_SEL_HIGH 0x114
+#define  DCSH_DctSelBaseOffset_47_26_SHIFT 10
+#define   DCSH_DctSelBaseOffset_47_26_MASK 0x3fffff
+
+#define MEM_CTRL_CONF_LOW 0x118
+#define  MCCL_MctPriCpuRd (1<<0)
+#define  MCCL_MctPriCpuWr (1<<1)
+#define  MCCL_MctPriIsocRd_SHIFT 4
+#define   MCCL_MctPriIsoc_MASK 0x3
+#define  MCCL_MctPriIsocWr_SHIFT 6
+#define   MCCL_MctPriIsocWe_MASK 0x3
+#define  MCCL_MctPriDefault_SHIFT 8
+#define   MCCL_MctPriDefault_MASK 0x3
+#define  MCCL_MctPriWr_SHIFT 10
+#define   MCCL_MctPriWr_MASK 0x3
+#define  MCCL_MctPriIsoc_SHIFT 12
+#define   MCCL_MctPriIsoc_MASK 0x3
+#define  MCCL_MctPriTrace_SHIFT 14
+#define   MCCL_MctPriTrace_MASK 0x3
+#define  MCCL_MctPriScrub_SHIFT 16
+#define   MCCL_MctPriScrub_MASK 0x3
+#define  MCCL_McqMedPriByPassMax_SHIFT 20
+#define   MCCL_McqMedPriByPassMax_MASK 0x7
+#define  MCCL_McqHiPriByPassMax_SHIFT 24
+#define   MCCL_McqHiPriByPassMax_MASK 0x7
+#define  MCCL_MctVarPriCntLmt_SHIFT 28
+#define   MCCL_MctVarPriCntLmt_MASK 0x7
+
+#define MEM_CTRL_CONF_HIGH 0x11c
+#define  MCCH_DctWrLimit_SHIFT 0
+#define   MCCH_DctWrLimit_MASK 0x3
+#define  MCCH_MctWrLimit_SHIFT 2
+#define   MCCH_MctWrLimit_MASK 0x1f
+#define  MCCH_MctPrefReqLimit_SHIFT 7
+#define   MCCH_MctPrefReqLimit_MASK 0x1f
+#define  MCCH_PrefCpuDis (1<<12)
+#define  MCCH_PrefIoDis (1<<13)
+#define  MCCH_PrefIoFixStrideEn (1<<14)
+#define  MCCH_PrefFixStrideEn (1<<15)
+#define  MCCH_PrefFixDist_SHIFT 16
+#define   MCCH_PrefFixDist_MASK 0x3
+#define  MCCH_PrefConfSat_SHIFT 18
+#define   MCCH_PrefConfSat_MASK 0x3
+#define  MCCH_PrefOneConf_SHIFT 20
+#define   MCCH_PrefOneConf_MASK 0x3
+#define  MCCH_PrefTwoConf_SHIFT 22
+#define   MCCH_PrefTwoConf_MASK 0x7
+#define  MCCH_PrefThreeConf_SHIFT 25
+#define   MCCH_prefThreeConf_MASK 0x7
+#define  MCCH_PrefDramTrainMode (1<<28)
+#define  MCCH_FlushWrOnStpGnt (1<<29)
+#define  MCCH_FlushWr (1<<30)
+#define  MCCH_MctScrubEn (1<<31)
+
+
+/* Function 3 */
+#define MCA_NB_CONTROL		0x40
+#define  MNCT_CorrEccEn (1<<0)
+#define  MNCT_UnCorrEccEn (1<<1)
+#define  MNCT_CrcErr0En	(1<<2) /* Link 0 */
+#define  MNCT_CrcErr1En (1<<3)
+#define  MNCT_CrcErr2En (1<<4)
+#define  MBCT_SyncPkt0En (1<<5) /* Link 0 */
+#define  MBCT_SyncPkt1En (1<<6)
+#define  MBCT_SyncPkt2En (1<<7)
+#define  MBCT_MstrAbrtEn (1<<8)
+#define  MBCT_TgtAbrtEn	 (1<<9)
+#define  MBCT_GartTblEkEn (1<<10)
+#define  MBCT_AtomicRMWEn  (1<<11)
+#define  MBCT_WdogTmrRptEn (1<<12)
+#define  MBCT_DevErrEn	(1<<13)
+#define  MBCT_L3ArrayCorEn (1<<14)
+#define  MBCT_L3ArrayUncEn (1<<15)
+#define  MBCT_HtProtEn	(1<<16)
+#define  MBCT_HtDataEn	(1<<17)
+#define  MBCT_DramParEn	(1<<18)
+#define  MBCT_RtryHt0En (1<<19) /* Link 0 */
+#define  MBCT_RtryHt1En (1<<20)
+#define  MBCT_RtryHt2En (1<<21)
+#define  MBCT_RtryHt3En (1<<22)
+#define  MBCT_CrcErr3En (1<<23) /* Link 3*/
+#define  MBCT_SyncPkt3En (1<<24) /* Link 4 */
+#define  MBCT_McaUsPwDatErrEn (1<<25)
+#define  MBCT_NbArrayParEn (1<<26)
+#define  MBCT_TblWlkDatErrEn (1<<27)
+#define  MBCT_FbDimmCorErrEn (1<<28)
+#define  MBCT_FbDimmUnCorErrEn (1<<29)
+
+
+
+#define MCA_NB_CONFIG	    0x44
+#define   MNC_CpuRdDatErrEn   (1<<1)
+#define   MNC_SyncOnUcEccEn   (1<<2)
+#define   MNC_SynvPktGenDis   (1<<3)
+#define   MNC_SyncPktPropDis  (1<<4)
+#define   MNC_IoMstAbortDis   (1<<5)
+#define   MNC_CpuErrDis	      (1<<6)
+#define   MNC_IoErrDis	      (1<<7)
+#define   MNC_WdogTmrDis      (1<<8)
+#define   MNC_WdogTmrCntSel_2_0_SHIFT 9 /* 3 is ar f3x180 */
+#define    MNC_WdogTmrCntSel_2_0_MASK 0x3
+#define   MNC_WdogTmrBaseSel_SHIFT 12
+#define    MNC_WdogTmrBaseSel_MASK 0x3
+#define   MNC_LdtLinkSel_SHIFT 14
+#define    MNC_LdtLinkSel_MASK 0x3
+#define   MNC_GenCrcErrByte0	(1<<16)
+#define   MNC_GenCrcErrByte1	(1<<17)
+#define   MNC_SubLinkSel_SHIFT 18
+#define    MNC_SubLinkSel_MASK 0x3
+#define   MNC_SyncOnWdogEn  (1<<20)
+#define   MNC_SyncOnAnyErrEn (1<<21)
+#define   MNC_DramEccEn       (1<<22)
+#define   MNC_ChipKillEccEn  (1<<23)
+#define   MNC_IoRdDatErrEn (1<<24)
+#define   MNC_DisPciCfgCpuErrRsp (1<<25)
+#define   MNC_CorrMcaExcEn (1<<26)
+#define   MNC_NbMcaToMstCpuEn (1<<27)
+#define   MNC_DisTgtAbtCpuErrRsp (1<<28)
+#define   MNC_DisMstAbtCpuErrRsp (1<<29)
+#define   MNC_SyncOnDramAdrParErrEn (1<<30)
+#define   MNC_NbMcaLogEn (1<<31)
+
+#define MCA_NB_STATUS_LOW 0x48
+#define  MNSL_ErrorCode_SHIFT 0
+#define   MNSL_ErrorCode_MASK 0xffff
+#define  MNSL_ErrorCodeExt_SHIFT 16
+#define   MNSL_ErrorCodeExt_MASK 0x1f
+#define  MNSL_Syndrome_15_8_SHIFT 24
+#define   MNSL_Syndrome_15_8_MASK 0xff
+
+#define MCA_NB_STATUS_HIGH 0x4c
+#define  MNSH_ErrCPU_SHIFT 0
+#define   MNSH_ErrCPU_MASK 0xf
+#define  MNSH_LDTLink_SHIFT 4
+#define   MNSH_LDTLink_MASK 0xf
+#define  MNSH_ErrScrub (1<<8)
+#define  MNSH_SubLink (1<<9)
+#define  MNSH_McaStatusSubCache_SHIFT 10
+#define   MNSH_McaStatusSubCache_MASK 0x3
+#define  MNSH_Deffered (1<<12)
+#define  MNSH_UnCorrECC (1<<13)
+#define  MNSH_CorrECC (1<<14)
+#define  MNSH_Syndrome_7_0_SHIFT 15
+#define   MNSH_Syndrome_7_0_MASK 0xff
+#define  MNSH_PCC (1<<25)
+#define  MNSH_ErrAddrVal (1<<26)
+#define  MNSH_ErrMiscVal (1<<27)
+#define  MNSH_ErrEn  (1<<28)
+#define  MNSH_ErrUnCorr (1<<29)
+#define  MNSH_ErrOver (1<<30)
+#define  MNSH_ErrValid (1<<31)
+
+#define MCA_NB_ADDR_LOW 0x50
+#define  MNAL_ErrAddr_31_1_SHIFT 1
+#define   MNAL_ErrAddr_31_1_MASK 0x7fffffff
+
+#define MCA_NB_ADDR_HIGH 0x54
+#define  MNAL_ErrAddr_47_32_SHIFT 0
+#define   MNAL_ErrAddr_47_32_MASK 0xffff
+
+#define DRAM_SCRUB_RATE_CTRL	   0x58
+#define	  SCRUB_NONE	    0
+#define	  SCRUB_40ns	    1
+#define	  SCRUB_80ns	    2
+#define	  SCRUB_160ns	    3
+#define	  SCRUB_320ns	    4
+#define	  SCRUB_640ns	    5
+#define	  SCRUB_1_28us	    6
+#define	  SCRUB_2_56us	    7
+#define	  SCRUB_5_12us	    8
+#define	  SCRUB_10_2us	    9
+#define	  SCRUB_20_5us	   0xa
+#define	  SCRUB_41_0us	   0xb
+#define	  SCRUB_81_9us	   0xc
+#define	  SCRUB_163_8us	   0xd
+#define	  SCRUB_327_7us	   0xe
+#define	  SCRUB_655_4us	   0xf
+#define	  SCRUB_1_31ms	   0x10
+#define	  SCRUB_2_62ms	   0x11
+#define	  SCRUB_5_24ms	   0x12
+#define	  SCRUB_10_49ms	   0x13
+#define	  SCRUB_20_97ms	   0x14
+#define	  SCRUB_42ms	   0x15
+#define	  SCRUB_84ms	   0x16
+#define	 DSRC_DramScrub_SHFIT  0
+#define	  DSRC_DramScrub_MASK	0x1f
+#define	 DSRC_L2Scrub_SHIFT	   8
+#define	  DSRC_L2Scrub_MASK	   0x1f
+#define	 DSRC_DcacheScrub_SHIFT	  16
+#define	  DSRC_DcacheScrub_MASK	   0x1f
+#define	 DSRC_L3Scrub_SHIFT	   24
+#define	  DSRC_L3Scrub_MASK	   0x1f
+
+#define DRAM_SCRUB_ADDR_LOW	   0x5C
+#define  DSAL_ScrubReDirEn (1<<0)
+#define  DSAL_ScrubAddrLo_SHIFT 6
+#define   DSAL_ScrubAddrLo_MASK 0x3ffffff
+
+#define DRAM_SCRUB_ADDR_HIGH	   0x60
+#define  DSAH_ScrubAddrHi_SHIFT 0
+#define   DSAH_ScrubAddrHi_MASK 0xffff
+
+#define HW_THERMAL_CTRL 0x64
+
+#define SW_THERMAL_CTRL 0x68
+
+#define DATA_BUF_CNT 0x6c
+
+#define SRI_XBAR_CMD_BUF_CNT 0x70
+
+#define XBAR_SRI_CMD_BUF_CNT 0x74
+
+#define MCT_XBAR_CMD_BUF_CNT 0x78
+
+#define ACPI_PWR_STATE_CTRL 0x80 /* till 0x84 */
+
+#define NB_CONFIG_LOW 0x88
+#define NB_CONFIG_HIGH 0x8c
+
+#define GART_APERTURE_CTRL 0x90
+
+#define GART_APERTURE_BASE 0x94
+
+#define GART_TBL_BASE 0x98
+
+#define GART_CACHE_CTRL 0x9c
+
+#define PWR_CTRL_MISC 0xa0
+
+#define RPT_TEMP_CTRL 0xa4
+
+#define ON_LINE_SPARE_CTRL 0xb0
+
+#define SBI_P_STATE_LIMIT 0xc4
+
+#define CLK_PWR_TIMING_CTRL0 0xd4
+#define CLK_PWR_TIMING_CTRL1 0xd8
+#define CLK_PWR_TIMING_CTRL2 0xdc
+
+#define THERMTRIP_STATUS 0xE4
+
+
+#define NORTHBRIDGE_CAP	   0xE8
+#define	 NBCAP_TwoChanDRAMcap	      (1 << 0)
+#define	 NBCAP_DualNodeMPcap	      (1 << 1)
+#define	 NBCAP_EightNodeMPcap	      (1 << 2)
+#define	 NBCAP_ECCcap	      (1 << 3)
+#define	 NBCAP_ChipkillECCcap	(1 << 4)
+#define	 NBCAP_DdrMaxRate_SHIFT	  5
+#define	 NBCAP_DdrMaxRate_MASK	  7
+#define	  NBCAP_DdrMaxRate_400	7
+#define	  NBCAP_DdrMaxRate_533	6
+#define	  NBCAP_DdrMaxRate_667	5
+#define	  NBCAP_DdrMaxRate_800	4
+#define	  NBCAP_DdrMaxRate_1067 3
+#define	  NBCAP_DdrMaxRate_1333 2
+#define	  NBCAP_DdrMaxRate_1600 1
+#define	  NBCAP_DdrMaxRate_3_2G	 6
+#define	  NBCAP_DdrMaxRate_4_0G	 5
+#define	  NBCAP_DdrMaxRate_4_8G	 4
+#define	  NBCAP_DdrMaxRate_6_4G 3
+#define	  NBCAP_DdrMaxRate_8_0G 2
+#define	  NBCAP_DdrMaxRate_9_6G 1
+#define	 NBCAP_Mem_ctrl_cap	      (1 << 8)
+#define  MBCAP_SVMCap	     (1<<9)
+#define  NBCAP_HtcCap		(1<<10)
+#define  NBCAP_CmpCap_SHIFT	12
+#define  NBCAP_CmpCap_MASK	3
+#define  NBCAP_MpCap_SHIFT 16
+#define  NBCAP_MpCap_MASK 7
+#define   NBCAP_MpCap_1N 7
+#define   NBCAP_MpCap_2N 6
+#define   NBCAP_MpCap_4N 5
+#define   NBCAP_MpCap_8N 4
+#define   NBCAP_MpCap_32N 0
+#define  NBCAP_UnGangEn_SHIFT 20
+#define   NBCAP_UnGangEn_MASK 0xf
+#define  NBCAP_L3Cap (1<<25)
+#define  NBCAP_HtAcCap (1<<26)
+
+/* 04/04/2006 18:00 */
+
+#define EXT_NB_MCA_CTRL	0x180
+
+#define NB_EXT_CONF	0x188
+#define DOWNCORE_CTRL	0x190
+#define  DWNCC_DisCore_SHIFT 0
+#define	 DWNCC_DisCore_MASK 0xf
+
+/* Function 5 for FBDIMM */
+#define FBD_DRAM_TIMING_LOW
+
+#define LinkConnected	   (1 << 0)
+#define InitComplete	   (1 << 1)
+#define NonCoherent	   (1 << 2)
+#define ConnectionPending (1 << 4)
+
+
+#include "amdfam10_nums.h"
+
+#ifdef __ROMCC__
+#if NODE_NUMS==64
+	 #define NODE_PCI(x, fn) ((x<32)?(PCI_DEV(CBB,(CDB+x),fn)):(PCI_DEV((CBB-1),(CDB+x-32),fn)))
+#else
+	 #define NODE_PCI(x, fn) PCI_DEV(CBB,(CDB+x),fn)
+#endif
+#endif
+
+#include "raminit.h"
+
+#if CONFIG_AMDMCT == 0
+
+//struct definitions
+
+struct dimm_size {
+	u8 per_rank; // it is rows + col + bank_lines + data lines */
+	u8 rows;
+	u8 col;
+	u8 bank; //1, 2, 3 mean 2, 4, 8
+	u8 rank;
+} __attribute__((packed));
+
+struct mem_info { // pernode
+	u32 dimm_mask;
+	struct dimm_size sz[DIMM_SOCKETS*2]; // for ungang support
+	u32 x4_mask;
+	u32 x16_mask;
+	u32 single_rank_mask;
+	u32 page_1k_mask;
+//	  u32 ecc_mask;
+//	  u32 registered_mask;
+	u8 is_opteron;
+	u8 is_registered; //don't support mixing on the same channel or between channel
+	u8 is_ecc; //don't support mixing on the same channel or between channel
+	u8 is_Width128;
+	u8 memclk_set; // we need to use this to retrieve the mem param, all dimms need to work at same freq for one node
+	u8 is_cs_interleaved[2]; //cs
+	u8 rsv[1];
+} __attribute__((packed));
+#else
+#include "../amdmct/mct/mct_d.h"
+#endif
+
+struct link_pair_t {
+	device_t udev;
+	u32 upos;
+	u32 uoffs;
+	device_t dev;
+	u32 pos;
+	u32 offs;
+	u8 host;
+	u8 nodeid;
+	u8 linkn;
+	u8 rsv;
+} __attribute__((packed));
+
+struct nodes_info_t {
+	u32 nodes_in_group; // could be 2, 3, 4, 5, 6, 7, 8
+	u32 groups_in_plane; // could be 1, 2, 3, 4, 5
+	u32 planes; // could be 1, 2
+	u32 up_planes; // down planes will be [up_planes, planes)
+} __attribute__((packed));
+
+/* be careful with the alignment of sysinfo, bacause sysinfo may be shared by linuxbios_car and linuxbios_ram stage. and linuxbios_ram may be running at 64bit later.*/
+#if CONFIG_AMDMCT == 0
+
+//#define MEM_CS_COPY 1
+#define MEM_CS_COPY NODE_NUMS
+
+#if MEM_TRAIN_SEQ == 0
+	#define DQS_DELAY_COPY NODE_NUMS
+#else
+//	#define DQS_DELAY_COPY 1
+	#define DQS_DELAY_COPY NODE_NUMS
+#endif
+#endif
+
+
+struct sys_info {
+	int32_t needs_reset;
+
+	u8 ln[NODE_NUMS*NODE_NUMS];// [0, 3] link n, [4, 7] will be hop num
+	u16 ln_tn[NODE_NUMS*8]; // for 0x0zzz: bit [0,7] target node num, bit[8,11] respone link from target num; 0x80ff mean not inited, 0x4yyy mean non coherent and yyy is link pair index
+	struct nodes_info_t nodes_info;
+	u32 nodes;
+
+	u8 host_link_freq[NODE_NUMS*8]; // record freq for every link from cpu, 0x0f means don't need to touch it
+	u16 host_link_freq_cap[NODE_NUMS*8]; //cap
+
+	u32 segbit;
+	u32 sbdn;
+	u32 sblk;
+	u32 sbbusn;
+
+	u32 ht_c_num;
+	u32 ht_c_conf_bus[HC_NUMS]; // 4-->32
+
+	struct link_pair_t link_pair[HC_NUMS*4];// enough? only in_conherent, 32 chain and every chain have 4 HT device
+	u32 link_pair_num;
+
+	struct mem_controller ctrl[NODE_NUMS];
+
+#if CONFIG_AMDMCT
+//	sMCTStruct MCTData;
+//	sDCTStruct *DCTNodeData[NODE_NUMS];
+//	sDCTStruct DCTNodeData_a[NODE_NUMS];
+	struct MCTStatStruc MCTstat;
+	struct DCTStatStruc DCTstatA[NODE_NUMS];
+#else
+
+	u8 ctrl_present[NODE_NUMS];
+	struct mem_info meminfo[NODE_NUMS];
+	u8 mem_trained[NODE_NUMS]; //0: no dimm, 1: trained, 0x80: not started, 0x81: recv1 fail, 0x82: Pos Fail, 0x83:recv2 fail
+	u32 tom_m;
+	u32 tom2_m;
+
+	//if we are getting tight of global space, may need to squesh following to one copy
+	u32 mem_base[MEM_CS_COPY][2]; // two dct
+	u32 cs_base[MEM_CS_COPY][2][8]; //8 cs_idx
+	u32 hole_startk; // 0 mean hole
+
+	u8 dqs_delay_a[DQS_DELAY_COPY*2*4*2*9]; //8 node, channel 2, dimm 4, direction 2 , bytelane *9
+	u8 dqs_rcvr_dly_a[DQS_DELAY_COPY*2*4*9]; //8 node, channel 2, dimm 4, bytelane *9
+	u8 dqs_rcvr_dly_a_1[9]; //8 node, channel 2, dimm 4, bytelane *9
+#endif
+
+} __attribute__((packed));
+
+#if CONFIG_AMDMCT == 0
+
+#ifdef __ROMCC__
+static void soft_reset(void);
+#endif
+static void wait_all_core0_mem_trained(struct sys_info *sysinfo)
+{
+	int i;
+	u32 mask_lo = 0;
+	u32 mask_hi = 0;
+	unsigned needs_reset = 0;
+
+	if(sysinfo->nodes == 1) return; // in case only one cpu installed
+		for(i=1; i<sysinfo->nodes; i++) {
+			/* Skip everything if I don't have any memory on this controller */
+			if(sysinfo->mem_trained[i]==0x00) continue;
+
+			if(i<32) {
+				mask_lo |= (1<<i);
+			} else {
+				mask_hi |= (1<<(i-32));
+			}
+	}
+
+	i = 1;
+	while(1) {
+		if(i<32) {
+			if(mask_lo & (1<<i)) {
+				if(sysinfo->mem_trained[i] != 0x80) {
+					mask_lo &= ~(1<<i);
+				}
+			}
+		} else {
+			if(mask_hi & (1<<(i-32))) {
+				if(sysinfo->mem_trained[i] != 0x80) {
+					 mask_hi &= ~(1<<(i-32));
+				}
+			}
+		}
+
+			if((!mask_lo) && (!mask_hi)) break;
+
+		i++;
+		i%=sysinfo->nodes;
+	}
+
+	for(i=0; i<sysinfo->nodes; i++) {
+#ifdef __ROMCC__
+		print_debug("mem_trained["); print_debug_hex8(i); print_debug("]="); print_debug_hex8(sysinfo->mem_trained[i]); print_debug("\n");
+#else
+		printk_debug("mem_trained[%02x]=%02x\n", i, sysinfo->mem_trained[i]);
+#endif
+		switch(sysinfo->mem_trained[i]) {
+		case 0: //don't need train
+		case 1: //trained
+			break;
+		case 0x81: //recv1: fail
+		case 0x82: //Pos :fail
+		case 0x83: //recv2: fail
+			needs_reset = 1;
+			break;
+		}
+	}
+	if(needs_reset) {
+#ifdef __ROMCC__
+		print_debug("mem trained failed\n");
+		soft_reset();
+#else
+		printk_debug("mem trained failed\n");
+		hard_reset();
+#endif
+	}
+
+}
+
+#endif
+
+#endif /* AMDFAM10_H */
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_acpi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_acpi.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,382 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <console/console.h>
+#include <string.h>
+#include <arch/acpi.h>
+#include <device/pci.h>
+#include <cpu/x86/msr.h>
+#include <cpu/amd/mtrr.h>
+#include <cpu/amd/amdfam10_sysconf.h>
+#include "amdfam10.h"
+
+//it seems some functions can be moved arch/i386/boot/acpi.c
+
+unsigned long acpi_create_madt_lapics(unsigned long current)
+{
+	device_t cpu;
+	int cpu_index = 0;
+
+	for(cpu = all_devices; cpu; cpu = cpu->next) {
+		if ((cpu->path.type != DEVICE_PATH_APIC) ||
+		   (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
+			continue;
+		}
+		if (!cpu->enabled) {
+			continue;
+		}
+		current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, cpu_index, cpu->path.u.apic.apic_id);
+		cpu_index++;
+	}
+	return current;
+}
+
+unsigned long acpi_create_madt_lapic_nmis(unsigned long current, u16 flags, u8 lint)
+{
+	device_t cpu;
+	int cpu_index = 0;
+
+	for(cpu = all_devices; cpu; cpu = cpu->next) {
+		if ((cpu->path.type != DEVICE_PATH_APIC) ||
+		   (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
+			continue;
+		}
+		if (!cpu->enabled) {
+			continue;
+		}
+		current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, cpu_index, flags, lint);
+		cpu_index++;
+	}
+	return current;
+}
+
+
+unsigned long acpi_create_srat_lapics(unsigned long current)
+{
+	device_t cpu;
+	int cpu_index = 0;
+
+	for(cpu = all_devices; cpu; cpu = cpu->next) {
+		if ((cpu->path.type != DEVICE_PATH_APIC) ||
+		   (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
+			continue;
+		}
+		if (!cpu->enabled) {
+			continue;
+		}
+		printk_debug("SRAT: lapic cpu_index=%02x, node_id=%02x, apic_id=%02x\n", cpu_index, cpu->path.u.apic.node_id, cpu->path.u.apic.apic_id);
+		current += acpi_create_srat_lapic((acpi_srat_lapic_t *)current, cpu->path.u.apic.node_id, cpu->path.u.apic.apic_id);
+		cpu_index++;
+	}
+	return current;
+}
+
+static unsigned long resk(uint64_t value)
+{
+	unsigned long resultk;
+	if (value < (1ULL << 42)) {
+		resultk = value >> 10;
+	} else {
+		resultk = 0xffffffff;
+	}
+	return resultk;
+}
+
+
+struct acpi_srat_mem_state {
+	unsigned long current;
+};
+
+void set_srat_mem(void *gp, struct device *dev, struct resource *res)
+{
+	struct acpi_srat_mem_state *state = gp;
+	unsigned long basek, sizek;
+	basek = resk(res->base);
+	sizek = resk(res->size);
+
+	printk_debug("set_srat_mem: dev %s, res->index=%04x startk=%08x, sizek=%08x\n",
+			dev_path(dev), res->index, basek, sizek);
+	/*
+	 0-640K must be on node 0
+	 next range is from 1M---
+	 So will cut off before 1M in the mem range
+	*/
+	if((basek+sizek)<1024) return;
+
+	if(basek<1024) {
+		sizek -= 1024 - basek;
+		basek = 1024;
+	}
+
+	// need to figure out NV
+	state->current += acpi_create_srat_mem((acpi_srat_mem_t *)state->current, (res->index & 0xf), basek, sizek, 1);
+}
+
+
+unsigned long acpi_fill_srat(unsigned long current)
+{
+	struct acpi_srat_mem_state srat_mem_state;
+
+	/* create all subtables for processors */
+	current = acpi_create_srat_lapics(current);
+
+	/* create all subteble for memory range */
+
+	/* 0-640K must be on node 0 */
+	current += acpi_create_srat_mem((acpi_srat_mem_t *)current, 0, 0, 640, 1);//enable
+
+	srat_mem_state.current = current;
+	search_global_resources(
+		IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE,
+		set_srat_mem, &srat_mem_state);
+
+	current = srat_mem_state.current;
+	return current;
+}
+
+unsigned long acpi_fill_slit(unsigned long current)
+{
+	/* need to find out the node num at first */
+	/* fill the first 8 byte with that num */
+	/* fill the next num*num byte with distance, local is 10, 1 hop mean 20, and 2 hop with 30.... */
+
+	struct sys_info *sysinfox = (struct sys_info *)((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_GLOBAL_VAR_SIZE);
+	u8 *ln = sysinfox->ln;
+
+
+	u8 *p = (u8 *)current;
+	int nodes = sysconf.nodes;
+	int i,j;
+	u32 hops;
+
+	memset(p, 0, 8+nodes*nodes);
+	*p = (u8) nodes;
+	p += 8;
+
+	for(i=0;i<nodes;i++) {
+		for(j=0;j<nodes; j++) {
+			if(i==j) {
+				p[i*nodes+j] = 10;
+			} else {
+				hops = (((ln[i*NODE_NUMS+j]>>4) & 0x7)+1);
+				p[i*nodes+j] = hops * 2 + 10;
+			}
+		}
+	}
+
+	current += 8+nodes*nodes;
+	return current;
+}
+
+
+// moved from mb acpi_tables.c
+static void intx_to_stream(u32 val, u32 len, u8 *dest)
+{
+	int i;
+	for(i=0;i<len;i++) {
+		*(dest+i) = (val >> (8*i)) & 0xff;
+	}
+}
+
+
+static void int_to_stream(u32 val, u8 *dest)
+{
+	return intx_to_stream(val, 4, dest);
+}
+
+
+// used by acpi_tables.h
+void update_ssdt(void *ssdt)
+{
+	u8 *BUSN;
+	u8 *MMIO;
+	u8 *PCIO;
+	u8 *SBLK;
+	u8 *TOM1;
+	u8 *SBDN;
+	u8 *HCLK;
+	u8 *HCDN;
+	u8 *CBST;
+	u8 *CBBX;
+	u8 *CBS2;
+	u8 *CBB2;
+
+
+	int i;
+	u32 dword;
+	msr_t msr;
+
+	// the offset could be different if have different HC_NUMS, and HC_POSSIBLE_NUM and ssdt.asl
+	BUSN = ssdt+0x3b; //+5 will be next BUSN
+	MMIO = ssdt+0xe4; //+5 will be next MMIO
+	PCIO = ssdt+0x36d; //+5 will be next PCIO
+	SBLK = ssdt+0x4b2; // one byte
+	TOM1 = ssdt+0x4b9; //
+	SBDN = ssdt+0x4c3;//
+	HCLK = ssdt+0x4d1; //+5 will be next HCLK
+	HCDN = ssdt+0x57a; //+5 will be next HCDN
+	CBBX = ssdt+0x61f; //
+	CBST = ssdt+0x626;
+	CBB2 = ssdt+0x62d; //
+	CBS2 = ssdt+0x634;
+
+	for(i=0;i<HC_NUMS;i++) {
+		dword = sysconf.ht_c_conf_bus[i];
+		int_to_stream(dword, BUSN+i*5);
+	}
+
+	for(i=0;i<(HC_NUMS*2);i++) { // FIXME: change to more chain
+		dword = sysconf.conf_mmio_addrx[i]; //base
+		int_to_stream(dword, MMIO+(i*2)*5);
+		dword = sysconf.conf_mmio_addr[i]; //mask
+		int_to_stream(dword, MMIO+(i*2+1)*5);
+	}
+	for(i=0;i<HC_NUMS;i++) { // FIXME: change to more chain
+		dword = sysconf.conf_io_addrx[i];
+		int_to_stream(dword, PCIO+(i*2)*5);
+		dword = sysconf.conf_io_addr[i];
+		int_to_stream(dword, PCIO+(i*2+1)*5);
+	}
+
+	*SBLK = (u8)(sysconf.sblk);
+
+	msr = rdmsr(TOP_MEM);
+	int_to_stream(msr.lo, TOM1);
+
+	int_to_stream(sysconf.sbdn, SBDN);
+
+	for(i=0;i<sysconf.hc_possible_num;i++) {
+		int_to_stream(sysconf.pci1234[i], HCLK + i*5);
+		int_to_stream(sysconf.hcdn[i],	   HCDN + i*5);
+	}
+	for(i=sysconf.hc_possible_num; i<HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8
+		int_to_stream(0x00000000, HCLK + i*5);
+		int_to_stream(0x20202020, HCDN + i*5);
+	}
+
+	*CBBX = (u8)(CBB);
+
+	if(CBB == 0xff) {
+		*CBST = (u8) (0x0f);
+	} else {
+		if((sysconf.pci1234[0] >> 12) & 0xff) { //sb chain on  other than bus 0
+			*CBST = (u8) (0x0f);
+		}
+		else {
+			*CBST = (u8) (0x00);
+		}
+	}
+
+	if((CBB == 0xff) && (sysconf.nodes>32)) {
+		 *CBS2 = 0x0f;
+		 *CBB2 = (u8)(CBB-1);
+	} else {
+		*CBS2 = 0x00;
+		*CBB2 = 0x00;
+	}
+
+}
+
+
+void update_sspr(void *sspr, u32 nodeid, u32 cpuindex)
+{
+	u8 *CPU;
+	u8 *CPUIN;
+	u8 *COREFREQ;
+	u8 *POWER;
+	u8 *TRANSITION_LAT;
+	u8 *BUSMASTER_LAT;
+	u8 *CONTROL;
+	u8 *STATUS;
+	unsigned offset = 0x94 - 0x7f;
+	int i;
+
+	CPU = sspr + 0x38;
+	CPUIN = sspr + 0x3a;
+
+	COREFREQ = sspr + 0x7f; //2 byte
+	POWER = sspr + 0x82; //3 bytes
+	TRANSITION_LAT = sspr + 0x87; //two bytes
+	BUSMASTER_LAT = sspr + 0x8a; //two bytes
+	CONTROL = sspr + 0x8d;
+	STATUS = sspr + 0x8f;
+
+	sprintf(CPU, "%02x", (u8)cpuindex);
+	*CPUIN = (u8) cpuindex;
+
+	for(i=0;i<sysconf.p_state_num;i++) {
+		struct p_state_t *p_state = &sysconf.p_state[nodeid * 5 + i];
+		intx_to_stream(COREFREQ + i*offset, 2, p_state->corefreq);
+		intx_to_stream(POWER + i*offset, 3, p_state->power);
+		intx_to_stream(TRANSITION_LAT + i*offset, 2, p_state->transition_lat);
+		intx_to_stream(BUSMASTER_LAT + i*offset, 2, p_state->busmaster_lat);
+		*((u8 *)(CONTROL + i*offset)) =(u8) p_state->control;
+		*((u8 *)(STATUS + i*offset)) =(u8) p_state->status;
+	}
+}
+
+extern unsigned char AmlCode_sspr5[];
+extern unsigned char AmlCode_sspr4[];
+extern unsigned char AmlCode_sspr3[];
+extern unsigned char AmlCode_sspr2[];
+extern unsigned char AmlCode_sspr1[];
+
+/* fixme: find one good way for different p_state_num */
+unsigned long acpi_add_ssdt_pstates(acpi_rsdt_t *rsdt, unsigned long current)
+{
+	device_t cpu;
+	int cpu_index = 0;
+
+	acpi_header_t *ssdt;
+
+	if(!sysconf.p_state_num) return current;
+
+	u8 *AmlCode_sspr;
+	switch(sysconf.p_state_num) {
+		case 1: AmlCode_sspr = AmlCode_sspr1; break;
+		case 2: AmlCode_sspr = AmlCode_sspr2; break;
+		case 3: AmlCode_sspr = AmlCode_sspr3; break;
+		case 4: AmlCode_sspr = AmlCode_sspr4; break;
+		default: AmlCode_sspr = AmlCode_sspr5; break;
+	}
+
+	for(cpu = all_devices; cpu; cpu = cpu->next) {
+		if ((cpu->path.type != DEVICE_PATH_APIC) ||
+		   (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
+			continue;
+		}
+		if (!cpu->enabled) {
+			 continue;
+		}
+		printk_debug("ACPI: pstate cpu_index=%02x, node_id=%02x, core_id=%02x\n", cpu_index, cpu->path.u.apic.node_id, cpu->path.u.apic.core_id);
+
+		current	  = ( current + 0x0f) & -0x10;
+		ssdt = (acpi_header_t *)current;
+		current += ((acpi_header_t *)AmlCode_sspr)->length;
+		memcpy((void *)ssdt, (void *)AmlCode_sspr, ((acpi_header_t *)AmlCode_sspr)->length);
+		update_sspr((void*)ssdt,cpu->path.u.apic.node_id, cpu_index);
+		/* recalculate checksum */
+		ssdt->checksum = 0;
+		ssdt->checksum = acpi_checksum((unsigned char *)ssdt,ssdt->length);
+		acpi_add_table(rsdt,ssdt);
+
+		cpu_index++;
+	}
+	return current;
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_conf.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_conf.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,874 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#if defined(__ROMCC__)
+typedef struct sys_info sys_info_conf_t;
+#else
+typedef struct amdfam10_sysconf_t sys_info_conf_t;
+#endif
+
+struct dram_base_mask_t {
+	u32 base; //[47:27] at [28:8]
+	u32 mask; //[47:27] at [28:8] and enable at bit 0
+};
+
+static struct dram_base_mask_t get_dram_base_mask(u32 nodeid)
+{
+	device_t dev;
+	struct dram_base_mask_t d;
+#if defined(__ROMCC__)
+	dev = PCI_DEV(CBB, CDB, 1);
+#else
+	dev = __f1_dev[0];
+#endif
+
+#if EXT_CONF_SUPPORT == 1
+	// I will use ext space only for simple
+	pci_write_config32(dev, 0x110, nodeid | (1<<28)); // [47:27] at [28:8]
+	d.mask = pci_read_config32(dev, 0x114);  // enable is bit 0
+	pci_write_config32(dev, 0x110, nodeid | (0<<28));
+	d.base = pci_read_config32(dev, 0x114) & 0x1fffff00; //[47:27] at [28:8];
+#else
+	u32 temp;
+	temp = pci_read_config32(dev, 0x44 + (nodeid << 3)); //[39:24] at [31:16]
+	d.mask = ((temp & 0xfff80000)>>(8+3)); // mask out  DramMask [26:24] too
+	temp = pci_read_config32(dev, 0x144 + (nodeid <<3)) & 0xff; //[47:40] at [7:0]
+	d.mask |= temp<<21;
+
+	temp = pci_read_config32(dev, 0x40 + (nodeid << 3)); //[39:24] at [31:16]
+	d.mask |= (temp & 1); // enable bit
+
+	d.base = ((temp & 0xfff80000)>>(8+3)); // mask out DramBase [26:24) too
+	temp = pci_read_config32(dev, 0x140 + (nodeid <<3)) & 0xff; //[47:40] at [7:0]
+	d.base |= temp<<21;
+#endif
+	return d;
+}
+
+static void set_dram_base_mask(u32 nodeid, struct dram_base_mask_t d, u32 nodes)
+{
+	u32 i;
+	device_t dev;
+#if EXT_CONF_SUPPORT == 1
+	// I will use ext space only for simple
+	u32 d_base_i, d_base_d, d_mask_i, d_mask_d;
+	d_base_i = nodeid | (0<<28);
+	d_base_d = d.base | nodeid; //[47:27] at [28:8];
+	d_mask_i = nodeid | (1<<28); // [47:27] at [28:8]
+	d_mask_d = d.mask;  // enable is bit 0
+
+#else
+	u32 d_base_lo, d_base_hi, d_mask_lo, d_mask_hi;
+	u32 d_base_lo_reg, d_base_hi_reg, d_mask_lo_reg, d_mask_hi_reg;
+	d_mask_lo =  (((d.mask<<(8+3))|(0x07<<16)) & 0xffff0000)|nodeid; // need to fill DramMask[26:24] with ones
+	d_mask_hi =  (d.mask>>21) & 0xff;
+	d_base_lo = ((d.base<<(8+3)) & 0xffff0000);
+	if(d.mask & 1) d_base_lo |= 3;
+	d_base_hi = (d.base>>21) & 0xff;
+	d_mask_lo_reg = 0x44+(nodeid<<3);
+	d_mask_hi_reg = 0x144+(nodeid<<3);
+	d_base_lo_reg = 0x40+(nodeid<<3);
+	d_base_hi_reg = 0x140+(nodeid<<3);
+#endif
+
+	for(i=0;i<nodes;i++) {
+#if defined(__ROMCC__)
+		dev = NODE_PCI(i, 1);
+#else
+		dev = __f1_dev[i];
+#endif
+
+#if EXT_CONF_SUPPORT == 1
+		// I will use ext space only for simple
+		pci_write_config32(dev, 0x110, d_base_i);
+		pci_write_config32(dev, 0x114, d_base_d); //[47:27] at [28:8];
+		pci_write_config32(dev, 0x110, d_mask_i); // [47:27] at [28:8]
+		pci_write_config32(dev, 0x114, d_mask_d);  // enable is bit 0
+#else
+		pci_write_config32(dev, d_mask_lo_reg, d_mask_lo); // need to fill DramMask[26:24] with ones
+		pci_write_config32(dev, d_mask_hi_reg, d_mask_hi);
+		pci_write_config32(dev, d_base_lo_reg, d_base_lo);
+		pci_write_config32(dev, d_base_hi_reg, d_base_hi);
+#endif
+	}
+
+#if defined(__ROMCC__)
+	dev = NODE_PCI(nodeid, 1);
+#else
+	dev = __f1_dev[nodeid];
+#endif
+	pci_write_config32(dev, 0x120, d.base>>8);
+	pci_write_config32(dev, 0x124, d.mask>>8);
+
+}
+
+
+static void set_DctSelBaseAddr(u32 i, u32 sel_m)
+{
+	device_t dev;
+#if defined(__ROMCC__)
+	dev = NODE_PCI(i, 2);
+#else
+		dev = __f2_dev[i];
+#endif
+	u32 dcs_lo;
+	dcs_lo = pci_read_config32(dev, DRAM_CTRL_SEL_LOW);
+	dcs_lo &= ~(DCSL_DctSelBaseAddr_47_27_MASK<<DCSL_DctSelBaseAddr_47_27_SHIFT);
+	dcs_lo |= (sel_m<<(20+DCSL_DctSelBaseAddr_47_27_SHIFT-27));
+	pci_write_config32(dev, DRAM_CTRL_SEL_LOW, dcs_lo);
+
+}
+
+
+static u32 get_DctSelBaseAddr(u32 i)
+{
+	device_t dev;
+#if defined(__ROMCC__)
+	dev = NODE_PCI(i, 2);
+#else
+		dev = __f2_dev[i];
+#endif
+	u32 sel_m;
+	u32 dcs_lo;
+	dcs_lo = pci_read_config32(dev, DRAM_CTRL_SEL_LOW);
+	dcs_lo &= DCSL_DctSelBaseAddr_47_27_MASK<<DCSL_DctSelBaseAddr_47_27_SHIFT;
+	sel_m = dcs_lo>>(20+DCSL_DctSelBaseAddr_47_27_SHIFT-27);
+	return sel_m;
+}
+
+
+static void set_DctSelHiEn(u32 i, u32 val)
+{
+	device_t dev;
+#if defined(__ROMCC__)
+	dev = NODE_PCI(i, 2);
+#else
+		dev = __f2_dev[i];
+#endif
+	u32 dcs_lo;
+	dcs_lo = pci_read_config32(dev, DRAM_CTRL_SEL_LOW);
+	dcs_lo &= ~(7);
+	dcs_lo |= (val & 7);
+	pci_write_config32(dev, DRAM_CTRL_SEL_LOW, dcs_lo);
+
+}
+
+static u32 get_DctSelHiEn(u32 i)
+{
+	device_t dev;
+#if defined(__ROMCC__)
+	dev = NODE_PCI(i, 2);
+#else
+	dev = __f2_dev[i];
+#endif
+	u32 dcs_lo;
+	dcs_lo = pci_read_config32(dev, DRAM_CTRL_SEL_LOW);
+	dcs_lo &= 7;
+	return dcs_lo;
+
+}
+
+static void set_DctSelBaseOffset(u32 i, u32 sel_off_m)
+{
+	device_t dev;
+#if defined(__ROMCC__)
+	dev = NODE_PCI(i, 2);
+#else
+	dev = __f2_dev[i];
+#endif
+	u32 dcs_hi;
+	dcs_hi = pci_read_config32(dev, DRAM_CTRL_SEL_HIGH);
+	dcs_hi &= ~(DCSH_DctSelBaseOffset_47_26_MASK<<DCSH_DctSelBaseOffset_47_26_SHIFT);
+	dcs_hi |= sel_off_m<<(20+DCSH_DctSelBaseOffset_47_26_SHIFT-26);
+	pci_write_config32(dev, DRAM_CTRL_SEL_HIGH, dcs_hi);
+
+}
+
+static u32 get_DctSelBaseOffset(u32 i)
+{
+	device_t dev;
+#if defined(__ROMCC__)
+	dev = NODE_PCI(i, 2);
+#else
+	dev = __f2_dev[i];
+#endif
+	u32 sel_off_m;
+	u32 dcs_hi;
+	dcs_hi = pci_read_config32(dev, DRAM_CTRL_SEL_HIGH);
+	dcs_hi &= DCSH_DctSelBaseOffset_47_26_MASK<<DCSH_DctSelBaseOffset_47_26_SHIFT;
+	sel_off_m = dcs_hi>>(20+DCSH_DctSelBaseOffset_47_26_SHIFT-26);
+	return sel_off_m;
+}
+#if CONFIG_AMDMCT == 0
+
+static u32 get_one_DCT(struct mem_info *meminfo)
+{
+	u32 one_DCT = 1;
+	if(meminfo->is_Width128) {
+		one_DCT = 1;
+	} else {
+		u32 dimm_mask = meminfo->dimm_mask;
+		if((dimm_mask >> DIMM_SOCKETS) && (dimm_mask & ((1<<DIMM_SOCKETS)-1))) {
+			 one_DCT = 0;
+		}
+	}
+
+	return one_DCT;
+}
+#endif
+#if HW_MEM_HOLE_SIZEK != 0
+
+static u32 hoist_memory(u32 hole_startk, u32 i, u32 one_DCT, u32 nodes)
+{
+	u32 ii;
+	u32 carry_over;
+	device_t dev;
+	struct dram_base_mask_t d;
+	u32 sel_m;
+	u32 sel_hi_en;
+	u32 hoist;
+
+
+	carry_over = (4*1024*1024) - hole_startk;
+
+	for(ii=nodes - 1;ii>i;ii--) {
+		d = get_dram_base_mask(ii);
+		if(!(d.mask & 1)) continue;
+		d.base += (carry_over>>9);
+		d.mask += (carry_over>>9);
+		set_dram_base_mask(ii, d, nodes);
+
+		if(get_DctSelHiEn(ii) & 1) {
+			sel_m = get_DctSelBaseAddr(ii);
+			sel_m += carry_over>>10;
+			set_DctSelBaseAddr(ii, sel_m);
+		}
+
+	}
+	d = get_dram_base_mask(i);
+	d.mask += (carry_over>>9);
+	set_dram_base_mask(i,d, nodes);
+#if defined(__ROMCC__)
+	dev = NODE_PCI(i, 1);
+#else
+	dev = __f1_dev[i];
+#endif
+	sel_hi_en =  get_DctSelHiEn(i);
+	if(sel_hi_en & 1) {
+		sel_m = get_DctSelBaseAddr(i);
+	}
+	if(d.base == (hole_startk>>9)) {
+		//don't need set memhole here, because hole off set will be 0, overflow
+		//so need to change base reg instead, new basek will be 4*1024*1024
+		d.base = (4*1024*1024)>>9;
+		set_dram_base_mask(i, d, nodes);
+
+		if(sel_hi_en & 1) {
+			sel_m += carry_over>>10;
+			set_DctSelBaseAddr(i, sel_m);
+		}
+	} else {
+		hoist = /* hole start address */
+			((hole_startk << 10) & 0xff000000) +
+			/* enable */
+			1;
+		if(one_DCT||(sel_m>=(hole_startk>>10))) { //one DCT or hole in DCT0
+			hoist +=
+			/* hole address to memory controller address */
+			((((d.base<<9) + carry_over) >> 6) & 0x0000ff00) ;
+
+			if(sel_hi_en & 1) {
+				sel_m += (carry_over>>10);
+				set_DctSelBaseAddr(i, sel_m);
+				set_DctSelBaseOffset(i, sel_m);
+			}
+		} else { // hole in DCT1 range
+			hoist +=
+			/* hole address to memory controller address */
+			((((sel_m<<10) + carry_over) >> 6) & 0x0000ff00) ;
+			// don't need to update DctSelBaseAddr
+			if(sel_hi_en & 1) {
+				set_DctSelBaseOffset(i, sel_m);
+			}
+		}
+		pci_write_config32(dev, 0xf0, hoist);
+
+	}
+
+	return carry_over;
+}
+#endif
+
+
+#if EXT_CONF_SUPPORT
+static void set_addr_map_reg_4_6_in_one_node(u32 nodeid, u32 cfg_map_dest,
+						u32 busn_min, u32 busn_max,
+						u32 type)
+{
+	device_t dev;
+	u32 i;
+	u32 tempreg;
+	u32 index_min, index_max;
+	u32 dest_min, dest_max;
+	index_min = busn_min>>2; dest_min = busn_min - (index_min<<2);
+	index_max = busn_max>>2; dest_max = busn_max - (index_max<<2);
+
+	// three case: index_min==index_max, index_min+1=index_max; index_min+1<index_max
+#if defined(__ROMCC__)
+	dev = NODE_PCI(nodeid, 1);
+#else
+	dev = __f1_dev[nodeid];
+#endif
+	if(index_min== index_max) {
+		pci_write_config32(dev, 0x110, index_min | (type<<28));
+		tempreg = pci_read_config32(dev, 0x114);
+		for(i=dest_min; i<=dest_max; i++) {
+			tempreg &= ~(0xff<<(i*8));
+			tempreg |= (cfg_map_dest<<(i*8));
+		}
+		pci_write_config32(dev, 0x110, index_min | (type<<28)); // do i need to write it again
+		pci_write_config32(dev, 0x114, tempreg);
+	} else if(index_min<index_max) {
+		pci_write_config32(dev, 0x110, index_min | (type<<28));
+		tempreg = pci_read_config32(dev, 0x114);
+		for(i=dest_min; i<=3; i++) {
+			tempreg &= ~(0xff<<(i*8));
+			tempreg |= (cfg_map_dest<<(i*8));
+		}
+		pci_write_config32(dev, 0x110, index_min | (type<<28)); // do i need to write it again
+		pci_write_config32(dev, 0x114, tempreg);
+
+		pci_write_config32(dev, 0x110, index_max | (type<<28));
+		tempreg = pci_read_config32(dev, 0x114);
+		for(i=0; i<=dest_max; i++) {
+			tempreg &= ~(0xff<<(i*8));
+			tempreg |= (cfg_map_dest<<(i*8));
+		}
+		pci_write_config32(dev, 0x110, index_max | (type<<28)); // do i need to write it again
+		pci_write_config32(dev, 0x114, tempreg);
+		if((index_max-index_min)>1) {
+			tempreg = 0;
+			for(i=0; i<=3; i++) {
+				tempreg &= ~(0xff<<(i*8));
+				tempreg |= (cfg_map_dest<<(i*8));
+			}
+			for(i=index_min+1; i<index_max;i++) {
+				pci_write_config32(dev, 0x110, i | (type<<28));
+				pci_write_config32(dev, 0x114, tempreg);
+			}
+		}
+	}
+}
+#endif
+
+static void set_config_map_reg(u32 nodeid, u32 linkn, u32 ht_c_index,
+				u32 busn_min, u32 busn_max, u32 segbit,
+				u32 nodes)
+{
+	u32 tempreg;
+	u32 i;
+	device_t dev;
+
+	busn_min>>=segbit;
+	busn_max>>=segbit;
+
+#if EXT_CONF_SUPPORT
+	if(ht_c_index < 4) {
+#endif
+		tempreg = 3 | ((nodeid&0xf)<<4) | ((nodeid & 0x30)<<(12-4))|(linkn<<8)|((busn_min & 0xff)<<16)|((busn_max&0xff)<<24);
+		for(i=0; i<nodes; i++) {
+		#if defined(__ROMCC__)
+			dev = NODE_PCI(i, 1);
+		#else
+			dev = __f1_dev[i];
+		#endif
+			pci_write_config32(dev, 0xe0 + ht_c_index * 4, tempreg);
+		}
+#if EXT_CONF_SUPPORT
+
+		return;
+	}
+
+	// if ht_c_index > 3, We should use extend space x114_x6
+	u32 cfg_map_dest;
+	u32 j;
+
+	// for nodeid at first
+	cfg_map_dest = (1<<7) | (1<<6) | (linkn<<0);
+
+	set_addr_map_reg_4_6_in_one_node(nodeid, cfg_map_dest, busn_min, busn_max, 6);
+
+	// all other nodes
+	cfg_map_dest = (1<<7) | (0<<6) | (nodeid<<0);
+	for(j = 0; j< nodes; j++) {
+		if(j== nodeid) continue;
+		set_addr_map_reg_4_6_in_one_node(j,cfg_map_dest, busn_min, busn_max, 6);
+	}
+#endif
+}
+
+static void clear_config_map_reg(u32 nodeid, u32 linkn, u32 ht_c_index,
+					u32 busn_min, u32 busn_max, u32 nodes)
+{
+	u32 i;
+	device_t dev;
+
+#if EXT_CONF_SUPPORT
+	if(ht_c_index<4) {
+#endif
+		for(i=0; i<nodes; i++) {
+		#if defined(__ROMCC__)
+			dev = NODE_PCI(i, 1);
+		#else
+			dev = __f1_dev[i];
+		#endif
+			pci_write_config32(dev, 0xe0 + ht_c_index * 4, 0);
+		}
+#if EXT_CONF_SUPPORT
+		return;
+	}
+
+	// if hc_c_index >3, We should use busn_min and busn_max to clear extend space
+	u32 cfg_map_dest;
+	u32 j;
+
+
+	// all nodes
+	cfg_map_dest = 0;
+	for(j = 0; j< nodes; j++) {
+		set_addr_map_reg_4_6_in_one_node(j,cfg_map_dest, busn_min, busn_max, 6);
+	}
+#endif
+
+}
+
+#if PCI_BUS_SEGN_BITS
+static u32 check_segn(device_t dev, u32 segbusn, u32 nodes,
+			sys_info_conf_t *sysinfo)
+{
+	//check segbusn here, We need every node have the same segn
+	if((segbusn & 0xff)>(0xe0-1)) {// use next segn
+		u32 segn = (segbusn >> 8) & 0x0f;
+		segn++;
+		segbusn = segn<<8;
+	}
+	if(segbusn>>8) {
+		u32 val;
+		val = pci_read_config32(dev, 0x160);
+		val &= ~(0xf<<25);
+		val |= (segbusn & 0xf00)<<(25-8);
+		pci_write_config32(dev, 0x160, val);
+	}
+
+	return segbusn;
+}
+#endif
+
+#if defined(__ROMCC__)
+static void set_ht_c_io_addr_reg(u32 nodeid, u32 linkn, u32 ht_c_index,
+					u32 io_min, u32 io_max, u32 nodes)
+{
+	u32 i;
+	u32 tempreg;
+	device_t dev;
+
+#if EXT_CONF_SUPPORT
+	if(ht_c_index<4) {
+#endif
+		/* io range allocation */
+		tempreg = (nodeid&0xf) | ((nodeid & 0x30)<<(8-4)) | (linkn<<4) |  ((io_max&0xf0)<<(12-4)); //limit
+		for(i=0; i<nodes; i++) {
+		#if defined(__ROMCC__)
+			dev = NODE_PCI(i, 1);
+		#else
+			dev = __f1_dev[i];
+		#endif
+			pci_write_config32(dev, 0xC4 + ht_c_index * 8, tempreg);
+		}
+		tempreg = 3 /*| ( 3<<4)*/ | ((io_min&0xf0)<<(12-4));	     //base :ISA and VGA ?
+		for(i=0; i<nodes; i++){
+		#if defined(__ROMCC__)
+			dev = NODE_PCI(i, 1);
+		#else
+			dev = __f1_dev[i];
+		#endif
+			pci_write_config32(dev, 0xC0 + ht_c_index * 8, tempreg);
+		}
+#if EXT_CONF_SUPPORT
+		return;
+	}
+
+	u32 cfg_map_dest;
+	u32 j;
+
+	// if ht_c_index > 3, We should use extend space
+
+	if(io_min>io_max) return;
+
+	// for nodeid at first
+	cfg_map_dest = (1<<7) | (1<<6) | (linkn<<0);
+
+	set_addr_map_reg_4_6_in_one_node(nodeid, cfg_map_dest, io_min, io_max, 4);
+
+	// all other nodes
+	cfg_map_dest = (1<<7) | (0<<6) | (nodeid<<0);
+	for(j = 0; j< nodes; j++) {
+		if(j== nodeid) continue;
+		set_addr_map_reg_4_6_in_one_node(j,cfg_map_dest, io_min, io_max, 4);
+	}
+#endif
+}
+
+
+static void clear_ht_c_io_addr_reg(u32 nodeid, u32 linkn, u32 ht_c_index,
+					u32 io_min, u32 io_max, u32 nodes)
+{
+	u32 i;
+	device_t dev;
+#if EXT_CONF_SUPPORT
+	if(ht_c_index<4) {
+#endif
+		 /* io range allocation */
+		for(i=0; i<nodes; i++) {
+		#if defined(__ROMCC__)
+			dev = NODE_PCI(i, 1);
+		#else
+			dev = __f1_dev[i];
+		#endif
+			pci_write_config32(dev, 0xC4 + ht_c_index * 8, 0);
+			pci_write_config32(dev, 0xC0 + ht_c_index * 8, 0);
+		}
+#if EXT_CONF_SUPPORT
+		return;
+	}
+	// : if hc_c_index > 3, We should use io_min, io_max to clear extend space
+	u32 cfg_map_dest;
+	u32 j;
+
+
+	// all nodes
+	cfg_map_dest = 0;
+	for(j = 0; j< nodes; j++) {
+		set_addr_map_reg_4_6_in_one_node(j,cfg_map_dest, io_min, io_max, 4);
+	}
+#endif
+}
+#endif
+
+
+static void re_set_all_config_map_reg(u32 nodes, u32 segbit,
+					sys_info_conf_t *sysinfo)
+{
+	u32 ht_c_index;
+	device_t dev;
+
+	set_config_map_reg(0, sysinfo->sblk, 0, 0, sysinfo->ht_c_conf_bus[0]>>20, segbit, nodes);
+
+	/* clean others */
+	for(ht_c_index=1;ht_c_index<4; ht_c_index++) {
+		u32 i;
+		for(i=0; i<nodes; i++) {
+		#if defined(__ROMCC__)
+			dev = NODE_PCI(i, 1);
+		#else
+			dev = __f1_dev[i];
+		#endif
+			pci_write_config32(dev, 0xe0 + ht_c_index * 4, 0);
+		}
+	}
+#if EXT_CONF_SUPPORT
+	u32 j;
+	// clear the extend space
+	for(j = 0; j< nodes; j++) {
+		set_addr_map_reg_4_6_in_one_node(j,0, 0, 0xff, 6);
+	}
+#endif
+
+	for(ht_c_index = 1; ht_c_index<sysinfo->ht_c_num; ht_c_index++) {
+		u32 nodeid, linkn;
+		u32 busn_max;
+		u32 busn_min;
+		nodeid = (sysinfo->ht_c_conf_bus[ht_c_index] >> 2) & 0x3f;
+		linkn = (sysinfo->ht_c_conf_bus[ht_c_index]>>8) & 0x7;
+		busn_max = sysinfo->ht_c_conf_bus[ht_c_index]>>20;
+		busn_min = (sysinfo->ht_c_conf_bus[ht_c_index]>>12) & 0xff;
+		busn_min |= busn_max & 0xf00;
+		set_config_map_reg(nodeid, linkn, ht_c_index, busn_min, busn_max, segbit, nodes);
+	}
+
+}
+
+
+static u32 get_ht_c_index(u32 nodeid, u32 linkn, sys_info_conf_t *sysinfo)
+{
+	u32 tempreg;
+	u32 ht_c_index = 0;
+
+#if 0
+	tempreg = 3 | ((nodeid & 0xf) <<4) | ((nodeid & 0x30)<<(12-4)) | (linkn<<8);
+
+	for(ht_c_index=0;ht_c_index<4; ht_c_index++) {
+		reg = pci_read_config32(PCI_DEV(CBB, CDB, 1), 0xe0 + ht_c_index * 4);
+		if(((reg & 0xffff) == 0x0000)) {  /*found free*/
+			break;
+		}
+	}
+#endif
+	tempreg = 3 | ((nodeid & 0x3f)<<2) | (linkn<<8);
+	for(ht_c_index=0; ht_c_index<32; ht_c_index++) {
+		if(((sysinfo->ht_c_conf_bus[ht_c_index] & 0xfff) == tempreg)){
+			return ht_c_index;
+		}
+	}
+
+	for(ht_c_index=0; ht_c_index<32; ht_c_index++) {
+		if((sysinfo->ht_c_conf_bus[ht_c_index] == 0)){
+			 return ht_c_index;
+		}
+	}
+
+	return	-1;
+
+}
+
+static void store_ht_c_conf_bus(u32 nodeid, u32 linkn, u32 ht_c_index,
+				u32 busn_min, u32 busn_max,
+				sys_info_conf_t *sysinfo)
+{
+	u32 val;
+	val = 3 | ((nodeid & 0x3f)<<2) | (linkn<<8);
+	sysinfo->ht_c_conf_bus[ht_c_index] = val | ((busn_min & 0xff) <<12) | (busn_max<<20);  // same node need segn are same
+
+}
+
+
+static  void set_BusSegmentEn(u32 node, u32 segbit)
+{
+#if PCI_BUS_SEGN_BITS
+	u32 dword;
+	device_t dev;
+
+#if defined(__ROMCC__)
+	dev = NODE_PCI(node, 0);
+#else
+	dev = __f0_dev[node];
+#endif
+
+	dword = pci_read_config32(dev, 0x68);
+	dword &= ~(7<<28);
+	dword |= (segbit<<28); /* bus segment enable */
+	pci_write_config32(dev, 0x68, dword);
+#endif
+}
+
+#if !defined(__ROMCC__)
+static u32 get_io_addr_index(u32 nodeid, u32 linkn)
+{
+	u32 index;
+
+	for(index=0; index<256; index++) {
+		if((sysconf.conf_io_addrx[index+4] == 0)){
+			sysconf.conf_io_addr[index+4] =  (nodeid & 0x3f)  ;
+			sysconf.conf_io_addrx[index+4] = 1 | ((linkn & 0x7)<<4);
+			return index;
+		 }
+	 }
+
+	 return	 0;
+
+}
+
+static u32 get_mmio_addr_index(u32 nodeid, u32 linkn)
+{
+	u32 index;
+
+
+	for(index=0; index<64; index++) {
+		if((sysconf.conf_mmio_addrx[index+8] == 0)){
+			sysconf.conf_mmio_addr[index+8] = (nodeid & 0x3f) ;
+			sysconf.conf_mmio_addrx[index+8] = 1 | ((linkn & 0x7)<<4);
+			return index;
+		}
+	}
+
+	return	 0;
+
+}
+
+static void store_conf_io_addr(u32 nodeid, u32 linkn, u32 reg, u32 index,
+				u32 io_min, u32 io_max)
+{
+	u32 val;
+#if EXT_CONF_SUPPORT
+	if(reg!=0x110) {
+#endif
+		/* io range allocation */
+		index = (reg-0xc0)>>3;
+#if EXT_CONF_SUPPORT
+	} else {
+		index+=4;
+	}
+#endif
+
+	val = (nodeid & 0x3f); // 6 bits used
+	sysconf.conf_io_addr[index] = val | ((io_max<<8) & 0xfffff000); //limit : with nodeid
+	val = 3 | ((linkn & 0x7)<<4) ; // 8 bits used
+	sysconf.conf_io_addrx[index] = val | ((io_min<<8) & 0xfffff000); // base : with enable bit
+
+	if( sysconf.io_addr_num<(index+1))
+		sysconf.io_addr_num = index+1;
+}
+
+
+static void store_conf_mmio_addr(u32 nodeid, u32 linkn, u32 reg, u32 index,
+					u32 mmio_min, u32 mmio_max)
+{
+	u32 val;
+#if EXT_CONF_SUPPORT
+	if(reg!=0x110) {
+#endif
+		/* io range allocation */
+		index = (reg-0x80)>>3;
+#if EXT_CONF_SUPPORT
+	} else {
+		index+=8;
+	}
+#endif
+
+	val = (nodeid & 0x3f) ; // 6 bits used
+	sysconf.conf_mmio_addr[index] = val | (mmio_max & 0xffffff00); //limit : with nodeid and linkn
+	val = 3 | ((linkn & 0x7)<<4) ; // 8 bits used
+	sysconf.conf_mmio_addrx[index] = val | (mmio_min & 0xffffff00); // base : with enable bit
+
+	if( sysconf.mmio_addr_num<(index+1))
+		sysconf.mmio_addr_num = index+1;
+}
+
+
+static void set_io_addr_reg(device_t dev, u32 nodeid, u32 linkn, u32 reg,
+				u32 io_min, u32 io_max)
+{
+
+	u32 i;
+	u32 tempreg;
+#if EXT_CONF_SUPPORT
+	if(reg!=0x110) {
+#endif
+		/* io range allocation */
+		tempreg = (nodeid&0xf) | ((nodeid & 0x30)<<(8-4)) | (linkn<<4) |  ((io_max&0xf0)<<(12-4)); //limit
+		for(i=0; i<sysconf.nodes; i++)
+			pci_write_config32(__f1_dev[i], reg+4, tempreg);
+
+		tempreg = 3 /*| ( 3<<4)*/ | ((io_min&0xf0)<<(12-4));	      //base :ISA and VGA ?
+#if 0
+		// FIXME: can we use VGA reg instead?
+		if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
+			printk_spew("%s, enabling legacy VGA IO forwarding for %s link %s\n",
+				__func__, dev_path(dev), link);
+			tempreg |= PCI_IO_BASE_VGA_EN;
+		}
+		if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) {
+			tempreg |= PCI_IO_BASE_NO_ISA;
+		}
+#endif
+		for(i=0; i<sysconf.nodes; i++)
+			pci_write_config32(__f1_dev[i], reg, tempreg);
+#if EXT_CONF_SUPPORT
+		return;
+	}
+
+	u32 cfg_map_dest;
+	u32 j;
+	// if ht_c_index > 3, We should use extend space
+	if(io_min>io_max) return;
+	// for nodeid at first
+	cfg_map_dest = (1<<7) | (1<<6) | (linkn<<0);
+
+	set_addr_map_reg_4_6_in_one_node(nodeid, cfg_map_dest, io_min, io_max, 4);
+
+	// all other nodes
+	cfg_map_dest = (1<<7) | (0<<6) | (nodeid<<0);
+	for(j = 0; j< sysconf.nodes; j++) {
+		if(j== nodeid) continue;
+		set_addr_map_reg_4_6_in_one_node(j,cfg_map_dest, io_min, io_max, 4);
+	}
+#endif
+
+}
+static void set_mmio_addr_reg(u32 nodeid, u32 linkn, u32 reg, u32 index, u32 mmio_min, u32 mmio_max, u32 nodes)
+{
+
+	u32 i;
+	u32 tempreg;
+#if EXT_CONF_SUPPORT
+	if(reg!=0x110) {
+#endif
+		/* io range allocation */
+		tempreg = (nodeid&0xf) | (linkn<<4) |	 (mmio_max&0xffffff00); //limit
+		for(i=0; i<nodes; i++)
+			pci_write_config32(__f1_dev[i], reg+4, tempreg);
+		tempreg = 3 | (nodeid & 0x30) | (mmio_min&0xffffff00);
+		for(i=0; i<sysconf.nodes; i++)
+			pci_write_config32(__f1_dev[i], reg, tempreg);
+#if EXT_CONF_SUPPORT
+		return;
+	}
+
+	device_t dev;
+	u32 j;
+	// if ht_c_index > 3, We should use extend space
+	// for nodeid at first
+	u32 enable;
+
+	if(mmio_min>mmio_max) {
+		return;
+	}
+
+	enable = 1;
+
+	dev = __f1_dev[nodeid];
+	tempreg = ((mmio_min>>3) & 0x1fffff00)| (1<<6) | (linkn<<0);
+	pci_write_config32(dev, 0x110, index | (2<<28));
+	pci_write_config32(dev, 0x114, tempreg);
+
+	tempreg = ((mmio_max>>3) & 0x1fffff00) | enable;
+	pci_write_config32(dev, 0x110, index | (3<<28));
+	pci_write_config32(dev, 0x114, tempreg);
+
+
+	// all other nodes
+	tempreg = ((mmio_min>>3) & 0x1fffff00) | (0<<6) | (nodeid<<0);
+	for(j = 0; j< sysconf.nodes; j++) {
+		if(j== nodeid) continue;
+		dev = __f1_dev[j];
+		pci_write_config32(dev, 0x110, index | (2<<28));
+		pci_write_config32(dev, 0x114, tempreg);
+	}
+
+	tempreg = ((mmio_max>>3) & 0x1fffff00) | enable;
+	for(j = 0; j< sysconf.nodes; j++) {
+		if(j==nodeid) continue;
+		dev = __f1_dev[j];
+		pci_write_config32(dev, 0x110, index | (3<<28));
+		pci_write_config32(dev, 0x114, tempreg);
+	 }
+#endif
+}
+
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_nums.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_nums.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef AMDFAM10_NUMS_H
+
+#define AMDFAM10_NUMS_H
+
+#if CONFIG_MAX_PHYSICAL_CPUS > 8
+	#if CONFIG_MAX_PHYSICAL_CPUS > 32
+		#define NODE_NUMS 64
+	#else
+		#define NODE_NUMS 32
+	#endif
+#else
+	#define NODE_NUMS 8
+#endif
+
+// max HC installed at the same time. ...could be bigger than (48+24) if we have 3x4x4
+#define HC_NUMS 32
+
+//it could be more bigger
+#define HC_POSSIBLE_NUM 32
+
+#endif
+
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_pci.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/amdfam10_pci.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#ifndef AMDFAM10_PCI_C
+#define AMDFAM10_PCI_C
+/* bit [10,8] are dev func, bit[1,0] are dev index */
+
+
+static u32 pci_read_config32_index(device_t dev, u32 index_reg, u32 index)
+{
+	u32 dword;
+
+	pci_write_config32(dev, index_reg, index);
+	dword = pci_read_config32(dev, index_reg+0x4);
+	return dword;
+}
+
+static void pci_write_config32_index(device_t dev, u32 index_reg, u32 index, u32 data)
+{
+
+	pci_write_config32(dev, index_reg, index);
+
+	pci_write_config32(dev, index_reg + 0x4, data);
+
+}
+
+static u32 pci_read_config32_index_wait(device_t dev, u32 index_reg, u32 index)
+{
+
+	u32 dword;
+
+	index &= ~(1<<30);
+	pci_write_config32(dev, index_reg, index);
+	do {
+		dword = pci_read_config32(dev, index_reg);
+	} while (!(dword & (1<<31)));
+	dword = pci_read_config32(dev, index_reg+0x4);
+	return dword;
+}
+
+static void pci_write_config32_index_wait(device_t dev, u32 index_reg, u32 index, u32 data)
+{
+
+	u32 dword;
+
+	pci_write_config32(dev, index_reg + 0x4, data);
+	index |= (1<<30);
+	pci_write_config32(dev, index_reg, index);
+	do {
+		dword = pci_read_config32(dev, index_reg);
+	} while (!(dword & (1<<31)));
+
+}
+#endif
+
+
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/chip.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/chip.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+struct northbridge_amd_amdfam10_config
+{
+};
+
+extern struct chip_operations northbridge_amd_amdfam10_ops;
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/debug.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/debug.c	2007-12-12 16:13:25.000000000 -0700
@@ -0,0 +1,331 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+/*
+ * Generic FAM10 debug code, used by mainboard specific car_auto.c
+ */
+
+#include "amdfam10_pci.c"
+
+static void udelay_tsc(u32 us);
+
+static  void print_debug_addr(const char *str, void *val)
+{
+#if CACHE_AS_RAM_ADDRESS_DEBUG == 1
+		printk_debug("------Address debug: %s%x------\n", str, val);
+#endif
+}
+
+static void print_debug_pci_dev(u32 dev)
+{
+#if PCI_BUS_SEGN_BITS==0
+	printk_debug("PCI: %02x:%02x.%02x", (dev>>20) & 0xff, (dev>>15) & 0x1f, (dev>>12) & 0x7);
+#else
+	printk_debug("PCI: %04x:%02x:%02x.%02x", (dev>>28) & 0x0f, (dev>>20) & 0xff, (dev>>15) & 0x1f, (dev>>12) & 0x7);
+#endif
+}
+
+static void print_pci_devices(void)
+{
+	device_t dev;
+	for(dev = PCI_DEV(0, 0, 0);
+		dev <= PCI_DEV(0xff, 0x1f, 0x7);
+		dev += PCI_DEV(0,0,1)) {
+		u32 id;
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0x0000)) {
+			continue;
+		}
+		print_debug_pci_dev(dev);
+		printk_debug(" %04x:%04x\n", (id & 0xffff), (id>>16));
+		if(((dev>>12) & 0x07) == 0) {
+			u8 hdr_type;
+			hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+			if((hdr_type & 0x80) != 0x80) {
+				dev += PCI_DEV(0,0,7);
+			}
+		}
+	}
+}
+
+static void print_pci_devices_on_bus(u32 busn)
+{
+	device_t dev;
+	for(dev = PCI_DEV(busn, 0, 0);
+		dev <= PCI_DEV(busn, 0x1f, 0x7);
+		dev += PCI_DEV(0,0,1)) {
+		u32 id;
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+		   (((id >> 16) & 0xffff) == 0xffff) ||
+		   (((id >> 16) & 0xffff) == 0x0000)) {
+			continue;
+		}
+		print_debug_pci_dev(dev);
+		printk_debug(" %04x:%04x\n", (id & 0xffff), (id>>16));
+		if(((dev>>12) & 0x07) == 0) {
+			u8 hdr_type;
+			hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+			if((hdr_type & 0x80) != 0x80) {
+				 dev += PCI_DEV(0,0,7);
+			}
+		}
+	}
+}
+
+
+
+static void dump_pci_device_range(u32 dev, u32 start_reg, u32 size)
+{
+	int i;
+	print_debug_pci_dev(dev);
+	int j;
+	int end = start_reg + size;
+
+	for(i = start_reg; i < end; i+=4) {
+		u32 val;
+		if ((i & 0x0f) == 0) {
+			printk_debug("\n%04x:",i);
+		}
+		val = pci_read_config32(dev, i);
+		for(j=0;j<4;j++) {
+			printk_debug(" %02x", val & 0xff);
+			val >>= 8;
+		}
+	}
+	print_debug("\n");
+}
+static void dump_pci_device(u32 dev)
+{
+	dump_pci_device_range(dev, 0, 4096);
+}
+static u32 pci_read_config32_index_wait(device_t dev, u32 index_reg, u32 index);
+static void dump_pci_device_index_wait_range(u32 dev, u32 index_reg, u32 start,
+					u32 size)
+{
+	int i;
+	int end = start + size;
+	print_debug_pci_dev(dev);
+	print_debug(" -- index_reg="); print_debug_hex32(index_reg);
+
+	for(i = start; i < end; i++) {
+		u32 val;
+		int j;
+		printk_debug("\n%02x:",i);
+		val = pci_read_config32_index_wait(dev, index_reg, i);
+		for(j=0;j<4;j++) {
+			printk_debug(" %02x", val & 0xff);
+			val >>= 8;
+		}
+
+	}
+	print_debug("\n");
+}
+static void dump_pci_device_index_wait(u32 dev, u32 index_reg)
+{
+	dump_pci_device_index_wait_range(dev, index_reg, 0, 0x54);
+	dump_pci_device_index_wait_range(dev, index_reg, 0x100, 0x08); //DIMM1 when memclk > 400Hz
+//	dump_pci_device_index_wait_range(dev, index_reg, 0x200, 0x08); //DIMM2
+//	dump_pci_device_index_wait_range(dev, index_reg, 0x300, 0x08); //DIMM3
+
+}
+
+static void dump_pci_device_index(u32 dev, u32 index_reg, u32 type, u32 length)
+{
+	int i;
+	print_debug_pci_dev(dev);
+
+	print_debug(" index reg: "); print_debug_hex16(index_reg); print_debug(" type: "); print_debug_hex8(type);
+
+	type<<=28;
+
+	for(i = 0; i < length; i++) {
+		u32 val;
+		if ((i & 0x0f) == 0) {
+			printk_debug("\n%02x:",i);
+		}
+		val = pci_read_config32_index(dev, index_reg, i|type);
+		printk_debug(" %08x", val);
+	}
+	print_debug("\n");
+}
+
+
+static void dump_pci_devices(void)
+{
+	device_t dev;
+	for(dev = PCI_DEV(0, 0, 0);
+		dev <= PCI_DEV(0xff, 0x1f, 0x7);
+		dev += PCI_DEV(0,0,1)) {
+		u32 id;
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0x0000)) {
+			continue;
+		}
+		dump_pci_device(dev);
+
+		if(((dev>>12) & 0x07) == 0) {
+			u8 hdr_type;
+			hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+			if((hdr_type & 0x80) != 0x80) {
+				dev += PCI_DEV(0,0,7);
+			}
+		}
+	}
+}
+
+
+static void dump_pci_devices_on_bus(u32 busn)
+{
+	device_t dev;
+	for(dev = PCI_DEV(busn, 0, 0);
+		dev <= PCI_DEV(busn, 0x1f, 0x7);
+		dev += PCI_DEV(0,0,1)) {
+		u32 id;
+		id = pci_read_config32(dev, PCI_VENDOR_ID);
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+		   (((id >> 16) & 0xffff) == 0xffff) ||
+		   (((id >> 16) & 0xffff) == 0x0000)) {
+			continue;
+		}
+		dump_pci_device(dev);
+
+		if(((dev>>12) & 0x07) == 0) {
+			u8 hdr_type;
+			hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+			if((hdr_type & 0x80) != 0x80) {
+				dev += PCI_DEV(0,0,7);
+			}
+		}
+	}
+}
+
+#ifndef DEBUG_SMBUS
+#define DEBUG_SMBUS 0
+#endif
+
+#if DEBUG_SMBUS == 1
+
+static void dump_spd_registers(const struct mem_controller *ctrl)
+{
+	int i;
+	print_debug("\n");
+	for(i = 0; i < DIMM_SOCKETS; i++) {
+		u32 device;
+		device = ctrl->spd_addr[i];
+		if (device) {
+			int j;
+			printk_debug("dimm: %02x.0: %02x", i, device);
+			for(j = 0; j < 128; j++) {
+				int status;
+				u8 byte;
+				if ((j & 0xf) == 0) {
+					printk_debug("\n%02x: ", j);
+				}
+				status = smbus_read_byte(device, j);
+				if (status < 0) {
+					break;
+				}
+				byte = status & 0xff;
+				printk_debug("%02x ", byte);
+			}
+			print_debug("\n");
+		}
+		device = ctrl->spd_addr[i+DIMM_SOCKETS];
+		if (device) {
+			int j;
+			printk_debug("dimm: %02x.1: %02x", i, device);
+			for(j = 0; j < 128; j++) {
+				int status;
+				u8 byte;
+				if ((j & 0xf) == 0) {
+					printk_debug("\n%02x: ", j);
+				}
+				status = smbus_read_byte(device, j);
+				if (status < 0) {
+					break;
+				}
+				byte = status & 0xff;
+				printk_debug("%02x ", byte);
+			}
+			print_debug("\n");
+		}
+	}
+}
+static void dump_smbus_registers(void)
+{
+	u32 device;
+	print_debug("\n");
+	for(device = 1; device < 0x80; device++) {
+		int j;
+		if( smbus_read_byte(device, 0) < 0 ) continue;
+		printk_debug("smbus: %02x", device);
+		for(j = 0; j < 256; j++) {
+			int status;
+			u8 byte;
+			status = smbus_read_byte(device, j);
+			if (status < 0) {
+				break;
+			}
+			if ((j & 0xf) == 0) {
+				printk_debug("\n%02x: ",j);
+			}
+			byte = status & 0xff;
+			printk_debug("%02x ", byte);
+		}
+		print_debug("\n");
+	}
+}
+#endif
+static void dump_io_resources(u32 port)
+{
+
+	int i;
+	udelay_tsc(2000);
+	printk_debug("%04x:\n", port);
+	for(i=0;i<256;i++) {
+		u8 val;
+		if ((i & 0x0f) == 0) {
+			printk_debug("%02x:", i);
+		}
+		val = inb(port);
+		printk_debug(" %02x",val);
+		if ((i & 0x0f) == 0x0f) {
+			print_debug("\n");
+		}
+		port++;
+	}
+}
+
+static void dump_mem(u32 start, u32 end)
+{
+	u32 i;
+	print_debug("dump_mem:");
+	for(i=start;i<end;i++) {
+		if((i & 0xf)==0) {
+			printk_debug("\n%08x:", i);
+		}
+		printk_debug(" %02x", (u8)*((u8 *)i));
+	}
+	print_debug("\n");
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/early_ht.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/early_ht.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+// For SB HT chain only
+// mmconf is not ready yet
+static  void set_bsp_node_CHtExtNodeCfgEn(void)
+{
+#if EXT_RT_TBL_SUPPORT == 1
+	u32 dword;
+	dword = pci_io_read_config32(PCI_DEV(0, 0x18, 0), 0x68);
+	dword |= (1<<27) | (1<<25);
+	/* CHtExtNodeCfgEn: coherent link extended node configuration enable,
+	   Nodes[31:0] will be 0xff:[31:0], Nodes[63:32] will be 0xfe:[31:0]
+	      ---- 32 nodes now only
+	   It can be used even nodes less than 8 nodes.
+	   We can have 8 more device on bus 0 in that case
+	 */
+
+	/* CHtExtAddrEn */
+	pci_io_write_config32(PCI_DEV(0, 0x18, 0), 0x68, dword);
+	// CPU on bus 0xff and 0xfe now. For now on we can use CBB and CDB.
+#endif
+}
+
+static void enumerate_ht_chain(void)
+{
+#if HT_CHAIN_UNITID_BASE != 0
+/* HT_CHAIN_UNITID_BASE could be 0 (only one ht device in the ht chain),
+   if so, don't need to go through the chain  */
+
+	/* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
+	 * On most boards this just happens.  If a cpu has multiple
+	 * non Coherent links the appropriate bus registers for the
+	 * links needs to be programed to point at bus 0.
+	 */
+	unsigned next_unitid, last_unitid = 0;
+#if HT_CHAIN_END_UNITID_BASE != 0x20
+	// let't record the device of last ht device, So we can set the
+	// Unitid to HT_CHAIN_END_UNITID_BASE
+	unsigned real_last_unitid = 0;
+	u8 real_last_pos = 0;
+	int ht_dev_num = 0; // except host_bridge
+	u8 end_used = 0;
+#endif
+
+	next_unitid = HT_CHAIN_UNITID_BASE;
+	do {
+		u32 id;
+		u8 hdr_type, pos;
+		last_unitid = next_unitid;
+
+		id = pci_io_read_config32(PCI_DEV(0,0,0), PCI_VENDOR_ID);
+		/* If the chain is enumerated quit */
+		if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0xffff) ||
+			(((id >> 16) & 0xffff) == 0x0000))
+		{
+			break;
+		}
+
+		hdr_type = pci_io_read_config8(PCI_DEV(0,0,0), PCI_HEADER_TYPE);
+		pos = 0;
+		hdr_type &= 0x7f;
+
+		if ((hdr_type == PCI_HEADER_TYPE_NORMAL) ||
+			(hdr_type == PCI_HEADER_TYPE_BRIDGE))
+		{
+			pos = pci_io_read_config8(PCI_DEV(0,0,0), PCI_CAPABILITY_LIST);
+		}
+		while(pos != 0) {
+			u8 cap;
+			cap = pci_io_read_config8(PCI_DEV(0,0,0), pos + PCI_CAP_LIST_ID);
+			if (cap == PCI_CAP_ID_HT) {
+				u16 flags;
+				/* Read and write and reread flags so the link
+				 * direction bit is valid.
+				 */
+				flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS);
+				pci_io_write_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS, flags);
+				flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS);
+				if ((flags >> 13) == 0) {
+					unsigned count;
+					unsigned ctrl, ctrl_off;
+					device_t devx;
+
+#if HT_CHAIN_END_UNITID_BASE != 0x20
+					if(next_unitid>=0x18) {
+						if(!end_used) {
+							next_unitid = HT_CHAIN_END_UNITID_BASE;
+							end_used = 1;
+						} else {
+							goto out;
+						}
+					}
+					real_last_unitid = next_unitid;
+					real_last_pos = pos;
+					ht_dev_num++ ;
+#endif
+		#if HT_CHAIN_END_UNITID_BASE == 0
+					if (!next_unitid)
+						goto out;
+		#endif
+					flags &= ~0x1f;
+					flags |= next_unitid & 0x1f;
+					count = (flags >> 5) & 0x1f;
+					devx = PCI_DEV(0, next_unitid, 0);
+					next_unitid += count;
+
+					pci_io_write_config16(PCI_DEV(0, 0, 0), pos + PCI_CAP_FLAGS, flags);
+
+					/* Test for end of chain */
+					ctrl_off = ((flags >> 10) & 1)?
+						PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1;
+
+					do {
+						ctrl = pci_read_config16(devx, pos + ctrl_off);
+						/* Is this the end of the hypertransport chain? */
+						if (ctrl & (1 << 6)) {
+							goto out;
+						}
+
+						if (ctrl & ((1 << 4) | (1 << 8))) {
+							/*
+							 * Either the link has failed, or we have
+							 * a CRC error.
+							 * Sometimes this can happen due to link
+							 * retrain, so lets knock it down and see
+							 * if its transient
+							 */
+							ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc
+							pci_write_config16(devx, pos + ctrl_off, ctrl);
+							ctrl = pci_read_config16(devx, pos + ctrl_off);
+							if (ctrl & ((1 << 4) | (1 << 8))) {
+								// can not clear the error
+								break;
+							}
+						}
+					} while((ctrl & (1 << 5)) == 0);
+
+					break;
+				}
+			}
+			pos = pci_io_read_config8(PCI_DEV(0, 0, 0), pos + PCI_CAP_LIST_NEXT);
+		}
+	} while(last_unitid != next_unitid);
+
+out:	;
+#if HT_CHAIN_END_UNITID_BASE != 0x20
+	if((ht_dev_num>1) && (real_last_unitid != HT_CHAIN_END_UNITID_BASE) && !end_used) {
+		u16 flags;
+		flags = pci_io_read_config16(PCI_DEV(0,real_last_unitid,0), real_last_pos + PCI_CAP_FLAGS);
+		flags &= ~0x1f;
+		flags |= HT_CHAIN_END_UNITID_BASE & 0x1f;
+		pci_io_write_config16(PCI_DEV(0, real_last_unitid, 0), real_last_pos + PCI_CAP_FLAGS, flags);
+	}
+#endif
+
+#endif
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/get_pci1234.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/get_pci1234.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <console/console.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <cpu/amd/amdfam10_sysconf.h>
+
+
+/* Need pci1234 array
+ * pci1234[0] will record sblink and bus range
+ * pci1234[i] will record ht chain i.
+ * It will keep the sequence when some ht io card is not installed.
+ *
+ *	1n: 8
+ *	2n: 7x2
+ *	3n: 6x3
+ *	4n: 5x4
+ *	5n: 4x5
+ *	6n: 3x6
+ *	7n: 2x7
+ *	8n: 1x8
+ *
+ *	8n(4x2): 8x4
+ *	16n(4x4): 16*2
+ *	20n(4x5): 20x1
+ *	32n(4x4+4x4): 16x1
+ *
+ * Total: xxx: I just want to use 32 instead, If you have more, you may need to
+ * reset HC_POSSIBLE_NUM and update ssdt.dsl (hcdn, hclk)
+ *
+ * Put all the possible ht node/link to the list tp pci1234[] in  get_bus_conf.c
+ * on MB dir. Also, don't forget to increase the ACPI_SSDTX_NUM etc if you have
+ * too much SSDT. How about co-processor on socket 1 on 2 way system.
+ * or socket 2, and socket3 on 4 way system? treat that as one hc too!
+ *
+ */
+
+
+void get_pci1234(void)
+{
+
+	int i,j;
+	u32 dword;
+
+	dword = sysconf.sblk<<8;
+	dword |= 1;
+	sysconf.pci1234[0] = dword; // sblink
+	sysconf.hcid[0] = 0;
+
+	/* about hardcode numbering for HT_IO support
+	  set the node_id and link_id that could have ht chain in the one array,
+	  then check if is enabled.... then update final value
+	*/
+
+	//here we need to set hcdn
+	//1. hypertransport.c need to record hcdn_reg together with 0xe0, 0xe4, 0xe8, 0xec when are set
+	//2. so at the same time we need update hsdn with hcdn_reg here
+//	printk_debug("sysconf.ht_c_num = %02d\n", sysconf.ht_c_num);
+
+	for(j=0;j<sysconf.ht_c_num;j++) {
+		u32 dwordx;
+		dwordx = sysconf.ht_c_conf_bus[j];
+//		printk_debug("sysconf.ht_c_conf_bus[%02d] = %08x\n", j, sysconf.ht_c_conf_bus[j]);
+		dwordx &=0xfffffffd; //keep bus num, node_id, link_num, enable bits
+		if((dwordx & 0x7fd) == dword) { //SBLINK
+			sysconf.pci1234[0] = dwordx;
+			sysconf.hcdn[0] = sysconf.hcdn_reg[j];
+			continue;
+		}
+		if((dwordx & 1)) {
+			// We need to find out the number of HC
+			// for exact match
+			for(i=1;i<sysconf.hc_possible_num;i++) {
+				if((dwordx & 0x7fc) == (sysconf.pci1234[i] & 0x7fc)) { // same node and same linkn
+					sysconf.pci1234[i] = dwordx;
+					sysconf.hcdn[i] = sysconf.hcdn_reg[j];
+					break;
+				}
+			}
+			// for 0xffc match or same node
+			for(i=1;i<sysconf.hc_possible_num;i++) {
+				if((dwordx & 0x7fc) == (dwordx & sysconf.pci1234[i] & 0x7fc)) {
+					sysconf.pci1234[i] = dwordx;
+					sysconf.hcdn[i] = sysconf.hcdn_reg[j];
+					break;
+				}
+			}
+		}
+	}
+
+	for(i=1;i<sysconf.hc_possible_num;i++) {
+		if(!(sysconf.pci1234[i] & 1)) {
+			sysconf.pci1234[i] = 0;
+			sysconf.hcdn[i] = 0x20202020;
+		}
+		sysconf.hcid[i] = 0;
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/misc_control.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/misc_control.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2003 by Eric Biederman
+ * Copyright (C) Stefan Reinauer
+ * Copyright (C) 2007 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
+ */
+
+/* Turn off machine check triggers when reading
+ * pci space where there are no devices.
+ * This is necessary when scaning the bus for
+ * devices which is done by the kernel
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <part/hard_reset.h>
+#include <pc80/mc146818rtc.h>
+#include <bitops.h>
+#include <cpu/amd/model_10xxx_rev.h>
+
+#include "amdfam10.h"
+
+/**
+ * @brief Read resources for AGP aperture
+ *
+ * @param
+ *
+ * There is only one AGP aperture resource needed. The resoruce is added to
+ * the northbridge of BSP.
+ *
+ * The same trick can be used to augment legacy VGA resources which can
+ * be detect by generic pci reousrce allocator for VGA devices.
+ * BAD: it is more tricky than I think, the resource allocation code is
+ * implemented in a way to NOT DOING legacy VGA resource allcation on
+ * purpose :-(.
+ */
+static void mcf3_read_resources(device_t dev)
+{
+	struct resource *resource;
+	unsigned char iommu;
+	/* Read the generic PCI resources */
+	pci_dev_read_resources(dev);
+
+	/* If we are not the first processor don't allocate the gart apeture */
+	if (dev->path.u.pci.devfn != PCI_DEVFN(CDB, 3)) {
+		return;
+	}
+
+	iommu = 1;
+	get_option(&iommu, "iommu");
+
+	if (iommu) {
+		/* Add a Gart apeture resource */
+		resource = new_resource(dev, 0x94);
+		resource->size = iommu?AGP_APERTURE_SIZE:1;
+		resource->align = log2(resource->size);
+		resource->gran  = log2(resource->size);
+		resource->limit = 0xffffffff; /* 4G */
+		resource->flags = IORESOURCE_MEM;
+	}
+}
+
+static void set_agp_aperture(device_t dev)
+{
+	struct resource *resource;
+
+	resource = probe_resource(dev, 0x94);
+	if (resource) {
+		device_t pdev;
+		u32 gart_base, gart_acr;
+
+		/* Remember this resource has been stored */
+		resource->flags |= IORESOURCE_STORED;
+
+		/* Find the size of the GART aperture */
+		gart_acr = (0<<6)|(0<<5)|(0<<4)|((resource->gran - 25) << 1)|(0<<0);
+
+		/* Get the base address */
+		gart_base = ((resource->base) >> 25) & 0x00007fff;
+
+		/* Update the other northbriges */
+		pdev = 0;
+		while((pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1203, pdev))) {
+			/* Store the GART size but don't enable it */
+			pci_write_config32(pdev, 0x90, gart_acr);
+
+			/* Store the GART base address */
+			pci_write_config32(pdev, 0x94, gart_base);
+
+			/* Don't set the GART Table base address */
+			pci_write_config32(pdev, 0x98, 0);
+
+			/* Report the resource has been stored... */
+			report_resource_stored(pdev, resource, " <gart>");
+		}
+	}
+}
+
+static void mcf3_set_resources(device_t dev)
+{
+	/* Set the gart apeture */
+	set_agp_aperture(dev);
+
+	/* Set the generic PCI resources */
+	pci_dev_set_resources(dev);
+}
+
+static void misc_control_init(struct device *dev)
+{
+	u32 cmd;
+
+	printk_debug("NB: Function 3 Misc Control.. ");
+
+	/* Disable Machine checks from Invalid Locations.
+	 * This is needed for PC backwards compatibility.
+	 */
+	cmd = pci_read_config32(dev, 0x44);
+	cmd |= (1<<6) | (1<<25);
+	pci_write_config32(dev, 0x44, cmd );
+
+	printk_debug("done.\n");
+}
+
+
+static struct device_operations mcf3_ops  = {
+	.read_resources   = mcf3_read_resources,
+	.set_resources    = mcf3_set_resources,
+	.enable_resources = pci_dev_enable_resources,
+	.init             = misc_control_init,
+	.scan_bus         = 0,
+	.ops_pci          = 0,
+};
+
+static struct pci_driver mcf3_driver __pci_driver = {
+	.ops    = &mcf3_ops,
+	.vendor = PCI_VENDOR_ID_AMD,
+	.device = 0x1203,
+};
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/northbridge.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/northbridge.c	2007-12-12 11:53:40.000000000 -0700
@@ -0,0 +1,1477 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/hypertransport.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bitops.h>
+#include <cpu/cpu.h>
+
+#include <cpu/x86/lapic.h>
+
+#if CONFIG_LOGICAL_CPUS==1
+#include <cpu/amd/quadcore.h>
+#include <pc80/mc146818rtc.h>
+#endif
+
+#include "chip.h"
+#include "root_complex/chip.h"
+#include "northbridge.h"
+
+#include "amdfam10.h"
+
+#if HW_MEM_HOLE_SIZEK != 0
+#include <cpu/amd/model_10xxx_rev.h>
+#endif
+
+#include <cpu/amd/amdfam10_sysconf.h>
+
+struct amdfam10_sysconf_t sysconf;
+
+#define FX_DEVS NODE_NUMS
+static device_t __f0_dev[FX_DEVS];
+static device_t __f1_dev[FX_DEVS];
+static device_t __f2_dev[FX_DEVS];
+static device_t __f4_dev[FX_DEVS];
+
+device_t get_node_pci(u32 nodeid, u32 fn)
+{
+#if NODE_NUMS == 64
+	if(nodeid<32) {
+		return dev_find_slot(CBB, PCI_DEVFN(CDB + nodeid, fn));
+	} else {
+		return dev_find_slot(CBB-1, PCI_DEVFN(CDB + nodeid - 32, fn));
+	}
+
+#else
+	return dev_find_slot(CBB, PCI_DEVFN(CDB + nodeid, fn));
+#endif
+
+}
+static void get_fx_devs(void)
+{
+	int i;
+	if (__f1_dev[0]) {
+		return;
+	}
+	for(i = 0; i < FX_DEVS; i++) {
+		__f0_dev[i] = get_node_pci(i, 0);
+		__f1_dev[i] = get_node_pci(i, 1);
+		__f2_dev[i] = get_node_pci(i, 2);
+		__f4_dev[i] = get_node_pci(i, 4);
+	}
+	if (!__f1_dev[0]) {
+		printk_err("Cannot find %02x:%02x.1", CBB, CDB);
+		die("Cannot go on\n");
+	}
+}
+
+static u32 f1_read_config32(u32 reg)
+{
+	get_fx_devs();
+	return pci_read_config32(__f1_dev[0], reg);
+}
+
+static void f1_write_config32(u32 reg, u32 value)
+{
+	int i;
+	get_fx_devs();
+	for(i = 0; i < FX_DEVS; i++) {
+		device_t dev;
+		dev = __f1_dev[i];
+		if (dev && dev->enabled) {
+			pci_write_config32(dev, reg, value);
+		}
+	}
+}
+
+
+static u32 amdfam10_nodeid(device_t dev)
+{
+#if NODE_NUMS == 64
+	unsigned busn;
+	busn = dev->bus->secondary;
+	if(busn != CBB) {
+		return (dev->path.u.pci.devfn >> 3) - CDB + 32;
+	} else {
+		return (dev->path.u.pci.devfn >> 3) - CDB;
+	}
+
+#else
+	return (dev->path.u.pci.devfn >> 3) - CDB;
+#endif
+}
+
+#include "amdfam10_conf.c"
+
+static void set_vga_enable_reg(u32 nodeid, u32 linkn)
+{
+	u32 val;
+
+	val =  1 | (nodeid<<4) | (linkn<<12);
+	/* it will routing (1)mmio  0xa0000:0xbffff (2) io 0x3b0:0x3bb,
+	 0x3c0:0x3df */
+	f1_write_config32(0xf4, val);
+
+}
+
+static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, u32 link, u32 sblink,
+				u32 max, u32 offset_unitid)
+{
+//	I want to put sb chain in bus 0 can I?
+
+
+		u32 link_type;
+		int i;
+		u32 ht_c_index;
+		u32 ht_unitid_base[4]; // here assume only 4 HT device on chain
+		u32 max_bus;
+		u32 min_bus;
+		u32 is_sublink1 = (link>3);
+		device_t devx;
+		u32 busses;
+		u32 segn = max>>8;
+		u32 busn = max&0xff;
+		u32 max_devfn;
+
+#if HT3_SUPPORT==1
+		if(is_sublink1) {
+			u32 regpos;
+			u32 reg;
+			regpos = 0x170 + 4 * (link&3); // it is only on sublink0
+			reg = pci_read_config32(dev, regpos);
+			if(reg & 1) return max; // already ganged no sblink1
+			devx = get_node_pci(nodeid, 4);
+		} else
+#endif
+			devx = dev;
+
+
+		dev->link[link].cap = 0x80 + ((link&3) *0x20);
+		do {
+			link_type = pci_read_config32(devx, dev->link[link].cap + 0x18);
+		} while(link_type & ConnectionPending);
+		if (!(link_type & LinkConnected)) {
+			return max;
+		}
+		do {
+			link_type = pci_read_config32(devx, dev->link[link].cap + 0x18);
+		} while(!(link_type & InitComplete));
+		if (!(link_type & NonCoherent)) {
+			return max;
+		}
+		/* See if there is an available configuration space mapping
+		 * register in function 1.
+		 */
+		ht_c_index = get_ht_c_index(nodeid, link, &sysconf);
+
+#if EXT_CONF_SUPPORT == 0
+		if(ht_c_index>=4) return max;
+#endif
+
+		/* Set up the primary, secondary and subordinate bus numbers.
+		 * We have no idea how many busses are behind this bridge yet,
+		 * so we set the subordinate bus number to 0xff for the moment.
+		 */
+
+#if SB_HT_CHAIN_ON_BUS0 > 0
+		// first chain will on bus 0
+		if((nodeid == 0) && (sblink==link)) { // actually max is 0 here
+			 min_bus = max;
+		}
+	#if SB_HT_CHAIN_ON_BUS0 > 1
+		// second chain will be on 0x40, third 0x80, forth 0xc0
+		// i would refined that to  2, 3, 4 ==> 0, 0x, 40, 0x80, 0xc0
+		//			    >4 will use	 more segments, We can have 16 segmment and every segment have 256 bus, For that case need the kernel support mmio pci config.
+		else {
+			min_bus = ((busn>>3) + 1) << 3; // one node can have 8 link and segn is the same
+		}
+		max = min_bus | (segn<<8);
+	 #else
+		//other ...
+		else {
+			min_bus = ++max;
+		}
+	 #endif
+#else
+		min_bus = ++max;
+#endif
+		max_bus = 0xfc | (segn<<8);
+
+		dev->link[link].secondary = min_bus;
+		dev->link[link].subordinate = max_bus;
+		/* Read the existing primary/secondary/subordinate bus
+		 * number configuration.
+		 */
+		busses = pci_read_config32(devx, dev->link[link].cap + 0x14);
+
+		/* Configure the bus numbers for this bridge: the configuration
+		 * transactions will not be propagates by the bridge if it is
+		 * not correctly configured
+		 */
+		busses &= 0xffff00ff;
+		busses |= ((u32)(dev->link[link].secondary) << 8);
+		pci_write_config32(devx, dev->link[link].cap + 0x14, busses);
+
+
+		/* set the config map space */
+
+		set_config_map_reg(nodeid, link, ht_c_index, dev->link[link].secondary, dev->link[link].subordinate, sysconf.segbit, sysconf.nodes);
+
+		/* Now we can scan all of the subordinate busses i.e. the
+		 * chain on the hypertranport link
+		 */
+		for(i=0;i<4;i++) {
+			ht_unitid_base[i] = 0x20;
+		}
+
+		//if ext conf is enabled, only need use 0x1f
+		if (min_bus == 0)
+			max_devfn = (0x17<<3) | 7;
+		else
+			max_devfn = (0x1f<<3) | 7;
+
+		max = hypertransport_scan_chain(&dev->link[link], 0, max_devfn, max, ht_unitid_base, offset_unitid);
+
+
+		/* We know the number of busses behind this bridge.  Set the
+		 * subordinate bus number to it's real value
+		 */
+		if(ht_c_index>3) { // clear the extend reg
+			clear_config_map_reg(nodeid, link, ht_c_index, (max+1)>>sysconf.segbit, (dev->link[link].subordinate)>>sysconf.segbit, sysconf.nodes);
+		}
+
+		dev->link[link].subordinate = max;
+		set_config_map_reg(nodeid, link, ht_c_index, dev->link[link].secondary, dev->link[link].subordinate, sysconf.segbit, sysconf.nodes);
+		sysconf.ht_c_num++;
+
+		{
+		// config config_reg, and ht_unitid_base to update hcdn_reg;
+			u32 temp = 0;
+			for(i=0;i<4;i++) {
+				temp |= (ht_unitid_base[i] & 0xff) << (i*8);
+			}
+
+			sysconf.hcdn_reg[ht_c_index] = temp;
+
+		}
+
+		store_ht_c_conf_bus(nodeid, link, ht_c_index, dev->link[link].secondary, dev->link[link].subordinate, &sysconf);
+
+
+	return max;
+}
+
+static u32 amdfam10_scan_chains(device_t dev, u32 max)
+{
+	u32 nodeid;
+	u32 link;
+	u32 sblink = sysconf.sblk;
+	u32 offset_unitid = 0;
+
+	nodeid = amdfam10_nodeid(dev);
+
+
+// Put sb chain in bus 0
+#if SB_HT_CHAIN_ON_BUS0 > 0
+	if(nodeid==0) {
+	#if ((HT_CHAIN_UNITID_BASE != 1) || (HT_CHAIN_END_UNITID_BASE != 0x20))
+		offset_unitid = 1;
+	#endif
+		max = amdfam10_scan_chain(dev, nodeid, sblink, sblink, max, offset_unitid ); // do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0
+	}
+#endif
+
+
+#if PCI_BUS_SEGN_BITS
+	max = check_segn(dev, max, sysconf.nodes, &sysconf);
+#endif
+
+
+	for(link = 0; link < dev->links; link++) {
+#if SB_HT_CHAIN_ON_BUS0 > 0
+		if( (nodeid == 0) && (sblink == link) ) continue; //already done
+#endif
+		offset_unitid = 0;
+		#if ((HT_CHAIN_UNITID_BASE != 1) || (HT_CHAIN_END_UNITID_BASE != 0x20))
+			#if SB_HT_CHAIN_UNITID_OFFSET_ONLY == 1
+			if((nodeid == 0) && (sblink == link))
+			#endif
+				offset_unitid = 1;
+		#endif
+
+		max = amdfam10_scan_chain(dev, nodeid, link, sblink, max, offset_unitid);
+	}
+	return max;
+}
+
+
+static int reg_useable(u32 reg,device_t goal_dev, u32 goal_nodeid,
+			u32 goal_link)
+{
+	struct resource *res;
+	u32 nodeid, link;
+	int result;
+	res = 0;
+	for(nodeid = 0; !res && (nodeid < NODE_NUMS); nodeid++) {
+		device_t dev;
+		dev = __f0_dev[nodeid];
+		for(link = 0; !res && (link < 8); link++) {
+			res = probe_resource(dev, 0x1000 + reg + (link<<16)); // 8 links, 0x1000 man f1,
+		}
+	}
+	result = 2;
+	if (res) {
+		result = 0;
+		if (	(goal_link == (link - 1)) &&
+			(goal_nodeid == (nodeid - 1)) &&
+			(res->flags <= 1)) {
+			result = 1;
+		}
+	}
+	return result;
+}
+
+static struct resource *amdfam10_find_iopair(device_t dev, u32 nodeid, u32 link)
+{
+	struct resource *resource;
+	u32 free_reg, reg;
+	resource = 0;
+	free_reg = 0;
+	for(reg = 0xc0; reg <= 0xd8; reg += 0x8) {
+		int result;
+		result = reg_useable(reg, dev, nodeid, link);
+		if (result == 1) {
+			/* I have been allocated this one */
+			break;
+		}
+		else if (result > 1) {
+			/* I have a free register pair */
+			free_reg = reg;
+		}
+	}
+	if (reg > 0xd8) {
+		reg = free_reg; // if no free, the free_reg still be 0
+	}
+
+	//Ext conf space
+	if(!reg) {
+		//because of Extend conf space, we will never run out of reg, but we need one index to differ them. so same node and same link can have multi range
+		u32 index = get_io_addr_index(nodeid, link);
+		reg = 0x110+ (index<<24) + (4<<20); // index could be 0, 255
+	}
+
+	resource = new_resource(dev, 0x1000 + reg + (link<<16));
+
+	return resource;
+}
+
+static struct resource *amdfam10_find_mempair(device_t dev, u32 nodeid, u32 link)
+{
+	struct resource *resource;
+	u32 free_reg, reg;
+	resource = 0;
+	free_reg = 0;
+	for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
+		int result;
+		result = reg_useable(reg, dev, nodeid, link);
+		if (result == 1) {
+			/* I have been allocated this one */
+			break;
+		}
+		else if (result > 1) {
+			/* I have a free register pair */
+			free_reg = reg;
+		}
+	}
+	if (reg > 0xb8) {
+		reg = free_reg;
+	}
+
+	//Ext conf space
+	if(!reg) {
+		//because of Extend conf space, we will never run out of reg,
+		// but we need one index to differ them. so same node and
+		// same link can have multi range
+		u32 index = get_mmio_addr_index(nodeid, link);
+		reg = 0x110+ (index<<24) + (6<<20); // index could be 0, 63
+
+	}
+	resource = new_resource(dev, 0x1000 + reg + (link<<16));
+	return resource;
+}
+
+
+static void amdfam10_link_read_bases(device_t dev, u32 nodeid, u32 link)
+{
+	struct resource *resource;
+
+	/* Initialize the io space constraints on the current bus */
+	resource =  amdfam10_find_iopair(dev, nodeid, link);
+	if (resource) {
+		u32 align;
+#if EXT_CONF_SUPPORT == 1
+		if((resource->index & 0x1fff) == 0x1110) { // ext
+			align = 8;
+		}
+		else
+#endif
+			align = log2(HT_IO_HOST_ALIGN);
+		resource->base	= 0;
+		resource->size	= 0;
+		resource->align = align;
+		resource->gran	= align;
+		resource->limit = 0xffffUL;
+		resource->flags = IORESOURCE_IO;
+		compute_allocate_resource(&dev->link[link], resource,
+					IORESOURCE_IO, IORESOURCE_IO);
+	}
+
+	/* Initialize the prefetchable memory constraints on the current bus */
+	resource = amdfam10_find_mempair(dev, nodeid, link);
+	if (resource) {
+		resource->base	= 0;
+		resource->size	= 0;
+		resource->align = log2(HT_MEM_HOST_ALIGN);
+		resource->gran	= log2(HT_MEM_HOST_ALIGN);
+		resource->limit = 0xffffffffffULL;
+		resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		compute_allocate_resource(&dev->link[link], resource,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH);
+
+#if EXT_CONF_SUPPORT == 1
+		if((resource->index & 0x1fff) == 0x1110) { // ext
+			normalize_resource(resource);
+		}
+#endif
+
+	}
+
+	/* Initialize the memory constraints on the current bus */
+	resource = amdfam10_find_mempair(dev, nodeid, link);
+	if (resource) {
+		resource->base	= 0;
+		resource->size	= 0;
+		resource->align = log2(HT_MEM_HOST_ALIGN);
+		resource->gran	= log2(HT_MEM_HOST_ALIGN);
+		resource->limit = 0xffffffffffULL;
+		resource->flags = IORESOURCE_MEM;
+		compute_allocate_resource(&dev->link[link], resource,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH,
+			IORESOURCE_MEM);
+
+#if EXT_CONF_SUPPORT == 1
+		if((resource->index & 0x1fff) == 0x1110) { // ext
+			normalize_resource(resource);
+		}
+#endif
+
+	}
+}
+
+
+static void amdfam10_read_resources(device_t dev)
+{
+	u32 nodeid, link;
+
+	nodeid = amdfam10_nodeid(dev);
+	for(link = 0; link < dev->links; link++) {
+		if (dev->link[link].children) {
+			amdfam10_link_read_bases(dev, nodeid, link);
+		}
+	}
+}
+
+
+static void amdfam10_set_resource(device_t dev, struct resource *resource,
+				u32 nodeid)
+{
+	resource_t rbase, rend;
+	unsigned reg, link;
+	char buf[50];
+
+	/* Make certain the resource has actually been set */
+	if (!(resource->flags & IORESOURCE_ASSIGNED)) {
+		return;
+	}
+
+	/* If I have already stored this resource don't worry about it */
+	if (resource->flags & IORESOURCE_STORED) {
+		return;
+	}
+
+	/* Only handle PCI memory and IO resources */
+	if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+		return;
+
+	/* Ensure I am actually looking at a resource of function 1 */
+	if ((resource->index & 0xffff) < 0x1000) {
+		return;
+	}
+	/* Get the base address */
+	rbase = resource->base;
+
+	/* Get the limit (rounded up) */
+	rend  = resource_end(resource);
+
+	/* Get the register and link */
+	reg  = resource->index & 0xfff; // 4k
+	link = ( resource->index>> 16)& 0x7; // 8 links
+
+	if (resource->flags & IORESOURCE_IO) {
+		compute_allocate_resource(&dev->link[link], resource,
+			IORESOURCE_IO, IORESOURCE_IO);
+
+		set_io_addr_reg(dev, nodeid, link, reg, rbase>>8, rend>>8);
+		store_conf_io_addr(nodeid, link, reg, (resource->index >> 24), rbase>>8, rend>>8);
+	}
+	else if (resource->flags & IORESOURCE_MEM) {
+		compute_allocate_resource(&dev->link[link], resource,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH,
+			resource->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH));
+		set_mmio_addr_reg(nodeid, link, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
+		store_conf_mmio_addr(nodeid, link, reg, (resource->index >>24), rbase>>8, rend>>8);
+	}
+	resource->flags |= IORESOURCE_STORED;
+	sprintf(buf, " <node %02x link %02x>",
+		nodeid, link);
+	report_resource_stored(dev, resource, buf);
+}
+
+/**
+ *
+ * I tried to reuse the resource allocation code in amdfam10_set_resource()
+ * but it is too diffcult to deal with the resource allocation magic.
+ */
+#if CONFIG_CONSOLE_VGA_MULTI == 1
+extern device_t vga_pri;	// the primary vga device, defined in device.c
+#endif
+
+static void amdfam10_create_vga_resource(device_t dev, unsigned nodeid)
+{
+	unsigned link;
+
+	/* find out which link the VGA card is connected,
+	 * we only deal with the 'first' vga card */
+	for (link = 0; link < dev->links; link++) {
+		if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
+#if CONFIG_CONSOLE_VGA_MULTI == 1
+			printk_debug("VGA: vga_pri bus num = %d dev->link[link] bus range [%d,%d]\n", vga_pri->bus->secondary,
+				dev->link[link].secondary,dev->link[link].subordinate);
+			/* We need to make sure the vga_pri is under the link */
+			if((vga_pri->bus->secondary >= dev->link[link].secondary ) &&
+				(vga_pri->bus->secondary <= dev->link[link].subordinate )
+			)
+#endif
+			break;
+		}
+	}
+
+	/* no VGA card installed */
+	if (link == dev->links)
+		return;
+
+	printk_debug("VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link);
+	set_vga_enable_reg(nodeid, link);
+}
+
+static void amdfam10_set_resources(device_t dev)
+{
+	u32 nodeid, link;
+	int i;
+
+	/* Find the nodeid */
+	nodeid = amdfam10_nodeid(dev);
+
+	amdfam10_create_vga_resource(dev, nodeid);
+
+	/* Set each resource we have found */
+	for(i = 0; i < dev->resources; i++) {
+		amdfam10_set_resource(dev, &dev->resource[i], nodeid);
+	}
+
+	for(link = 0; link < dev->links; link++) {
+		struct bus *bus;
+		bus = &dev->link[link];
+		if (bus->children) {
+			assign_resources(bus);
+		}
+	}
+}
+
+
+static void amdfam10_enable_resources(device_t dev)
+{
+	pci_dev_enable_resources(dev);
+	enable_childrens_resources(dev);
+}
+
+static void mcf0_control_init(struct device *dev)
+{
+}
+
+static struct device_operations northbridge_operations = {
+	.read_resources	  = amdfam10_read_resources,
+	.set_resources	  = amdfam10_set_resources,
+	.enable_resources = amdfam10_enable_resources,
+	.init		  = mcf0_control_init,
+	.scan_bus	  = amdfam10_scan_chains,
+	.enable		  = 0,
+	.ops_pci	  = 0,
+};
+
+
+static struct pci_driver mcf0_driver __pci_driver = {
+	.ops	= &northbridge_operations,
+	.vendor = PCI_VENDOR_ID_AMD,
+	.device = 0x1200,
+};
+
+#if CONFIG_CHIP_NAME == 1
+
+struct chip_operations northbridge_amd_amdfam10_ops = {
+	CHIP_NAME("AMD FAM10 Northbridge")
+	.enable_dev = 0,
+};
+
+#endif
+
+static void pci_domain_read_resources(device_t dev)
+{
+	struct resource *resource;
+	unsigned reg;
+	unsigned link;
+
+	/* Find the already assigned resource pairs */
+	get_fx_devs();
+	for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
+		u32 base, limit;
+		base  = f1_read_config32(reg);
+		limit = f1_read_config32(reg + 0x04);
+		/* Is this register allocated? */
+		if ((base & 3) != 0) {
+			unsigned nodeid, link;
+			device_t dev;
+			if(reg<0xc0) { // mmio
+				nodeid = (limit & 0xf) + (base&0x30);
+			} else { // io
+				nodeid =  (limit & 0xf) + ((base>>4)&0x30);
+			}
+			link   = (limit >> 4) & 7;
+			dev = __f0_dev[nodeid];
+			if (dev) {
+				/* Reserve the resource	 */
+				struct resource *resource;
+				resource = new_resource(dev, 0x1000 + reg + (link<<16));
+				if (resource) {
+					resource->flags = 1;
+				}
+			}
+		}
+	}
+	/* FIXME: do we need to check extend conf space?
+	   I don't believe that much preset value */
+
+#if CONFIG_PCI_64BIT_PREF_MEM == 0
+	/* Initialize the system wide io space constraints */
+	resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
+	resource->base	= 0x400;
+	resource->limit = 0xffffUL;
+	resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+
+	/* Initialize the system wide memory resources constraints */
+	resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
+	resource->limit = 0xfcffffffffULL;
+	resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+#else
+	for(link=0; link<dev->links; link++) {
+		/* Initialize the system wide io space constraints */
+		resource = new_resource(dev, 0|(link<<2));
+		resource->base	= 0x400;
+		resource->limit = 0xffffUL;
+		resource->flags = IORESOURCE_IO;
+		compute_allocate_resource(&dev->link[link], resource,
+			IORESOURCE_IO, IORESOURCE_IO);
+
+		/* Initialize the system wide prefetchable memory resources constraints */
+		resource = new_resource(dev, 1|(link<<2));
+		resource->limit = 0xfcffffffffULL;
+		resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		compute_allocate_resource(&dev->link[link], resource,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH);
+
+		/* Initialize the system wide memory resources constraints */
+		resource = new_resource(dev, 2|(link<<2));
+		resource->limit = 0xfcffffffffULL;
+		resource->flags = IORESOURCE_MEM;
+		compute_allocate_resource(&dev->link[link], resource,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH,
+			IORESOURCE_MEM);
+	}
+#endif
+}
+
+static void ram_resource(device_t dev, unsigned long index,
+	resource_t basek, resource_t sizek)
+{
+	struct resource *resource;
+
+	if (!sizek) {
+		return;
+	}
+	resource = new_resource(dev, index);
+	resource->base	= basek << 10;
+	resource->size	= sizek << 10;
+	resource->flags =  IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
+		IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+}
+
+static void tolm_test(void *gp, struct device *dev, struct resource *new)
+{
+	struct resource **best_p = gp;
+	struct resource *best;
+	best = *best_p;
+	if (!best || (best->base > new->base)) {
+		best = new;
+	}
+	*best_p = best;
+}
+
+static u32 find_pci_tolm(struct bus *bus, u32 tolm)
+{
+	struct resource *min;
+	min = 0;
+	search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
+	if (min && tolm > min->base) {
+		tolm = min->base;
+	}
+	return tolm;
+}
+
+#if CONFIG_PCI_64BIT_PREF_MEM == 1
+#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH)
+#endif
+
+#if HW_MEM_HOLE_SIZEK != 0
+
+struct hw_mem_hole_info {
+	unsigned hole_startk;
+	int node_id;
+};
+
+static struct hw_mem_hole_info get_hw_mem_hole_info(void)
+{
+		struct hw_mem_hole_info mem_hole;
+		int i;
+
+		mem_hole.hole_startk = HW_MEM_HOLE_SIZEK;
+		mem_hole.node_id = -1;
+
+		for (i = 0; i < sysconf.nodes; i++) {
+			struct dram_base_mask_t d;
+			u32 hole;
+			d = get_dram_base_mask(i);
+			if(!(d.mask & 1)) continue; // no memory on this node
+
+			hole = pci_read_config32(__f1_dev[i], 0xf0);
+			if(hole & 1) { // we find the hole
+				mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
+				mem_hole.node_id = i; // record the node No with hole
+				break; // only one hole
+			}
+		}
+
+		//We need to double check if there is speical set on base reg and limit reg are not continous instead of hole, it will find out it's hole_startk
+		if(mem_hole.node_id==-1) {
+			resource_t limitk_pri = 0;
+			for(i=0; i<sysconf.nodes; i++) {
+				struct dram_base_mask_t d;
+				resource_t base_k, limit_k;
+				d = get_dram_base_mask(i);
+				if(!(d.base & 1)) continue;
+
+				base_k = ((resource_t)(d.base & 0x1fffff00)) <<9;
+				if(base_k > 4 *1024 * 1024) break; // don't need to go to check
+				if(limitk_pri != base_k) { // we find the hole
+					mem_hole.hole_startk = (unsigned)limitk_pri; // must beblow 4G
+					mem_hole.node_id = i;
+					break; //only one hole
+				}
+
+				limit_k = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9;
+				limitk_pri = limit_k;
+			}
+		}
+		return mem_hole;
+}
+
+
+#if CONFIG_AMDMCT == 0
+static void disable_hoist_memory(unsigned long hole_startk, int i)
+{
+	int ii;
+	device_t dev;
+	struct dram_base_mask_t d;
+	u32 sel_m;
+	u32 sel_hi_en;
+	u32 hoist;
+	u32 hole_sizek;
+
+	u32 one_DCT;
+	struct sys_info *sysinfox = (struct sys_info *)((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_GLOBAL_VAR_SIZE); // in RAM
+	struct mem_info *meminfo;
+	meminfo = &sysinfox->meminfo[i];
+
+	one_DCT = get_one_DCT(meminfo);
+
+	// 1. find which node has hole
+	// 2. change limit in that node.
+	// 3. change base and limit in later node
+	// 4. clear that node f0
+
+	// if there is not mem hole enabled, we need to change it's base instead
+
+	hole_sizek = (4*1024*1024) - hole_startk;
+
+	for(ii=NODE_NUMS-1;ii>i;ii--) {
+
+		d = get_dram_base_mask(ii);
+
+		if(!(d.mask & 1)) continue;
+
+		d.base -= (hole_sizek>>9);
+		d.mask -= (hole_sizek>>9);
+		set_dram_base_mask(ii, d, sysconf.nodes);
+
+		if(get_DctSelHiEn(ii) & 1) {
+			sel_m = get_DctSelBaseAddr(ii);
+			sel_m -= hole_startk>>10;
+			set_DctSelBaseAddr(ii, sel_m);
+		}
+	}
+
+	d = get_dram_base_mask(i);
+	dev = __f1_dev[i];
+	hoist = pci_read_config32(dev, 0xf0);
+	sel_hi_en = get_DctSelHiEn(i);
+
+	if(sel_hi_en & 1) {
+		sel_m = get_DctSelBaseAddr(i);
+	}
+
+	if(hoist & 1) {
+		pci_write_config32(dev, 0xf0, 0);
+		d.mask -= (hole_sizek>>9);
+		set_dram_base_mask(i, d, sysconf.nodes);
+		if(one_DCT || (sel_m >= (hole_startk>>10))) {
+			if(sel_hi_en & 1) {
+				sel_m -= hole_startk>>10;
+				set_DctSelBaseAddr(i, sel_m);
+			}
+		}
+		if(sel_hi_en & 1) {
+			set_DctSelBaseOffset(i, 0);
+		}
+	}
+	else {
+		d.base -= (hole_sizek>>9);
+		d.mask -= (hole_sizek>>9);
+		set_dram_base_mask(i, d, sysconf.nodes);
+
+		if(sel_hi_en & 1) {
+			sel_m -= hole_startk>>10;
+			set_DctSelBaseAddr(i, sel_m);
+		}
+	}
+
+}
+#endif
+
+#endif
+
+static void pci_domain_set_resources(device_t dev)
+{
+#if CONFIG_PCI_64BIT_PREF_MEM == 1
+	struct resource *io, *mem1, *mem2;
+	struct resource *resource, *last;
+#endif
+	unsigned long mmio_basek;
+	u32 pci_tolm;
+	int i, idx;
+	u32 link;
+#if HW_MEM_HOLE_SIZEK != 0
+	struct hw_mem_hole_info mem_hole;
+	u32 reset_memhole = 1;
+#endif
+
+#if CONFIG_PCI_64BIT_PREF_MEM == 1
+
+	for(link=0; link<dev->links; link++) {
+		/* Now reallocate the pci resources memory with the
+		 * highest addresses I can manage.
+		 */
+		mem1 = find_resource(dev, 1|(link<<2));
+		mem2 = find_resource(dev, 2|(link<<2));
+
+		printk_debug("base1: 0x%08Lx limit1: 0x%08Lx size: 0x%08Lx align: %d\n",
+			mem1->base, mem1->limit, mem1->size, mem1->align);
+		printk_debug("base2: 0x%08Lx limit2: 0x%08Lx size: 0x%08Lx align: %d\n",
+			mem2->base, mem2->limit, mem2->size, mem2->align);
+
+		/* See if both resources have roughly the same limits */
+		if (((mem1->limit <= 0xffffffff) && (mem2->limit <= 0xffffffff)) ||
+			((mem1->limit > 0xffffffff) && (mem2->limit > 0xffffffff)))
+		{
+			/* If so place the one with the most stringent alignment first
+			 */
+			if (mem2->align > mem1->align) {
+				struct resource *tmp;
+				tmp = mem1;
+				mem1 = mem2;
+				mem2 = tmp;
+			}
+			/* Now place the memory as high up as it will go */
+			mem2->base = resource_max(mem2);
+			mem1->limit = mem2->base - 1;
+			mem1->base = resource_max(mem1);
+		}
+		else {
+			/* Place the resources as high up as they will go */
+			mem2->base = resource_max(mem2);
+			mem1->base = resource_max(mem1);
+		}
+
+		printk_debug("base1: 0x%08Lx limit1: 0x%08Lx size: 0x%08Lx align: %d\n",
+			mem1->base, mem1->limit, mem1->size, mem1->align);
+		printk_debug("base2: 0x%08Lx limit2: 0x%08Lx size: 0x%08Lx align: %d\n",
+			mem2->base, mem2->limit, mem2->size, mem2->align);
+	}
+
+	last = &dev->resource[dev->resources];
+	for(resource = &dev->resource[0]; resource < last; resource++)
+	{
+		resource->flags |= IORESOURCE_ASSIGNED;
+		resource->flags &= ~IORESOURCE_STORED;
+		link = (resource>>2) & 3;
+		compute_allocate_resource(&dev->link[link], resource,
+			BRIDGE_IO_MASK, resource->flags & BRIDGE_IO_MASK);
+
+		resource->flags |= IORESOURCE_STORED;
+		report_resource_stored(dev, resource, "");
+
+	}
+#endif
+
+	pci_tolm = 0xffffffffUL;
+	for(link=0;link<dev->links; link++) {
+		pci_tolm = find_pci_tolm(&dev->link[link], pci_tolm);
+	}
+
+#warning "FIXME handle interleaved nodes"
+	mmio_basek = pci_tolm >> 10;
+	/* Round mmio_basek to something the processor can support */
+	mmio_basek &= ~((1 << 6) -1);
+
+#warning "FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M MMIO hole"
+	/* Round the mmio hold to 64M */
+	mmio_basek &= ~((64*1024) - 1);
+
+#if HW_MEM_HOLE_SIZEK != 0
+/* if the hw mem hole is already set in raminit stage, here we will compare
+ * mmio_basek and hole_basek. if mmio_basek is bigger that hole_basek and will
+ * use hole_basek as mmio_basek and we don't need to reset hole.
+ * otherwise We reset the hole to the mmio_basek
+ */
+
+	mem_hole = get_hw_mem_hole_info();
+
+	// Use hole_basek as mmio_basek, and we don't need to reset hole anymore
+	if ((mem_hole.node_id !=  -1) && (mmio_basek > mem_hole.hole_startk)) {
+		mmio_basek = mem_hole.hole_startk;
+		reset_memhole = 0;
+	}
+
+	#if CONFIG_AMDMCT == 0
+	//mmio_basek = 3*1024*1024; // for debug to meet boundary
+
+	if(reset_memhole) {
+		if(mem_hole.node_id!=-1) {
+		/* We need to select HW_MEM_HOLE_SIZEK for raminit, it can not
+		    make hole_startk to some basek too!
+		   We need to reset our Mem Hole, because We want more big HOLE
+		    than we already set
+		   Before that We need to disable mem hole at first, becase
+		    memhole could already be set on i+1 instead
+		 */
+			disable_hoist_memory(mem_hole.hole_startk, mem_hole.node_id);
+		}
+
+	#if HW_MEM_HOLE_SIZE_AUTO_INC == 1
+		// We need to double check if the mmio_basek is valid for hole
+		// setting, if it is equal to basek, we need to decrease it some
+		resource_t basek_pri;
+		for (i = 0; i < sysconf.nodes; i++) {
+			struct dram_base_mask_t d;
+			resource_t basek;
+			d = get_dram_base_mask(i);
+
+			if(!(d.mask &1)) continue;
+
+			basek = ((resource_t)(d.base & 0x1fffff00)) << 9;
+			if(mmio_basek == (u32)basek) {
+				mmio_basek -= (uin32_t)(basek - basek_pri); // increase mem hole size to make sure it is on middle of pri node
+				break;
+			}
+			basek_pri = basek;
+		}
+	#endif
+	}
+	#endif
+
+
+#endif
+
+	idx = 0x10;
+	for(i = 0; i < sysconf.nodes; i++) {
+		struct dram_base_mask_t d;
+		resource_t basek, limitk, sizek; // 4 1T
+		d = get_dram_base_mask(i);
+
+		if(!(d.mask & 1)) continue;
+		basek = ((resource_t)(d.base & 0x1fffff00)) << 9; // could overflow, we may lost 6 bit here
+		limitk = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9 ;
+		sizek = limitk - basek;
+
+		/* see if we need a hole from 0xa0000 to 0xbffff */
+		if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) {
+			ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek);
+			idx += 0x10;
+			basek = (8*64)+(16*16);
+			sizek = limitk - ((8*64)+(16*16));
+
+		}
+
+//		printk_debug("node %d : mmio_basek=%08x, basek=%08x, limitk=%08x\n", i, mmio_basek, basek, limitk);
+
+		/* split the region to accomodate pci memory space */
+		if ( (basek < 4*1024*1024 ) && (limitk > mmio_basek) ) {
+			if (basek <= mmio_basek) {
+				unsigned pre_sizek;
+				pre_sizek = mmio_basek - basek;
+				if(pre_sizek>0) {
+					ram_resource(dev, (idx | i), basek, pre_sizek);
+					idx += 0x10;
+					sizek -= pre_sizek;
+				}
+				#if CONFIG_AMDMCT == 0
+				#if HW_MEM_HOLE_SIZEK != 0
+				if(reset_memhole) {
+					struct sys_info *sysinfox = (struct sys_info *)((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_GLOBAL_VAR_SIZE); // in RAM
+					struct mem_info *meminfo;
+					meminfo = &sysinfox->meminfo[i];
+					sizek += hoist_memory(mmio_basek,i, get_one_DCT(meminfo), sysconf.nodes);
+				}
+				#endif
+				#endif
+
+				basek = mmio_basek;
+			}
+			if ((basek + sizek) <= 4*1024*1024) {
+				sizek = 0;
+			}
+			else {
+				basek = 4*1024*1024;
+				sizek -= (4*1024*1024 - mmio_basek);
+			}
+		}
+		ram_resource(dev, (idx | i), basek, sizek);
+		idx += 0x10;
+	}
+
+	for(link = 0; link < dev->links; link++) {
+		struct bus *bus;
+		bus = &dev->link[link];
+		if (bus->children) {
+			assign_resources(bus);
+		}
+	}
+}
+
+static u32 pci_domain_scan_bus(device_t dev, u32 max)
+{
+	u32 reg;
+	int i;
+	/* Unmap all of the HT chains */
+	for(reg = 0xe0; reg <= 0xec; reg += 4) {
+		f1_write_config32(reg, 0);
+	}
+#if EXT_CONF_SUPPORT == 1
+	// all nodes
+	for(i = 0; i< sysconf.nodes; i++) {
+		int index;
+		for(index = 0; index < 64; index++) {
+			pci_write_config32(__f1_dev[i], 0x110, index | (6<<28));
+			pci_write_config32(__f1_dev[i], 0x114, 0);
+		}
+
+	}
+#endif
+
+
+	for(i=0;i<dev->links;i++) {
+		max = pci_scan_bus(&dev->link[i], PCI_DEVFN(CDB, 0), 0xff, max);
+	}
+
+	/* Tune the hypertransport transaction for best performance.
+	 * Including enabling relaxed ordering if it is safe.
+	 */
+	get_fx_devs();
+	for(i = 0; i < FX_DEVS; i++) {
+		device_t f0_dev;
+		f0_dev = __f0_dev[i];
+		if (f0_dev && f0_dev->enabled) {
+			u32 httc;
+			httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
+			httc &= ~HTTC_RSP_PASS_PW;
+			if (!dev->link[0].disable_relaxed_ordering) {
+				httc |= HTTC_RSP_PASS_PW;
+			}
+			printk_spew("%s passpw: %s\n",
+				dev_path(dev),
+				(!dev->link[0].disable_relaxed_ordering)?
+				"enabled":"disabled");
+			pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
+		}
+	}
+	return max;
+}
+
+static struct device_operations pci_domain_ops = {
+	.read_resources	  = pci_domain_read_resources,
+	.set_resources	  = pci_domain_set_resources,
+	.enable_resources = enable_childrens_resources,
+	.init		  = 0,
+	.scan_bus	  = pci_domain_scan_bus,
+#if MMCONF_SUPPORT
+	.ops_pci_bus	  = &pci_ops_mmconf,
+#else
+	.ops_pci_bus	  = &pci_cf8_conf1,
+#endif
+};
+
+static void sysconf_init(device_t dev) // first node
+{
+	sysconf.sblk = (pci_read_config32(dev, 0x64)>>8) & 7; // don't forget sublink1
+	sysconf.segbit = 0;
+	sysconf.ht_c_num = 0;
+
+	unsigned ht_c_index;
+
+	for(ht_c_index=0; ht_c_index<32; ht_c_index++) {
+		sysconf.ht_c_conf_bus[ht_c_index] = 0;
+	}
+
+	sysconf.nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) + 1;
+#if CONFIG_MAX_PHYSICAL_CPUS > 8
+	sysconf.nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
+#endif
+
+	sysconf.enabled_apic_ext_id = 0;
+	sysconf.lift_bsp_apicid = 0;
+
+	/* Find the bootstrap processors apicid */
+	sysconf.bsp_apicid = lapicid();
+	sysconf.apicid_offset = sysconf.bsp_apicid;
+
+#if (ENABLE_APIC_EXT_ID == 1)
+	if (pci_read_config32(dev, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
+	{
+		sysconf.enabled_apic_ext_id = 1;
+	}
+	#if (APIC_ID_OFFSET>0)
+	if(sysconf.enabled_apic_ext_id) {
+		if(sysconf.bsp_apicid == 0) {
+			/* bsp apic id is not changed */
+			sysconf.apicid_offset = APIC_ID_OFFSET;
+		} else {
+			sysconf.lift_bsp_apicid = 1;
+		}
+
+	}
+	#endif
+#endif
+
+}
+
+static u32 cpu_bus_scan(device_t dev, u32 max)
+{
+	struct bus *cpu_bus;
+	device_t dev_mc;
+	device_t pci_domain;
+	int i,j;
+	int nodes;
+	unsigned nb_cfg_54;
+	unsigned siblings;
+	int cores_found;
+	int disable_siblings;
+	unsigned ApicIdCoreIdSize;
+
+	nb_cfg_54 = 0;
+	ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
+	if(ApicIdCoreIdSize) {
+		siblings = (1<<ApicIdCoreIdSize)-1;
+	} else {
+		siblings = 3; //quad core
+	}
+
+	disable_siblings = !CONFIG_LOGICAL_CPUS;
+#if CONFIG_LOGICAL_CPUS == 1
+	get_option(&disable_siblings, "quad_core");
+#endif
+
+	// for pre_e0, nb_cfg_54 can not be set, ( even set, when you read it
+	//    still be 0)
+	// How can I get the nb_cfg_54 of every node' nb_cfg_54 in bsp???
+	//    and differ d0 and e0 single core
+
+	nb_cfg_54 = read_nb_cfg_54();
+
+#if CBB
+	dev_mc = dev_find_slot(0, PCI_DEVFN(CDB, 0)); //0x00
+	if(dev_mc && dev_mc->bus) {
+		printk_debug("%s found", dev_path(dev_mc));
+		pci_domain = dev_mc->bus->dev;
+		if(pci_domain && (pci_domain->path.type == DEVICE_PATH_PCI_DOMAIN)) {
+			printk_debug("\n%s move to ",dev_path(dev_mc));
+			dev_mc->bus->secondary = CBB; // move to 0xff
+			printk_debug("%s",dev_path(dev_mc));
+
+		} else {
+			printk_debug(" but it is not under pci_domain directly ");
+		}
+		printk_debug("\n");
+
+	}
+	dev_mc = dev_find_slot(CBB, PCI_DEVFN(CDB, 0));
+	if(!dev_mc) {
+		dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0));
+		if (dev_mc && dev_mc->bus) {
+			printk_debug("%s found\n", dev_path(dev_mc));
+			pci_domain = dev_mc->bus->dev;
+			if(pci_domain && (pci_domain->path.type == DEVICE_PATH_PCI_DOMAIN)) {
+				if((pci_domain->links==1) && (pci_domain->link[0].children == dev_mc)) {
+					printk_debug("%s move to ",dev_path(dev_mc));
+					dev_mc->bus->secondary = CBB; // move to 0xff
+					printk_debug("%s\n",dev_path(dev_mc));
+					while(dev_mc){
+						printk_debug("%s move to ",dev_path(dev_mc));
+						dev_mc->path.u.pci.devfn -= PCI_DEVFN(0x18,0);
+						printk_debug("%s\n",dev_path(dev_mc));
+						dev_mc = dev_mc->sibling;
+					}
+				}
+			}
+		}
+	}
+
+#endif
+
+	dev_mc = dev_find_slot(CBB, PCI_DEVFN(CDB, 0));
+	if (!dev_mc) {
+		printk_err("%02x:%02x.0 not found", CBB, CDB);
+		die("");
+	}
+
+	sysconf_init(dev_mc);
+
+	nodes = sysconf.nodes;
+
+#if CBB && (NODE_NUMS > 32)
+	if(nodes>32) { // need to put node 32 to node 63 to bus 0xfe
+		if(pci_domain->links==1) {
+			pci_domain->links++; // from 1 to 2
+			pci_domain->link[1].link = 1;
+			pci_domain->link[1].dev = pci_domain;
+			pci_domain->link[1].children = 0;
+			printk_debug("%s links increase to %d\n", dev_path(pci_domain), pci_domain->links);
+		}
+		pci_domain->link[1].secondary = CBB - 1;
+	}
+#endif
+	/* Find which cpus are present */
+	cpu_bus = &dev->link[0];
+	for(i = 0; i < nodes; i++) {
+		device_t dev, cpu;
+		struct device_path cpu_path;
+		unsigned busn, devn;
+		struct bus *pbus;
+
+		busn = CBB;
+		devn = CDB+i;
+		pbus = dev_mc->bus;
+#if CBB && (NODE_NUMS > 32)
+		if(i>=32) {
+			busn--;
+			devn-=32;
+			pbus = &(pci_domain->link[1]);
+		}
+#endif
+
+		/* Find the cpu's pci device */
+		dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
+		if (!dev) {
+			/* If I am probing things in a weird order
+			 * ensure all of the cpu's pci devices are found.
+			 */
+			int j;
+			for(j = 0; j <= 5; j++) { //FBDIMM?
+				dev = pci_probe_dev(NULL, pbus,
+					PCI_DEVFN(devn, j));
+			}
+			dev = dev_find_slot(busn, PCI_DEVFN(devn,0));
+		}
+		if(dev) {
+			/* Ok, We need to set the links for that device.
+			 * otherwise the device under it will not be scanned
+			 */
+			int j;
+			int linknum;
+#if HT3_SUPPORT==1
+			linknum = 8;
+#else
+			linknum = 4;
+#endif
+			if(dev->links < linknum) {
+				for(j=dev->links; j<linknum; j++) {
+					 dev->link[j].link = j;
+					 dev->link[j].dev = dev;
+				}
+				dev->links = linknum;
+				printk_debug("%s links increase to %d\n", dev_path(dev), dev->links);
+			}
+		}
+
+		cores_found = 0; // one core
+		dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
+		if (dev && dev->enabled) {
+			j = pci_read_config32(dev, 0xe8);
+			cores_found = (j >> 12) & 3; // dev is func 3
+			printk_debug("  %s siblings=%d\n", dev_path(dev), cores_found);
+		}
+
+		u32 jj;
+		if(disable_siblings) {
+			jj = 0;
+		} else
+		{
+			jj = cores_found;
+		}
+
+		for (j = 0; j <=jj; j++ ) {
+
+			/* Build the cpu device path */
+			cpu_path.type = DEVICE_PATH_APIC;
+			cpu_path.u.apic.apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
+
+			/* See if I can find the cpu */
+			cpu = find_dev_path(cpu_bus, &cpu_path);
+
+			/* Enable the cpu if I have the processor */
+			if (dev && dev->enabled) {
+				if (!cpu) {
+					cpu = alloc_dev(cpu_bus, &cpu_path);
+				}
+				if (cpu) {
+					cpu->enabled = 1;
+				}
+			}
+
+			/* Disable the cpu if I don't have the processor */
+			if (cpu && (!dev || !dev->enabled)) {
+				cpu->enabled = 0;
+			}
+
+			/* Report what I have done */
+			if (cpu) {
+				cpu->path.u.apic.node_id = i;
+				cpu->path.u.apic.core_id = j;
+	#if (ENABLE_APIC_EXT_ID == 1) && (APIC_ID_OFFSET>0)
+				 if(sysconf.enabled_apic_ext_id) {
+					if(sysconf.lift_bsp_apicid) {
+						cpu->path.u.apic.apic_id += sysconf.apicid_offset;
+					} else
+					{
+						if (cpu->path.u.apic.apic_id != 0)
+							cpu->path.u.apic.apic_id += sysconf.apicid_offset;
+					 }
+				}
+	#endif
+				printk_debug("CPU: %s %s\n",
+					dev_path(cpu), cpu->enabled?"enabled":"disabled");
+			}
+
+		} //j
+	}
+	return max;
+}
+
+
+static void cpu_bus_init(device_t dev)
+{
+	initialize_cpus(&dev->link[0]);
+}
+
+
+static void cpu_bus_noop(device_t dev)
+{
+}
+
+
+static struct device_operations cpu_bus_ops = {
+	.read_resources	  = cpu_bus_noop,
+	.set_resources	  = cpu_bus_noop,
+	.enable_resources = cpu_bus_noop,
+	.init		  = cpu_bus_init,
+	.scan_bus	  = cpu_bus_scan,
+};
+
+
+static void root_complex_enable_dev(struct device *dev)
+{
+	/* Set the operations if it is a special bus type */
+	if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
+		dev->ops = &pci_domain_ops;
+	}
+	else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
+		dev->ops = &cpu_bus_ops;
+	}
+}
+
+struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
+	CHIP_NAME("AMD FAM10 Root Complex")
+	.enable_dev = root_complex_enable_dev,
+};
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/northbridge.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/northbridge.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef NORTHBRIDGE_AMD_AMDFAM10_H
+#define NORTHBRIDGE_AMD_AMDFAM10_H
+
+extern u32 amdfam10_scan_root_bus(device_t root, u32 max);
+
+#endif /* NORTHBRIDGE_AMD_AMDFAM10_H */
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef RAMINIT_H
+#define RAMINIT_H
+
+#if 0
+#if DIMM_SUPPORT==0x0110
+//FBDIMM REG
+/* each channel can have 8 fbdimm */
+#define DIMM_SOCKETS 8
+struct mem_controller {
+	u32 node_id;
+	device_t f0, f1, f2, f3, f4, f5;
+	/* channelA, channelB belong to DCT0,
+	 * channelC, channelD belong to DCT1
+	 * Each DCT may support one ganged logical FBDIMM ---> 128 bit
+	 *			 or a single unganged channel --->64 bit
+	 * a DCT can not support 2 unganged channels
+	 * two DCTs can not be ganged
+	 */
+	u8 spd_switch_addr;
+	u8 spd_addr[DIMM_SOCKETS*4];
+};
+
+#endif
+#endif
+
+//#if (DIMM_SUPPORT & 0x00ff)==0x0004
+//DDR2 REG and unbuffered : Socket F 1027 and AM3
+/* every channel have 4 DDR2 DIMM for socket F
+ *		       2 for socket M2/M3
+ *		       1 for socket s1g1
+ */
+#define DIMM_SOCKETS 4
+struct mem_controller {
+	u32 node_id;
+	device_t f0, f1, f2, f3, f4, f5;
+	/* channel0 is DCT0 --- channelA
+	 * channel1 is DCT1 --- channelB
+	 * can be ganged, a single dual-channel DCT ---> 128 bit
+	 *	 or unganged a two single-channel DCTs ---> 64bit
+	 * When the DCTs are ganged, the writes to DCT1 set of registers
+	 * (F2x1XX) are ignored and reads return all 0's
+	 * The exception is the DCT phy registers, F2x[1,0]98, F2x[1,0]9C,
+	 * and all the associated indexed registers, are still
+	 * independently accessiable
+	 */
+	/* FIXME: I will only support ganged mode for easy support */
+	u8 spd_switch_addr;
+	u8 spd_addr[DIMM_SOCKETS*2];
+};
+
+//#endif
+
+
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_amdmct.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_amdmct.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 print_raminit(const char *strval, u32 val)
+{
+	printk_debug("%s%08x\n", strval, val);
+}
+
+
+#define RAMINIT_DEBUG 1
+
+
+static  void print_tx(const char *strval, u32 val)
+{
+#if RAMINIT_DEBUG == 1
+	print_raminit(strval, val);
+#endif
+}
+
+
+static  void print_t(const char *strval)
+{
+#if RAMINIT_DEBUG == 1
+	print_debug(strval);
+#endif
+}
+#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"
+
+#include "../amdmct/wrappers/mcti_d.c"
+#include "../amdmct/mct/mct_d.c"
+
+
+#include "../amdmct/mct/mctmtr_d.c"
+#include "../amdmct/mct/mctcsi_d.c"
+#include "../amdmct/mct/mctecc_d.c"
+#include "../amdmct/mct/mctpro_d.c"
+#include "../amdmct/mct/mctdqs_d.c"
+#include "../amdmct/mct/mctsrc.c"
+#include "../amdmct/mct/mctsrc1p.c"
+#include "../amdmct/mct/mcttmrl.c"
+#include "../amdmct/mct/mcthdi.c"
+#include "../amdmct/mct/mctndi_d.c"
+#include "../amdmct/mct/mctchi_d.c"
+
+#if SYSTEM_TYPE == SERVER
+//L1
+#include "../amdmct/mct/mctardk3.c"
+#elif SYSTEM_TYPE == DESKTOP
+//AM2
+#include "../amdmct/mct/mctardk4.c"
+//#elif SYSTEM_TYPE == MOBILE
+//s1g1
+//#include "../amdmct/mct/mctardk5.c"
+#endif
+
+#include "../amdmct/mct/mct_fd.c"
+
+int mctRead_SPD(u32 smaddr, u32 reg)
+{
+	return spd_read_byte(smaddr, reg);
+}
+
+
+void mctSMBhub_Init(u32 node)
+{
+	struct sys_info *sysinfo = (struct sys_info *)(DCACHE_RAM_BASE + DCACHE_RAM_SIZE - DCACHE_RAM_GLOBAL_VAR_SIZE);
+	struct mem_controller *ctrl = &( sysinfo->ctrl[node] );
+	activate_spd_rom(ctrl);
+}
+
+
+void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 node)
+{
+	int j;
+	struct sys_info *sysinfo = (struct sys_info *)(DCACHE_RAM_BASE + DCACHE_RAM_SIZE - DCACHE_RAM_GLOBAL_VAR_SIZE);
+	struct mem_controller *ctrl = &( sysinfo->ctrl[node] );
+
+	for(j=0;j<DIMM_SOCKETS;j++) {
+		pDCTstat->DIMMAddr[j*2] = ctrl->spd_addr[j] & 0xff;
+		pDCTstat->DIMMAddr[j*2+1] = ctrl->spd_addr[DIMM_SOCKETS + j] & 0xff;
+	}
+
+}
+
+
+u32 mctGetLogicalCPUID(u32 Node)
+{
+	u32 dev;
+	u32 val, valx;
+	u32 family, model, stepping;
+	u32 ret;
+	dev = PA_NBMISC(Node);
+	val = Get_NB32(dev, 0xfc);
+	print_debug("Family_Model:"); print_debug_hex32(val); print_debug("\n");
+
+	family = ((val >> 8) & 0x0f) + ((val>>20) & 0xff);
+	model = ((val>>4) & 0x0f) | ((val>>(16-4)) & 0xf0);
+	stepping = val & 0xff;
+	print_debug("Family:"); print_debug_hex8(family); print_debug("\t");
+	print_debug("Model:"); print_debug_hex8(model); print_debug("\t");
+	print_debug("Stepping:"); print_debug_hex8(stepping); print_debug("\n");
+
+	valx = (family<<12) | (model<<4) | (stepping);
+	print_debug("converted:"); print_debug_hex32(valx); print_debug("\n");
+
+	switch (valx) {
+	case 0x10000:
+		ret = AMD_DR_A0A;
+		break;
+	case 0x10001:
+		ret = AMD_DR_A1B;
+		break;
+	case 0x10002:
+		ret = AMD_DR_A2;
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
+
+void raminit_amdmct(struct sys_info *sysinfo)
+{
+	struct MCTStatStruc *pMCTstat = &(sysinfo->MCTstat);
+	struct DCTStatStruc *pDCTstatA = sysinfo->DCTstatA;
+
+	print_debug("raminit_amdmct begin:\n");
+
+	mctAutoInitMCT_D(pMCTstat, pDCTstatA);
+
+	print_debug("raminit_amdmct end:\n");
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_ddr2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_ddr2.c	2007-12-12 14:14:12.000000000 -0700
@@ -0,0 +1,3115 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <cpu/x86/mem.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/tsc.h>
+
+#include "raminit.h"
+#include "amdfam10.h"
+#include "spd_ddr2.h"
+
+#ifndef QRANK_DIMM_SUPPORT
+#define QRANK_DIMM_SUPPORT 0
+#endif
+
+static  void print_raminit(const char *strval, u32 val)
+{
+	printk_debug("%s%08x\n", strval, val);
+}
+
+#define RAM_TIMING_DEBUG 1
+
+static  void print_tx(const char *strval, u32 val)
+{
+#if RAM_TIMING_DEBUG == 1
+	print_raminit(strval, val);
+#endif
+}
+
+
+static  void print_t(const char *strval)
+{
+#if RAM_TIMING_DEBUG == 1
+	print_debug(strval);
+#endif
+}
+
+
+
+#if (CONFIG_LB_MEM_TOPK & (CONFIG_LB_MEM_TOPK -1)) != 0
+# error "CONFIG_LB_MEM_TOPK must be a power of 2"
+#endif
+
+#include "amdfam10_pci.c"
+
+	// for PCI_ADDR(CBB, CDB, 2, 0x98) index,
+	//   and PCI_ADDR(CBB, CDB, 2, 0x9c) data
+	/*
+	 * index:
+	 * [29: 0] DctOffset (Dram Controller Offset)
+	 * [30:30] DctAccessWrite (Dram Controller Read/Write Select)
+	 * 	0 = read access
+	 * 	1 = write access
+	 * [31:31] DctAccessDone (Dram Controller Access Done)
+	 * 	0 = Access in progress
+	 * 	1 = No access is progress
+	 *
+	 * Data:
+	 * [31: 0] DctOffsetData (Dram Controller Offset Data)
+	 *
+	 * Read:
+	 * 	- Write the register num to DctOffset with DctAccessWrite = 0
+	 * 	- poll the DctAccessDone until it = 1
+	 * 	- Read the data from DctOffsetData
+	 * Write:
+	 * 	- Write the data to DctOffsetData
+	 * 	- Write register num to DctOffset with DctAccessWrite = 1
+	 * 	- poll the DctAccessDone untio it = 1
+	*/
+
+
+
+static u8 controller_present(const struct mem_controller *ctrl)
+{
+	return pci_read_config32(ctrl->f0, 0) == 0x12001022;
+}
+
+static void sdram_set_registers(const struct mem_controller *ctrl,
+				struct sys_info *sysinfo)
+{
+	static const u32 register_values[] = {
+
+	/* Careful set limit registers before base registers which contain
+	 *  the enables */
+	/* DRAM Limit i Registers
+	 * F1:0x44 i = 0
+	 * F1:0x4C i = 1
+	 * F1:0x54 i = 2
+	 * F1:0x5C i = 3
+	 * F1:0x64 i = 4
+	 * F1:0x6C i = 5
+	 * F1:0x74 i = 6
+	 * F1:0x7C i = 7
+	 * [ 5: 0] Destination Node ID
+	 *	   000 = Node 0
+	 *	   001 = Node 1
+	 *	   010 = Node 2
+	 *	   011 = Node 3
+	 *	   100 = Node 4
+	 *	   101 = Node 5
+	 *	   110 = Node 6
+	 *	   111 = Node 7
+	 *	   ......
+	 *	011111 = Node 31
+	 * [ 7: 6] Reserved
+	 * [10: 8] Interleave select
+	 *	specifies the values of A[14:12] to use with interleave enable.
+	 * [15:11] Reserved
+	 * [31:16] DRAM Limit Address i Bits 39-24 : Reset X
+	 *	This field defines the upper address bits of a 40 bit address
+	 *	that define the end of the DRAM region.
+	 */
+//	   PCI_ADDR(CBB, CDB, 1, 0x44), 0x0000f8c0, 0x00000000, // Don't touch it, we need it for CAR_FAM10
+	PCI_ADDR(CBB, CDB, 1, 0x4C), 0x0000f8c0, 0x00000001,
+	PCI_ADDR(CBB, CDB, 1, 0x54), 0x0000f8c0, 0x00000002,
+	PCI_ADDR(CBB, CDB, 1, 0x5C), 0x0000f8c0, 0x00000003,
+	PCI_ADDR(CBB, CDB, 1, 0x64), 0x0000f8c0, 0x00000004,
+	PCI_ADDR(CBB, CDB, 1, 0x6C), 0x0000f8c0, 0x00000005,
+	PCI_ADDR(CBB, CDB, 1, 0x74), 0x0000f8c0, 0x00000006,
+	PCI_ADDR(CBB, CDB, 1, 0x7C), 0x0000f8c0, 0x00000007,
+
+	/* DRAM Limit Address High Reg
+	 * F1:0x144, 0x14C, 0x154, 0x15C, 0x164, 0x16C, 0x174, 0x17C
+	 * [ 7: 0] DramLimit[47:40] : Reset 0
+	 */
+
+	/* DRAM Base i Registers
+	 * F1:0x40 i = 0
+	 * F1:0x48 i = 1
+	 * F1:0x50 i = 2
+	 * F1:0x58 i = 3
+	 * F1:0x60 i = 4
+	 * F1:0x68 i = 5
+	 * F1:0x70 i = 6
+	 * F1:0x78 i = 7
+	 * [ 0: 0] Read Enable
+	 *	   0 = Reads Disabled
+	 *	   1 = Reads Enabled
+	 * [ 1: 1] Write Enable
+	 *	   0 = Writes Disabled
+	 *	   1 = Writes Enabled
+	 * [ 7: 2] Reserved
+	 * [13: 8] Interleave Enable
+	 *	   000 = No interleave
+	 *	   001 = Interleave on A[12] (2 nodes)
+	 *	   011 = Interleave on A[12] and A[13] (4 nodes)
+	 *	   ...
+	 *	011111 = Interleve on A[12] through A[16] (32 nodes)
+
+	 * [15:14] Reserved
+	 * [31:16] DRAM Base Address i Bits 39-24 : Reset X
+	 *	This field defines the upper address bits of a 40-bit address
+	 *	that define the start of the DRAM region.
+	 */
+//	PCI_ADDR(CBB, CDB, 1, 0x40), 0x0000c0fc, 0x00000000, // Don't touch it, we need it for CAR_FAM10
+	PCI_ADDR(CBB, CDB, 1, 0x48), 0x0000c0fc, 0x00000000,
+	PCI_ADDR(CBB, CDB, 1, 0x50), 0x0000c0fc, 0x00000000,
+	PCI_ADDR(CBB, CDB, 1, 0x58), 0x0000c0fc, 0x00000000,
+	PCI_ADDR(CBB, CDB, 1, 0x60), 0x0000c0fc, 0x00000000,
+	PCI_ADDR(CBB, CDB, 1, 0x68), 0x0000c0fc, 0x00000000,
+	PCI_ADDR(CBB, CDB, 1, 0x70), 0x0000c0fc, 0x00000000,
+	PCI_ADDR(CBB, CDB, 1, 0x78), 0x0000c0fc, 0x00000000,
+
+	 /* DRAM Base Address High Reg
+	  * F1:0x140, 0x148, 0x150, 0x158, 0x160, 0x168, 0x170, 0x178
+	  * [ 7: 0] DramBase[47:40] : Reset 0
+	  */
+
+	/* DRAM Limit System Addr Reg
+	 * [31:27] Reserved
+	 * [26:21] DramIntlvEn[5:0] interleave on nodes
+	 * [20: 0] DramLimitAddr[47:27]
+	 */
+	PCI_ADDR(CBB, CDB, 1, 0x124), 0x00000000, 0x00000000,
+
+	/* DRAM Base System Addr Reg
+	 * [31:24] Reserved
+	 * [23:21] DramIntlvSel: interleave select
+	 * [20: 0] DramLimitAddr[47:27]
+	 */
+	PCI_ADDR(CBB, CDB, 1, 0x120), 0x00000000, 0x00000000,
+
+
+	/* DRAM CS Base Address i Registers
+	 * F2:0x40 i = 0
+	 * F2:0x44 i = 1
+	 * F2:0x48 i = 2
+	 * F2:0x4C i = 3
+	 * F2:0x50 i = 4
+	 * F2:0x54 i = 5
+	 * F2:0x58 i = 6
+	 * F2:0x5C i = 7
+	 * [ 0: 0] Chip-Select Bank Enable
+	 *	   0 = Bank Disabled
+	 *	   1 = Bank Enabled
+	 * [ 1: 1] Spare Rank
+	 * [ 3: 3] OnDimmMirr: on-DIMM mirroring(ODM) enabled
+	 * [ 4: 4] Reserved
+	 * [13: 5] Base Address (21-13)
+	 *	   An optimization used when all DIMM are the same size...
+	 * [18:14] Reserved
+	 * [28:19] Base Address (36-27)
+	 *	   This field defines the top 11 addresses bit of a 40-bit
+	 *	   address that define the memory address space.  These
+	 *	   bits decode 32-MByte blocks of memory.
+	 * [31:29] Reserved
+	 */
+	PCI_ADDR(CBB, CDB, 2, 0x40), 0xe007c018, 0x00000000, //DCT0
+	PCI_ADDR(CBB, CDB, 2, 0x44), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x48), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x4C), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x50), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x54), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x58), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x5C), 0xe007c018, 0x00000000,
+
+	PCI_ADDR(CBB, CDB, 2, 0x140), 0xe007c018, 0x00000000, //DCT1
+	PCI_ADDR(CBB, CDB, 2, 0x144), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x148), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x14C), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x150), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x154), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x158), 0xe007c018, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x15C), 0xe007c018, 0x00000000,
+
+	/* DRAM CS Mask Address i Registers
+	 * F2:0x60 i = 0,1
+	 * F2:0x64 i = 2,3
+	 * F2:0x68 i = 4,5
+	 * F2:0x6C i = 6,7
+	 * Select bits to exclude from comparison with the DRAM Base
+	 *  address register.
+	 * [ 4: 0] Reserved
+	 * [13: 5] Address Mask (21-13)
+	 *	   Address to be excluded from the optimized case
+	 * [18:14] Reserved
+	 * [28:19] Address Mask (36-27)
+	 *	   The bits with an address mask of 1 are excluded from
+	 *  address comparison
+	 * [31:29] Reserved
+	 *
+	 */
+	PCI_ADDR(CBB, CDB, 2, 0x60), 0xe007c01f, 0x00000000, //DCT0
+	PCI_ADDR(CBB, CDB, 2, 0x64), 0xe007c01f, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x68), 0xe007c01f, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x6C), 0xe007c01f, 0x00000000,
+
+	PCI_ADDR(CBB, CDB, 2, 0x160), 0xe007c01f, 0x00000000, //DCT1
+	PCI_ADDR(CBB, CDB, 2, 0x164), 0xe007c01f, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x168), 0xe007c01f, 0x00000000,
+	PCI_ADDR(CBB, CDB, 2, 0x16C), 0xe007c01f, 0x00000000,
+
+	/* DRAM Control Register
+	 * F2:0x78
+	 * [ 3: 0] RdPtrInit ( Read Pointer Initial Value)
+	 *	0x03-0x00: reserved
+	 * [ 7: 4] Reseved
+	 * [ 9: 8] Twrrd[3:2] write ro read DIMM termination turnaround.
+	 *    together with F2x[1,0]8C, only valid when F2x[1,0]94[Ddr3Mode] = 1
+	 * [11:10] Twrwr[3:2] write to write timing
+	 *    together with F2x[1,0]8C, only valid when F2x[1,0]94[Ddr3Mode] = 1
+	 * [13:12] Trdrd[3:2] read to read timing
+	 *    together with F2x[1,0]8C, only valid when F2x[1,0]94[Ddr3Mode] = 1
+	 * [15:14] Reserved
+	 * [16:16] AltVidC3MemClkTriEn (AltVID Memory Clock Tristate Enable)
+	 *    Enables the DDR memory clocks to be tristated when alternate VID
+	 *  mode is enabled. This bit has no effect if the DisNbClkRamp bit
+	 *  (F3, 0x88) is set
+	 * [17:17] Reserved
+	 * [18:18] DqsRcvEnTrain (DQS Receiver Enable Training Mode)
+	 *	0 = Normal DQS Receiver enable operation
+	 *	1 = DQS receiver enable training mode
+	 * [21:19] reverved
+	 * [31:22] MaxRdLatency: maximum read latency
+	 */
+	PCI_ADDR(CBB, CDB, 2, 0x78),  0x003ac0f0, 0x00000000, //DCT0
+	PCI_ADDR(CBB, CDB, 2, 0x178),	0x003ac0f0, 0x00000000, //DCT1
+
+
+	/* DRAM Initialization Register
+	 * F2:0x7C
+	 * [15: 0] MrsAddress (Address for MRS/EMRS Commands)
+	 *	 this field specifies the dsata driven on the DRAM address pins
+	 *	15-0 for MRS and EMRS commands
+	 * [18:16] MrsBank (Bank Address for MRS/EMRS Commands)
+	 *	this files specifies the data driven on the DRAM bank pins for
+	 *	the MRS and EMRS commands
+	 * [19:19] reverved
+	 * [23:20] MrsChipSel : MRS/EMRS command chip select, only valid when
+	 *	EnDramInit=0, otherwise MRS/EMRS commands are snet to all
+	 *	chip selects
+	 *	000 MRS/EMRS command is sent to CS0
+	 *	001 MRS/EMRS command is sent to CS1
+	 *	...
+	 *	111 MRS/EMRS command is sent to CS7
+	 * [23:23] reverved
+	 * [24:24] SendPchgAll (Send Precharge All Command)
+	 *	Setting this bit causes the DRAM controller to send a precharge
+	 *	all command. This bit is cleared by the hardware after the
+	 *	command completes
+	 * [25:25] SendAutoRefresh (Send Auto Refresh Command)
+	 *	Setting this bit causes the DRAM controller to send an auto
+	 *	refresh command. This bit is cleared by the hardware after the
+	 *	command completes
+	 * [26:26] SendMrsCmd (Send MRS/EMRS Command)
+	 *	Setting this bit causes the DRAM controller to send the MRS or
+	 *	EMRS command defined by the MrsAddress and MrsBank fields.
+	 *	This bit is cleared by the hardware adter the commmand completes
+	 * [27:27] DeassertMemRstX (De-assert Memory Reset)
+	 *	Setting this bit causes the DRAM controller to de-assert the
+	 *	memory reset pin. This bit cannot be used to assert the memory
+	 *	reset pin
+	 * [28:28] AssertCke (Assert CKE)
+	 *	setting this bit causes the DRAM controller to assert the CKE
+	 *	pins. This bit cannot be used to de-assert the CKE pins
+	 * [29:29] SendZQCmd: send ZQ command. Read, Write-1-only. cleared by
+	 *	HW after command done. Only valid on F2x[1,0]94[Ddr3Mode]=1
+	 * [30:30] reserved
+	 * [31:31] EnDramInit (Enable DRAM Initialization)
+	 *	Setting this bit puts the DRAM controller in a BIOS controlled
+	 * 	DRAM initialization mode. BIOS must clear this bit aster DRAM
+	 *	initialization is complete.
+	 */
+//	   PCI_ADDR(CBB, CDB, 2, 0x7C), 0x60f80000, 0, //DCT0
+//	   PCI_ADDR(CBB, CDB, 2, 0x17C), 0x60f80000, 0, //DCT1
+
+
+	/* DRAM Bank Address Mapping Register
+	 * F2:0x80
+	 * Specify the memory module size
+	 * [ 3: 0] CS1/0
+	 * [ 7: 4] CS3/2
+	 * [11: 8] CS5/4
+	 * [15:12] CS7/6
+	 * [31:16]
+	DDR2
+	      row    col   bank
+	  0:  13     9	    2	 :128M
+	  1:  13     10	    2	 :256M
+	  2:  14     10	    2	 :512M
+	  3:  13     11	    2	 :512M
+	  4:  13     10	    3	 :512M
+	  5:  14     10	    3	 :1G
+	  6:  14     11	    2	 :1G
+	  7:  15     10	    3	 :2G
+	  8:  14     11	    3	 :2G
+	  9:  15     11	    3	 :4G
+	 10:  16     10	    3	 :4G
+	 11:  16     11	    3	 :8G
+	DDR3
+	       row    col   bank
+	   0:			  :reserved
+	   1:  12     10     3	  :256M
+	   2:  13     10     3	  :512M
+	   3:			  :reserved
+	   4:			  :reserved
+	   5:  14     10     3	  :1G
+	   6:  13     11     3	  :1G
+	   7:  15     10     3	  :2G
+	   8:  14     11     3	  :2G
+	   9:  15     11     3	  :4G
+	  10:  16     10     3	  :4G
+	  11:  16     11     3	  :8G
+
+	*/
+	PCI_ADDR(CBB, CDB, 2, 0x80), 0xffff0000, 0x00000000, //DCT0
+	PCI_ADDR(CBB, CDB, 2, 0x80), 0xffff0000, 0x00000000, //DCT1
+	/* DRAM Timing Low Register
+	 * F2:0x88
+	 * [ 3: 0] Tcl (Cas# Latency, Cas# to read-data-valid)
+	 DDR2
+	 *	   0000 = reserved
+	 *	   0001 = reserved
+	 *	   0010 = CL 3
+	 *	   0011 = CL 4
+	 *	   0100 = CL 5
+	 *	   0101 = CL 6
+	 *	   0110 - 1111 = reserved
+	 * [ 5: 4] Trcd (Ras#-active to Cas# read/write delay)
+	 DDR2
+	 *	   00 = 3 clocks
+	 *	   01 = 4 clocks
+	 *	   10 = 5 clocks
+	 *	   11 = 6 clocks
+	  * [ 7: 6] Reserved
+	 * [ 9: 8] Trp (Row Precharge Time, Precharge-to-Active or Auto-Refresh)
+	 DDR2
+	 *	   00 = 3 clocks
+	 *	   01 = 4 clocks
+	 *	   10 = 5 clocks
+	 *	   11 = 6 clocks
+	 * [10:10] Reserved
+	 * [11:11] Trtp (Read to Precharge Time, read Cas# to precharge time)
+	 DDR2
+	 *	   0 = 2 clocks for Burst Length of 32 Bytes
+	 *	       4 clocks for Burst Length of 64 Bytes
+	 *	    1 = 3 clocks for Burst Length of 32 Bytes
+	 *		5 clocks for Burst Length of 64 Bytes
+	 * [15:12] Tras (Minimum Ras# Active Time)
+	 DDR2
+	 *	    0000 = reserved
+	 *	   0001 = reserved
+	 *	    0010 = 5 bus clocks
+	 *	    ...
+	 *	    1111 = 18 bus clocks
+	 * [19:16] Trc (Row Cycle Time, Ras#-active to Ras#-active or auto
+	 *  refresh of the same bank)
+	 DDR2
+	 *	   0000 = 11 bus clocks
+	 *	   0010 = 12 bus clocks
+	 *	   ...
+	 *	   1110 = 25 bus clocks
+	 *	   1111 = 26 bus clocks
+	 * [21:20] Twr (Write Recovery Time, From the last data to precharge,
+	 * 	writes can go back-to-back)
+	 Only for DDR2
+	 *	    00 = 3 bus clocks
+	 *	    01 = 4 bus clocks
+	 *	    10 = 5 bus clocks
+	 *	    11 = 6 bus clocks
+	 * [23:22] Trrd (Active-to-active (Ras#-to-Ras#) Delay of different
+	 * 	banks)
+	 * DDR2
+	 *	    00 = 2 bus clocks
+	 *	    01 = 3 bus clocks
+	 *	    10 = 4 bus clocks
+	 *	    11 = 5 bus clocks
+	 * [31:24] MemClkDis ( Disable the MEMCLK outputs for DRAM channel A in
+	 *	 0x88, channel B in 0x188, BIOS should set it to reduce the
+	 *	power consumption)
+	 *	    Bit		F(1207)		M2 Package	S1g1 Package
+	 *	    0		N/A		MA1_CLK1	N/A
+	 *	    1		N/A		MA0_CLK1	MA0_CLK1
+	 *	    2		MA3_CLK		N/A		N/A
+	 *	    3		MA2_CLK		N/A		N/A
+	 *	    4		MA1_CLK		MA1_CLK0	N/A
+	 *	    5		MA0_CLK		MA0_CLK0	MA0_CLK0
+	 *	    6		N/A		MA1_CLK2	N/A
+	 *	    7		N/A		MA0_CLK2	MA0_CLK2
+	 */
+	PCI_ADDR(CBB, CDB, 2, 0x88), 0x000004c8, 0xff000002 /* 0x03623125 */ ,//DCT0
+	PCI_ADDR(CBB, CDB, 2, 0x188), 0x000004c8, 0xff000002 /* 0x03623125 */ , //???
+	/* DRAM Timing High Register
+	 * F2:0x8C
+	 * [ 3: 0] TrwtWB read to write turnaround for opportunitistic write
+	 * bursting
+	 DDR2
+	 *	   0000 = 3 clocks
+	 *	   0001 = 4 clocks
+	 *	   ...
+	 *	   0111 = 10 clocks
+	 *	   1000 - 1111 reserved
+	 * [ 7: 4] TrwtTO (Read-to-Write Turnaround for Data, DQS Contention)
+	 DDR2
+	 *	   0000 = 2 bus clocks
+	 *	   0001 = 3 bus clocks
+	 *	   ...
+	 *	   0111 = 9 bus clocks
+	 *	   1000 - 1111 reserved
+	 * [ 9: 8] Twtr (Internal DRAM Write-to-Read Command Delay, minium
+	 * 	write-to-read delay when both access the same chip select)
+	 DDR2
+	 *	    00 = Reserved
+	 *	    01 = 1 bus clocks
+	 *	    10 = 2 bus clocks
+	 *	    11 = 3 bus clocks
+	 * [11:10] Twrrd (Write to Read DIMM Termination Turnaround, minimum
+	 * 	write-to-read delay when accessing two different DIMMs)
+	DDR2
+	 *	    00 = 0 bus clocks
+	 *	    01 = 1 bus clocks
+	 *	    10 = 2 bus clocks
+	 *	    11 = 3 bus clocks
+	 * [13:12] Twrwr (Write to Write Timing)
+	DDR2
+	 *	    00 = 1 bus clocks ( 0 idle cycle on the bus)
+	 *	    01 = 2 bus clocks ( 1 idle cycle on the bus)
+	 *	    10 = 3 bus clocks ( 2 idle cycles on the bus)
+	 *	    11 = Reserved
+	 * [15:14] Trdrd ( Read to Read Timing)
+	DDR2
+	 *	    00 = 2 bus clocks ( 1 idle cycle on the bus)
+	 *	    01 = 3 bus clocks ( 2 idle cycles on the bus)
+	 *	    10 = 4 bus clocks ( 3 idle cycles on the bus)
+	 *	    11 = 5 bus clocks ( 4 idel cycles on the bus)
+	 * [17:16] Tref (Refresh Rate)
+	 *	    00 = Undefined behavior
+	 *	    01 = Reserved
+	 *	    10 = Refresh interval of 7.8 microseconds
+	 *	    11 = Refresh interval of 3.9 microseconds
+	 * [18:18] DisAutoRefresh (disable automatic refresh)
+	 * [19:19] Reserved
+	 * [22:20] Trfc0 ( Auto-Refresh Row Cycle Time for the Logical DIMM0,
+	 * 	based on DRAM density and speed)
+	DDR2
+	 *	    000 = 75 ns (all speeds, 256Mbit)
+	 *	    001 = 105 ns (all speeds, 512Mbit)
+	 *	    010 = 127.5 ns (all speeds, 1Gbit)
+	 *	    011 = 195 ns (all speeds, 2Gbit)
+	 *	    100 = 327.5 ns (all speeds, 4Gbit)
+	 *	    101 = reserved
+	 *	    110 = reserved
+	 *	    111 = reserved
+	 * [25:23] Trfc1 ( Auto-Refresh Row Cycle Time for the Logical DIMM1,
+	 *  based on DRAM density and speed)
+	 * [28:26] Trfc2 ( Auto-Refresh Row Cycle Time for the Logical DIMM2,
+	 *  based on DRAM density and speed)
+	 * [31:29] Trfc3 ( Auto-Refresh Row Cycle Time for the Logical DIMM3,
+	 *  based on DRAM density and speed)
+	 */
+	PCI_ADDR(CBB, CDB, 2, 0x8c), 0x000c008f, (2 << 16)|(1 << 8),//DCT0
+	PCI_ADDR(CBB, CDB, 2, 0x18c), 0x000c008f, (2 << 16)|(1 << 8),//DCT1
+
+	/* DRAM Config Low Register
+	 * F2:0x90
+	 * [ 0: 0] InitDram (Initialize DRAM)
+	 *	1 = write 1 cause DRAM controller to execute the DRAM
+	 *	initialization, when done it read to 0
+	 * [ 1: 1] ExitSelfRef ( Exit Self Refresh Command )
+	 *	1 = write 1 causes the DRAM controller to bring the DRAMs out
+	 * 	for self refresh mode
+	 * [ 3: 2] Reserved
+	 * [ 5: 4] DramTerm (DRAM Termination)
+	DDR2 only
+	 *	    00 = On die termination disabled
+	 *	    01 = 75 ohms
+	 *	    10 = 150 ohms
+	 *	    11 = 50 ohms
+	 * [ 6: 6] Reserved
+	 * [ 7: 7] DramDrvWeak ( DRAM Drivers Weak Mode)
+	DDR2 only
+	 *	   0 = Normal drive strength mode.
+	 *	   1 = Weak drive strength mode
+	 * [ 8: 8] ParEn (Parity Enable)
+	 *	   1 = Enable address parity computation output, PAR, and
+	 *	enables the parity error input, ERR
+	 * [ 9: 9] SelfRefRateEn (Faster Self Refresh Rate Enable)
+	 DDR2 only
+	 *	    1 = Enable high temperature ( two times normal ) self
+	 *	 refresh rate
+	 * [10:10] BurstLength32 ( DRAM Burst Length Set for 32 Bytes)
+	 *	   0 = 64-byte mode
+	 *	   1 = 32-byte mode
+	 * [11:11] Width128 ( Width of DRAM interface)
+	 *	   0 = the controller DRAM interface is 64-bits wide
+	 *	   1 = the controller DRAM interface is 128-bits wide
+	  * [12:12] X4Dimm (DIMM 0 is x4)
+	  * [13:13] X4Dimm (DIMM 1 is x4)
+	  * [14:14] X4Dimm (DIMM 2 is x4)
+	  * [15:15] X4Dimm (DIMM 3 is x4)
+	  *	    0 = DIMM is not x4
+	  *	    1 = x4 DIMM present
+	 * [16:16] UnBuffDimm ( Unbuffered DIMMs)
+	 *	   0 = Buffered DIMMs
+	 *	   1 = Unbuffered DIMMs
+	 * [17:17] EnterSelfRef
+	 * [18:18] PendRefPayback
+	 * [19:19] DimmEccEn ( DIMM ECC Enable )
+		   1 =	ECC checking is being enabled for all DIMMs on the DRAM
+	*	 controller ( Through F3 0x44[EccEn])
+	 * [20:20] DynPageCloseEn: dynamic page close enable
+	 * [22:21] IdleCycInit: idle cycle count initial value
+	 * [23:23] ForceAutoPchg: force auto precharging
+	 * [31:24] Reserved
+	 */
+	PCI_ADDR(CBB, CDB, 2, 0x90), 0xfff6004c, 0x00000010,//DCT0
+	PCI_ADDR(CBB, CDB, 2, 0x190), 0xfff6004c, 0x00000010,//DCT1
+	/* DRAM Config High Register
+	 * F2:0x94
+	 * [ 0: 2] MemClkFreq ( Memory Clock Frequency)
+	 DDR2
+	 *	   000 = 200MHz
+	 *	   001 = 266MHz
+	 *	   010 = 333MHz
+	 *	   011 = 400MHz
+	 *	   1xx = reserved
+	 * [ 3: 3] MemClkFreqVal (Memory Clock Freqency Valid)
+	 *	   1 = BIOS need to set the bit when setting up MemClkFreq to
+	 * 	 the proper value
+	 * [ 7: 4] reserved
+	 * [ 8: 8] Ddr3Mode
+	 * [ 9: 9] LegacyBiosMode : DCT1 is disabled
+	 * [11:10] Reserved
+	 * [12:12] RDqsEn ( Read DQS Enable) This bit is only be set if x8
+	 *	 registered DIMMs are present in the system
+	 *	    0 = DM pins function as data mask pins
+	 *	    1 = DM pins function as read DQS pins
+	 * [13:13] DissimulRdWr: disable simulataueous read and write: this bit
+	 * 	shoule be low if the DCTs are gunged (F2x110[DctGangEn])
+	 * [14:14] DisDramInterface ( Disable the DRAM interface ) When this bit
+	 *	is set, the DRAM controller is disabled, and interface in low
+	 *	 power state
+	 *	    0 = Enabled (default)
+	 *	    1 = Disabled
+	 * [15:15] PowerDownEn ( Power Down Mode Enable )
+	 *	    0 = Disabled (default)
+	 *	    1 = Enabled
+	 * [16:16] PowerDown ( Power Down Mode )
+	 *	    0 = Channel CKE Control
+	 *	    1 = Chip Select CKE Control
+	 * [17:17] FourRankSODimm (Four Rank SO-DIMM)
+	 *	    1 = this bit is set by BIOS to indicate that a four rank
+	 * 	SO-DIMM is present
+	 * [18:18] FourRankRDimm (Four Rank Registered DIMM)
+	 *	    1 = this bit is set by BIOS to indicate that a four rank
+	 *	registered DIMM is present
+	 * [19:19] Reserved
+	 * [20:20] SlowAccessMode (Slow Access Mode (2T Mode))
+	 *	    0 = DRAM address and control signals are driven for one
+	 *	 MEMCLK cycle
+	 *	    1 = One additional MEMCLK of setup time is provided on all
+	 *	DRAM address and control signals except CS, CKE, and ODT;
+	 *	 i.e., these signals are drivern for two MEMCLK cycles rather
+	 *	than one
+	 * [21:21] FreqChgInProg: frequency change in progress: BIOS should not
+	 *	program the phy registers while this bit is set.
+	 * [22:22] BankSwizzleMode ( Bank Swizzle Mode),
+	 *	    0 = Disabled (default)
+	 *	    1 = Enabled
+	 * [23:23] ProcOdtDis: processor on-die termination disable
+	 * [27:24] DcqBypassMax ( DRAM Controller Queue Bypass Maximum)
+	 DDR2
+	 *	   0000 = No bypass; the oldest request is never bypassed
+	 *	   0001 = The oldest request may be bypassed no more than 1 time
+	 *	   ...
+	 *	   1111 = The oldest request may be bypassed no more than 15
+	 *	          times
+	 * [31:28] FourActWindow ( Four Bank Activate Window) , not more than
+	 *	 4 banks in a 8 bank device are activated
+	 *	    0000 = No tFAW window restriction
+	 *	    0001 = 8 MEMCLK cycles
+	 *	   0010 = 9 MEMCLK cycles
+	 *	    ...
+	 *	   1101 = 20 MEMCLK cycles
+	 *	   111x = reserved
+	 */
+//	  PCI_ADDR(CBB, CDB, 2, 0x94), 0x00a82f00,0x00008000, //DCT0 --- legacy mode DCT1 is disabled. and [2b:10] only use byte0 info
+	PCI_ADDR(CBB, CDB, 2, 0x94), 0x00a82e00,0x00008000, //DCT0 ---
+	PCI_ADDR(CBB, CDB, 2, 0x194), 0x00a82e00,0x00008000, //DCT1 ---
+
+	/* DRAM DRAM Controller Miscellaneous Reg
+	 * F2:0xa0, 0x1a0
+	 * [ 0: 0] MemCleared (Memory Cleared) : Readonly
+	 * [ 8: 1] reserved
+	 * [ 9: 9] DramEnabled ( DRAM Enabled) : Readonly
+	 * [31:10] Reserved
+	 */
+
+	/* DRAM Controller Select Low Reg
+	 * F2:0x110
+	 * [ 4: 4] DctGangEn: DRAM controller ganging enable. If ganging is to
+	 * be enabled, this bit must be set prior to programming anying DCT
+	 *  registers
+	 */
+//	   PCI_ADDR(CBB, CDB, 2, 0x110), 0xffffffe0, 0x00000010,
+
+	/* DRAM Controller Select High Reg
+	 * F2:0x114
+	 */
+	/* DRAM Memory Controller Configuration Low Reg
+	 * F2:0x118
+	 */
+	/* DRAM Memory Controller Configuration High Reg
+	 * F2:0x11c
+	 */
+
+
+	/* DRAM Scrub Control Register
+	 * F3:0x58
+	 * [ 4: 0] DRAM Scrube Rate
+	 * [ 7: 5] reserved
+	 * [12: 8] L2 Scrub Rate
+	 * [15:13] reserved
+	 * [20:16] Dcache Scrub
+	 * [23:21] reserved
+	 * [28:24] L3Scrub: L3 cache scrub rate
+	 * [31:29] reserved
+	 *	   Scrub Rates
+	 *	   00000 = Do not scrub
+	 *	   00001 =  40.00 ns
+	 *	   00010 =  80.00 ns
+	 *	   00011 = 160.00 ns
+	 *	   00100 = 320.00 ns
+	 *	   00101 = 640.00 ns
+	 *	   00110 =   1.28 us
+	 *	   00111 =   2.56 us
+	 *	   01000 =   5.12 us
+	 *	   01001 =  10.20 us
+	 *	   01011 =  41.00 us
+	 *	   01100 =  81.90 us
+	 *	   01101 = 163.80 us
+	 *	   01110 = 327.70 us
+	 *	   01111 = 655.40 us
+	 *	   10000 =   1.31 ms
+	 *	   10001 =   2.62 ms
+	 *	   10010 =   5.24 ms
+	 *	   10011 =  10.49 ms
+	 *	   10100 =  20.97 ms
+	 *	   10101 =  42.00 ms
+	 *	   10110 =  84.00 ms
+	 *	   All Others = Reserved
+	 */
+	PCI_ADDR(CBB, CDB, 3, 0x58), 0xffe0e0e0, 0x00000000,
+	/* DRAM Scrub Address Low Register
+	 * F3:0x5C
+	 * [ 0: 0] DRAM Scrubber Redirect Enable
+	 *	   0 = Do nothing
+	 *	   1 = Scrubber Corrects errors found in normal operation
+	 * [ 5: 1] Reserved
+	 * [31: 6] DRAM Scrub Address 31-6
+	 */
+	PCI_ADDR(CBB, CDB, 3, 0x5C), 0x0000003e, 0x00000000,
+	/* DRAM Scrub Address High Register
+	 * F3:0x60
+	 * [ 7: 0] DRAM Scrubb Address 39-32
+	 * [31: 8] Reserved
+	 */
+	PCI_ADDR(CBB, CDB, 3, 0x60), 0xffffff00, 0x00000000,
+
+	};
+	// for PCI_ADDR(CBB, CDB, 2, 0x98) index, and PCI_ADDR(CBB, CDB, 2, 0x9c) data
+	/*
+	 * index:
+	 * [29: 0] DctOffset (Dram Controller Offset)
+	 * [30:30] DctAccessWrite (Dram Controller Read/Write Select)
+	 * 	0 = read access
+	 * 	1 = write access
+	 * [31:31] DctAccessDone (Dram Controller Access Done)
+	 * 	0 = Access in progress
+	 * 	1 = No access is progress
+	 *
+	 * Data:
+	 * [31: 0] DctOffsetData (Dram Controller Offset Data)
+	 *
+	 * Read:
+	 * 	- Write the register num to DctOffset with DctAccessWrite = 0
+	 * 	- poll the DctAccessDone until it = 1
+	 * 	- Read the data from DctOffsetData
+	 * Write:
+	 * 	- Write the data to DctOffsetData
+	 * 	- Write register num to DctOffset with DctAccessWrite = 1
+	 * 	- poll the DctAccessDone untio it = 1
+	 *
+	 */
+
+	u32 i;
+	u32 max;
+
+	if (!controller_present(ctrl)) {
+//		print_debug("No memory controller present\n");
+		sysinfo->ctrl_present[ctrl->node_id] = 0;
+		return;
+	}
+	sysinfo->ctrl_present[ctrl->node_id] = 1;
+
+	print_spew("setting up CPU");
+	print_spew_hex8(ctrl->node_id);
+	print_spew(" northbridge registers\n");
+	max = sizeof(register_values)/sizeof(register_values[0]);
+	for(i = 0; i < max; i += 3) {
+		device_t dev;
+		u32 where;
+		unsigned long reg;
+		dev = (register_values[i] & ~0xfff) - PCI_DEV(CBB, CDB, 0) + ctrl->f0;
+
+		where = register_values[i] & 0xfff;
+		reg = pci_read_config32(dev, where);
+		reg &= register_values[i+1];
+		reg |= register_values[i+2];
+		pci_write_config32(dev, where, reg);
+	}
+
+	print_spew("done.\n");
+}
+
+
+static u32 is_dual_channel(const struct mem_controller *ctrl)
+{
+	u32 dcl;
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+	return dcl & DCL_Width128;
+}
+
+
+static u32 is_opteron(const struct mem_controller *ctrl)
+{
+	/* Test to see if I am an Opteron.
+	 * FIXME Testing dual channel capability is correct for now
+	 * but a beter test is probably required.
+	 * m2 and s1g1 support dual channel too. but only support unbuffered dimm
+	 */
+#warning "FIXME implement a better test for opterons"
+	u32 nbcap;
+	nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
+	return !!(nbcap & NBCAP_TwoChanDRAMcap);
+}
+
+
+static u32 is_registered(const struct mem_controller *ctrl, u32 dct)
+{
+	/* Test to see if we are dealing with registered SDRAM.
+	 * If we are not registered we are unbuffered.
+	 * This function must be called after spd_handle_unbuffered_dimms.
+	 */
+	u32 dcl;
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW + 0x100*dct);
+	return !(dcl & DCL_UnBuffDimm);
+}
+
+
+static void spd_get_dimm_size(u32 device, struct dimm_size *sz)
+{
+	/* Calculate the log base 2 size of a DIMM in bits */
+	int value;
+	sz->per_rank = 0;
+	sz->rows = 0;
+	sz->col = 0;
+	sz->rank = 0;
+
+	value = spd_read_byte(device, SPD_ROW_NUM);	/* rows */
+	if (value < 0) goto hw_err;
+	if ((value & 0xff) == 0) goto val_err; // max is 16 ?
+	sz->per_rank += value & 0xff;
+	sz->rows = value & 0xff;
+
+	value = spd_read_byte(device, SPD_COL_NUM);	/* columns */
+	if (value < 0) goto hw_err;
+	if ((value & 0xff) == 0) goto val_err;	//max is 11
+	sz->per_rank += value & 0xff;
+	sz->col = value & 0xff;
+
+	value = spd_read_byte(device, SPD_BANK_NUM);	/* banks */
+	if (value < 0) goto hw_err;
+	if ((value & 0xff) == 0) goto val_err;
+	sz->bank = log2(value & 0xff);	// convert 4 to 2, and 8 to 3
+	sz->per_rank += sz->bank;
+
+	/* Get the module data width and convert it to a power of two */
+	value = spd_read_byte(device, SPD_DATA_WIDTH);
+	if (value < 0) goto hw_err;
+	value &= 0xff;
+	if ((value != 72) && (value != 64)) goto val_err;
+	sz->per_rank += log2(value) - 3; //64 bit So another 3 lines
+
+	/* How many ranks? */
+	value = spd_read_byte(device, SPD_MOD_ATTRIB_RANK);	/* number of physical banks */
+	if (value < 0) goto hw_err;
+//	value >>= SPD_MOD_ATTRIB_RANK_NUM_SHIFT;
+	value &= SPD_MOD_ATTRIB_RANK_NUM_MASK;
+	value += SPD_MOD_ATTRIB_RANK_NUM_BASE; // 0-->1, 1-->2, 3-->4
+	/*
+	  rank == 1 only one rank or say one side
+	  rank == 2 two side , and two ranks
+	  rank == 4 two side , and four ranks total
+	  Some one side two ranks, because of stacked
+	*/
+	if ((value != 1) && (value != 2) && (value != 4 )) {
+		goto val_err;
+	}
+	sz->rank = value;
+
+	/* verify if per_rank is equal byte 31
+	  it has the DIMM size as a multiple of 128MB.
+	  */
+	 value = spd_read_byte(device, SPD_RANK_SIZE);
+	 if (value < 0) goto hw_err;
+	 value &= 0xff;
+	value = log2(value);
+	if(value <=4 ) value += 8; // add back to 1G to high
+	value += (27-5); // make 128MB to the real lines
+	if( value != (sz->per_rank)) {
+		print_err("Bad RANK Size --\n");
+		goto val_err;
+	}
+
+	goto out;
+
+val_err:
+	die("Bad SPD value\n");
+	/* If an hw_error occurs report that I have no memory */
+hw_err:
+	sz->per_rank = 0;
+	sz->rows = 0;
+	sz->col = 0;
+	sz->bank = 0;
+	sz->rank = 0;
+out:
+	return;
+}
+
+static void set_dimm_size(const struct mem_controller *ctrl, u32 dct,
+				struct dimm_size *sz, u32 index, u8 is_Width128)
+{
+	u32 base0, base1;
+	u32 offset = 0x100 * dct;
+
+
+	print_tx("set_dimm_size: dct ", dct);
+	print_tx("               i   ", index);
+
+	/* For each base register.
+	 * Place the dimm size in 32 MB quantities in the bits 31 - 21.
+	 * The initialize dimm size is in bits.
+	 * Set the base enable bit0.
+	 */
+
+	base0 = base1 = 0;
+
+	/* Make certain side1 of the dimm is at least 128MB */
+	if (sz->per_rank >= 27) {
+		base0 = (1 << ((sz->per_rank - 27 ) + 19)) | 1;
+	}
+
+	/* Make certain side2 of the dimm is at least 128MB */
+	if (sz->rank > 1) { // 2 ranks or 4 ranks
+		base1 = (1 << ((sz->per_rank - 27 ) + 19)) | 1;
+	}
+
+	/* Double the size if we are using dual channel memory */
+	if (is_Width128) {
+		base0 = (base0 << 1) | (base0 & 1);
+		base1 = (base1 << 1) | (base1 & 1);
+	}
+
+	/* Clear the reserved bits */
+	base0 &= ~0xe007fffe;
+	base1 &= ~0xe007fffe;
+
+	/* Set the appropriate DIMM base address register */
+	pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2) + offset, base0);
+	pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2) + offset, base1);
+#if QRANK_DIMM_SUPPORT == 1
+	if(sz->rank == 4) {
+		pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+4)<<2) + offset, base0);
+		pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+5)<<2) + offset, base1);
+	}
+#endif
+
+	/* Enable the memory clocks for this DIMM by Clear the MemClkDis bit*/
+	if (base0) {
+		u32 dword;
+		u32 ClkDis0;
+#if CPU_SOCKET_TYPE == 0x10 /* L1 */
+		ClkDis0 = DTL_MemClkDis0;
+#else
+	#if CPU_SOCKET_TYPE == 0x11 /* AM2 */
+		ClkDis0 = DTL_MemClkDis0_AM2;
+	#endif
+#endif
+
+		dword = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW + offset); //Channel A
+		dword &= ~(ClkDis0 >> index);
+#if QRANK_DIMM_SUPPORT == 1
+		if(sz->rank == 4) {
+			dword &= ~(ClkDis0 >> (index+2));
+		}
+#endif
+		pci_write_config32(ctrl->f2, DRAM_TIMING_LOW + offset, dword);
+
+		if (is_Width128 && (!dct)) { //Channel B
+			dword = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW + 0x100); //Channel A
+			dword &= ~(ClkDis0 >> index);
+#if QRANK_DIMM_SUPPORT == 1
+			if(sz->rank == 4) {
+				dword &= ~(ClkDis0 >> (index+2));
+			}
+#endif
+			pci_write_config32(ctrl->f2, DRAM_TIMING_LOW + 0x100, dword);
+
+		}
+
+	}
+}
+
+	/*  row  col   bank  for 64 bit
+	 *   0:  13     9      2  :128M
+	 *   1:  13     10     2  :256M
+	 *   2:  14     10     2  :512M
+	 *   3:  13     11     2  :512M
+	 *   4:  13     10     3  :512M
+	 *   5:  14     10     3  :1G
+	 *   6:  14     11     2  :1G
+	 *   7:  15     10     3  :2G
+	 *   8:  14     11     3  :2G
+	 *   9:  15     11     3  :4G
+	 *  10:  16     10     3  :4G
+	 *  11:  16     11     3  :8G
+	 */
+
+
+static void set_dimm_cs_map(const struct mem_controller *ctrl, u32 dct,
+				struct dimm_size *sz, u32 index)
+{
+	static const u8 cs_map_aaa[24] = {
+	/* (bank=2, row=13, col=9)(3, 16, 11) ---> (0, 0, 0) (1, 3, 2) */
+	//Bank2
+		0, 1, 3,
+		0, 2, 6,
+		0, 0, 0,
+		0, 0, 0,
+	//Bank3
+		0, 4, 0,
+		0, 5, 8,
+		0, 7, 9,
+		0,10,11,
+	};
+
+	u32 map;
+	u32 offset = dct * 0x100;
+
+	map = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP + offset);
+	map &= ~(0xf << (index * 4));
+#if QRANK_DIMM_SUPPORT == 1
+	if(sz->rank == 4) {
+		map &= ~(0xf << ( (index + 2) * 4));
+	}
+#endif
+
+	/* Make certain side1 of the dimm is at least 128MB */
+	if (sz->per_rank >= 27) {
+		u32 temp_map;
+		temp_map = cs_map_aaa[(sz->bank-2)*3*4 + (sz->rows - 13)*3 + (sz->col - 9) ];
+		map |= temp_map << (index*4);
+#if QRANK_DIMM_SUPPORT == 1
+		if(sz->rank == 4) {
+			map |= temp_map << ( (index + 2) * 4);
+		}
+#endif
+	}
+
+	pci_write_config32(ctrl->f2, DRAM_BANK_ADDR_MAP + offset, map);
+}
+
+
+static long spd_set_ram_size(const struct mem_controller *ctrl,
+				long dimm_mask, struct mem_info *meminfo)
+{
+	u32 i;
+
+	for(i = 0; i < (DIMM_SOCKETS*(2-meminfo->is_Width128)); i++) {
+		struct dimm_size *sz = &(meminfo->sz[i]);
+		u32 index;
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+		print_tx("spd_set_ram_size dimm_socket:", i);
+		u32 dct;
+		if(i<DIMM_SOCKETS) {
+			dct = 0;
+			index = i;
+		} else {
+			dct = 1;
+			index = (i-DIMM_SOCKETS);
+		}
+		spd_get_dimm_size(ctrl->spd_addr[i], sz);
+		if (sz->per_rank == 0) {
+			return -1; /* Report SPD error */
+		}
+		set_dimm_size(ctrl, dct, sz, index, meminfo->is_Width128);
+		set_dimm_cs_map (ctrl, dct, sz, index);
+	}
+	return dimm_mask;
+}
+
+
+static void route_dram_accesses(const struct mem_controller *ctrl,
+	unsigned long base_m, unsigned long limit_m, u32 nodes)
+{
+	/* Route the addresses to the controller node */
+	struct dram_base_mask_t d;
+
+	d.base = (base_m<<1) & 0x1fffff00;
+	d.mask = (((limit_m<<1) & 0x1fffff00) - (1<<8)) | 1;
+
+	print_t("route_dram_accesses ");
+	print_tx("node_id", ctrl->node_id);
+	print_tx("d.base", d.base);
+	print_tx("d.mask", d.mask);
+
+	/* FIXME: for CAR_FAM10, if there is no dimms on node0, and we are not
+	 *  use ext dram map need to leave [0, 16M) to node0. and let
+	 * disble_bsp_cache_as_ram to restore it. if node_id != 0, and
+	 * d.base = 0, we need to increase base to 1 How about ext dram map?
+	 * we don't need to worry about it, ext dram map will be override by
+	 * standard conf space. But is disable_bsp_cache_as_ram need to clear
+	 * standard map to get the [0, 16M) ram back. Also we need to make sure
+	 * CONFIG_TOP_MEM is 32M, otherwise we can not access CAR and RAM at
+	 * the same time to copy data from CAR to RAM
+	 */
+	set_dram_base_mask(ctrl->node_id, d, nodes);
+}
+
+
+static void set_top_mem(u32 tom_m, u32 hole_startk)
+{
+	/* Error if I don't have memory */
+	if (!tom_m) {
+		die("No memory?");
+	}
+
+	/* Report the amount of memory. */
+	print_debug("RAM: 0x");
+	print_debug_hex32(tom_m);
+	print_debug(" MB\n");
+
+	msr_t msr;
+	if(tom_m > (4*1024)) {
+		/* Now set top of memory */
+		msr.lo = (tom_m & 0x00000ff8) << 20;
+		msr.hi = (tom_m & 0x0ffff000) >> 12;
+		wrmsr(TOP_MEM2, msr);
+	}
+
+	/* Leave a 64M hole between TOP_MEM and TOP_MEM2
+	 * so I can see my rom chip and other I/O devices.
+	 */
+	if (tom_m >= (0x003f0000>>10)) {
+#if HW_MEM_HOLE_SIZEK != 0
+		if(hole_startk != 0) {
+			tom_m = (hole_startk>>10);
+		} else
+#endif
+		tom_m = (0x3f0000>>10);
+	}
+	msr.lo = (tom_m & 0x00000ff8) << 20;
+	msr.hi = (tom_m & 0x0ffff000) >> 12;
+	wrmsr(TOP_MEM, msr);
+}
+
+
+static unsigned long interleave_chip_selects(const struct mem_controller *ctrl,
+						u32 dct, u8 is_Width128)
+{
+	/* 36 - 27 */
+
+	static const u8 csbase_low_shift[] = {
+	/* 128MB */	(14 - (13-5)),
+	/* 256MB */	(15 - (13-5)),
+	/* 512MB */	(15 - (13-5)),
+	/* 512MB */	(16 - (13-5)),
+	/* 512MB */	(16 - (13-5)),
+	/* 1GB  */	(16 - (13-5)),
+	/* 1GB  */	(16 - (13-5)),
+	/* 2GB  */	(16 - (13-5)),
+	/* 2GB  */	(17 - (13-5)),
+	/* 4GB  */	(17 - (13-5)),
+	/* 4GB  */	(16 - (13-5)),
+	/* 8GB  */	(17 - (13-5)),
+	};
+
+	/* cs_base_high is not changed */
+
+	u32 csbase_inc;
+	u8 chip_selects, index;
+	u8 bits;
+	u32 common_size;
+	u32 common_cs_mode;
+	u32 csbase, csmask;
+	u32 offset = 0x100 * dct;
+
+	/* See if all of the memory chip selects are the same size
+	 * and if so count them.
+	 */
+	chip_selects = 0;
+	common_size = 0;
+	common_cs_mode = 0xff;
+	for(index = 0; index < 8; index++) {
+		u32 size;
+		u32 cs_mode;
+		u32 value;
+
+		value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2) + offset);
+
+		/* Is it enabled? */
+		if (!(value & 1)) {
+			continue;
+		}
+		chip_selects++;
+		size = (value >> 19) & 0x3ff;
+		if (common_size == 0) {
+			common_size = size;
+		}
+		/* The size differed fail */
+		if (common_size != size) {
+			return 0;
+		}
+
+		value = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP + offset);
+		cs_mode =( value >> ((index>>1)*4)) & 0xf;
+		if(common_cs_mode == 0xff) {
+			common_cs_mode = cs_mode;
+		}
+		/* The cs_mode differed fail */
+		if(common_cs_mode != cs_mode) {
+			return 0;
+		}
+	}
+
+	/* Chip selects can only be interleaved when there is
+	 * more than one and their is a power of two of them.
+	 */
+	bits = log2(chip_selects);
+
+	//chip_selects max = 8
+	if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) {
+		return 0;
+	}
+
+	/* Find the bits of csbase that we need to interleave on */
+	csbase_inc = 1 << (csbase_low_shift[common_cs_mode]);
+	if(is_Width128) {
+		csbase_inc <<=1;
+	}
+
+
+	/* Compute the initial values for csbase and csbask.
+	 * In csbase just set the enable bit and the base to zero.
+	 * In csmask set the mask bits for the size and page level interleave.
+	 */
+	csbase = 0 | 1;
+	csmask = (((common_size	 << bits) - 1) << 19);
+	csmask |= 0x3fe0 & ~((csbase_inc << bits) - csbase_inc);
+	for(index = 0; index < 8; index++) {
+		u32 value;
+
+		value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2) + offset);
+		/* Is it enabled? */
+		if (!(value & 1)) {
+			continue;
+		}
+		pci_write_config32(ctrl->f2, DRAM_CSBASE + (index << 2) + offset, csbase );
+		if((index & 1) == 0) {	//only have 4 CSMASK
+			pci_write_config32(ctrl->f2, DRAM_CSMASK + ((index>>1) << 2) + offset, csmask);
+		}
+		csbase += csbase_inc;
+	}
+	if(!is_Width128) {
+		print_debug("dct ");
+		print_debug_hex8(dct);
+		print_debug(" ");
+	}
+	print_debug("CS Interleaved\n");
+
+	/* Return the memory size in M */
+	return common_size << ((27-20) + bits);
+}
+static unsigned long order_chip_selects(const struct mem_controller *ctrl,
+					u32 dct)
+{
+	unsigned long tom;
+	u32 offset = 0x100 * dct;
+
+	/* Remember which registers we have used in the high 8 bits of tom */
+	tom = 0;
+	for(;;) {
+		/* Find the largest remaining canidate */
+		u32 index, canidate;
+		u32 csbase, csmask;
+		u32 size;
+		csbase = 0;
+		canidate = 0;
+		for(index = 0; index < 8; index++) {
+			u32 value;
+			value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2) + offset);
+
+			/* Is it enabled? */
+			if (!(value & 1)) {
+				continue;
+			}
+
+			/* Is it greater? */
+			if (value <= csbase) {
+				continue;
+			}
+
+			/* Has it already been selected */
+			if (tom & (1 << (index + 24))) {
+				continue;
+			}
+			/* I have a new canidate */
+			csbase = value;
+			canidate = index;
+		}
+		/* See if I have found a new canidate */
+		if (csbase == 0) {
+			break;
+		}
+
+		/* Remember the dimm size */
+		size = csbase >> 19;
+
+		/* Remember I have used this register */
+		tom |= (1 << (canidate + 24));
+
+		/* Recompute the cs base register value */
+		csbase = (tom << 19) | 1;
+
+		/* Increment the top of memory */
+		tom += size;
+
+		/* Compute the memory mask */
+		csmask = ((size -1) << 19);
+		csmask |= 0x3fe0;		/* For now don't optimize */
+
+		/* Write the new base register */
+		pci_write_config32(ctrl->f2, DRAM_CSBASE + (canidate << 2) + offset, csbase);
+		/* Write the new mask register */
+		 if((canidate & 1) == 0) {  //only have 4 CSMASK
+			 pci_write_config32(ctrl->f2, DRAM_CSMASK + ((canidate>>1) << 2) + offset, csmask);
+		 }
+
+	}
+	/* Return the memory size in M */
+	return (tom & ~0xff000000) << (27-20);
+}
+
+
+unsigned long memory_end_m(const struct mem_controller *ctrl, u32 max_node_id)
+{
+	u32 node_id;
+	u32 end_m;
+	struct dram_base_mask_t d;
+	/* Find the last memory address used */
+	end_m = 0;
+	for(node_id = 0; node_id < max_node_id; node_id++) {
+
+		d = get_dram_base_mask(node_id);
+
+		print_tx("memory_end_m: node_id=", node_id);
+		print_tx("d.base", d.base);
+		print_tx("d.mask", d.mask);
+
+		/* Only look at the limit if the base is enabled */
+		if (d.mask & 1) {
+			d.mask &= 0x1fffff00;
+			end_m = (d.mask >>1) + (1<<7);
+		}
+	}
+	return end_m;
+}
+
+
+static void order_dimms(const struct mem_controller *ctrl,
+			struct mem_info *meminfo, struct sys_info *sysinfo)
+{
+	unsigned long tom_m = 0, base_m, sel_m = 0;
+
+	if (read_option(CMOS_VSTART_interleave_chip_selects, CMOS_VLEN_interleave_chip_selects, 1) != 0) {
+		meminfo->is_cs_interleaved[0] = 1;
+		meminfo->is_cs_interleaved[1] = 1;
+	} else {
+		print_debug("Interleaving disabled\n");
+		meminfo->is_cs_interleaved[0] = 0;
+		meminfo->is_cs_interleaved[1] = 0;
+	}
+
+
+	if(meminfo->dimm_mask & ((1<<DIMM_SOCKETS)-1)) {
+		if(meminfo->is_cs_interleaved[0]) {
+			sel_m = tom_m = interleave_chip_selects(ctrl,0, meminfo->is_Width128);
+			if(!tom_m) meminfo->is_cs_interleaved[0] = 0;
+		}
+		if(!meminfo->is_cs_interleaved[0]) {
+			sel_m = tom_m = order_chip_selects(ctrl, 0);
+		}
+	}
+	if((!meminfo->is_Width128) && ((meminfo->dimm_mask>>DIMM_SOCKETS) & ((1<<DIMM_SOCKETS)-1))) {
+		if(meminfo->is_cs_interleaved[1]) {
+			tom_m += interleave_chip_selects(ctrl, 1, meminfo->is_Width128); //DCT1
+			if( tom_m==sel_m ) meminfo->is_cs_interleaved[1] = 0;
+		}
+		if(!meminfo->is_cs_interleaved[1]) {
+			tom_m += order_chip_selects(ctrl, 1); //DCT1
+		}
+	}
+
+	/* Compute the memory base address */
+	base_m = memory_end_m(ctrl, ctrl->node_id);
+//	print_raminit("order_dimms: node=", ctrl->node_id);
+	print_raminit("base_m = ", base_m);
+
+	if(!meminfo->is_Width128) { // if only has DIMM with DCT0, Do we need to set it?
+		if(sel_m != tom_m) { // there dimm on DCT1
+			print_raminit(" SelHiEn= ", 3);
+			set_DctSelHiEn(ctrl->node_id, 3);
+			sel_m += base_m;
+			print_raminit(" sel_m = ", sel_m);
+			set_DctSelBaseAddr(ctrl->node_id, sel_m); //DCT1 Start Addr
+		}
+	}
+
+	tom_m += base_m;
+	print_raminit("tom_m = ", tom_m);
+	route_dram_accesses(ctrl, base_m, tom_m, sysinfo->nodes);
+	set_top_mem(tom_m, 0);
+}
+
+static long disable_dimm(const struct mem_controller *ctrl, u32 dct,
+			u32 index, long dimm_mask, struct mem_info *meminfo)
+{
+	u32 offset = 0x100 * dct;
+	print_debug("disabling dimm");
+	print_debug_hex8(index);
+	print_debug("\n");
+	pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2) + offset, 0);
+	pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2) + offset, 0);
+
+#if QRANK_DIMM_SUPPORT == 1
+	 if(meminfo->sz[index].rank == 4) {
+		 pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+4)<<2) + offset, 0);
+		 pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+5)<<2) + offset, 0);
+	 }
+#endif
+
+	dimm_mask &= ~(1 << (index + dct*DIMM_SOCKETS));
+	if(meminfo->is_Width128) {
+		dimm_mask &= ~(1 << (index + DIMM_SOCKETS));
+	}
+	return dimm_mask;
+}
+
+static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl,
+					long dimm_mask, struct mem_info *meminfo)
+{
+	u8 i;
+	u32 registered;
+	u32 dcl;
+	registered = 0;
+	for(i = 0; i < (DIMM_SOCKETS*(2-meminfo->is_Width128)); i++) {
+		int value;
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+		value = spd_read_byte(ctrl->spd_addr[i], SPD_DIMM_TYPE);
+		if (value < 0) {
+			return -1;
+		}
+		/* Registered dimm ? */
+		value &= 0x3f;
+		if ((value == SPD_DIMM_TYPE_RDIMM) || (value == SPD_DIMM_TYPE_mRDIMM)) {
+			//check SPD_MOD_ATTRIB to verify it is SPD_MOD_ATTRIB_REGADC (0x11)?
+			registered |= (1<<i);
+		}
+	}
+
+	if (is_opteron(ctrl)) {
+	}
+
+
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+	dcl &= ~DCL_UnBuffDimm;
+	meminfo->is_registered = 1;
+	if (!registered) {
+		dcl |= DCL_UnBuffDimm;
+		meminfo->is_registered = 0;
+	}
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+
+	if(!meminfo->is_Width128) { //DCT1
+		dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW + 0x100);
+		dcl &= ~DCL_UnBuffDimm;
+		if (!registered) {
+			dcl |= DCL_UnBuffDimm;
+		}
+		pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW + 0x100, dcl);
+	}
+
+	if (meminfo->is_registered) {
+		print_debug("Registered\n");
+	} else {
+		print_debug("Unbuffered\n");
+	}
+	return dimm_mask;
+}
+
+static u32 spd_detect_dimms(const struct mem_controller *ctrl)
+{
+	u32 dimm_mask;
+	u8 i;
+	dimm_mask = 0;
+	for(i = 0; i < DIMM_SOCKETS * 2; i++) {
+		int byte;
+		u32 device;
+		device = ctrl->spd_addr[i];
+		if (device) {
+			byte = spd_read_byte(device, SPD_MEM_TYPE);  /* Type */
+			if (byte == SPD_MEM_TYPE_SDRAM_DDR2) {
+				dimm_mask |= (1 << i);
+			}
+		}
+	}
+	print_debug("dimm_mask:"); print_debug_hex32(dimm_mask); print_debug("\n");
+	return dimm_mask;
+}
+
+static long spd_enable_2channels(const struct mem_controller *ctrl, long dimm_mask, struct mem_info *meminfo)
+{
+	u8 i;
+	u32 nbcap;
+	/* SPD addresses to verify are identical */
+	static const u8 addresses[] = {
+		2,	/* Type should be DDR2 SDRAM */
+		3,	/* *Row addresses */
+		4,	/* *Column addresses */
+		5,	/* *Number of DIMM Ranks */
+		6,	/* *Module Data Width*/
+		9,	/* *Cycle time at highest CAS Latency CL=X */
+		11,	/* *DIMM Conf Type */
+		13,	/* *Pri SDRAM Width */
+		17,	/* *Logical Banks */
+		18,	/* *Supported CAS Latencies */
+		20,	/* *DIMM Type Info */
+		21,	/* *SDRAM Module Attributes */
+		23,	/* *Cycle time at CAS Latnecy (CLX - 1) */
+		26,	/* *Cycle time at CAS Latnecy (CLX - 2) */
+		27,	/* *tRP Row precharge time */
+		28,	/* *Minimum Row Active to Row Active Delay (tRRD) */
+		29,	/* *tRCD RAS to CAS */
+		30,	/* *tRAS Activate to Precharge */
+		36,	/* *Write recovery time (tWR) */
+		37,	/* *Internal write to read command delay (tRDP) */
+		38,	/* *Internal read to precharge commanfd delay (tRTP) */
+		41,	/* *Extension of Byte 41 tRC and Byte 42 tRFC */
+		41,	/* *Minimum Active to Active/Auto Refresh Time(Trc) */
+		42,	/* *Minimum Auto Refresh Command Time(Trfc) */
+	};
+
+	/* If the dimms are not in pairs do not do dual channels */
+	if ((dimm_mask & ((1 << DIMM_SOCKETS) - 1)) !=
+		((dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) {
+		goto single_channel;
+	}
+	/* If the cpu is not capable of doing dual channels don't do dual
+	 channels */
+	nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
+	if (!(nbcap & NBCAP_TwoChanDRAMcap)) {
+		goto single_channel;
+	}
+	for(i = 0; (i < DIMM_SOCKETS) && (ctrl->spd_addr[i]); i++) {
+		u32 device0, device1;
+		int value0, value1;
+		int j;
+		/* If I don't have a dimm skip this one */
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+		device0 = ctrl->spd_addr[i];
+		device1 = ctrl->spd_addr[i+DIMM_SOCKETS]; //DCT1
+		for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) {
+			u32 addr;
+			addr = addresses[j];
+			value0 = spd_read_byte(device0, addr);
+			if (value0 < 0) {
+				return -1;
+			}
+			value1 = spd_read_byte(device1, addr);
+			if (value1 < 0) {
+				return -1;
+			}
+			if (value0 != value1) {
+				goto single_channel;
+			}
+		}
+	}
+	print_debug("Width128\n");
+	//GangEn
+	u32 dcs_lo;
+	dcs_lo = pci_read_config32(ctrl->f2, DRAM_CTRL_SEL_LOW);
+	dcs_lo |= DCSL_DctGangEn;
+	pci_write_config32(ctrl->f2, DRAM_CTRL_SEL_LOW, dcs_lo);
+
+	/* 32byte mode may be preferred in platforms that include graphics
+	 * controllers that generate a lot of 32-bytes system memory accesses
+	 * 32byte mode is not supported when the DRAM interface is 128 bits
+	 * wides, even 32byte mode is set, system still use 64 byte mode
+	 */
+	u32 dcl;
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+	dcl &= ~DCL_BurstLength32;
+	dcl |= DCL_Width128;
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+	meminfo->is_Width128 = 1;
+	return dimm_mask;
+single_channel:
+	meminfo->is_Width128 = 0;
+	return dimm_mask;
+}
+
+
+struct mem_param {
+	u16 cycle_time;
+	u8 divisor; /* In 1/40 ns increments */
+	u8 TrwtTO;
+	u8 Twrrd;
+	u8 Twrwr;
+	u8 Trdrd;
+	u8 DcqByPassMax;
+	u8 dch_memclk;
+	char name[9];
+};
+
+static const struct mem_param speed[] = {
+	{
+		.name	    = "200Mhz\n",
+		.cycle_time = 0x500,
+		.divisor    = 200, // how many 1/40ns per clock
+		.dch_memclk = DCH_MemClkFreq_200MHz, //0
+		.TrwtTO	    = 7,
+		.Twrrd	    = 2,
+		.Twrwr	    = 2,
+		.Trdrd	    = 3,
+		.DcqByPassMax = 4,
+
+	},
+	{
+		.name	    = "266Mhz\n",
+		.cycle_time = 0x375,
+		.divisor    = 150, //????
+		.dch_memclk = DCH_MemClkFreq_266MHz, //1
+		.TrwtTO     = 7,
+		.Twrrd	     = 2,
+		.Twrwr	     = 2,
+		.Trdrd	     = 3,
+		.DcqByPassMax = 4,
+	},
+	 {
+		 .name	     = "333Mhz\n",
+		 .cycle_time = 0x300,
+		 .divisor    = 120,
+		 .dch_memclk = DCH_MemClkFreq_333MHz, //2
+		 .TrwtTO     = 7,
+		 .Twrrd	     = 2,
+		 .Twrwr	     = 2,
+		 .Trdrd	     = 3,
+		 .DcqByPassMax = 4,
+
+	 },
+	{
+		.name	    = "400Mhz\n",
+		.cycle_time = 0x250,
+		.divisor    = 100,
+		.dch_memclk = DCH_MemClkFreq_400MHz,//3
+		 .TrwtTO     = 7,
+		 .Twrrd	     = 2,
+		 .Twrwr	     = 2,
+		 .Trdrd	     = 3,
+		 .DcqByPassMax = 4,
+	},
+	{
+		.cycle_time = 0x000,
+	},
+};
+
+
+static const struct mem_param *get_mem_param(u32 min_cycle_time)
+{
+
+	const struct mem_param *param;
+	for(param = &speed[0]; param->cycle_time ; param++) {
+		if (min_cycle_time > (param+1)->cycle_time) {
+			break;
+		}
+	}
+	if (!param->cycle_time) {
+		die("min_cycle_time to low");
+	}
+	print_spew(param->name);
+#ifdef DRAM_MIN_CYCLE_TIME
+	print_debug(param->name);
+#endif
+	return param;
+}
+
+static u8 get_exact_divisor(u8 i, u8 divisor)
+{
+	//input divisor could be 200(200), 150(266), 120(333), 100 (400)
+	static const u8 dv_a[] = {
+			/* 200  266  333 400 */
+		/*4 */	  250, 250, 250, 250,
+		/*5 */	  200, 200, 200, 100,
+		/*6 */	  200, 166, 166, 100,
+		/*7 */	  200, 171, 142, 100,
+
+		/*8 */	  200, 150, 125, 100,
+		/*9 */	  200, 156, 133, 100,
+		/*10*/	  200, 160, 120, 100,
+		/*11*/	  200, 163, 127, 100,
+
+		/*12*/	  200, 150, 133, 100,
+		/*13*/	  200, 153, 123, 100,
+		/*14*/	  200, 157, 128, 100,
+		/*15*/	  200, 160, 120, 100,
+	};
+
+	u32 fid_cur;
+	u8 index;
+
+	msr_t msr;
+	msr = rdmsr(0xc0010071);
+	fid_cur = msr.lo & 0x3f;
+
+	index = fid_cur>>1;
+
+	if(index>12) return divisor;
+
+	if(i>3) return divisor;
+
+	return dv_a[index * 4+i];
+}
+
+
+struct spd_set_memclk_result {
+	const struct mem_param *param;
+	long dimm_mask;
+};
+
+
+static u32 convert_to_linear(u32 value)
+{
+	static const u32 fraction[] = { 0x25, 0x33, 0x66, 0x75 };
+	u32 valuex;
+
+	/* We need to convert value to more readable */
+	if((value & 0xf) < 10) { //no .25, .33, .66, .75
+		 value <<= 4;
+	} else {
+		valuex = ((value & 0xf0) << 4) | fraction [(value & 0xf)-10];
+		value = valuex;
+	}
+	return value;
+}
+
+
+static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl,
+					long dimm_mask, struct mem_info *meminfo)
+{
+	/* Compute the minimum cycle time for these dimms */
+	struct spd_set_memclk_result result;
+	u32 min_cycle_time, min_latency, bios_cycle_time;
+	u8 i;
+	u32 value;
+
+	static const u8 latency_indicies[] = { 25, 23, 9 };
+
+	static const u16 min_cycle_times[] = { // use full speed to compare
+		[NBCAP_DdrMaxRate_1600] = 0x125, /* 1.25ns */
+		[NBCAP_DdrMaxRate_1333] = 0x150, /* 1.5ns */
+		[NBCAP_DdrMaxRate_1067] = 0x187, /* 1.875ns */
+		[NBCAP_DdrMaxRate_800]	= 0x250, /* 2.5ns */
+		[NBCAP_DdrMaxRate_667]	= 0x300, /* 3.0ns */
+		[NBCAP_DdrMaxRate_533]	= 0x375, /* 3.75ns */
+		[NBCAP_DdrMaxRate_400]	= 0x500, /* 5.0s */
+	};
+
+
+	value = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
+	min_cycle_time = min_cycle_times[(value >> NBCAP_DdrMaxRate_SHIFT) & NBCAP_DdrMaxRate_MASK];
+	bios_cycle_time = min_cycle_times[
+		read_option(CMOS_VSTART_max_mem_clock, CMOS_VLEN_max_mem_clock, 0)];
+	if (bios_cycle_time > min_cycle_time) {
+		min_cycle_time = bios_cycle_time;
+	}
+	min_latency = 3;
+
+	print_tx("1 min_cycle_time:", min_cycle_time);
+
+	/* Compute the least latency with the fastest clock supported
+	 * by both the memory controller and the dimms.
+	 */
+	for(i = 0; i < (DIMM_SOCKETS * (2-meminfo->is_Width128)); i++) {
+		// if unganged, we need scan DIMM on DCT1 too
+		int new_cycle_time, new_latency;
+		int index;
+		int latencies;
+		int latency;
+		u32 device;
+		device = ctrl->spd_addr[i];
+		if(!device ) continue;
+
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+
+		/* First find the supported CAS latencies
+		 * Byte 18 for DDR SDRAM is interpreted:
+		 * bit 2 == CAS Latency = 2
+		 * bit 3 == CAS Latency = 3
+		 * bit 4 == CAS Latency = 4
+		 * bit 5 == CAS Latency = 5
+		 */
+		new_cycle_time = 0x500;
+		new_latency = 6;
+
+		latencies = spd_read_byte(device, SPD_CAS_LAT);
+		if (latencies <= 0) continue;
+
+		print_tx("i:",i);
+		print_tx("\tlatencies:", latencies);
+		/* Compute the lowest cas latency supported */
+		latency = log2(latencies) - 2;
+
+		/* Loop through and find a fast clock with a low latency */
+		for(index = 0; index < 3; index++, latency++) {
+			int value;
+			if ((latency < 3) || (latency > 6) ||
+				(!(latencies & (1 << latency)))) {
+				continue;
+			}
+			value = spd_read_byte(device, latency_indicies[index]);
+			if (value < 0) {
+				goto hw_error;
+			}
+			print_tx("\tindex:", index);
+			print_tx("\t\tlatency:", latency);
+			print_tx("\t\tvalue1:", value);
+
+			value = convert_to_linear(value);
+
+			print_tx("\t\tvalue2:", value);
+
+			/* Only increase the latency if we decreas the clock */
+			if ((value >= min_cycle_time) && (value < new_cycle_time)) {
+				new_cycle_time = value;
+				new_latency = latency;
+			}
+			if (value >= min_cycle_time ) {
+				 if(value < new_cycle_time) {
+					 new_cycle_time = value;
+					 new_latency = latency;
+				 } else if (value == new_cycle_time) {
+					 if(new_latency > latency) {
+						 new_latency = latency;
+					 }
+				 }
+			}
+			 print_tx("\t\tnew_cycle_time:", new_cycle_time);
+			 print_tx("\t\tnew_latency:", new_latency);
+
+		}
+		if (new_latency > 6){
+			continue;
+		}
+		/* Does min_latency need to be increased? */
+		if (new_cycle_time > min_cycle_time) {
+			min_cycle_time = new_cycle_time;
+		}
+		/* Does min_cycle_time need to be increased? */
+		if (new_latency > min_latency) {
+			min_latency = new_latency;
+		}
+
+		print_tx("2 min_cycle_time:", min_cycle_time);
+		print_tx("2 min_latency:", min_latency);
+	}
+
+	/* Make a second pass through the dimms and disable
+	 * any that cannot support the selected memclk and cas latency.
+	 */
+
+	print_tx("3 min_cycle_time:", min_cycle_time);
+	print_tx("3 min_latency:", min_latency);
+
+	for(i = 0; i < (DIMM_SOCKETS * (2-meminfo->is_Width128)); i++) {
+		int latencies;
+		int latency;
+		int index;
+		int value;
+
+		u32 device;
+		 device = ctrl->spd_addr[i];
+		if (!device ) continue;
+
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+		latencies = spd_read_byte(device, SPD_CAS_LAT);
+		if (latencies < 0) goto hw_error;
+		if (latencies == 0) {
+			continue;
+//			goto dimm_err;
+		}
+
+		/* Compute the lowest cas latency supported */
+		latency = log2(latencies) -2;
+
+		/* Walk through searching for the selected latency */
+		for(index = 0; index < 3; index++, latency++) {
+			if (!(latencies & (1 << latency))) {
+				continue;
+			}
+			if (latency == min_latency)
+				break;
+		}
+		/* If I can't find the latency or my index is bad error */
+		if ((latency != min_latency) || (index >= 3)) {
+			goto dimm_err;
+		}
+
+		/* Read the min_cycle_time for this latency */
+		value = spd_read_byte(device, latency_indicies[index]);
+		if (value < 0) goto hw_error;
+
+		value = convert_to_linear(value);
+		/* All is good if the selected clock speed
+		 * is what I need or slower.
+		 */
+		if (value <= min_cycle_time) {
+			continue;
+		}
+		/* Otherwise I have an error, disable the dimm */
+	dimm_err:
+		dimm_mask = disable_dimm(ctrl, (i<DIMM_SOCKETS)?0:1, i%DIMM_SOCKETS, dimm_mask, meminfo);
+	}
+
+	print_tx("4 min_cycle_time:", min_cycle_time);
+
+	/* Now that I know the minimum cycle time lookup the memory parameters */
+	result.param = get_mem_param(min_cycle_time);
+
+	for (i=0; i<2; i++) {
+		u32 offset = 0x100 * i;
+		if(meminfo->is_Width128 && i) break;
+		/* Update DRAM Config High with our selected memory speed */
+		value = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH + offset);
+		value &= ~(DCH_MemClkFreq_MASK << DCH_MemClkFreq_SHIFT);
+
+		value |= result.param->dch_memclk << DCH_MemClkFreq_SHIFT;
+		pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH + offset, value);
+
+
+		/* Update DRAM Timing Low with our selected cas latency */
+		value = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW + offset);
+		value &= ~(DTL_TCL_MASK << DTL_TCL_SHIFT);
+		value |= (min_latency - DTL_TCL_BASE)  << DTL_TCL_SHIFT;
+		pci_write_config32(ctrl->f2, DRAM_TIMING_LOW + offset, value);
+	}
+	print_debug(result.param->name);
+
+	result.dimm_mask = dimm_mask;
+	return result;
+hw_error:
+	result.param = (const struct mem_param *)0;
+	result.dimm_mask = -1;
+	return result;
+}
+
+
+static u32 convert_to_1_4(u32 value)
+{
+	static const u8 fraction[] = { 0, 1, 2, 2, 3, 3, 0 };
+	u32 valuex;
+
+	/* We need to convert value to more readable */
+	valuex =  fraction [value & 0x7];
+	return valuex;
+}
+
+
+static int update_dimm_Trc(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+	u32 clocks, old_clocks;
+	u32 dtl;
+	int value;
+	int value2;
+
+	u32 offset = 0x100 * dct;
+	u32 device;
+	device = ctrl->spd_addr[dct * DIMM_SOCKETS + i];
+
+	value = spd_read_byte(device, SPD_TRC);
+	if (value < 0) return -1;
+
+	value2 = spd_read_byte(device, SPD_TRC -1);
+	value <<= 2;
+	value += convert_to_1_4(value2>>4);
+
+	value *=10;
+
+	clocks = (value + param->divisor - 1)/param->divisor;
+
+	if (clocks < DTL_TRC_MIN) {
+		clocks = DTL_TRC_MIN;
+	}
+	if (clocks > DTL_TRC_MAX) {
+		return 0;
+	}
+
+	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW + offset);
+	old_clocks = ((dtl >> DTL_TRC_SHIFT) & DTL_TRC_MASK) + DTL_TRC_BASE;
+	if (old_clocks >= clocks) {  //?? someone did it
+		// clocks = old_clocks;
+		return 1;
+	}
+	dtl &= ~(DTL_TRC_MASK << DTL_TRC_SHIFT);
+	dtl |=	((clocks - DTL_TRC_BASE) << DTL_TRC_SHIFT);
+	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW + offset, dtl);
+	return 1;
+}
+
+
+static int update_dimm_Trfc(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i,
+				struct mem_info *meminfo)
+{
+	u32 clocks, old_clocks;
+	u32 dth;
+	int value;
+
+	u32 offset = 0x100 * dct;
+	u32 device;
+	device = ctrl->spd_addr[dct * DIMM_SOCKETS + i];
+
+	//get the cs_size --> logic dimm size
+	value = spd_read_byte(device, SPD_PRI_WIDTH);
+	if (value < 0) {
+		return -1;
+	}
+
+	value = 6 - log2(value); //4-->4, 8-->3, 16-->2
+
+	clocks = meminfo->sz[dct * DIMM_SOCKETS + i].per_rank - 27 + 2 - value;
+
+	dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH + offset);
+
+	old_clocks = ((dth >> (DTH_TRFC0_SHIFT+i*3)) & DTH_TRFC_MASK);
+	if (old_clocks >= clocks) { // some one did it?
+//		clocks = old_clocks;
+		return 1;
+	}
+	dth &= ~(DTH_TRFC_MASK << (DTH_TRFC0_SHIFT+i*3));
+	dth |= clocks  << (DTH_TRFC0_SHIFT+i*3);
+	pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH + offset, dth);
+	return 1;
+}
+
+
+static int update_dimm_TT_1_4(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i,u32 TT_REG,
+				u32 SPD_TT, u32 TT_SHIFT, u32 TT_MASK,
+				u32 TT_BASE, u32 TT_MIN, u32 TT_MAX )
+{
+	u32 clocks, old_clocks;
+	u32 dtl;
+	int value;
+	u32 offset = 0x100 * dct;
+	u32 device;
+	device = ctrl->spd_addr[dct * DIMM_SOCKETS + i];
+
+	value = spd_read_byte(device, SPD_TT); //already in 1/4 ns
+	if (value < 0) return -1;
+	value *=10;
+	clocks = (value + param->divisor -1)/param->divisor;
+	if (clocks < TT_MIN) {
+		clocks = TT_MIN;
+	}
+	if (clocks > TT_MAX) {
+		 return 0;
+	}
+	dtl = pci_read_config32(ctrl->f2, TT_REG+offset);
+
+	old_clocks = ((dtl >> TT_SHIFT) & TT_MASK) + TT_BASE;
+	if (old_clocks >= clocks) { //some one did it?
+//		clocks = old_clocks;
+		return 1;
+	}
+	dtl &= ~(TT_MASK << TT_SHIFT);
+	dtl |= ((clocks - TT_BASE) << TT_SHIFT);
+	pci_write_config32(ctrl->f2, TT_REG+offset, dtl);
+	return 1;
+}
+
+
+static int update_dimm_Trcd(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+	return update_dimm_TT_1_4(ctrl, dct, param, i, DRAM_TIMING_LOW,
+				SPD_TRCD, DTL_TRCD_SHIFT, DTL_TRCD_MASK,
+				DTL_TRCD_BASE, DTL_TRCD_MIN, DTL_TRCD_MAX);
+}
+
+
+static int update_dimm_Trrd(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+	return update_dimm_TT_1_4(ctrl, dct, param, i, DRAM_TIMING_LOW,
+				SPD_TRRD, DTL_TRRD_SHIFT, DTL_TRRD_MASK,
+				DTL_TRRD_BASE, DTL_TRRD_MIN, DTL_TRRD_MAX);
+}
+
+
+static int update_dimm_Tras(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+	u32 clocks, old_clocks;
+	u32 dtl;
+	int value;
+	u32 offset = 0x100 * dct;
+	u32 device;
+	device = ctrl->spd_addr[dct * DIMM_SOCKETS + i];
+
+	value = spd_read_byte(device, SPD_TRAS); //in 1 ns
+	if (value < 0) return -1;
+	value<<=2; //convert it to in 1/4ns
+
+	value *= 10;
+	clocks = (value	 + param->divisor - 1)/param->divisor;
+	if (clocks < DTL_TRAS_MIN) {
+		clocks = DTL_TRAS_MIN;
+	}
+	if (clocks > DTL_TRAS_MAX) {
+		return 0;
+	}
+	dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW + offset);
+	old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE;
+	if (old_clocks >= clocks) { // someone did it?
+//		clocks = old_clocks;
+		return 1;
+	}
+	dtl &= ~(DTL_TRAS_MASK << DTL_TRAS_SHIFT);
+	dtl |= ((clocks - DTL_TRAS_BASE) << DTL_TRAS_SHIFT);
+	pci_write_config32(ctrl->f2, DRAM_TIMING_LOW + offset, dtl);
+	return 1;
+}
+
+
+static int update_dimm_Trp(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+	return update_dimm_TT_1_4(ctrl, dct, param, i, DRAM_TIMING_LOW,
+				SPD_TRP, DTL_TRP_SHIFT, DTL_TRP_MASK,
+				DTL_TRP_BASE, DTL_TRP_MIN, DTL_TRP_MAX);
+}
+
+static int update_dimm_Trtp(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i,
+				struct mem_info *meminfo)
+{
+	//need to figure if it is 32 byte burst or 64 bytes burst
+	int offset = 2;
+	if(!meminfo->is_Width128) {
+		u32 dword;
+		dword = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+		if((dword &  DCL_BurstLength32)) offset = 0;
+	}
+	return update_dimm_TT_1_4(ctrl, dct, param, i, DRAM_TIMING_LOW, SPD_TRTP,
+				DTL_TRTP_SHIFT, DTL_TRTP_MASK,
+				DTL_TRTP_BASE+offset, DTL_TRTP_MIN+offset,
+				DTL_TRTP_MAX+offset);
+}
+
+
+static int update_dimm_Twr(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+	return update_dimm_TT_1_4(ctrl, dct, param, i, DRAM_TIMING_LOW, SPD_TWR,
+				DTL_TWR_SHIFT, DTL_TWR_MASK, DTL_TWR_BASE,
+				DTL_TWR_MIN, DTL_TWR_MAX);
+}
+
+
+static int update_dimm_Tref(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+	u32 dth, dth_old;
+	int value;
+	u32 offset = 0x100 * dct;
+	u32 device;
+	device = ctrl->spd_addr[dct * DIMM_SOCKETS + i];
+
+	// 0: 15.625us, 1: 3.9us 2: 7.8 us....
+	value = spd_read_byte(device, SPD_TREF);
+	if (value < 0) return -1;
+
+	if(value == 1 ) {
+		value = 3;
+	} else {
+		value = 2;
+	}
+
+	dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH +offset);
+
+	dth_old = dth;
+	dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT);
+	dth |= (value << DTH_TREF_SHIFT);
+	if(dth_old != dth) {
+		pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH + offset, dth);
+	}
+	return 1;
+}
+
+static void set_4RankRDimm(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param, struct mem_info *meminfo)
+{
+#if QRANK_DIMM_SUPPRT == 1
+	int value;
+	int i;
+
+	u32 offset = 0x100 * dct;
+
+	if(!(meminfo->is_registered)) return;
+
+	value = 0;
+
+	for(i = 0; i < DIMM_SOCKETS; i++) {
+		if (!(dimm_mask & (1 << (i+dct * DIMM_SOCKETS)))) {
+			 continue;
+		}
+
+		if(meminfo->sz[i + dct * DIMM_SOCKETS].rank == 4) {
+			value = 1;
+			break;
+		}
+	}
+
+	if(value == 1) {
+		u32 dch;
+		dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH + offset);
+		dch |= DCH_FourRankRDimm;
+		pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH + offset, dch);
+	}
+#endif
+}
+
+
+static u32 get_extra_dimm_mask(const struct mem_controller *ctrl,
+				struct mem_info *meminfo)
+{
+	u8 i;
+	u32 mask_x4;
+	u32 mask_x16;
+	u32 mask_single_rank;
+	u32 mask_page_1k;
+	int value;
+	long dimm_mask;
+#if QRANK_DIMM_SUPPORT == 1
+	int rank;
+#endif
+
+
+	dimm_mask = meminfo->dimm_mask;
+	mask_x4 = 0;
+	mask_x16 = 0;
+	mask_single_rank = 0;
+	mask_page_1k = 0;
+
+	for(i = 0; i < (DIMM_SOCKETS * (2-meminfo->is_Width128)); i++) {
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+		if(meminfo->sz[i].rank == 1) {
+			mask_single_rank |= 1<<i;
+		}
+		if(meminfo->sz[i].col==10) {
+			mask_page_1k |= 1<<i;
+		}
+
+		u32 device;
+		device = ctrl->spd_addr[i];
+
+		value = spd_read_byte(device, SPD_PRI_WIDTH);
+
+		#if QRANK_DIMM_SUPPORT == 1
+			rank = meminfo->sz[i].rank;
+		#endif
+
+		if(value==4) {
+			mask_x4 |= (1<<i);
+			#if QRANK_DIMM_SUPPORT == 1
+			if(rank==4) {
+				mask_x4 |= 1<<(i+2);
+			}
+			#endif
+		} else if(value==16) {
+			mask_x16 |= (1<<i);
+			#if QRANK_DIMM_SUPPORT == 1
+			 if(rank==4) {
+				 mask_x16 |= 1<<(i+2);
+			 }
+			#endif
+		}
+
+	}
+
+	meminfo->x4_mask= mask_x4;
+	meminfo->x16_mask = mask_x16;
+	meminfo->single_rank_mask = mask_single_rank;
+	meminfo->page_1k_mask = mask_page_1k;
+	return mask_x4;
+}
+
+
+static void set_dimm_x4(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param, struct mem_info *meminfo)
+{
+	u32 dcl;
+	u32 offset = 0x100 * dct;
+
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW+offset);
+	dcl &= ~(DCL_X4Dimm_MASK<<DCL_X4Dimm_SHIFT);
+	dcl |= ((meminfo->x4_mask>>(dct*DIMM_SOCKETS)) & 0xf) << (DCL_X4Dimm_SHIFT);
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW+offset, dcl);
+}
+
+static int count_ones(u32 dimm_mask, u32 dct)
+{
+	int dimms;
+	u32 index;
+	dimm_mask >>= dct * DIMM_SOCKETS;
+	dimms = 0;
+	for(index = 0; index < DIMM_SOCKETS; index++, dimm_mask>>=1) {
+		if (dimm_mask & 1) {
+			dimms++;
+		}
+	}
+	return dimms;
+}
+
+
+static void set_DramTerm(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param, struct mem_info *meminfo)
+{
+	u32 dcl;
+	u32 odt;
+	odt = 1; // 75 ohms
+	u32 offset = 0x100 * dct;
+
+	//FIXME: need to find the value for DH
+	if(param->divisor == 100) { //DDR2 800
+		if(meminfo->is_Width128) {
+			if(count_ones(meminfo->dimm_mask, dct)==2) {
+				odt = 3;  //50 ohms
+			}
+		}
+
+	}
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW + offset);
+	dcl &= ~(DCL_DramTerm_MASK<<DCL_DramTerm_SHIFT);
+	dcl |= (odt & DCL_DramTerm_MASK) << (DCL_DramTerm_SHIFT);
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW+offset, dcl);
+}
+
+
+static void set_ecc(const struct mem_controller *ctrl,
+			const struct mem_param *param, long dimm_mask,
+			struct mem_info *meminfo)
+{
+	int i;
+	int value;
+
+	u32 dcl, nbcap;
+	nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+	dcl &= ~DCL_DimmEccEn;
+	if (nbcap & NBCAP_ECCcap) {
+		dcl |= DCL_DimmEccEn;
+	}
+	if (read_option(CMOS_VSTART_ECC_memory, CMOS_VLEN_ECC_memory, 1) == 0) {
+		dcl &= ~DCL_DimmEccEn;
+	}
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+
+	meminfo->is_ecc = 1;
+	if(!(dcl & DCL_DimmEccEn)) {
+		meminfo->is_ecc = 0;
+		// already disabled the ECC, so don't need to read SPD any more
+		return;
+	}
+
+	for(i = 0; i < (DIMM_SOCKETS* (2-meminfo->is_Width128)); i++) {
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+		u32 device;
+		device = ctrl->spd_addr[i];
+
+		value = spd_read_byte(device, SPD_DIMM_CONF_TYPE);
+
+		if(!(value & SPD_DIMM_CONF_TYPE_ECC)) {
+			dcl &= ~DCL_DimmEccEn;
+			pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+			if(!meminfo->is_Width128) {
+				pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW+0x100, dcl);
+			}
+			meminfo->is_ecc = 0;
+			return;
+		}
+
+	}
+}
+
+static int update_dimm_Twtr(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param, int i)
+{
+
+	return update_dimm_TT_1_4(ctrl, dct, param, i, DRAM_TIMING_HIGH,
+				SPD_TWTR, DTH_TWTR_SHIFT, DTH_TWTR_MASK,
+				DTH_TWTR_BASE, DTH_TWTR_MIN, DTH_TWTR_MAX);
+
+}
+
+static void set_TT(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param, u32 TT_REG, u32 TT_SHIFT,
+			u32 TT_MASK, u32 TT_BASE, u32 TT_MIN, u32 TT_MAX,
+			u32 val, const char *str)
+{
+	u32 reg;
+	u32 offset = 0x100 * dct;
+
+	if ((val < TT_MIN) || (val > TT_MAX)) {
+		print_err(str);
+		die(" Unknown\n");
+	}
+
+	reg = pci_read_config32(ctrl->f2, TT_REG + offset);
+	reg &= ~(TT_MASK << TT_SHIFT);
+	reg |= ((val - TT_BASE) << TT_SHIFT);
+	pci_write_config32(ctrl->f2, TT_REG + offset, reg);
+	return;
+}
+
+
+static void set_TrwtTO(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param)
+{
+	set_TT(ctrl, dct, param, DRAM_TIMING_HIGH, DTH_TRWTTO_SHIFT,
+		DTH_TRWTTO_MASK,DTH_TRWTTO_BASE, DTH_TRWTTO_MIN,
+		DTH_TRWTTO_MAX, param->TrwtTO, "TrwtTO");
+}
+
+
+static void set_Twrrd(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param)
+{
+	set_TT(ctrl, dct, param, DRAM_TIMING_HIGH, DTH_TWRRD_SHIFT,
+		DTH_TWRRD_MASK,DTH_TWRRD_BASE, DTH_TWRRD_MIN, DTH_TWRRD_MAX,
+		param->Twrrd, "Twrrd");
+}
+
+
+static void set_Twrwr(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param)
+{
+	set_TT(ctrl, dct, param, DRAM_TIMING_HIGH, DTH_TWRWR_SHIFT,
+		DTH_TWRWR_MASK,DTH_TWRWR_BASE, DTH_TWRWR_MIN, DTH_TWRWR_MAX,
+		param->Twrwr, "Twrwr");
+}
+
+
+static void set_Trdrd(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param)
+{
+	set_TT(ctrl, dct, param, DRAM_TIMING_HIGH, DTH_TRDRD_SHIFT,
+		DTH_TRDRD_MASK,DTH_TRDRD_BASE, DTH_TRDRD_MIN, DTH_TRDRD_MAX,
+		param->Trdrd, "Trdrd");
+}
+
+static void set_DcqBypassMax(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param)
+{
+	// value need to be in CMOS
+	set_TT(ctrl, dct, param, DRAM_CONFIG_HIGH, DCH_DcqBypassMax_SHIFT,
+		DCH_DcqBypassMax_MASK,DCH_DcqBypassMax_BASE,
+		DCH_DcqBypassMax_MIN, DCH_DcqBypassMax_MAX,
+		param->DcqByPassMax, "DcqBypassMax");
+}
+
+static void set_Tfaw(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param, long dimm_mask,
+			struct mem_info *meminfo)
+{
+	static const u8 faw_1k[] = {8, 10, 13, 14};
+	static const u8 faw_2k[] = {10, 14, 17, 18};
+	u32 memclkfreq_index;
+	u32 faw;
+
+
+	memclkfreq_index = param->dch_memclk;
+
+	if(meminfo->page_1k_mask != 0) { //1k page
+		faw = faw_1k[memclkfreq_index];
+	} else {
+		faw = faw_2k[memclkfreq_index];
+	}
+
+	set_TT(ctrl, dct, param, DRAM_CONFIG_HIGH, DCH_FourActWindow_SHIFT, DCH_FourActWindow_MASK, DCH_FourActWindow_BASE, DCH_FourActWindow_MIN, DCH_FourActWindow_MAX, faw, "FourActWindow");
+
+}
+
+static void set_SlowAccessMode(const struct mem_controller *ctrl, u32 dct)
+{
+#if CPU_SOCKET_TYPE==0x11
+	u32 dch;
+	u32 offset = 0x100 * dct;
+
+	dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH + offset);
+
+	dch |= (1<<20);
+
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH+offset, dch);
+#endif
+}
+
+
+/*
+	DRAM_OUTPUT_DRV_COMP_CTRL 0, 0x20
+	DRAM_ADDR_TIMING_CTRL 04, 0x24
+*/
+
+
+static void set_misc_timing(const struct mem_controller *ctrl, u32 dct,
+				struct mem_info *meminfo)
+{
+	u32 dword;
+	u32 dwordx;
+	u32 SlowAccessMode = 0;
+	u32 offset = 0x100 * dct;
+	long dimm_mask;
+
+	dimm_mask = (meminfo->dimm_mask>>(DIMM_SOCKETS*dct)) & ((1<<DIMM_SOCKETS) -1);
+
+#if DIMM_SUPPORT == 0x0104   /* DDR2 and REG */
+	/* for REG DIMM */
+	dword = 0x00111222;
+	dwordx = 0x002f0000;
+	switch (meminfo->memclk_set) {
+	case DCH_MemClkFreq_266MHz:
+		if( (dimm_mask == 0x03) || (dimm_mask == 0x02) || (dimm_mask == 0x01)) {
+			dwordx = 0x002f2700;
+		}
+		break;
+	case DCH_MemClkFreq_333MHz:
+		if( (dimm_mask == 0x03) || (dimm_mask == 0x02) || (dimm_mask == 0x01)) {
+			if ((meminfo->single_rank_mask & 0x03)!=0x03) { //any double rank there?
+				dwordx = 0x002f2f00;
+			}
+		}
+		break;
+	}
+#endif
+
+#if DIMM_SUPPORT == 0x0004  /* DDR2 and unbuffered */
+	/* for UNBUF DIMM */
+	dword = 0x00111222;
+	dwordx = 0x002f2f2f;
+	switch (meminfo->memclk_set) {
+	case DCH_MemClkFreq_200MHz:
+		if(dimm_mask == 0x03) {
+			SlowAccessMode = 1;
+			dword = 0x00111322;
+		}
+		break;
+	case DCH_MemClkFreq_266MHz:
+		if(dimm_mask == 0x03) {
+			SlowAccessMode = 1;
+			dword = 0x00111322;
+			if((meminfo->x4_mask == 0 ) && (meminfo->x16_mask == 0)) {
+				switch (meminfo->single_rank_mask) {
+				case 0x03:
+					dwordx = 0x00002f2f; //x8 single Rank
+					break;
+				case 0x00:
+					dwordx = 0x00342f2f; //x8 double Rank
+					break;
+				default:
+					dwordx = 0x00372f2f; //x8 single Rank and double Rank mixed
+				}
+			} else if((meminfo->x4_mask == 0 ) && (meminfo->x16_mask == 0x01) && (meminfo->single_rank_mask == 0x01)) {
+					 dwordx = 0x00382f2f; //x8 Double Rank and x16 single Rank mixed
+			 } else if((meminfo->x4_mask == 0 ) && (meminfo->x16_mask == 0x02) && (meminfo->single_rank_mask == 0x02)) {
+					 dwordx = 0x00382f2f; //x16 single Rank and x8 double Rank mixed
+			}
+
+		}
+		break;
+	case DCH_MemClkFreq_333MHz:
+		dwordx = 0x00202020;
+		if(dimm_mask == 0x03) {
+			SlowAccessMode = 1;
+			dword = 0x00111322;
+			if((meminfo->x4_mask == 0 ) && (meminfo->x16_mask == 0)) {
+				switch (meminfo->single_rank_mask) {
+				case 0x03:
+					dwordx = 0x00302020; //x8 single Rank
+					break;
+				case 0x00:
+					dwordx = 0x002b2020; //x8 double Rank
+					break;
+				default:
+					dwordx = 0x00372f2f; //x8 single Rank and double Rank mixed
+				}
+			} else if((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x01) && (meminfo->single_rank_mask == 0x01)) {
+					dwordx = 0x002c2020; //x8 Double Rank and x16 single Rank mixed
+			} else if((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x02) && (meminfo->single_rank_mask == 0x02)) {
+					dwordx = 0x002c2020; //x16 single Rank and x8 double Rank mixed
+			} else if((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x01) && (meminfo->single_rank_mask == 0x03)) {
+					dwordx = 0x002a2020; //x8 Double Rank and x8 single Rank mixed
+			} else if((meminfo->x4_mask == 0) && (meminfo->x16_mask == 0x02) && (meminfo->single_rank_mask == 0x03)) {
+					dwordx = 0x002a2020; //x8 single Rank and x8 double Rank mixed
+			}
+
+		}
+		break;
+	case DCH_MemClkFreq_400MHz:
+		dwordx = 0x00202520;
+		SlowAccessMode = 1;
+		if(dimm_mask == 0x03) {
+			dword = 0x00113322;
+		} else {
+			 word = 0x00113222;
+		}
+		break;
+	}
+
+	print_raminit("\tdimm_mask = ", meminfo->dimm_mask);
+	print_raminit("\tx4_mask = ", meminfo->x4_mask);
+	print_raminit("\tx16_mask = ", meminfo->x16_mask);
+	print_raminit("\tsingle_rank_mask = ", meminfo->single_rank_mask);
+	print_raminit("\tODC = ", dword);
+	print_raminit("\tAddr Timing= ", dwordx);
+
+	if(SlowAccessMode) {
+		set_SlowAccessMode(ctrl, dct);
+	}
+#endif
+	/* Program the Output Driver Compensation Control Registers (Function 2:Offset 0x9c, index 0, 0x20) */
+	pci_write_config32_index_wait(ctrl->f2, 0x98 + offset, 0, dword);
+	if(meminfo->is_Width128) {
+		pci_write_config32_index_wait(ctrl->f2, 0x98 + offset, 0x20, dword);
+	}
+
+	/* Program the Address Timing Control Registers (Function 2:Offset 0x9c, index 4, 0x24) */
+	pci_write_config32_index_wait(ctrl->f2, 0x98 + offset, 4, dwordx);
+	if(meminfo->is_Width128) {
+		pci_write_config32_index_wait(ctrl->f2, 0x98+ offset, 0x24, dwordx);
+	}
+
+}
+
+
+static void set_RDqsEn(const struct mem_controller *ctrl, u32 dct,
+			 const struct mem_param *param, struct mem_info *meminfo)
+{
+#if CPU_SOCKET_TYPE==0x10
+	//only need to set for reg and x8
+	u32 dch;
+	u32 offset = 0x100 * dct;
+
+	dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH + offset);
+
+	dch &= ~DCH_RDqsEn;
+	if((!( (meminfo->x4_mask>>(dct*DIMM_SOCKETS)) & ((1<<DIMM_SOCKETS) - 1) ) )
+	&& (!((meminfo->x16_mask>>(dct*DIMM_SOCKETS)) & ((1<<DIMM_SOCKETS) - 1) ) ) ) {
+		dch |= DCH_RDqsEn;
+	}
+
+		pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH + offset, dch);
+#endif
+}
+
+
+static void set_idle_cycle_init(const struct mem_controller *ctrl, u32 dct,
+				const struct mem_param *param)
+{
+	//FIXME: DH
+	u32 dcl;
+	u32 offset = 0x100 * dct;
+
+	/* AMD says to Hardcode this */
+	dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW+offset);
+	dcl &= ~(DCL_IdleCycInit_MASK << DCL_IdleCycInit_SHIFT);
+	dcl |= DCL_IdleCycInit_16CLK << DCL_IdleCycInit_SHIFT;
+	pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW+offset, dcl);
+}
+
+
+static void set_RdWrQByp(const struct mem_controller *ctrl, u32 dct,
+			const struct mem_param *param)
+{
+}
+
+
+
+static long spd_set_dram_timing(const struct mem_controller *ctrl,
+				const struct mem_param *param, long dimm_mask,
+				struct mem_info *meminfo)
+{
+	u8 i;
+	u32 dct;
+
+	for(i = 0; i < (DIMM_SOCKETS * (2-meminfo->is_Width128)); i++) {
+		int rc;
+		if (!(dimm_mask & (1 << i))) {
+			continue;
+		}
+		u8 ii;
+
+		if(i<DIMM_SOCKETS) {
+			ii = i;
+			dct = 0;
+		}
+		else {
+			ii= i-DIMM_SOCKETS;
+			dct = 1;
+		}
+		print_tx("dimm socket: ", i);
+		/* DRAM Timing Low Register */
+		print_t("\ttrc\n");
+		if ((rc = update_dimm_Trc (ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		print_t("\ttrcd\n");
+		if ((rc = update_dimm_Trcd(ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		print_t("\ttrrd\n");
+		if ((rc = update_dimm_Trrd(ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		print_t("\ttras\n");
+		if ((rc = update_dimm_Tras(ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		print_t("\ttrp\n");
+		if ((rc = update_dimm_Trp (ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		print_t("\ttrtp\n");
+		if ((rc = update_dimm_Trtp(ctrl, dct, param, ii, meminfo)) <= 0) goto dimm_err;
+
+		print_t("\ttwr\n");
+		if ((rc = update_dimm_Twr (ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		/* DRAM Timing High Register */
+		print_t("\ttref\n");
+		if ((rc = update_dimm_Tref(ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		print_t("\ttwtr\n");
+		if ((rc = update_dimm_Twtr(ctrl, dct, param, ii)) <= 0) goto dimm_err;
+
+		print_t("\ttrfc\n");
+		if ((rc = update_dimm_Trfc(ctrl, dct, param, ii, meminfo)) <= 0) goto dimm_err;
+
+		/* DRAM Config Low */
+
+		continue;
+	dimm_err:
+		if (rc < 0) {
+			return -1;
+		}
+		dimm_mask = disable_dimm(ctrl, dct, ii, dimm_mask, meminfo);
+	}
+
+	meminfo->dimm_mask = dimm_mask; // store final dimm_mask
+
+	get_extra_dimm_mask(ctrl, meminfo); // will be used by RDqsEn and dimm_x4
+	/* DRAM Timing Low Register */
+
+	for(dct=0; dct<2; dct++){
+		if(meminfo->is_Width128 && dct) break;
+
+		if( !(meminfo->dimm_mask>>(dct*DIMM_SOCKETS) ) & ( (1<<DIMM_SOCKETS) -1)) continue;
+
+		/* DRAM Timing High Register */
+		set_TrwtTO(ctrl, dct, param);
+		set_Twrrd (ctrl, dct, param);
+		set_Twrwr (ctrl, dct, param);
+		set_Trdrd (ctrl, dct, param);
+
+		set_4RankRDimm(ctrl, dct, param, meminfo);
+
+		/* DRAM Config High */
+		set_Tfaw(ctrl, dct, param, dimm_mask, meminfo);
+		set_DcqBypassMax(ctrl, dct, param);
+		set_RDqsEn(ctrl, dct, param, meminfo);
+
+		/* DRAM Config Low */
+		set_dimm_x4(ctrl, dct, param, meminfo);
+		set_DramTerm(ctrl, dct, param, meminfo);
+		set_idle_cycle_init(ctrl, dct, param);
+	}
+
+	set_ecc(ctrl, param, dimm_mask, meminfo); //need to cordination between DCT0 and DCT1
+
+	return dimm_mask;
+}
+
+static void sdram_set_spd_registers(const struct mem_controller *ctrl,
+					struct sys_info *sysinfo)
+{
+	struct spd_set_memclk_result result;
+	const struct mem_param *param;
+	struct mem_param paramx;
+	struct mem_info *meminfo;
+	long dimm_mask;
+	if (!sysinfo->ctrl_present[ctrl->node_id]) {
+//		print_debug("No memory controller present\n");
+		return;
+	}
+
+	meminfo = &sysinfo->meminfo[ctrl->node_id];
+
+	print_debug_addr("sdram_set_spd_registers: paramx :", &paramx);
+
+	activate_spd_rom(ctrl);
+
+	print_t("\tspd_reg 1\n");
+	dimm_mask = spd_detect_dimms(ctrl);
+	if (!(dimm_mask & ((1 << (DIMM_SOCKETS * 2)) - 1))) {
+		print_debug("No memory for this node\n");
+		return;
+	}
+	print_t("\tspd_reg 2\n");
+
+	dimm_mask = spd_enable_2channels(ctrl, dimm_mask, meminfo);
+	if (dimm_mask < 0)
+		goto hw_spd_err;
+
+	print_t("\tspd_reg 3\n");
+	dimm_mask = spd_set_ram_size(ctrl , dimm_mask, meminfo);
+	if (dimm_mask < 0)
+		goto hw_spd_err;
+
+	print_t("\tspd_reg 4\n");
+	dimm_mask = spd_handle_unbuffered_dimms(ctrl, dimm_mask, meminfo);
+	if (dimm_mask < 0)
+		goto hw_spd_err;
+	print_t("\tspd_reg 5\n");
+	result = spd_set_memclk(ctrl, dimm_mask, meminfo);
+	param	  = result.param;
+	dimm_mask = result.dimm_mask;
+	if (dimm_mask < 0)
+		goto hw_spd_err;
+
+	//store memclk set to sysinfo, incase we need rebuilt param again
+	meminfo->memclk_set = param->dch_memclk;
+
+	memcpy(&paramx, param, sizeof(paramx));
+
+	paramx.divisor = get_exact_divisor(param->dch_memclk, paramx.divisor);
+	print_t("\tspd_reg 6\n");
+
+	// dimm_mask will be stored to meminfo->dimm_mask
+	dimm_mask = spd_set_dram_timing(ctrl, &paramx , dimm_mask, meminfo);
+	if (dimm_mask < 0)
+		goto hw_spd_err;
+	print_t("\tspd_reg 7\n");
+
+	order_dimms(ctrl, meminfo, sysinfo);
+
+	return;
+hw_spd_err:
+	/* Unrecoverable error reading SPD data */
+	print_err("SPD error - reset\n");
+	hard_reset();
+	return;
+}
+
+#include "raminit_ddr2_dqs.c"
+
+#if HW_MEM_HOLE_SIZEK != 0
+static void set_hw_mem_hole(int controllers, const struct mem_controller *ctrl,
+				struct sys_info *sysinfo)
+{
+
+	u32 hole_startk;
+	u32 i;
+
+	sysinfo->hole_startk = 0;
+
+	hole_startk = 4*1024*1024 - HW_MEM_HOLE_SIZEK;
+
+#if HW_MEM_HOLE_SIZE_AUTO_INC == 1
+	//We need to double check if the hole_startk is valid, if it is equal to basek, we need to decrease it some
+	u32 basem_pri;
+	 for(i=0; i<sysinfo->nodes; i++) {
+			struct dram_base_maskt d;
+			u32 base_m;
+			d = get_dram_base_mask(i);
+			if(!(d.mask & 1)) continue;
+			base_m = (d.base & 0x1fffff00)>>1;
+			if(base_m == (hole_startk>>10)) {
+				/* decrease mem hole startk to make sure it is
+				  on middle of previous node*/
+				hole_startk -= (base_m - basem_pri)<<(10-1);
+				break; //only one hole
+			}
+			basem_pri = base_m;
+
+#endif
+	//find node index that need do set hole
+	for(i=0; i<sysinfo->nodes; i++) {
+			struct dram_base_mask_t d;
+			u32 base_m, limit_m;
+			d = get_dram_base_mask(i);
+			if(!(d.mask & 1)) continue;
+			base_m = (d.base & 0x1fffff00) >> 1;
+			limit_m = ((d.mask + (1<<8)) & 0x1fffff00) >> 1;
+			if ((base_m <= (hole_startk>>10)) && (limit_m > (hole_startk>>10))) {
+				u32 end_m;
+				hoist_memory(hole_startk, i, get_one_DCT(&sysinfo->meminfo[i]), sysinfo->nodes);
+				end_m = memory_end_m(ctrl, sysinfo->nodes);
+				set_top_mem(end_m, hole_startk);
+				sysinfo->hole_startk = hole_startk;
+				break; //only one hole
+			}
+	}
+}
+
+#endif
+
+#define TIMEOUT_LOOPS 300000
+static void sdram_enable(int controllers, const struct mem_controller *ctrl,
+			struct sys_info *sysinfo)
+{
+	int i, dct;
+
+
+	/* Error if I don't have memory */
+	print_debug("sysinfo->nodes="); print_debug_hex8(sysinfo->nodes); print_debug("\n");
+	if (memory_end_m(ctrl, sysinfo->nodes) == 0) {
+		die("No memory\n");
+	}
+
+	/* Before enabling memory start the memory clocks */
+	for(i = 0; i < controllers; i++) {
+		u32 dch;
+		if (!sysinfo->ctrl_present[ i ])
+			continue;
+		for(dct=0;dct<2; dct++) {
+			if(sysinfo->meminfo[i].is_Width128 && dct) break;
+			u32 offset = 0x100 * dct;
+			dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH + offset);
+			// if no memory installed, disabled the interface
+			if(((sysinfo->meminfo[i].dimm_mask>>(dct*DIMM_SOCKETS)) & ((1<<DIMM_SOCKETS)-1))==0x00){
+				dch |= DCH_DisDramInterface;
+				pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH+offset, dch);
+
+			} else {
+				/* address timing and Output driver comp Control */
+				/* If the DCT channels are ganged, then DRAM Address/Command Timing Control Reg (F2x[1,0]9c_x04) must be programming before setting F2x[1,0]94[MemClkFreqVal]=1 */
+				set_misc_timing(ctrl+i, dct, sysinfo->meminfo+i );
+
+				dch |= DCH_MemClkFreqVal;
+				pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH+offset, dch);
+			}
+		}
+	}
+
+	/* We need to wait a mimmium of 20 MEMCLKS to enable the  InitDram */
+	memreset(controllers, ctrl);
+
+	for(i = 0; i < controllers; i++) {
+		u32 dcl, dch;
+		if (!sysinfo->ctrl_present[ i ])
+			continue;
+
+		for(dct=0;dct<2; dct++) {
+			if(sysinfo->meminfo[i].is_Width128 && dct) break;
+			u32 offset = 0x100 * dct;
+
+			/* Skip everything if I don't have any memory on this controller */
+			dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH+offset);
+			if (!(dch & DCH_MemClkFreqVal)) {
+				continue;
+			}
+
+			/* ChipKill */
+			dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW+offset);
+			if (dcl & DCL_DimmEccEn) {
+				u32 mnc;
+				print_spew("ECC enabled\n");
+				mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG);
+				mnc |= MNC_DramEccEn;
+				if (dcl & DCL_Width128) {
+					mnc |= MNC_ChipKillEccEn;
+				}
+				pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc);
+			}
+
+			pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW+offset, dcl);
+			dcl |= DCL_InitDram;
+			pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW+offset, dcl);
+		}
+
+	}
+	for(i = 0; i < controllers; i++) {
+		u32 dcl, dcsl;
+		if (!sysinfo->ctrl_present[ i ])
+			continue;
+		for(dct=0;dct<2; dct++) {
+			if(sysinfo->meminfo[i].is_Width128 && dct) break;
+			u32 offset = 0x100 * dct;
+			/* Skip everything if I don't have any memory on this controller */
+			if(((sysinfo->meminfo[i].dimm_mask>>(dct*DIMM_SOCKETS)) & ((1<<DIMM_SOCKETS)-1))==0x00)
+				continue;
+
+			print_debug("Initializing memory: ");
+			if(!sysinfo->meminfo[i].is_Width128) {
+				print_debug("dct "); print_debug_hex8(dct);
+			}
+
+			int loops = 0;
+			do {
+				dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW+offset);
+				loops++;
+				if ((loops & 1023) == 0) {
+					print_debug(".");
+				}
+			} while(((dcl & DCL_InitDram) != 0) && (loops < TIMEOUT_LOOPS));
+			if (loops >= TIMEOUT_LOOPS) {
+				print_debug(" failed\n");
+				continue;
+			}
+
+			/* Wait until it is safe to touch memory */
+			do {
+				dcsl = pci_read_config32(ctrl[i].f2, DRAM_CTRL_SEL_LOW);
+			} while((dcsl & DCSL_DramEnable) == 0);
+
+			dcsl = pci_read_config32(ctrl[i].f2, DRAM_CTRL_SEL_LOW);
+			dcsl |= DCSL_MemClrInit;
+			pci_write_config32(ctrl[i].f2, DRAM_CTRL_SEL_LOW, dcsl);
+
+			do {
+				dcsl = pci_read_config32(ctrl[i].f2, DRAM_CTRL_SEL_LOW);
+			} while((dcsl & DCSL_MemCleared) == 0);
+
+			print_debug(" done\n");
+		}
+	}
+
+#if HW_MEM_HOLE_SIZEK != 0
+	// init hw mem hole here
+	/* DramHoleValid bit only can be set after MemClrStatus is set by
+	  Hardware */
+	set_hw_mem_hole(controllers, ctrl, sysinfo);
+#endif
+
+	//FIXME add enable node interleaving here!
+	/*needed?
+	 * 1. check how many nodes we have , if not all has ram installed get out
+	 * 2. check cs_base lo is 0, node 0 f2 0x40,,,,, if any one is not using
+	 *    lo is CS_BASE, get out
+	 * 3. check if other node is the same as node 0 about f2 0x40,,,,,
+	 *     otherwise get out
+	 * 4. if all ready enable node_interleaving in f1 0x40.....
+	 *    of every node
+	 * 5. for node interleaving we need to set mem hole to every node
+	 *    ( need recalcute hole offset in f0 for every node)
+	 */
+	//store tom to sysinfo, and it will be used by dqs_timing by other core0
+	{
+		msr_t msr;
+		//[1M, TOM)
+		msr = rdmsr(TOP_MEM);
+		sysinfo->tom_m = ((msr.hi<<12) | (msr.lo>>20));
+
+		//[4G, TOM2)
+		msr = rdmsr(TOP_MEM2);
+		sysinfo->tom2_m = ((msr.hi<<12)| (msr.lo>>20));
+	}
+
+	for(i = 0; i < controllers; i++) {
+
+		sysinfo->mem_trained[i] = 0; // dont need trained
+
+		if (!sysinfo->ctrl_present[ i ])
+			 continue;
+
+		/* Skip everything if I don't have any memory on this controller */
+		if(sysinfo->meminfo[i].dimm_mask==0x00)
+			continue;
+
+		sysinfo->mem_trained[i] = 0x80; // need trained
+
+	}
+
+#if MEM_TRAIN_SEQ != 1
+	//need to enable mtrr, so dqs training could access the test address
+	setup_mtrr_dqs(sysinfo->tom_m, sysinfo->tom2_m);
+#endif
+
+
+	for(i = 0; i < controllers; i++) {
+		/* Skip everything if I don't have any memory on this
+		   controller */
+		if(sysinfo->mem_trained[i]!=0x80)
+			// don't need trained because no dimm
+			continue;
+
+		dqs_timing(i, &ctrl[i], sysinfo, 1);
+
+#if MEM_TRAIN_SEQ == 1
+		break; // only train the first node with ram
+#endif
+	}
+
+#if MEM_TRAIN_SEQ != 1
+	clear_mtrr_dqs(sysinfo->tom2_m);
+	wait_all_core0_mem_trained(sysinfo);
+#endif
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_ddr2_dqs.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_ddr2_dqs.c	2007-12-12 11:53:40.000000000 -0700
@@ -0,0 +1,2168 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#define DQS_TRAIN_DEBUG 5
+
+static  void print_debug_dqs(const char *str, u32 val, u32 level)
+{
+#if DQS_TRAIN_DEBUG > 0
+	if(DQS_TRAIN_DEBUG >= level) {
+		printk_debug("%s%x\n", str, val);
+	}
+#endif
+}
+
+static  void print_debug_dqs_pair(const char *str, u32 val, const char *str2, u32 val2, u32 level)
+{
+#if DQS_TRAIN_DEBUG > 0
+	if(DQS_TRAIN_DEBUG >= level) {
+		printk_debug("%s%08x%s%08x\n", str, val, str2, val2);
+	}
+#endif
+}
+
+static  void print_debug_dqs_tsc(const char *str, u32 i, u32 val, u32 val2, u32 level)
+{
+#if DQS_TRAIN_DEBUG > 0
+	if(DQS_TRAIN_DEBUG > level) {
+		printk_debug("%s[%02x]=%08x%08x\n", str, i, val, val2);
+	}
+#endif
+}
+
+static  void print_debug_dqs_tsc_x(const char *str, u32 i, u32 val, u32 val2)
+{
+	printk_debug("%s[%02x]=%08x%08x\n", str, i, val, val2);
+
+}
+
+u32 read32_fs(u32 addr_lo)
+{
+	u32 value;
+	__asm__ volatile (
+		"movl %%fs:(%1), %0\n\t"
+		:"=b"(value): "a" (addr_lo)
+	);
+	return value;
+}
+
+
+static void fill_mem_cs_sysinfo(u32 nodeid, const struct mem_controller *ctrl, struct sys_info *sysinfo)
+{
+	struct dram_base_mask_t d;
+	int i;
+	u32 nodeidx;
+	u32 dct;
+	u32 offset;
+	u32 sel_hi_en;
+	u32 sel_m;
+#if MEM_CS_COPY == 1
+	nodeidx = 0;
+#else
+	nodeidx = nodeid;
+#endif
+	for(dct=0; dct<2; dct++) {
+		if(sysinfo->meminfo[nodeid].is_Width128 && dct) {
+			sysinfo->mem_base[nodeidx][1] = sysinfo->mem_base[nodeidx][0];
+			for(i=0;i<8; i++)
+				sysinfo->cs_base[nodeidx][1][i] = sysinfo->cs_base[nodeidx][1][i];
+
+			break;
+		}
+
+		d = get_dram_base_mask(nodeid);
+		sysinfo->mem_base[nodeidx][dct] = (d.base<<11) | (d.mask & 1);
+			//how about interleave between dct0 and dct1, and have different size?
+		sel_hi_en = get_DctSelHiEn(nodeid);
+		if((sel_hi_en & 0x7) == ((dct<<1)|1)) {
+			sel_m = get_DctSelBaseAddr(nodeid);
+			sysinfo->mem_base[nodeidx][dct] = (sel_m<<(20-8)) | (d.mask & 1);
+		}
+		offset = 0x100 * dct;
+
+		for(i=0;i<8; i++) {
+			sysinfo->cs_base[nodeidx][dct][i] = pci_read_config32(ctrl->f2, 0x40 + (i<<2) + offset);
+		}
+	}
+
+}
+
+static u32 Get_MCTSysAddr(const struct mem_controller *ctrl,  u32 dct, u32 cs_idx, struct sys_info * sysinfo)
+{
+	u32 dword;
+	u32 mem_base;
+#if MEM_CS_COPY == 1
+	u32 nodeid = 0;
+#else
+	u32 nodeid = ctrl->node_id;
+#endif
+
+	//get the local base addr of the chipselect
+	dword = sysinfo->cs_base[nodeid][dct][cs_idx];
+	dword &= 0xfffffff0;
+
+	//sys addr= node base + local cs base
+	mem_base = sysinfo->mem_base[nodeid][dct];
+	mem_base &= 0xffff0000;
+
+	dword += mem_base;
+#if HW_MEM_HOLE_SIZEK != 0
+		u32 hole_startk;
+		hole_startk = sysinfo->hole_startk;
+		if(hole_startk>0) {
+			if( (dword >= (hole_startk<<2)) && (dword < ((4*1024*1024)<<2))) {
+				dword += ((4*1024*1024 - hole_startk)<<2);
+			}
+		}
+#endif
+
+	//add 1MB offset to avoid compat area
+	dword += (1<<(20-8));
+
+	//So final result is upper 32 bit addr
+	return dword;
+}
+
+
+static u32 Get_RcvrSysAddr(const struct mem_controller * ctrl, u32 channel, u32 cs_idx, struct sys_info *sysinfo)
+{
+	return Get_MCTSysAddr(ctrl, channel, cs_idx, sysinfo);
+}
+
+
+static  unsigned long read_cr4(void)
+{
+	unsigned long cr4;
+	asm volatile ("movl %%cr4, %0" : "=r" (cr4));
+	return cr4;
+}
+
+
+static  void write_cr4(unsigned long cr4)
+{
+	asm volatile ("movl %0, %%cr4" : : "r" (cr4));
+}
+
+
+static  void enable_sse2()
+{
+	unsigned long cr4;
+	cr4 = read_cr4();
+	cr4 |= (1<<9);
+	write_cr4(cr4);
+}
+
+static  void disable_sse2()
+{
+	unsigned long cr4;
+	cr4 = read_cr4();
+	cr4 &= ~(1<<9);
+	write_cr4(cr4);
+}
+
+
+static void set_wrap32dis(void)
+{
+	msr_t msr;
+
+	msr = rdmsr(0xc0010015);
+	msr.lo |= (1<<17);
+	wrmsr(0xc0010015, msr);
+}
+
+
+static void clear_wrap32dis(void)
+{
+	msr_t msr;
+
+	msr = rdmsr(0xc0010015);
+	msr.lo &= ~(1<<17);
+	wrmsr(0xc0010015, msr);
+}
+
+
+static void set_FSBASE(u32 addr_hi)
+{
+	msr_t msr;
+
+	//set fs and use fs prefix to access the mem
+	msr.hi = addr_hi;
+	msr.lo = 0;
+	wrmsr(0xc0000100, msr); //FS_BASE
+}
+
+
+static u32 ChipSelPresent(const struct mem_controller *ctrl, u32 channel, u32 cs_idx, struct sys_info *sysinfo)
+{
+	u32 enabled;
+#if MEM_CS_COPY == 1
+	u32 nodeid = 0;
+#else
+	u32 nodeid = ctrl->node_id;
+#endif
+
+	enabled = sysinfo->cs_base[nodeid][channel][cs_idx];
+	enabled &= 1;
+	return enabled;
+}
+
+
+static u32 RcvrRankEnabled(const struct mem_controller *ctrl, int channel, int cs_idx, u8 is_Width128, struct sys_info *sysinfo)
+{
+
+	return ChipSelPresent(ctrl, channel, cs_idx, sysinfo);
+}
+
+static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 line_num)
+{
+	__asm__ volatile (
+		 "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"
+		:: "a" (addr_lo), "d" (16), "c" (line_num * 4), "b"(buf_a)
+	);
+}
+
+
+static void Write1LTestPattern(u32 addr, u32 p, u8 *buf_a, u8 *buf_b)
+{
+	u8 *buf;
+	if(p==1) { buf = buf_b; }
+	else { buf = buf_a; }
+
+	set_FSBASE (addr>>24);
+	WriteLNTestPattern(addr<<8, buf, 1);
+}
+
+
+static void Read1LTestPattern(u32 addr)
+{
+	u32 value;
+
+	set_FSBASE(addr>>24);
+
+	/* 1st move causes read fill (to exclusive or shared)*/
+	__asm__ volatile (
+		 "movl %%fs:(%1), %0\n\t"
+		 :"=b"(value): "a" (addr<<8)
+	);
+
+}
+
+#define DQS_PASS 0
+#define DQS_FAIL 1
+
+#define DQS_FIRST_PASS 1
+#define DQS_SECOND_PASS 2
+
+#define SB_NORCVREN 11
+#define RCVREN_MARGIN 6
+#define SB_SmallRCVR 13
+#define SB_CHA2BRCVREN 12
+#define SB_NODQSPOS  14
+#define MIN_DQS_WNDW 3
+#define SB_SMALLDQS 15
+
+const static u32 TestPattern0[] = {
+	0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+	0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+	0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+	0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+};
+const static u32 TestPattern1[] = {
+	0x55555555, 0x55555555, 0x55555555, 0x55555555,
+	0x55555555, 0x55555555, 0x55555555, 0x55555555,
+	0x55555555, 0x55555555, 0x55555555, 0x55555555,
+	0x55555555, 0x55555555, 0x55555555, 0x55555555,
+};
+const static u32 TestPattern2[] = {
+	0x12345678, 0x87654321, 0x23456789, 0x98765432,
+	0x59385824, 0x30496724, 0x24490795, 0x99938733,
+	0x40385642, 0x38465245, 0x29432163, 0x05067894,
+	0x12349045, 0x98723467, 0x12387634, 0x34587623,
+};
+
+
+static u32 CompareTestPatternQW0(u32 channel, u32 addr, u32 pattern, u32 Pass, u8 is_Width128)
+{
+	u32 addr_lo;
+	u8 *test_buf;
+	u32 i;
+	u32 mask;
+	u8 buf_A[8+16];
+	u8 *buf;
+	u32 *lo, *hi;
+
+	buf = (u8 *)(((u32)buf_A + 0x10) & (0xfffffff0));
+	lo = (u32 *)buf;
+	hi = (u32 *)(buf + 4);
+
+	if(Pass == DQS_FIRST_PASS) {
+		if(pattern==1) {
+			test_buf = (u8 *)TestPattern1;
+		}
+		else {
+			test_buf = (u8 *)TestPattern0;
+		}
+	}
+	else {
+		test_buf = (u8 *)TestPattern2;
+	}
+
+	set_FSBASE(addr>>24);
+
+	addr_lo = addr<<8;
+
+	if(is_Width128 && (channel == 1)) {
+		addr_lo += 8; //second channel
+		test_buf += 8;
+	}
+
+//	   _EXECFENCE;/*prevent speculative execution of following instructions*/
+	/* FIXME: needed? */
+
+	/* compare 1st QW of beat 0 */
+	 mask = 0;
+
+	*lo = read32_fs(addr_lo);
+	*hi = read32_fs(addr_lo + 4);
+
+#if DQS_TRAIN_DEBUG > 4
+	print_debug("\t\t\t\t\t\tQW0 : test_buf= ");
+	print_debug_hex32((u32)test_buf);
+	print_debug(": ");
+	for (i=0; i<8; i++) {
+		print_debug_hex8(test_buf[i]); print_debug(" ");
+	}
+	print_debug("\n");
+
+	print_debug("\t\t\t\t\t\tQW0 : addr_lo = ");
+	print_debug_hex32((u32)addr_lo);
+	print_debug(": ");
+	for (i=0; i<8; i++) {
+		print_debug_hex8(buf[i]); print_debug(" ");
+	}
+	print_debug("\n");
+#endif
+
+	for (i=0; i<8; i++) {
+		if(buf[i] == test_buf[i]) {
+			mask |= (1<<i);
+		}
+	}
+
+	//FIXME: reverse the mask in Compare instead of Save
+	if(Pass == DQS_SECOND_PASS) { /* second pass need to be inverted */
+		mask = 0xff - mask;
+	}
+	return mask;
+}
+
+
+static void SetMaxAL_RcvrDly(const struct mem_controller *ctrl, u32 dct,
+			u32 dly)
+{
+	u32 reg;
+	u32 offset = 0x100 * dct;
+
+	dly += (20-1); // round it
+	dly /= 20; // convert from unit 50ps to 1ns
+
+	dly += 6;
+
+	reg = pci_read_config32(ctrl->f2, DRAM_CTRL + offset);
+	reg &= ~(DC_MaxRdLatency_MASK << DC_MaxRdLatency_SHIFT);
+	reg |= (dly  << DC_MaxRdLatency_SHIFT);
+	pci_write_config32(ctrl->f2, DRAM_CTRL + offset, reg);
+}
+
+static u32 get_max(u32 a[], u32 size)
+{
+	u32 x = a[0];
+	int i;
+	for(i=1;i<size; i++) {
+		if(a[i]<x) {
+			x = a[i];
+		}
+	}
+
+	return x;
+}
+
+
+/*
+	Set the Target range to WT IO (using an IORR overlapping the already existing
+	WB dram type). Use IORR0
+*/
+static void SetTargetWTIO(u32 addr)
+{
+	msr_t msr;
+	msr.hi = addr>>24;
+	msr.lo = addr<<8;
+	wrmsr(0xc0010016, msr); //IORR0 BASE
+
+	msr.hi = 0xff;
+	msr.lo = 0xfc000800;  // 64MB Mask
+	wrmsr(0xc0010017, msr); // IORR0 Mask
+}
+
+
+static void ResetTargetWTIO(void)
+{
+	msr_t msr;
+
+	msr.hi = 0;
+	msr.lo = 0;
+	wrmsr(0xc0010017, msr); // IORR0 Mask
+}
+
+
+static void proc_CLFLUSH(u32 addr)
+{
+	set_FSBASE(addr>>24);
+
+	/* 1st move causes read fill (to exclusive or shared)*/
+	__asm__ volatile (
+		/* clflush fs:[eax] */
+		"clflush %%fs:(%0)\n\t"
+		::"a" (addr<<8)
+	);
+}
+
+
+static void proc_IOCLFLUSH(u32 addr)
+{
+	SetTargetWTIO(addr);
+	proc_CLFLUSH(addr);
+	ResetTargetWTIO();
+}
+
+
+static void ResetDCTWrPtr(const struct mem_controller *ctrl, u32 index_reg,
+			u32 index)
+{
+	u32 dword;
+
+	dword = pci_read_config32_index_wait(ctrl->f2, index_reg, index);
+	pci_write_config32_index_wait(ctrl->f2, index_reg, index, dword);
+}
+
+
+static u16 get_exact_T1000(u32 i)
+{
+	//				      200  266,  333,  400
+	const static u16 T1000_a[]= { 5000, 3759, 3003, 2500, 1875 };
+
+	static const u16 TT_a[] = {
+		/*200   266   333   400  533*/
+	/*4 */   6250, 6250, 6250, 6250, 6250,
+	/*5 */   5000, 5000, 5000, 5000, 5000,
+	/*6 */   5000, 4166, 4166, 2500, 2083,
+	/*7 */   5000, 4285, 3571, 2500, 2142,
+
+	/*8 */   5000, 3750, 3125, 2500, 1877,
+	/*9 */   5000, 3888, 3333, 2500, 1944,
+	/*10*/   5000, 4000, 3000, 2500, 2000,
+	/*11*/   5000, 4090, 3181, 2500, 2045,
+
+	/*12*/   5000, 3750, 3333, 2500, 1877,
+	/*13*/   5000, 3846, 3076, 2500, 1923,
+	/*14*/   5000, 3928, 3214, 2500, 1964,
+	/*15*/   5000, 4000, 3000, 2500, 2000,
+	};
+
+
+	u32 fid_cur;
+	int index;
+
+	msr_t msr;
+	msr = rdmsr(0xc0010071);
+	fid_cur = msr.lo & 0x3f;
+
+	index = fid_cur>>1;
+
+	if(index>12) return T1000_a[i];
+
+	return TT_a[index * 5+i];
+}
+
+
+static void InitDQSPos4RcvrEn(const struct mem_controller *ctrl,
+				u32 dct)
+{
+	int i, j;
+	u32 dword;
+	int dn = 2; // NOTE: Rev C could be 4
+
+	u32 index_reg = 0x98 + 0x100 * dct;
+
+	dword = 0x00000000;
+	for(i=1; i<=3; i++) {
+		for(j=0; j<dn; j++)
+			pci_write_config32_index_wait(ctrl->f2, index_reg, i + 0x100 * j, dword);
+	}
+
+	/*errata#180 */
+	dword = 0x2f2f2f2f;
+	for(i=5; i<=6; i++) {
+		for(j=0; j<dn; j++)
+			pci_write_config32_index_wait(ctrl->f2, index_reg, i + 0x100 * j, dword);
+	}
+
+	dword = 0x0000002f;
+	for(j=0; j<dn; j++)
+		pci_write_config32_index_wait(ctrl->f2, index_reg, 7 + 0x100 * j, dword);
+}
+
+
+static u32 Get_Start_RcvrEnDly_Pass(const struct mem_controller *ctrl,
+					u32 Channel, u32 Receiver, u32 Pass,
+					struct sys_info *sysinfo)
+{
+	u32 RcvrEnDly;
+	if (Pass == DQS_FIRST_PASS) {
+		RcvrEnDly = 0;
+	} else {
+		int max = 0;
+		u32 val;
+		int i;
+		u8 *p = &sysinfo->dqs_rcvr_dly_a[ctrl->node_id*2*4*9 + Channel*4*9 + (Receiver>>1)*9] ; //8 node, channel 2, dimm 4, 9 byte
+//		print_tx("Get_Start_RcvrEnDly_Pass: Channel:", Channel);
+//		print_tx("Get_Start_RcvrEnDly_Pass: Receiver:", Receiver);
+		for ( i=0;i<8; i++) {
+			val  = p[i];
+//			print_tx("Get_Start_RcvrEnDly_Pass: i:", i);
+//			print_tx("Get_Start_RcvrEnDly_Pass: val:", val);
+			if(val > max) {
+				max = val;
+			}
+		}
+		RcvrEnDly = max;
+	}
+
+	return RcvrEnDly;
+}
+
+
+static u32 CalcDelay(u32 Delay0, u32 Delay1, u32 InterFactor)
+/* InterFactor: 0: 100% ByteLane 0
+		 0x80: 50% between ByteLane 0 and 1
+		 0xff: 99.6% ByteLane 1 and 0.4% like 0
+*/
+{
+	u32 Delay;
+
+	if(Delay0>Delay1) {
+		Delay = Delay0 - Delay1;
+		InterFactor = 0xff - InterFactor;
+	} else {
+		Delay = Delay1 - Delay0;
+	}
+
+	Delay *= InterFactor;
+	Delay >>= 8; // /255
+
+	if(Delay0>Delay1) {
+		Delay += Delay1;
+	} else {
+		Delay += Delay0;
+	}
+
+	return Delay;
+}
+
+
+void SetRcvrEnDly(const struct mem_controller *ctrl, u32 RcvrEnDly,
+		u32 FinalValue, u32 Channel, u32 Receiver, u32 index_reg,
+		u32 Addl_Index, u32 Pass, struct sys_info *sysinfo)
+{
+	u32 index;
+	u32 i;
+	u8 *p;
+	u32 val;
+
+	const static u32 byte_index[] = { 0, 1, 0x10, 0x11, 0x2 };
+
+	// FIXME: make sure skip ECC bit, if non ECC
+
+	if(FinalValue) {
+		/*calculate dimm offset */
+		p = &sysinfo->dqs_rcvr_dly_a[ctrl->node_id*2*4*9 + Channel*4*9 + (Receiver>>1)*9] ; //8 node, channel 2, dimm 4, 9 byte
+		p[8] = CalcDelay(p[4], p[5], 0); // Ecc
+	}
+
+	for(i=0; i < 9; i++) {
+		if(FinalValue) {
+			/* when we get final value from stack */
+			RcvrEnDly = p[i];
+		}
+		/* if flag=0, set DqsRcvEn value to reg. */
+
+		/* get the register index from table */
+		index = byte_index[i>>1];
+		index += Addl_Index;   /*DIMMx DqsRcvEn byte0*/
+		val = pci_read_config32_index_wait(ctrl->f2, index_reg, index);
+		if(i&1) {
+			/* odd byte lane */
+			val &= ~(0xffff<<16);
+			val |= (RcvrEnDly<<16);
+		} else {
+			/* even byte lane */
+			val &= ~(0xffff);
+			val |= RcvrEnDly;
+		}
+		pci_write_config32_index_wait(ctrl->f2, index_reg, index, val);
+	}
+
+}
+
+
+static void SetFinalRcvrEnDly(const struct mem_controller *ctrl,
+				u32 RcvrEnDly, u32 where, u32 Channel,
+				u32 Receiver, u32 index_reg, u32 Addl_Index,
+				u32 Pass, struct sys_info *sysinfo)
+{
+	SetRcvrEnDly(ctrl, RcvrEnDly, where, Channel, Receiver, index_reg, Addl_Index, Pass, sysinfo);
+}
+
+
+static u32 Average_RcvrEnDly_Pass(const struct mem_controller *ctrl,
+				u32 RcvrEnDlyLimit, u32 Channel, u32 Receiver,
+				u32 Pass, struct sys_info *sysinfo)
+{
+	int i;
+	u8 *p;
+	u8 *p_1;
+	u32 val;
+	u32 val_1;
+	u32 Errors;
+
+	p = &sysinfo->dqs_rcvr_dly_a[ctrl->node_id*2*4*9 + Channel*4*9 + (Receiver>>1)*9] ; //8 node, channel 2, dimm 4, 9 byte
+
+	if (Pass == DQS_SECOND_PASS) { /* second pass must average values */
+		//FIXME: which byte?
+		p_1 = sysinfo->dqs_rcvr_dly_a_1;
+		for(i=0; i<8; i++) {
+			val = p[i];
+			/* left edge */
+			if (val != (RcvrEnDlyLimit - 1)) {
+				val_1 = p_1[i];
+				val += val_1;
+				val >>= 1;
+				p[i] = val;
+			} else {
+				Errors = 1<<SB_NORCVREN;
+				break;
+			}
+		}
+	}
+	else {
+		for(i=0; i < 8; i++) {
+			val = p[i];
+			/* Add 1/2 Memlock delay */
+			// val += Pass1MemClkDly;
+			val += 0x10;
+			p[i] = val;
+		}
+	}
+	return Errors;
+}
+
+
+static u32 SavePassRcvEnDly(const struct mem_controller *ctrl, u32 rcvrEnDly,
+				u32 Channel, u32 Receiver, u32 mask_Pass,
+				u32 mask_Saved, u32 Pass, struct sys_info *sysinfo)
+{
+	u32 i;
+	u8 *p;
+
+	/* calculate dimm offset */
+	/* cmp if there has new DqsRcvEnDly to be recorded */
+
+	if(mask_Pass != mask_Saved) {
+		// only mask mask_Saved with mask_Pass for FirstPass
+		/* find desired stack offset accroding to channel/dimm/byte*/
+		if(Pass == DQS_SECOND_PASS) {
+			p = sysinfo->dqs_rcvr_dly_a_1;
+//			p = pDCTstat->CH_D_B_RCVRDLY_1[Channel][receiver>>1];
+		} else {
+			mask_Saved &= mask_Pass;
+			p = &sysinfo->dqs_rcvr_dly_a[ctrl->node_id*2*4*9 + Channel*4*9 + (Receiver>>1)*9] ; //8 node, channel 2, dimm 4, 9 byte
+		}
+		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;
+				}
+			}
+		}
+	}
+	return mask_Saved;
+}
+
+
+static u32 CalcMaxLatency(const struct mem_controller *ctrl, u32 DQSRcvrEnDly,
+				u8 is_Width128, u32 Channel)
+{
+	u32 SubTotal;
+	u32 dev;
+	u32 index_reg;
+	u32 reg_off;
+	u32 val;
+	u32 valx;
+	u32 ch;
+
+	if(is_Width128)
+		ch = 0;
+	else
+		ch = Channel;
+
+
+	dev = ctrl->f2;
+	reg_off = 0x100 * ch;
+	index_reg = 0x98 + Channel;
+
+	/* Multiply CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
+	val = pci_read_config32(dev, 0x88 + reg_off);
+	/* SubTotal is 1/2 Memclk unit */
+	SubTotal = ((val & 0x0f) + 1) << 1;
+
+	/* If registered DIMMs are used then add 1 MEMCLK to the sub-total. */
+	val =pci_read_config32(dev, 0x90 + reg_off);
+	if(!(val & DCL_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 = pci_read_config32_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 = pci_read_config32(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 += DQSRcvrEnDly>>5;	/* FIXME?-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 = pci_read_config32(dev, 0x94 + reg_off);
+	/* SubTotal div 4 to scale 1/4 MemClk back to MemClk*/
+	valx = ((val & 0x07) + 3)<<2;
+
+	val = pci_read_config32(ctrl->f3, 0xD4);
+	SubTotal *= ((val & 0x1f) + 4 ) * 3;
+
+	SubTotal += (valx - 1);
+	SubTotal /= valx; /* round up */
+
+	/* Add 5 NCLKs to the sub-total. 5 represents part of the processor
+	 specific constant value in the northbridge clock domain. */
+
+	return SubTotal + 5;
+}
+
+static void SetMaxLatency(const struct mem_controller *ctrl, u32 CH_MaxRdLat,
+				u32 Channel)
+{
+	u32 reg;
+	u32 valx;
+	u32 val;
+
+	/* Program the F2x[1, 0]78[MaxRdLatency] register with the total delay
+	  value (in NCLKs). */
+
+	valx = CH_MaxRdLat & 0x3ff;
+
+	reg = 0x78 + 0x100 * Channel;
+	val = pci_read_config32(ctrl->f2, reg);
+	val &= ~(0x3ff<<22);
+	val |= valx<<22;
+	/* program MaxRdLatency to correspond with current delay */
+	pci_write_config32(ctrl->f2, reg, val);
+}
+
+
+static u32 TrainRcvrEn(const struct mem_controller *ctrl, u32 Pass,
+			struct sys_info *sysinfo)
+{
+
+	/* We need to two cache line So have more 16 bytes to keep 16
+	   byte alignment */
+	u8 pattern_buf_x[64 * 2 + 16];
+	u8 *buf_a, *buf_b;
+	u32 ecc_bit;
+	u32 dword;
+
+	int i;
+
+	u32 Channel, Receiver;
+	u32 Errors;
+	u32 CTLRMaxDelay;
+	u32 T1000;
+	u32 CurrTest;
+	u32 Test0, Test1;
+	u32 RcvrEnDlyRmin;
+	u32 two_ranks;
+	u32 RcvrEnDly;
+	u32 PatternA;
+	u32 PatternB;
+	u32 TestAddr0, TestAddr0B, TestAddr1, TestAddr1B;
+	u32 RcvrEnDlyLimit, MaxDelay_CH[2];
+	u32 CH_MaxRdLat[2];
+	u32 tmp;
+	u8 is_Width128 = sysinfo->meminfo[ctrl->node_id].is_Width128;
+#if DQS_DELAY_COPY == 1
+	//8 node, channel 2, dimm 4, 9 byte
+	u8 *dqs_rcvr_dly_a = &sysinfo->dqs_rcvr_dly_a[0*2*4*9] ;
+#else
+	//8 node, channel 2, dimm 4, 9 byte
+	u8 *dqs_rcvr_dly_a = &sysinfo->dqs_rcvr_dly_a[ctrl->node_id*2*4*9];
+#endif
+
+	u32 index_reg;
+	u32 index;
+	u32 reg;
+	u32 ch_start, ch_end, ch;
+	u32 dimm_mask = sysinfo->meminfo[ctrl->node_id].dimm_mask;
+	u32 DqsRcvEn_Saved;
+
+	ch_start = 0;
+	if(is_Width128) {
+		ch_end = 1;
+	} else {
+		ch_end = 2;
+	}
+
+	if(Pass == DQS_FIRST_PASS) {
+		for(ch=0; ch<2; ch++) {
+			InitDQSPos4RcvrEn(ctrl, ch);
+		}
+	}
+
+	// enable SSE2
+	enable_sse2();
+
+#if MMCONF_SUPPORT == 0
+	// wrap32dis
+	set_wrap32dis();
+#endif
+
+	// disable ECC temp
+	for(ch = ch_start; ch < ch_end; ch++) {
+		reg =  DRAM_CONFIG_LOW + 0x100 * ch;
+		dword = pci_read_config32(ctrl->f2, reg);
+		ecc_bit = dword & DCL_DimmEccEn;
+		dword &= ~(DCL_DimmEccEn);
+		pci_write_config32(ctrl->f2, reg, dword);
+	}
+
+
+	if(Pass == DQS_FIRST_PASS) {
+		for(ch = ch_start; ch < ch_end; ch++) {
+			reg =  DRAM_CTRL + 0x100 * ch;
+			/* Set the DqsRcvEnTrain bit */
+			dword = pci_read_config32(ctrl->f2, reg);
+			dword |= DC_DqsRcvEnTrain;
+			pci_write_config32(ctrl->f2, reg, dword);
+		}
+	}
+
+	// SetupRcvrPattern
+	buf_a = (u8 *)(((u32)(&pattern_buf_x[0]) + 0x10) & (0xfffffff0));
+	buf_b = buf_a + 64;
+	if(Pass==DQS_FIRST_PASS) {
+		for(i=0;i<16;i++) {
+			*((u32 *)(buf_a + i*4)) = TestPattern0[i];
+			*((u32 *)(buf_b + i*4)) = TestPattern1[i];
+		}
+	} else {
+		for(i=0;i<16;i++) {
+			*((u32 *)(buf_a + i*4)) = TestPattern2[i];
+		}
+		buf_b = buf_a;
+	}
+
+	print_debug_dqs("\nTrainRcvEn: 0 ctrl", ctrl->node_id, 0);
+	print_debug_addr("TrainRcvEn: buf_a:", buf_a);
+
+	Errors = 0;
+	/* for each channel */
+
+	for(Channel = 0; (Channel < 2) && (!Errors); Channel++)
+	{
+		print_debug_dqs("\tTrainRcvEn51: Channel ",Channel, 1);
+
+		if(!((dimm_mask >> (DIMM_SOCKETS * Channel)) & ((1<<DIMM_SOCKETS)-1)))
+			continue;
+
+		CTLRMaxDelay = 0;
+		index_reg = 0x98 + 0x100 * Channel;
+		/* for each rank */
+		/* there are four recriver pairs, loosely associated with CS */
+		for( Receiver = 0; (Receiver < 8) && (!Errors); Receiver+=2)
+		{
+
+			index=(Receiver>>1) * 3 + 0x10;
+			RcvrEnDlyRmin = RcvrEnDlyLimit = 0xff;
+
+			print_debug_dqs("\t\tTrainRcvEn52: index ", index, 2);
+
+			if(!RcvrRankEnabled(ctrl, Channel, Receiver, is_Width128, sysinfo))
+				continue;
+
+			/* for each DQS receiver enable setting */
+			TestAddr0 = Get_RcvrSysAddr(ctrl, Channel, Receiver, sysinfo);
+			TestAddr0B = TestAddr0 + (1<<(20+2-8)); // 4MB
+
+			if(RcvrRankEnabled(ctrl, Channel, Receiver+1, is_Width128, sysinfo)) {
+				TestAddr1 = Get_RcvrSysAddr(ctrl, Channel, Receiver+1, sysinfo);
+				TestAddr1B = TestAddr1 + (1<<(20+2-8)); //4MB
+				two_ranks = 1;
+			} else {
+				two_ranks = 0;
+			}
+
+			print_debug_dqs("\t\tTrainRcvEn53: TestAddr0B ", TestAddr0B, 2);
+
+			Write1LTestPattern(TestAddr0, 0, buf_a, buf_b); // rank0 of dimm, test p0
+			Write1LTestPattern(TestAddr0B, 1, buf_a, buf_b); //rank0 of dimm, test p1
+
+			if(two_ranks == 1) {
+				Write1LTestPattern(TestAddr1, 0, buf_a, buf_b); //rank 1 of dimm
+				Write1LTestPattern(TestAddr1B, 1, buf_a, buf_b);//rank 1 of dimm
+			}
+
+			RcvrEnDly = Get_Start_RcvrEnDly_Pass(ctrl, Channel, Receiver, Pass, sysinfo);
+			DqsRcvEn_Saved = 0;
+
+			while ( RcvrEnDly < RcvrEnDlyLimit) { // Sweep Delay value here
+				print_debug_dqs("\t\t\tTrainRcvEn541: RcvrEnDly ", RcvrEnDly, 3);
+
+				if(RcvrEnDly & 1) {
+					/* Odd steps get another pattern such
+					   that even and odd steps alternate.
+					   The pointers to the patterns will be
+					   swapped at the end of the loop so
+					   they are correspond
+					*/
+					PatternA = 1;
+					PatternB = 0;
+				} else {
+					/* Even step */
+					PatternA = 0;
+					PatternB = 1;
+				}
+
+				/* Program current Receiver enable delay */
+
+				SetRcvrEnDly(ctrl, RcvrEnDly, 0, Channel, Receiver, index_reg, index, Pass, sysinfo);
+
+				Read1LTestPattern(TestAddr0);  //Cache Fill
+				/* ROM vs cache compare */
+				Test0 = CompareTestPatternQW0(Channel, TestAddr0, PatternA, Pass, is_Width128);
+				proc_IOCLFLUSH(TestAddr0);
+
+				ResetDCTWrPtr(ctrl, index_reg, index);
+				print_debug_dqs("\t\t\tTrainRcvEn542: Test0 ", Test0, 3);
+				CurrTest = Test0;
+
+				if(((CurrTest != 0x00)&&(Pass==DQS_FIRST_PASS))||((CurrTest != 0xff) && (Pass==DQS_SECOND_PASS))) {
+
+					Read1LTestPattern(TestAddr0B);
+					Test1 = CompareTestPatternQW0(Channel, TestAddr0B, PatternB, Pass, is_Width128);
+					proc_IOCLFLUSH(TestAddr0B);
+					ResetDCTWrPtr(ctrl, index_reg, index);
+					print_debug_dqs("\t\t\tTrainRcvEn543: Test1 ", Test1, 3);
+					if(Pass==DQS_SECOND_PASS) {
+						CurrTest |= Test1;
+					} else {
+						CurrTest &= Test1;
+					}
+				}
+				if(two_ranks && (((CurrTest!=0x00)&&(Pass==DQS_FIRST_PASS))||((CurrTest != 0xff) && (Pass==DQS_SECOND_PASS)))) {
+					Read1LTestPattern(TestAddr1);
+					Test0 = CompareTestPatternQW0(Channel, TestAddr1, PatternA, Pass, is_Width128);
+					proc_IOCLFLUSH(TestAddr1);
+					ResetDCTWrPtr(ctrl, index_reg, index);
+
+					print_debug_dqs("\t\t\tTrainRcvEn544: Test0 ", Test0, 3);
+
+					if(Pass==DQS_SECOND_PASS) {
+						CurrTest |= Test0;
+					} else {
+						CurrTest &= Test0;
+					}
+
+					if(((CurrTest != 0x00)&&(Pass==DQS_FIRST_PASS))||((CurrTest != 0xff) && (Pass==DQS_SECOND_PASS))) {
+
+						Read1LTestPattern(TestAddr1B);
+						Test1 = CompareTestPatternQW0(Channel, TestAddr1B, PatternB, Pass, is_Width128);
+						proc_IOCLFLUSH(TestAddr1B);
+						ResetDCTWrPtr(ctrl, index_reg, index);
+
+						print_debug_dqs("\t\t\tTrainRcvEn545: Test1 ", Test1, 3);
+						if(Pass==DQS_SECOND_PASS) {
+							CurrTest |= Test1;
+						} else {
+							CurrTest &= Test1;
+						}
+
+					}
+				}
+
+				//NOTE: moved here for clear logic
+				/* if second pass, we can't find the fail until FFh,
+				then let it fail to save the final delay */
+				if ((RcvrEnDly == (RcvrEnDlyLimit - 1)) && (Pass == DQS_SECOND_PASS) )
+					CurrTest = 0xff;
+
+				if(CurrTest != 0x00) {
+					/* record first pass DqsRcvEn to stack */
+					DqsRcvEn_Saved = SavePassRcvEnDly(ctrl, RcvrEnDly, Channel, Receiver, CurrTest, DqsRcvEn_Saved, Pass, sysinfo);// use B_RCVRDLY_1
+					if(DqsRcvEn_Saved == 0xff) {
+						RcvrEnDlyRmin = RcvrEnDly;
+						break;
+					}
+				}
+
+				/* swap the rank 0 pointers */
+				tmp = TestAddr0;
+				TestAddr0 = TestAddr0B;
+				TestAddr0B = tmp;
+
+				/* swap the rank 1 pointers */
+				if(two_ranks) {
+					tmp = TestAddr1;
+					TestAddr1 = TestAddr1B;
+					TestAddr1B = tmp;
+				}
+
+				print_debug_dqs("\t\t\tTrainRcvEn545: RcvrEnDly ", RcvrEnDly, 3);
+
+				RcvrEnDly++;
+
+			} // while RcvrEnDly
+
+			if(RcvrEnDly > (RcvrEnDlyLimit - 1)) {
+				/*passing window too narrow, too far delayed*/
+				Errors |= 1<<SB_SmallRCVR;
+				RcvrEnDly = RcvrEnDlyLimit - 1;
+				//FIXME: failed, how to handle it?
+			}
+
+			Errors |= Average_RcvrEnDly_Pass(ctrl, RcvrEnDlyLimit, Channel, Receiver, Pass, sysinfo); // use B_RCVRDLY_1
+			SetFinalRcvrEnDly(ctrl, RcvrEnDly, 1, Channel, Receiver, index_reg, index, Pass, sysinfo);
+//FIXME??			RcvrEnDly += 0x20;
+			if(RcvrEnDly > CTLRMaxDelay)
+				CTLRMaxDelay = RcvrEnDly;
+
+		} /* receiver */
+
+		MaxDelay_CH[Channel] = CTLRMaxDelay;
+		CH_MaxRdLat[Channel] = CalcMaxLatency(ctrl, CTLRMaxDelay, is_Width128, Channel); /*program Ch A/B MaxAsyncLat to correspond with max delay */
+
+		if(!is_Width128) {
+			SetMaxLatency(ctrl, CH_MaxRdLat[Channel], Channel); /*program Ch A/B MaxAsyncLat to correspond with max delay */
+		}
+
+		if(is_Width128 && Channel) {
+			u32 max = 0;
+			int i;
+			for(i = 0; i < 2; i++) {
+				if(CH_MaxRdLat[i] > max)
+					max = CH_MaxRdLat[i];
+			}
+			for(i = 0; i < 2; i++)
+				CH_MaxRdLat[i] = max;
+
+			/* program Ch A/B MaxAsyncLat to correspond with
+			   max delay */
+			SetMaxLatency(ctrl, max, 0);
+		}
+		ResetDCTWrPtr(ctrl, index_reg, index); //FIXME:???
+	} /* channel */
+
+	print_debug_dqs("\tTrainRcvEn65: CTLRMaxDelay ", CTLRMaxDelay, 1);
+
+	//Enable ECC again
+	for(ch = ch_start; ch < ch_end; ch++) {
+		reg =	DRAM_CONFIG_LOW + 0x100 * ch;
+		dword = pci_read_config32(ctrl->f2, reg);
+		dword &= ~(DCL_DimmEccEn);
+		dword |= ecc_bit;
+		pci_write_config32(ctrl->f2, reg, dword);
+	}
+
+	if(Pass == DQS_FIRST_PASS) {
+		for(ch = ch_start; ch < ch_end; ch++) {
+			reg =	DRAM_CTRL + 0x100 * ch;
+			/* Set the DqsRcvEnTrain bit */
+			dword = pci_read_config32(ctrl->f2, reg);
+			dword &= ~DC_DqsRcvEnTrain;
+			pci_write_config32(ctrl->f2, reg, dword);
+		}
+	}
+
+#if MMCONF_SUPPORT == 0
+	//Clear wrap32dis
+	clear_wrap32dis();
+#endif
+
+	//restore SSE2 setting
+	disable_sse2();
+
+	return (CTLRMaxDelay==0xff)?1:0;
+}
+
+
+#define DQS_READDIR 1
+#define DQS_WRITEDIR 0
+
+static void SetDQSDelayCSR(const struct mem_controller *ctrl, u32 channel,
+			u32 cs, u32 bytelane, u32 direction, u32 dqs_delay)
+{ //ByteLane could be 0-8, last is for ECC
+	u32 index;
+	u32 dword;
+	u32 shift;
+	u32 index_reg = 0x98 + 0x100 * channel;
+
+	dqs_delay &= 0xff;
+
+	// for logical DIMM1/DIMM3
+	index = (bytelane>>2) + 1 + (direction << 2) + (cs>>1) * 0x100;
+	shift = bytelane%4;
+	shift <<= 3; // 8 bit
+
+	dword = pci_read_config32_index_wait(ctrl->f2, index_reg, index);
+	dword &= ~(0x7f<<shift);
+	dword |= (dqs_delay<<shift);
+	pci_write_config32_index_wait(ctrl->f2, index_reg, index, dword);
+}
+
+
+static void SetDQSDelayAllCSR(const struct mem_controller *ctrl, u32 channel,
+				u32 cs, u32 direction, u32 dqs_delay)
+{
+	u32 ByteLane;
+	u32 ChipSel = cs;
+	for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+		SetDQSDelayCSR(ctrl, channel, ChipSel, ByteLane, direction, dqs_delay);	     /*load the register with the value*/
+	}
+}
+
+
+static u32 MiddleDQS(u32 min_d, u32 max_d)
+{
+	u32 size_d;
+	size_d = max_d-min_d;
+	if(size_d & 1) { //need round up
+		min_d++;
+	}
+	return ( min_d + (size_d>>1));
+}
+
+static void save_dqs_delay(u32 channel, u32 cs_start, u32 bytelane,
+				u32 direction, u8 *dqs_delay_a, u8 dqs_delay)
+{
+	dqs_delay_a[channel * 4* 2*9 + cs_start * 2 * 9 + direction * 9 + bytelane] = dqs_delay;
+}
+
+
+static u8 get_dqs_delay(u32 channel, u32 cs_start, u32 bytelane, u32 direction, u8 *dqs_delay_a)
+{
+	u8 dqs_delay;
+	dqs_delay = dqs_delay_a[channel * 4* 2*9 + cs_start * 2 * 9 + direction * 9 + bytelane];
+	return dqs_delay;
+}
+
+
+static void WriteDQSTestPattern(u32 addr_lo, u32 pattern, u8 *buf_a)
+{
+	WriteLNTestPattern(addr_lo, buf_a, (pattern+1) * 9);
+}
+
+static void ReadL18TestPattern(u32 addr_lo)
+{
+	// set fs and use fs prefix to access the mem
+	__asm__ volatile (
+		"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
+
+		:: "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 (
+
+		"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
+
+		:: "a"(0), "b" (addr_lo+128+8*64), "c"(addr_lo+128),
+		   "d"(addr_lo+128+4*64)
+	);
+}
+
+
+static void ReadDQSTestPattern(u32 addr_lo, u32 pattern)
+{
+	if(pattern == 0) {
+		ReadL9TestPattern(addr_lo);
+	} else {
+		ReadL18TestPattern(addr_lo);
+	}
+}
+
+
+static void FlushDQSTestPattern_L9(u32 addr_lo)
+{
+	 __asm__ volatile (
+		"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__((no)) void FlushDQSTestPattern_L18(u32 addr_lo)
+{
+	__asm__ volatile (
+		"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 FlushDQSTestPattern(u32 addr_lo, u32 pattern )
+{
+	if(pattern == 0){
+		FlushDQSTestPattern_L9(addr_lo);
+	} else {
+		FlushDQSTestPattern_L18(addr_lo);
+	}
+}
+
+
+static u32 CompareDQSTestPattern(u32 channel, u32 addr_lo, u32 pattern,
+				u8 *buf_a)
+{
+	u32 *test_buf;
+	u32 bitmap = 0xff;
+	u32 bytelane;
+	int i;
+	u32 value;
+	int j;
+	u32 value_test;
+
+	test_buf = (u32 *)buf_a;
+
+
+	if(pattern && channel) {
+		addr_lo += 8; //second channel
+		test_buf+= 2;
+	}
+
+	bytelane = 0;
+	for(i=0;i<9*64/4;i++) {
+		__asm__ volatile (
+			"movl %%fs:(%1), %0\n\t"
+			:"=b"(value): "a" (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);
+
+		for(j=0;j<4*8;j+=8) {
+			if(((value>>j)&0xff) != ((value_test>>j)& 0xff)) {
+				bitmap &= ~(1<<bytelane);
+			}
+
+			bytelane++;
+			bytelane &= 0x7;
+		}
+		print_debug_dqs("\t\t\t\t\t\tbitmap = ", bitmap, 7);
+
+		if(bytelane == 0) {
+			if(pattern == 1) { //dual channel
+				addr_lo += 8; //skip over other channel's data
+				test_buf += 2;
+			}
+		}
+		addr_lo += 4;
+		test_buf +=1;
+
+	}
+	return bitmap;
+}
+
+static u32 TrainDQSPos(const struct mem_controller *ctrl, u32 channel,
+			u32 cs_start, u32 cs_end, u32 Direction, u32 Pattern,
+			u8 *buf_a, u8 *dqs_delay_a, struct sys_info *sysinfo)
+{
+	u32 ByteLane;
+	u32 Errors;
+	u32 BanksPresent;
+	u32 MutualCSPassW[64];
+	u32 ChipSel;
+	u32 DQSDelay;
+	u32 TestAddr;
+	u32 LastTest;
+	u32 RnkDlyFilterMax, RnkDlyFilterMin;
+	u32 RnkDlySeqPassMax, RnkDlySeqPassMin;
+	u32 dqsDelay_end;
+
+	Errors = 0;
+	BanksPresent = 0;
+	if(Direction == DQS_READDIR)
+		dqsDelay_end = 64;
+	else
+		dqsDelay_end = 32;
+
+
+	print_debug_dqs("\t\t\tTrainDQSPos begin ", 0, 3);
+	print_debug_addr("TrainDQSPos: MutualCSPassW[48] :", MutualCSPassW);
+
+	for(DQSDelay=0; DQSDelay<dqsDelay_end; DQSDelay++) {
+	/* Bitmapped status per delay setting, 0xff=All positions passing
+	  (1= PASS) */
+		MutualCSPassW[DQSDelay] = 0xff;
+	}
+
+	for(ChipSel = cs_start; ChipSel < cs_end; ChipSel++) {
+		//logical register chipselects 0..7
+		print_debug_dqs("\t\t\t\tTrainDQSPos: 11 ChipSel ", ChipSel, 4);
+		//FIXME: process 64MUXedMode
+		if(!ChipSelPresent(ctrl, channel, ChipSel, sysinfo)) continue;
+		BanksPresent  = 1;
+
+		TestAddr = Get_MCTSysAddr(ctrl, Pattern?0:channel, ChipSel, sysinfo);
+
+		print_debug_dqs("\t\t\t\tTrainDQSPos: 12 TestAddr ", TestAddr, 4);
+
+		//set fs and use fs prefix to access the mem
+		set_FSBASE(TestAddr>>24);
+
+		if(Direction == DQS_READDIR) {
+			print_debug_dqs("\t\t\t\tTrainDQSPos: 13 for read so write at first", 0, 4);
+			WriteDQSTestPattern(TestAddr<<8, Pattern, buf_a);
+		}
+
+		for(DQSDelay =0; DQSDelay < dqsDelay_end; DQSDelay++ ){
+			print_debug_dqs("\t\t\t\t\tTrainDQSPos: 141 DQSDelay ", DQSDelay, 5);
+			if(MutualCSPassW[DQSDelay] == 0) continue; //skip current delay value if other chipselects have failed all 8 bytelanes
+			SetDQSDelayAllCSR(ctrl, channel, cs_start, /*cs_end, */ Direction, DQSDelay);
+			print_debug_dqs("\t\t\t\t\tTrainDQSPos: 142 MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+			if(Direction == DQS_WRITEDIR) {
+				print_debug_dqs("\t\t\t\t\tTrainDQSPos: 143 for write", 0, 5);
+				WriteDQSTestPattern(TestAddr<<8, Pattern, buf_a);
+			}
+			print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 Pattern ", Pattern, 5);
+			ReadDQSTestPattern(TestAddr<<8, Pattern);
+			print_debug_dqs("\t\t\t\t\tTrainDQSPos: 145 MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+			MutualCSPassW[DQSDelay] &= CompareDQSTestPattern(channel, TestAddr<<8, Pattern, buf_a); //0: fail, 1=pass
+			print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+			SetTargetWTIO(TestAddr);
+			FlushDQSTestPattern(TestAddr<<8, Pattern);
+			ResetTargetWTIO();
+		}
+	}
+
+	if(BanksPresent) {
+		u32 mask_pass = 0;
+		for(ByteLane = 0; ByteLane < 8; ByteLane++) {
+			print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane ",ByteLane, 4);
+
+			LastTest = DQS_FAIL;
+			RnkDlySeqPassMax = 0;
+			RnkDlyFilterMax = 0;
+			RnkDlyFilterMin = 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);
+
+					RnkDlySeqPassMax = DQSDelay;
+					if(LastTest == DQS_FAIL) {
+						RnkDlySeqPassMin = DQSDelay; //start sequential run
+					}
+					if((RnkDlySeqPassMax - RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)){
+						RnkDlyFilterMin = RnkDlySeqPassMin;
+						RnkDlyFilterMax = RnkDlySeqPassMax;
+					}
+					LastTest = DQS_PASS;
+				} else {
+					LastTest = 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 {
+					u32 middle_dqs;
+					middle_dqs = MiddleDQS(RnkDlyFilterMin, RnkDlyFilterMax);
+					print_debug_dqs("\t\t\t\tTrainDQSPos: 35 middle_dqs ",middle_dqs, 4);
+					save_dqs_delay(channel, cs_start, ByteLane, Direction, dqs_delay_a, middle_dqs);
+					mask_pass |= 1<<ByteLane;
+				}
+			}
+		}
+		print_debug_dqs("\t\t\t\tTrainDQSPos: 41 mask_pass ",mask_pass, 3);
+		if(mask_pass == 0xff) {
+#if DQS_TRAIN_DEBUG > 4
+			print_debug("\t\t\t\tTrainDQSPos: 42 middle_dqs :");
+#endif
+			for(ByteLane = 0; ByteLane < 8; ByteLane++) {
+				u32 middle_dqs;
+				middle_dqs = get_dqs_delay(channel, cs_start, ByteLane, Direction, dqs_delay_a);
+#if DQS_TRAIN_DEBUG > 4
+				print_debug_hex8(middle_dqs);
+				print_debug(" ");
+#endif
+				SetDQSDelayCSR(ctrl, channel, cs_start, ByteLane, Direction, middle_dqs);
+			}
+#if DQS_TRAIN_DEBUG > 4
+		print_debug("\n");
+#endif
+		}
+	}
+	print_debug_dqs("\t\t\tTrainDQSPos: end", 0xff, 3);
+	return Errors;
+}
+
+
+static u32 TrainReadDQS(const struct mem_controller *ctrl, u32 channel,
+			u32 cs_start, u32 cs_end, u32 pattern, u8 *buf_a,
+			u8 *dqs_delay_a, struct sys_info *sysinfo)
+{
+	print_debug_dqs("\t\tTrainReadPos", 0, 2);
+	return TrainDQSPos(ctrl, channel, cs_start, cs_end, DQS_READDIR, pattern, buf_a, dqs_delay_a, sysinfo);
+}
+
+static u32 TrainWriteDQS(const struct mem_controller *ctrl, u32 channel,
+			u32 cs_start, u32 cs_end, u32 pattern, u8 *buf_a,
+			u8 *dqs_delay_a, struct sys_info *sysinfo)
+{
+	print_debug_dqs("\t\tTrainWritePos", 0, 2);
+	return TrainDQSPos(ctrl, channel, cs_start, cs_end, DQS_WRITEDIR, pattern, buf_a, dqs_delay_a, sysinfo);
+}
+
+
+static u32 TrainDQSRdWrPos(const struct mem_controller *ctrl, u32 cs_start,
+				u32 cs_end, struct sys_info *sysinfo)
+{
+	const static u32 TestPatternJD1a[] = {
+		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[] = {
+		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
+	};
+	/* We need to two cache line So have more 16 bytes to keep 16 byte
+	   alignment */
+	u8 pattern_buf_x[64 * 18 + 16];
+	u8 *buf_a;
+
+	u32 pattern;
+	u32 dword;
+	u32 ecc_bit;
+	u32 Errors;
+	u32 Channel;
+	int i;
+	u32 DQSWrDelay;
+	u32 is_Width128 = sysinfo->meminfo[ctrl->node_id].is_Width128;
+#if DQS_DELAY_COPY == 1
+	//channel 2, dimm 4 direction 2 , bytelane *9
+	u8 *dqs_delay_a = &sysinfo->dqs_delay_a[0 * 2*4*2*9];
+#else
+	//channel 2, dimm 4, direction 2 , bytelane *9
+	u8 *dqs_delay_a = &sysinfo->dqs_delay_a[ctrl->node_id * 2*4*2*9];
+#endif
+
+	u32 dqsWrDelay_end = 0x20; //FIXME: BKDG said 0x80?
+	u32 reg;
+	u32 ch, ch_start, ch_end;
+
+	ch_start = 0;
+	if(is_Width128) {
+		ch_end = 1;
+	} else {
+		ch_end = 2;
+	}
+
+	// enable SSE2
+	enable_sse2();
+
+#if MMCONF_SUPPORT == 0
+	// wrap32dis
+	set_wrap32dis();
+#endif
+
+	//disable ECC temp
+	for(ch = ch_start; ch < ch_end; ch++) {
+		reg =	DRAM_CONFIG_LOW + 0x100 * ch;
+		dword = pci_read_config32(ctrl->f2, reg);
+		ecc_bit = dword & DCL_DimmEccEn;
+		dword &= ~(DCL_DimmEccEn);
+		pci_write_config32(ctrl->f2, reg, dword);
+	}
+
+	// SetupDqsPattern
+	buf_a = (u8 *)(((u32)(&pattern_buf_x[0]) + 0x10) & (~0xf));
+
+	if(is_Width128){
+		pattern = 1;
+		for(i=0;i<16*18;i++) {
+			*((u32 *)(buf_a + i*4)) = TestPatternJD1b[i];
+			 }
+	} else {
+		pattern = 0;
+		for(i=0; i<16*9;i++) {
+			*((u32 *)(buf_a + i*4)) = TestPatternJD1a[i];
+		}
+	}
+
+	print_debug_dqs("\nTrainDQSRdWrPos: 0 ctrl ", ctrl->node_id, 0);
+	print_debug_addr("TrainDQSRdWrPos: buf_a:", buf_a);
+
+	Errors = 0;
+	Channel = 0;
+	while( (Channel<2) && (!Errors)) {
+		print_debug_dqs("\tTrainDQSRdWrPos: 1 channel ",Channel, 1);
+		for(DQSWrDelay = 0; DQSWrDelay < dqsWrDelay_end; DQSWrDelay++) {
+			u32 err;
+			SetDQSDelayAllCSR(ctrl, Channel, cs_start, /* cs_end, */ DQS_WRITEDIR, DQSWrDelay);
+			print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DQSWrDelay ", DQSWrDelay, 2);
+			err= TrainReadDQS(ctrl, Channel, cs_start, cs_end, pattern, buf_a, dqs_delay_a, sysinfo);
+			print_debug_dqs("\t\tTrainDQSRdWrPos: 22 err ",err, 2);
+			if(err == 0) {
+				print_debug_dqs("\tTrainDQSRdWrPos: 231 DQSWrDelay ", DQSWrDelay, 1);
+				Errors = TrainWriteDQS(ctrl, Channel, cs_start, cs_end, pattern, buf_a, dqs_delay_a, sysinfo);
+				print_debug_dqs("\tTrainDQSRdWrPos: 232 Errors ", Errors, 1);
+				if(Errors == 0)
+					break;
+			}
+			Errors |= err;
+		}
+		Channel++;
+	}
+	//Enable ECC again
+	for(ch = ch_start; ch < ch_end; ch++) {
+		reg =	DRAM_CONFIG_LOW + 0x100 * ch;
+		dword = pci_read_config32(ctrl->f2, reg);
+		dword &= ~(DCL_DimmEccEn);
+		dword |= ecc_bit;
+		pci_write_config32(ctrl->f2, reg, dword);
+	}
+
+#if MMCONF_SUPPORT == 0
+	// Clear wrap32dis
+	clear_wrap32dis();
+#endif
+
+	// restore SSE2 setting
+	disable_sse2();
+
+	print_debug_dqs("TrainDQSRdWrPos: ", 5, 0);
+
+	return Errors;
+}
+
+
+static void SetEccDQSRdWrPos(const struct mem_controller *ctrl, u32 cs,
+				struct sys_info * sysinfo)
+{
+	u32 channel;
+	u32 ByteLane;
+	u32 Direction;
+	u32 lane0, lane1, ratio;
+	u32 dqs_delay;
+	u32 DQSDelay0, DQSDelay1;
+
+	u32 direction[] = { DQS_READDIR, DQS_WRITEDIR };
+	int i;
+#if DQS_DELAY_COPY == 1
+	//channel 2, dimm 4 direction 2 , bytelane *9
+	u8 *dqs_delay_a = &sysinfo->dqs_delay_a[0 * 2*4*2*9];
+#else
+	//channel 2, dimm 4, direction 2 , bytelane *9
+	u8 *dqs_delay_a = &sysinfo->dqs_delay_a[ctrl->node_id * 2*4*2*9];
+#endif
+	ByteLane = 8;
+
+	for(channel = 0; channel < 2; channel++) {
+		for(i=0;i<2;i++) {
+			Direction = direction[i];
+			lane0 = 4; lane1 = 5; ratio = 0;
+			DQSDelay0 = get_dqs_delay(channel, cs, lane0, Direction, dqs_delay_a);
+			DQSDelay1 = get_dqs_delay(channel, cs, lane1, Direction, dqs_delay_a);
+			dqs_delay = CalcDelay(DQSDelay0, DQSDelay1, ratio);
+			print_debug_dqs_pair("\t\tSetEccDQSRdWrPos: channel ", channel, Direction==DQS_READDIR? " R dqs_delay":" W dqs_delay",	dqs_delay, 2);
+			SetDQSDelayCSR(ctrl, channel, cs, ByteLane, Direction, dqs_delay);
+			save_dqs_delay(channel, cs, ByteLane, Direction, dqs_delay_a, dqs_delay);
+		}
+	}
+}
+
+
+static u32 train_DqsRcvrEn(const struct mem_controller *ctrl, u32 Pass,
+				struct sys_info *sysinfo)
+{
+	print_debug_dqs("\ntrain_DqsRcvrEn: begin ctrl ", ctrl->node_id, 0);
+	if( TrainRcvrEn(ctrl, Pass, sysinfo) != 0) {
+		print_err("\ntrain_DqsRcvrEn failed ctrl"); print_err_hex8(ctrl->node_id); print_err("\n");
+		return 1; //fail
+	}
+	print_debug_dqs("\ntrain_DqsRcvrEn: end ctrl ", ctrl->node_id, 0);
+	return 0;
+}
+static u32 train_DqsPos(const struct mem_controller *ctrl,
+			 struct sys_info *sysinfo)
+{
+	u32 cs;
+	print_debug_dqs("\ntrain_DqsPos: begin ctrl ", ctrl->node_id, 0);
+	if(sysinfo->meminfo[ctrl->node_id].memclk_set >= DCH_MemClkFreq_400MHz) {
+		for(cs=0; cs<8; cs+=2) {
+			if(TrainDQSRdWrPos(ctrl, cs, cs+2, sysinfo) != 0) {
+				print_err("\nDQS Training Rd Wr failed ctrl"); print_err_hex8(ctrl->node_id); print_err("\n");
+				return 1; //fail
+			}
+			else {
+				SetEccDQSRdWrPos(ctrl, cs, sysinfo);
+			}
+		}
+	} else {
+			if(TrainDQSRdWrPos(ctrl, 0, 8, sysinfo) != 0) {
+				print_err("\nDQS Training Rd Wr failed ctrl"); print_err_hex8(ctrl->node_id); print_err("\n");
+				return 1; //fail
+			}
+			else {
+				SetEccDQSRdWrPos(ctrl, 0, sysinfo);
+			}
+	}
+
+
+	print_debug_dqs("\ntrain_DqsPos: end ctrl ", ctrl->node_id, 0);
+	return 0;
+}
+
+
+/* setting variable mtrr, comes from linux kernel source */
+static void set_var_mtrr_dqs(
+	 u32 reg, unsigned long basek, unsigned long sizek,
+	 u8 type, u32 address_bits)
+{
+	msr_t base, mask;
+	u32 address_mask_high;
+
+	address_mask_high = ((1u << (address_bits - 32u)) - 1u);
+
+	base.hi = basek >> 22;
+	base.lo  = basek << 10;
+
+	if (sizek < 4*1024*1024) {
+		mask.hi = address_mask_high;
+		mask.lo = ~((sizek << 10) -1);
+	} else {
+		mask.hi = address_mask_high & (~((sizek >> 22) -1));
+		mask.lo = 0;
+	}
+
+	if (reg >= 8)
+		return;
+
+	if (sizek == 0) {
+		msr_t zero;
+		zero.lo = zero.hi = 0;
+		/* The invalid bit is kept in the mask, so we simply clear the
+		    relevant mask register to disable a range. */
+		wrmsr (MTRRphysMask_MSR(reg), zero);
+	} else {
+		/* Bit 32-35 of MTRRphysMask should be set to 1 */
+		base.lo |= type;
+		mask.lo |= 0x800;
+		wrmsr (MTRRphysBase_MSR(reg), base);
+		wrmsr (MTRRphysMask_MSR(reg), mask);
+	}
+}
+
+
+/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
+static  u32 fms(u32 x)
+{
+	int r;
+
+	__asm__("bsrl %1,%0\n\t"
+		"jnz 1f\n\t"
+		"movl $0,%0\n"
+		"1:" : "=r" (r) : "g" (x));
+	return r;
+}
+
+/* fms: find least sigificant bit set */
+static  u32 fls(u32 x)
+{
+	int r;
+
+	__asm__("bsfl %1,%0\n\t"
+		"jnz 1f\n\t"
+		"movl $32,%0\n"
+		"1:" : "=r" (r) : "g" (x));
+	return r;
+}
+
+static u32 range_to_mtrr(u32 reg, unsigned long range_startk,
+			unsigned long range_sizek,
+			unsigned long next_range_startk, u8 type, u32 address_bits)
+{
+	if (!range_sizek || (reg >= 8)) {
+		return reg;
+	}
+	while(range_sizek) {
+		unsigned long max_align, align;
+		unsigned long sizek;
+		/* Compute the maximum size I can make a range */
+		max_align = fls(range_startk);
+		align = fms(range_sizek);
+		if (align > max_align) {
+			align = max_align;
+		}
+		sizek = 1 << align;
+
+#if MEM_TRAIN_SEQ != 1
+		printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type %s\n",
+			reg, range_startk >>10, sizek >> 10,
+			(type==MTRR_TYPE_UNCACHEABLE)?"UC":
+			    ((type==MTRR_TYPE_WRBACK)?"WB":"Other")
+			);
+#endif
+		set_var_mtrr_dqs(reg++, range_startk, sizek, type, address_bits);
+		range_startk += sizek;
+		range_sizek -= sizek;
+		if (reg >= 8)
+			break;
+	}
+	return reg;
+}
+
+
+static void setup_mtrr_dqs(u32 tom_m, u32 tom2_m){
+	u32 reg;
+	msr_t msr;
+
+	//[0,512k), [512k, 640k)
+	msr.hi = 0x1e1e1e1e;
+	msr.lo = msr.hi;
+	wrmsr(0x250, msr);
+	wrmsr(0x258, msr);
+
+	//[1M, TOM)
+	reg = range_to_mtrr(2, 0, (tom_m<<10),4*1024*1024, MTRR_TYPE_WRBACK, 40);
+
+	//[4G, TOM2)
+	if(tom2_m) {
+		//enable tom2 and type
+		msr = rdmsr(SYSCFG_MSR);
+		msr.lo |= (1<<21) | (1<<22); //MtrrTom2En and Tom2ForceMemTypeWB
+		wrmsr(SYSCFG_MSR, msr);
+	}
+}
+
+
+static void clear_mtrr_dqs(u32 tom2_k){
+	msr_t msr;
+	u32 i;
+
+	// still enable from cache_as_ram.inc
+	msr = rdmsr(SYSCFG_MSR);
+	msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
+	wrmsr(SYSCFG_MSR,msr);
+
+	//[0,512k), [512k, 640k)
+	msr.hi = 0;
+	msr.lo = msr.hi;
+	wrmsr(0x250, msr);
+	wrmsr(0x258, msr);
+
+	//[1M, TOM)
+	for(i=0x204;i<0x210;i++) {
+		wrmsr(i, msr);
+	}
+
+	//[4G, TOM2)
+	if(tom2_k) {
+		//enable tom2 and type
+		msr = rdmsr(SYSCFG_MSR);
+		msr.lo &= ~((1<<21) | (1<<22)); //MtrrTom2En and Tom2ForceMemTypeWB
+		wrmsr(SYSCFG_MSR, msr);
+	}
+}
+#include "raminit_sysinfo_in_ram.c"
+
+#if MEM_TRAIN_SEQ > 0
+
+
+static void set_top_mem_ap(u32 tom_m, u32 tom2_m)
+{
+	msr_t msr;
+
+	/* Now set top of memory */
+	msr.lo = (tom2_m & 0x00000ff8) << 20;
+	msr.hi = (tom2_m & 0x0ffff000) >> 12;
+	wrmsr(TOP_MEM2, msr);
+
+	msr.lo = (tom_m & 0x00000ff8) << 20;
+	msr.hi = (tom_m & 0x0ffff000) >> 12;
+	wrmsr(TOP_MEM, msr);
+}
+
+
+static void dqs_timing(int i, const struct mem_controller *ctrl,
+			struct sys_info *sysinfo, u32 v)
+{
+	int ii;
+
+	if(sysinfo->mem_trained[i] != 0x80) return;
+	tsc_t tsc[4];
+
+#if MEM_TRAIN_SEQ == 1
+	//need to enable mtrr, so dqs training could access the test address
+	setup_mtrr_dqs(sysinfo->tom_m, sysinfo->tom2_m);
+#endif
+	if(v) {
+		print_debug("dqs_timing: i=");
+		print_debug_hex8(i);
+		print_debug(" ctrl->node_id: ");
+		print_debug_hex8(ctrl->node_id);
+		print_debug("\n");
+	}
+
+//	u32 dimm_mask = sysinfo->meminfo[ctrl->node_id].dimm_mask;
+//	u8 is_Width128 = sysinfo->meminfo[ctrl->node_id].is_Width128;
+
+	fill_mem_cs_sysinfo(i, ctrl, sysinfo);
+
+	if(v) {
+		tsc[0] = rdtsc();
+		print_debug("set DQS timing:RcvrEn:Pass1 ");
+	}
+
+	if(train_DqsRcvrEn(ctrl, 1, sysinfo)) {
+		sysinfo->mem_trained[i] = 0x81;
+		goto out;
+	}
+	if(v) {
+		print_debug(" done\n");
+
+		tsc[1] = rdtsc();
+
+		print_debug("set DQS timing:DQSPos ");
+	}
+	if(train_DqsPos(ctrl, sysinfo)) {
+		sysinfo->mem_trained[i] = 0x82;
+		goto out;
+	}
+
+	if(v) {
+		print_debug(" done\n");
+		tsc[2] = rdtsc();
+
+		print_debug("set DQS timing:RcvrEn:Pass2 ");
+	}
+	if(train_DqsRcvrEn(ctrl, 2, sysinfo)) {
+		sysinfo->mem_trained[i] = 0x83;
+		goto out;
+	}
+
+	if(v) {
+		print_debug(" done\n");
+
+		print_debug("set Ecc DQS Rcvr En ");
+	}
+	SetEccDQSRcvrEn_D(ctrl, sysinfo);
+
+	if(v) {
+		print_debug(" done\n");
+
+		tsc[3] = rdtsc();
+	}
+
+out:
+
+#if MEM_TRAIN_SEQ == 1
+	clear_mtrr_dqs(sysinfo->tom2_m);
+#endif
+
+	if(v) {
+		for(ii=0;ii<4;ii++) {
+			print_debug_dqs_tsc_x("Total DQS Training : tsc ", ii,	tsc[ii].hi, tsc[ii].lo);
+		}
+	}
+
+	if(sysinfo->mem_trained[i] == 0x80) {
+		sysinfo->mem_trained[i] = 1;
+	}
+
+}
+#endif
+
+#if MEM_TRAIN_SEQ == 1
+static void train_ram(u32 nodeid, struct sys_info *sysinfo,
+			struct sys_info *sysinfox)
+{
+	dqs_timing(nodeid, &sysinfo->ctrl[nodeid], sysinfo, 0);
+#if DQS_DELAY_COPY != 1
+	memcpy(&sysinfox->dqs_rcvr_dly_a[nodeid *2*8*9],&sysinfo->dqs_rcvr_dly_a[nodeid *2*8*9], 2*8*9);
+	memcpy(&sysinfox->dqs_delay_a[nodeid *2*2*9], &sysinfo->dqs_delay_a[nodeid *2*2*9], 2*2*9);
+#endif
+	sysinfox->mem_trained[nodeid] = sysinfo->mem_trained[nodeid];
+}
+
+
+static void copy_and_run_ap_code_in_car(u32 ret_addr);
+
+
+static void train_ram_on_node(u32 nodeid, u32 coreid,
+					struct sys_info *sysinfo, u32 retcall)
+{
+	if(coreid) return; // only do it on core0
+	struct sys_info *sysinfox = (struct sys_info *)((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_GLOBAL_VAR_SIZE);
+	wait_till_sysinfo_in_ram(); // use pci to get it
+
+	if(sysinfox->mem_trained[nodeid] == 0x80) { // need train
+		memcpy(sysinfo, sysinfox, DCACHE_RAM_GLOBAL_VAR_SIZE);
+		set_top_mem_ap(sysinfo->tom_m, sysinfo->tom2_m); // keep the ap's tom consistent with bsp's
+	#if CONFIG_AP_CODE_IN_CAR 0
+		print_debug("CODE IN ROM AND RUN ON NODE:"); print_debug_hex8(nodeid); print_debug("\n");
+		train_ram(nodeid, sysinfo, sysinfox);
+	#else
+		/* Can copy dqs_timing to ap cache and run from cache?
+		* we need linuxbios_ap_car.rom? and treat it as linuxbios_ram.rom for ap ?
+		*/
+		copy_and_run_ap_code_in_car(retcall);
+		// will not go back
+	#endif
+	}
+}
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_sysinfo_in_ram.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/raminit_sysinfo_in_ram.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 set_htic_bit(u8 i, u32 val, u8 bit)
+{
+	u32 dword;
+	dword = pci_read_config32(NODE_PCI(i, 0), HT_INIT_CONTROL);
+	dword &= ~(1<<bit);
+	dword |= ((val & 1) <<bit);
+	pci_write_config32(NODE_PCI(i, 0), HT_INIT_CONTROL, dword);
+}
+
+
+static u32 get_htic_bit(u8 i, u8 bit)
+{
+	u32 dword;
+	dword = pci_read_config32(NODE_PCI(i, 0), HT_INIT_CONTROL);
+	dword &= (1<<bit);
+	return dword;
+}
+
+static void wait_till_sysinfo_in_ram(void)
+{
+	while(1) {
+		/* give the NB a break, many CPUs spinning on one bit makes a
+		 * lot of traffic and time is not too important to APs.
+		 */
+		udelay(1000);
+		if(get_htic_bit(0, 9)) return;
+	}
+}
+
+static void set_sysinfo_in_ram(u32 val)
+{
+	set_htic_bit(0, val, 9);
+}
+
+static void fill_mem_ctrl(u32 controllers, struct mem_controller *ctrl_a, const u8 *spd_addr)
+{
+	int i;
+	int j;
+	int index = 0;
+	struct mem_controller *ctrl;
+	for(i=0;i<controllers; i++) {
+		ctrl = &ctrl_a[i];
+		ctrl->node_id = i;
+		ctrl->f0 = NODE_PCI(i, 0);
+		ctrl->f1 = NODE_PCI(i, 1);
+		ctrl->f2 = NODE_PCI(i, 2);
+		ctrl->f3 = NODE_PCI(i, 3);
+		ctrl->f4 = NODE_PCI(i, 4);
+		ctrl->f5 = NODE_PCI(i, 5);
+
+		if(spd_addr == (void *)0) continue;
+
+		ctrl->spd_switch_addr = spd_addr[index++];
+
+		for(j=0; j < 8; j++) {
+			ctrl->spd_addr[j] = spd_addr[index++];
+
+		}
+	}
+}
+
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/reset_test.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/reset_test.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,169 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <stdint.h>
+#include <cpu/x86/lapic.h>
+
+#define NODE_ID		0x60
+#define HT_INIT_CONTROL	0x6c
+#define HTIC_ColdR_Detect	(1<<4)
+#define HTIC_BIOSR_Detect	(1<<5)
+#define HTIC_INIT_Detect	(1<<6)
+
+/* mmconf is not ready */
+/* io_ext is not ready */
+static u32 cpu_init_detected(u8 nodeid)
+{
+	u32 htic;
+	device_t dev;
+
+	dev = NODE_PCI(nodeid, 0);
+	htic = pci_io_read_config32(dev, HT_INIT_CONTROL);
+
+	return !!(htic & HTIC_INIT_Detect);
+}
+
+static u32 bios_reset_detected(void)
+{
+	u32 htic;
+	htic = pci_io_read_config32(PCI_DEV(CBB, CDB, 0), HT_INIT_CONTROL);
+
+	return (htic & HTIC_ColdR_Detect) && !(htic & HTIC_BIOSR_Detect);
+}
+
+static u32 cold_reset_detected(void)
+{
+	u32 htic;
+	htic = pci_io_read_config32(PCI_DEV(CBB, CDB, 0), HT_INIT_CONTROL);
+
+	return !(htic & HTIC_ColdR_Detect);
+}
+
+static u32 other_reset_detected(void)	// other warm reset not started by BIOS
+{
+	u32 htic;
+	htic = pci_io_read_config32(PCI_DEV(CBB, CDB, 0), HT_INIT_CONTROL);
+
+	return (htic & HTIC_ColdR_Detect) && (htic & HTIC_BIOSR_Detect);
+}
+
+static void distinguish_cpu_resets(u8 nodeid)
+{
+	u32 htic;
+	device_t device;
+	device = NODE_PCI(nodeid, 0);
+	htic = pci_io_read_config32(device, HT_INIT_CONTROL);
+	htic |= HTIC_ColdR_Detect | HTIC_BIOSR_Detect | HTIC_INIT_Detect;
+	pci_io_write_config32(device, HT_INIT_CONTROL, htic);
+}
+
+static u32 warm_reset_detect(u8 nodeid)
+{
+	u32 htic;
+	device_t device;
+	device = NODE_PCI(nodeid, 0);
+	htic = pci_io_read_config32(device, HT_INIT_CONTROL);
+	return (htic & HTIC_ColdR_Detect) && !(htic & HTIC_BIOSR_Detect);
+}
+
+static void set_bios_reset(void)
+{
+
+	u32 nodes;
+	u32 htic;
+	device_t dev;
+	int i;
+
+	nodes = ((pci_read_config32(PCI_DEV(CBB, CDB, 0), 0x60) >> 4) & 7) + 1;
+
+	for(i = 0; i < nodes; i++) {
+		dev = NODE_PCI(i,0);
+		htic = pci_read_config32(dev, HT_INIT_CONTROL);
+		htic &= ~HTIC_BIOSR_Detect;
+		pci_write_config32(dev, HT_INIT_CONTROL, htic);
+	}
+}
+
+
+/* Look up a which bus a given node/link combination is on.
+ * return 0 when we can't find the answer.
+ */
+static u8 node_link_to_bus(u8 node, u8 link) // node are 6 bit, and link three bit
+{
+	u32 reg;
+	u32 val;
+
+	// put node and link in correct bit
+	val = ((node & 0x0f)<<4) | ((node & 0x30)<< (12-4)) | ((link & 0x07)<<8) ;
+
+	for(reg = 0xE0; reg < 0xF0; reg += 0x04) {
+		u32 config_map;
+		config_map = pci_io_read_config32(PCI_DEV(CBB, CDB, 1), reg);
+		if ((config_map & 3) != 3) {
+			continue;
+		}
+		if ((config_map & (((63 & 0x0f)<<4) | ((63 & 0x30)<< (12-4)) | ((7 & 0x07)<<8) )
+			) == val )
+		{
+			return (config_map >> 16) & 0xff;
+		}
+	}
+
+#if EXT_CONF_SUPPORT == 1
+	// let's check that in extend space
+	// use the nodeid extend space to find out the bus for the linkn
+	u32 tempreg;
+	int i;
+	int j;
+	u32 cfg_map_dest;
+	device_t dev;
+
+	cfg_map_dest = (1<<7)|(1<<6)|link;
+
+	// three case: index_min==index_max, index_min+1=index_max; index_min+1<index_max
+	dev = NODE_PCI(node, 1);
+	for(j=0; j<64; j++) {
+		pci_io_write_config32(dev, 0x110, j | (6<<28));
+		tempreg = pci_io_read_config32(dev, 0x114);
+		for(i=0; i<=3; i++) {
+			tempreg >>= (i*8);
+			if((tempreg & ((1<<7)|(1<<6)|0x3f)) == cfg_map_dest) {
+				return (i+(j<<2)); //busn_min
+			}
+		}
+	}
+#endif
+
+	return 0;
+}
+
+static u32 get_sblk(void)
+{
+	u32 reg;
+	/* read PCI_DEV(CBB,CDB,0) 0x64 bit [8:9] to find out SbLink m */
+	reg = pci_io_read_config32(PCI_DEV(CBB, CDB, 0), 0x64);
+	return ((reg>>8) & 3) ;
+}
+
+
+static u8 get_sbbusn(u8 sblk)
+{
+	return node_link_to_bus(0, sblk);
+}
+
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/resourcemap.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/resourcemap.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 setup_default_resource_map(void)
+{
+	static const u32 register_values[] = {
+		/* Careful set limit registers before base registers which contain
+		 the enables */
+		/* DRAM Limit i Registers
+		 * F1:0x44 i = 0
+		 * F1:0x4C i = 1
+		 * F1:0x54 i = 2
+		 * F1:0x5C i = 3
+		 * F1:0x64 i = 4
+		 * F1:0x6C i = 5
+		 * F1:0x74 i = 6
+		 * F1:0x7C i = 7
+		 * [ 2: 0] Destination Node ID
+		 *	   000 = Node 0
+		 *	   001 = Node 1
+		 *	   010 = Node 2
+		 *	   011 = Node 3
+		 *	   100 = Node 4
+		 *	   101 = Node 5
+		 *	   110 = Node 6
+		 *	   111 = Node 7
+		 * [ 7: 3] Reserved
+		 * [10: 8] Interleave select
+		 *	   specifies the values of A[14:12] to use with
+		 *	   interleave enable.
+		 * [15:11] Reserved
+		 * [31:16] DRAM Limit Address i Bits 39-24
+		 *	   This field defines the upper address bits of a 40 bit
+		 *	   address that define the end of the DRAM region.
+		 */
+		PCI_ADDR(CBB, CDB, 1, 0x44), 0x0000f8f8, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x4C), 0x0000f8f8, 0x00000001,
+		PCI_ADDR(CBB, CDB, 1, 0x54), 0x0000f8f8, 0x00000002,
+		PCI_ADDR(CBB, CDB, 1, 0x5C), 0x0000f8f8, 0x00000003,
+		PCI_ADDR(CBB, CDB, 1, 0x64), 0x0000f8f8, 0x00000004,
+		PCI_ADDR(CBB, CDB, 1, 0x6C), 0x0000f8f8, 0x00000005,
+		PCI_ADDR(CBB, CDB, 1, 0x74), 0x0000f8f8, 0x00000006,
+		PCI_ADDR(CBB, CDB, 1, 0x7C), 0x0000f8f8, 0x00000007,
+		/* DRAM Base i Registers
+		 * F1:0x40 i = 0
+		 * F1:0x48 i = 1
+		 * F1:0x50 i = 2
+		 * F1:0x58 i = 3
+		 * F1:0x60 i = 4
+		 * F1:0x68 i = 5
+		 * F1:0x70 i = 6
+		 * F1:0x78 i = 7
+		 * [ 0: 0] Read Enable
+		 *	   0 = Reads Disabled
+		 *	   1 = Reads Enabled
+		 * [ 1: 1] Write Enable
+		 *	   0 = Writes Disabled
+		 *	   1 = Writes Enabled
+		 * [ 7: 2] Reserved
+		 * [10: 8] Interleave Enable
+		 *	   000 = No interleave
+		 *	   001 = Interleave on A[12] (2 nodes)
+		 *	   010 = reserved
+		 *	   011 = Interleave on A[12] and A[14] (4 nodes)
+		 *	   100 = reserved
+		 *	   101 = reserved
+		 *	   110 = reserved
+		 *	   111 = Interleve on A[12] and A[13] and A[14] (8 nodes)
+		 * [15:11] Reserved
+		 * [13:16] DRAM Base Address i Bits 39-24
+		 *	   This field defines the upper address bits of a 40-bit
+		 *	   address that define the start of the DRAM region.
+		 */
+		PCI_ADDR(CBB, CDB, 1, 0x40), 0x0000f8fc, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x48), 0x0000f8fc, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x50), 0x0000f8fc, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x58), 0x0000f8fc, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x60), 0x0000f8fc, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x68), 0x0000f8fc, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x70), 0x0000f8fc, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x78), 0x0000f8fc, 0x00000000,
+
+		/* Memory-Mapped I/O Limit i Registers
+		 * F1:0x84 i = 0
+		 * F1:0x8C i = 1
+		 * F1:0x94 i = 2
+		 * F1:0x9C i = 3
+		 * F1:0xA4 i = 4
+		 * F1:0xAC i = 5
+		 * F1:0xB4 i = 6
+		 * F1:0xBC i = 7
+		 * [ 2: 0] Destination Node ID
+		 *	   000 = Node 0
+		 *	   001 = Node 1
+		 *	   010 = Node 2
+		 *	   011 = Node 3
+		 *	   100 = Node 4
+		 *	   101 = Node 5
+		 *	   110 = Node 6
+		 *	   111 = Node 7
+		 * [ 3: 3] Reserved
+		 * [ 5: 4] Destination Link ID
+		 *	   00 = Link 0
+		 *	   01 = Link 1
+		 *	   10 = Link 2
+		 *	   11 = Reserved
+		 * [ 6: 6] Reserved
+		 * [ 7: 7] Non-Posted
+		 *	   0 = CPU writes may be posted
+		 *	   1 = CPU writes must be non-posted
+		 * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
+		 *	   This field defines the upp adddress bits of a 40-bit
+		 *	   address that defines the end of a memory-mapped
+		 * 	   I/O region n
+		 */
+		PCI_ADDR(CBB, CDB, 1, 0x84), 0x00000048, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x8C), 0x00000048, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x94), 0x00000048, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x9C), 0x00000048, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xA4), 0x00000048, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xAC), 0x00000048, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xB4), 0x00000048, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xBC), 0x00000048, 0x00ffff00,
+
+		/* Memory-Mapped I/O Base i Registers
+		 * F1:0x80 i = 0
+		 * F1:0x88 i = 1
+		 * F1:0x90 i = 2
+		 * F1:0x98 i = 3
+		 * F1:0xA0 i = 4
+		 * F1:0xA8 i = 5
+		 * F1:0xB0 i = 6
+		 * F1:0xB8 i = 7
+		 * [ 0: 0] Read Enable
+		 *	   0 = Reads disabled
+		 *	   1 = Reads Enabled
+		 * [ 1: 1] Write Enable
+		 *	   0 = Writes disabled
+		 *	   1 = Writes Enabled
+		 * [ 2: 2] Cpu Disable
+		 *	   0 = Cpu can use this I/O range
+		 *	   1 = Cpu requests do not use this I/O range
+		 * [ 3: 3] Lock
+		 *	   0 = base/limit registers i are read/write
+		 *	   1 = base/limit registers i are read-only
+		 * [ 7: 4] Reserved
+		 * [31: 8] Memory-Mapped I/O Base Address i (39-16)
+		 *	   This field defines the upper address bits of a 40bit
+		 * 	   address that defines the start of memory-mapped
+		 *	   I/O region i
+		 */
+		PCI_ADDR(CBB, CDB, 1, 0x80), 0x000000f0, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x88), 0x000000f0, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x90), 0x000000f0, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0x98), 0x000000f0, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xA0), 0x000000f0, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xA8), 0x000000f0, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xB0), 0x000000f0, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xB8), 0x000000f0, 0x00fc0003,
+
+		/* PCI I/O Limit i Registers
+		 * F1:0xC4 i = 0
+		 * F1:0xCC i = 1
+		 * F1:0xD4 i = 2
+		 * F1:0xDC i = 3
+		 * [ 2: 0] Destination Node ID
+		 *	   000 = Node 0
+		 *	   001 = Node 1
+		 *	   010 = Node 2
+		 *	   011 = Node 3
+		 *	   100 = Node 4
+		 *	   101 = Node 5
+		 *	   110 = Node 6
+		 *	   111 = Node 7
+		 * [ 3: 3] Reserved
+		 * [ 5: 4] Destination Link ID
+		 *	   00 = Link 0
+		 *	   01 = Link 1
+		 *	   10 = Link 2
+		 *	   11 = reserved
+		 * [11: 6] Reserved
+		 * [24:12] PCI I/O Limit Address i
+		 *	   This field defines the end of PCI I/O region n
+		 * [31:25] Reserved
+		 */
+		PCI_ADDR(CBB, CDB, 1, 0xC4), 0xFE000FC8, 0x01fff000,
+		PCI_ADDR(CBB, CDB, 1, 0xCC), 0xFE000FC8, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xD4), 0xFE000FC8, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xDC), 0xFE000FC8, 0x00000000,
+
+		/* PCI I/O Base i Registers
+		 * F1:0xC0 i = 0
+		 * F1:0xC8 i = 1
+		 * F1:0xD0 i = 2
+		 * F1:0xD8 i = 3
+		 * [ 0: 0] Read Enable
+		 *	   0 = Reads Disabled
+		 *	   1 = Reads Enabled
+		 * [ 1: 1] Write Enable
+		 *	   0 = Writes Disabled
+		 *	   1 = Writes Enabled
+		 * [ 3: 2] Reserved
+		 * [ 4: 4] VGA Enable
+		 *	   0 = VGA matches Disabled
+		 *	   1 = matches all address < 64K and where A[9:0] is in
+		 *	       the range 3B0-3BB or 3C0-3DF independent of the
+		 *	        base & limit registers
+		 * [ 5: 5] ISA Enable
+		 *	   0 = ISA matches Disabled
+		 *	   1 = Blocks address < 64K and in the last 768 bytes of
+		 *	       eack 1K block from matching agains this base/limit
+		 *	       pair
+		 * [11: 6] Reserved
+		 * [24:12] PCI I/O Base i
+		 *	   This field defines the start of PCI I/O region n
+		 * [31:25] Reserved
+		 */
+		PCI_ADDR(CBB, CDB, 1, 0xC0), 0xFE000FCC, 0x00000003,
+		PCI_ADDR(CBB, CDB, 1, 0xC8), 0xFE000FCC, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xD0), 0xFE000FCC, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xD8), 0xFE000FCC, 0x00000000,
+
+		/* Config Base and Limit i Registers
+		 * F1:0xE0 i = 0
+		 * F1:0xE4 i = 1
+		 * F1:0xE8 i = 2
+		 * F1:0xEC i = 3
+		 * [ 0: 0] Read Enable
+		 *	   0 = Reads Disabled
+		 *	   1 = Reads Enabled
+		 * [ 1: 1] Write Enable
+		 *	   0 = Writes Disabled
+		 *	   1 = Writes Enabled
+		 * [ 2: 2] Device Number Compare Enable
+		 *	   0 = The ranges are based on bus number
+		 *	   1 = The ranges are ranges of devices on bus 0
+		 * [ 3: 3] Reserved
+		 * [ 6: 4] Destination Node
+		 *	   000 = Node 0
+		 *	   001 = Node 1
+		 *	   010 = Node 2
+		 *	   011 = Node 3
+		 *	   100 = Node 4
+		 *	   101 = Node 5
+		 *	   110 = Node 6
+		 *	   111 = Node 7
+		 * [ 7: 7] Reserved
+		 * [ 9: 8] Destination Link
+		 *	   00 = Link 0
+		 *	   01 = Link 1
+		 *	   10 = Link 2
+		 *	   11 - Reserved
+		 * [15:10] Reserved
+		 * [23:16] Bus Number Base i
+		 *	   This field defines the lowest bus number in
+		 *	    configuration region i
+		 * [31:24] Bus Number Limit i
+		 *	   This field defines the highest bus number in
+		 *	   configuration regin i
+		 */
+		PCI_ADDR(CBB, CDB, 1, 0xE0), 0x0000FC88, 0xff000003,
+		PCI_ADDR(CBB, CDB, 1, 0xE4), 0x0000FC88, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xE8), 0x0000FC88, 0x00000000,
+		PCI_ADDR(CBB, CDB, 1, 0xEC), 0x0000FC88, 0x00000000,
+	};
+
+	u32 max;
+	max = sizeof(register_values)/sizeof(register_values[0]);
+	setup_resource_map(register_values, max);
+}
+
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/root_complex/Config.lb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/root_complex/Config.lb	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1 @@
+config chip.h
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/root_complex/chip.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/root_complex/chip.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+struct northbridge_amd_amdfam10_root_complex_config
+{
+};
+
+extern struct chip_operations northbridge_amd_amdfam10_root_complex_ops;
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/setup_resource_map.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/setup_resource_map.c	2007-12-12 11:53:36.000000000 -0700
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#define RES_DEBUG 0
+
+static void setup_resource_map(const u32 *register_values, u32 max)
+{
+	u32 i;
+//	print_debug("setting up resource map....");
+
+	for(i = 0; i < max; i += 3) {
+		device_t dev;
+		u32 where;
+		u32 reg;
+
+		dev = register_values[i] & ~0xff;
+		where = register_values[i] & 0xff;
+		reg = pci_read_config32(dev, where);
+		reg &= register_values[i+1];
+		reg |= register_values[i+2];
+		pci_write_config32(dev, where, reg);
+	}
+//	print_debug("done.\n");
+}
+
+
+static void setup_resource_map_offset(const u32 *register_values,
+					u32 max, u32 offset_pci_dev,
+					u32 offset_io_base)
+{
+	u32 i;
+//	print_debug("setting up resource map offset....");
+	for(i = 0; i < max; i += 3) {
+		device_t dev;
+		u32 where;
+		unsigned long reg;
+		dev = (register_values[i] & ~0xfff) + offset_pci_dev;
+		where = register_values[i] & 0xfff;
+		reg = pci_read_config32(dev, where);
+		reg &= register_values[i+1];
+		reg |= register_values[i+2] + offset_io_base;
+		pci_write_config32(dev, where, reg);
+	}
+//	print_debug("done.\n");
+}
+
+#define RES_PCI_IO 0x10
+#define RES_PORT_IO_8 0x22
+#define RES_PORT_IO_32 0x20
+#define RES_MEM_IO 0x40
+
+static void setup_resource_map_x_offset(const u32 *register_values, u32 max,
+					u32 offset_pci_dev, u32 offset_io_base)
+{
+	u32 i;
+
+#if RES_DEBUG
+	print_debug("setting up resource map ex offset....");
+
+#endif
+
+#if RES_DEBUG
+	print_debug("\n");
+#endif
+	for(i = 0; i < max; i += 4) {
+#if RES_DEBUG
+		printk_debug("%04x: %02x %08x <- & %08x | %08x\n",
+			i/4, register_values[i],
+			register_values[i+1] + ( (register_values[i]==RES_PCI_IO) ? offset_pci_dev : 0),
+			register_values[i+2],
+			register_values[i+3] + ( ( (register_values[i] & RES_PORT_IO_32) == RES_PORT_IO_32) ? offset_io_base : 0)
+			);
+#endif
+		switch (register_values[i]) {
+		case RES_PCI_IO: //PCI
+			{
+			device_t dev;
+			u32 where;
+			u32 reg;
+			dev = (register_values[i+1] & ~0xfff) + offset_pci_dev;
+			where = register_values[i+1] & 0xfff;
+			reg = pci_read_config32(dev, where);
+			reg &= register_values[i+2];
+			reg |= register_values[i+3];
+			pci_write_config32(dev, where, reg);
+			}
+			break;
+		case RES_PORT_IO_8: // io 8
+			{
+			u32 where;
+			u32 reg;
+			where = register_values[i+1] + offset_io_base;
+			reg = inb(where);
+			reg &= register_values[i+2];
+			reg |= register_values[i+3];
+			outb(reg, where);
+			}
+			break;
+		case RES_PORT_IO_32:  //io32
+			{
+			u32 where;
+			u32 reg;
+			where = register_values[i+1] + offset_io_base;
+			reg = inl(where);
+			reg &= register_values[i+2];
+			reg |= register_values[i+3];
+			outl(reg, where);
+			}
+			break;
+		} // switch
+
+
+	}
+
+#if RES_DEBUG
+	print_debug("done.\n");
+#endif
+}
+static void setup_resource_map_x(const u32 *register_values, u32 max)
+{
+	u32 i;
+
+#if RES_DEBUG
+	print_debug("setting up resource map ex offset....");
+#endif
+
+#if RES_DEBUG
+	print_debug("\n");
+#endif
+	for(i = 0; i < max; i += 4) {
+#if RES_DEBUG
+		printk_debug("%04x: %02x %08x <- & %08x | %08x\n",
+		i/4, register_values[i],register_values[i+1], register_values[i+2], register_values[i+3]);
+#endif
+		switch (register_values[i]) {
+		case RES_PCI_IO: //PCI
+			{
+			device_t dev;
+			u32 where;
+			u32 reg;
+			dev = register_values[i+1] & ~0xff;
+			where = register_values[i+1] & 0xff;
+			reg = pci_read_config32(dev, where);
+			reg &= register_values[i+2];
+			reg |= register_values[i+3];
+			pci_write_config32(dev, where, reg);
+			}
+			break;
+		case RES_PORT_IO_8: // io 8
+			{
+			u32 where;
+			u32 reg;
+			where = register_values[i+1];
+			reg = inb(where);
+			reg &= register_values[i+2];
+			reg |= register_values[i+3];
+			outb(reg, where);
+			}
+			break;
+		case RES_PORT_IO_32:  //io32
+			{
+			u32 where;
+			u32 reg;
+			where = register_values[i+1];
+			reg = inl(where);
+			reg &= register_values[i+2];
+			reg |= register_values[i+3];
+			outl(reg, where);
+			}
+			break;
+		} // switch
+
+
+	}
+
+#if RES_DEBUG
+	print_debug("done.\n");
+#endif
+}
+
+static void setup_iob_resource_map(const u32 *register_values, u32 max)
+{
+	u32 i;
+
+	for(i = 0; i < max; i += 3) {
+		u32 where;
+		u32 reg;
+
+		where = register_values[i];
+		reg = inb(where);
+		reg &= register_values[i+1];
+		reg |= register_values[i+2];
+		outb(reg, where);
+	}
+}
+
+static void setup_io_resource_map(const u32 *register_values, u32 max)
+{
+	u32 i;
+
+	for(i = 0; i < max; i += 3) {
+		u32 where;
+		u32 reg;
+
+		where = register_values[i];
+		reg = inl(where);
+		reg &= register_values[i+1];
+		reg |= register_values[i+2];
+
+		outl(reg, where);
+	}
+}
+
+
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/spd_ddr2.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/spd_ddr2.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+/* SPDs for DDR2 SDRAM */
+#define SPD_MEM_TYPE	2
+	#define SPD_MEM_TYPE_SDRAM_DDR	0x07
+	#define SPD_MEM_TYPE_SDRAM_DDR2	0x08
+
+#define SPD_DIMM_TYPE	20	/* x  bit0 or bit4 =1 mean registered*/
+	#define SPD_DIMM_TYPE_RDIMM	(1<<0)
+	#define SPD_DIMM_TYPE_UDIMM	(1<<1)
+	#define SPD_DIMM_TYPE_SODIMM	(1<<2)
+	#define SPD_DIMM_TYPE_uDIMM	(1<<3)
+	#define SPD_DIMM_TYPE_mRDIMM	(1<<4)
+	#define SPD_DIMM_TYPE_mUDIMM	(1<<5)
+#define SPD_MOD_ATTRIB	21
+	#define SPD_MOD_ATTRIB_DIFCK	0x20
+	#define SPD_MOD_ATTRIB_REGADC	0x11   /* x */
+	#define SPD_MOD_ATTRIB_PROBE	0x40
+
+#define SPD_DEV_ATTRIB	22  /* Device attributes --- general */
+#define SPD_DIMM_CONF_TYPE	11
+	#define SPD_DIMM_CONF_TYPE_ECC		0x02
+	#define SPD_DIMM_CONF_TYPE_ADDR_PARITY	0x04	 /* ? */
+
+#define SPD_ROW_NUM	3	/* Number of Row addresses */
+#define SPD_COL_NUM	4	/* Number of Column addresses */
+#define SPD_BANK_NUM	17	/* SDRAM Device attributes - Number of Banks on
+				 SDRAM device, it could be 0x4, 0x8, so address
+				 lines for that would be 2, and 3 */
+
+/* Number of Ranks bit [2:0], Package (bit4, 1=stack, 0=planr), Height bit[7:5] */
+#define SPD_MOD_ATTRIB_RANK	5
+	#define SPD_MOD_ATTRIB_RANK_NUM_SHIFT	0
+	#define SPD_MOD_ATTRIB_RANK_NUM_MASK	0x07
+		#define SPD_MOD_ATTRIB_RANK_NUM_BASE	1
+		#define SPD_MOD_ATTRIB_RANK_NUM_MIN	1
+		#define SPD_MOD_ATTRIB_RANK_NUM_MAX	8
+
+#define SPD_RANK_SIZE	31	/* Only one bit is set */
+	#define SPD_RANK_SIZE_1GB	(1<<0)
+	#define SPD_RANK_SIZE_2GB	(1<<1)
+	#define SPD_RANK_SIZE_4GB	(1<<2)
+	#define SPD_RANK_SIZE_8GB	(1<<3)
+	#define SPD_RANK_SIZE_16GB	(1<<4)
+	#define SPD_RANK_SIZE_128MB	(1<<5)
+	#define SPD_RANK_SIZE_256MB	(1<<6)
+	#define SPD_RANK_SIZE_512MB	(1<<7)
+
+#define SPD_DATA_WIDTH		6	/* valid value 0, 32, 33, 36, 64, 72, 80, 128, 144, 254, 255 */
+#define SPD_PRI_WIDTH		13	/* Primary SDRAM Width, it could be 0x08 or 0x10 */
+#define SPD_ERR_WIDTH		14	/* Error Checking SDRAM Width, it could be 0x08 or 0x10 */
+
+#define SPD_CAS_LAT	18	/* SDRAM Device Attributes -- CAS Latency */
+	#define SPD_CAS_LAT_2	(1<<2)
+	#define SPD_CAS_LAT_3	(1<<3)
+	#define SPD_CAS_LAT_4	(1<<4)
+	#define SPD_CAS_LAT_5	(1<<5)
+	#define SPD_CAS_LAT_6	(1<<6)
+
+#define SPD_TRP	27  /* bit [7:2] = 1-63 ns, bit [1:0] 0.25ns+, final value ((val>>2) + (val & 3) * 0.25)ns */
+#define SPD_TRRD	28
+#define SPD_TRCD	29
+#define SPD_TRAS	30
+#define SPD_TWR	36	/* x */
+#define SPD_TWTR	37	/* x */
+#define SPD_TRTP	38	/* x */
+
+#define SPD_TRC	41	/* add byte 0x40 bit [3:1] , so final val41+ table[((val40>>1) & 0x7)]  ... table[]={0, 0.25, 0.33, 0.5, 0.75, 0, 0}*/
+#define SPD_TRFC	42	/* add byte 0x40 bit [6:4] , so final val42+ table[((val40>>4) & 0x7)] + (val40 & 1)*256*/
+
+#define SPD_TREF	12
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/ssdt.dsl
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/ssdt.dsl	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,346 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+/*
+ * Make sure HC_NUMS and HC_POSSIBLE_NUM setting is consistent to this file
+ */
+
+DefinitionBlock ("SSDT.aml", "SSDT", 1, "AMD-FAM10", "AMD-ACPI", 100925440)
+{
+	/*
+	 * These objects were referenced but not defined in this table
+	 */
+	External (\_SB_.PCI0, DeviceObj)
+
+	Scope (\_SB.PCI0)
+	{
+		Name (BUSN, Package (0x20) /* HC_NUMS */
+		{
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x10101010,
+			0x11111111,
+			0x12121212,
+			0x13131313,
+			0x14141414,
+			0x15151515,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc
+		})
+		Name (MMIO, Package (0x80) /* HC_NUMS * 4 */
+		{
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x11111111,
+			0x22222222,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x11111111,
+			0x22222222,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x11111111,
+			0x22222222,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x11111111,
+			0x22222222,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x11111111,
+			0x22222222,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888
+		})
+		Name (PCIO, Package (0x40) /* HC_NUMS * 2 */
+		{
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0xaaaaaaaa,
+			0xbbbbbbbb,
+			0xcccccccc,
+			0xdddddddd,
+			0xeeeeeeee,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x99999999,
+			0xaaaaaaaa,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444
+		})
+		Name (SBLK, 0x11)
+		Name (TOM1, 0xaaaaaaaa)
+		Name (SBDN, 0xbbbbbbbb)
+		Name (HCLK, Package (0x20) /* HC_POSSIBLE_NUM */
+		{
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888
+		})
+		Name (HCDN, Package (0x20) /* HC_POSSIBLE_NUM */
+		{
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888,
+			0x11111111,
+			0x22222222,
+			0x33333333,
+			0x44444444,
+			0x55555555,
+			0x66666666,
+			0x77777777,
+			0x88888888
+		})
+		Name (CBB, 0x99)
+		Name (CBST, 0x88)
+		Name (CBB2, 0x77)
+		Name (CBS2, 0x66)
+
+	}
+}
+
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr1.dsl
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr1.dsl	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+DefinitionBlock ("SSPR.aml", "SSDT", 1, "AMD-FAM10", "AMD-ACPI", 100925441)
+{
+	Scope (\_SB)
+	{
+		Processor (\_SB.CPAA, 0xbb, 0x120, 6) // CPU0 and 0x01 need to be updated
+		{
+			Name(_PCT, Package ()
+			{
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_CTRL
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_STATUS
+			})
+
+			Name(_PSS, Package()
+			{
+				Package(0x06) {0x1111, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+			})
+		}
+
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr2.dsl
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr2.dsl	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+DefinitionBlock ("SSPR.aml", "SSDT", 1, "AMD-FAM10", "AMD-ACPI", 100925441)
+{
+	Scope (\_SB)
+	{
+		Processor (\_SB.CPAA, 0xbb, 0x120, 6) // CPU0 and 0x01 need to be updated
+		{
+			Name(_PCT, Package ()
+			{
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_CTRL
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_STATUS
+			})
+
+			Name(_PSS, Package()
+			{
+				Package(0x06) {0x1111, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x7777, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+			})
+		}
+
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr3.dsl
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr3.dsl	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+DefinitionBlock ("SSPR.aml", "SSDT", 1, "AMD-FAM10", "AMD-ACPI", 100925441)
+{
+	Scope (\_SB)
+	{
+		Processor (\_SB.CPAA, 0xbb, 0x120, 6) // CPU0 and 0x01 need to be updated
+		{
+			Name(_PCT, Package ()
+			{
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_CTRL
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_STATUS
+			})
+
+			Name(_PSS, Package()
+			{
+				Package(0x06) {0x1111, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x7777, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x8888, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+			})
+		}
+
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr4.dsl
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr4.dsl	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+DefinitionBlock ("SSPR.aml", "SSDT", 1, "AMD-FAM10", "AMD-ACPI", 100925441)
+{
+	Scope (\_SB)
+	{
+		Processor (\_SB.CPAA, 0xbb, 0x120, 6) // CPU0 and 0x01 need to be updated
+		{
+			Name(_PCT, Package ()
+			{
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_CTRL
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_STATUS
+			})
+
+			Name(_PSS, Package()
+			{
+				Package(0x06) {0x1111, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x7777, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x8888, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x9999, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+			})
+		}
+
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr5.dsl
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdfam10/sspr5.dsl	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+DefinitionBlock ("SSPR.aml", "SSDT", 1, "AMD-FAM10", "AMD-ACPI", 100925441)
+{
+	Scope (\_SB)
+	{
+		Processor (\_SB.CPAA, 0xbb, 0x120, 6) // CPU0 and 0x01 need to be updated
+		{
+			Name(_PCT, Package ()
+			{
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_CTRL
+				ResourceTemplate() {Register (FFixedHW, 0, 0, 0)}, //PERF_STATUS
+			})
+
+			Name(_PSS, Package()
+			{
+				Package(0x06) {0x1111, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x7777, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x8888, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0x9999, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+				Package(0x06) {0xaaaa, 0x222222, 0x3333, 0x4444, 0x55, 0x66 },
+			})
+		}
+
+	}
+}
Index: LinuxBIOSv2/src/cpu/amd/car/cache_as_ram.inc
===================================================================
--- LinuxBIOSv2.orig/src/cpu/amd/car/cache_as_ram.inc	2007-12-12 11:03:38.000000000 -0700
+++ LinuxBIOSv2/src/cpu/amd/car/cache_as_ram.inc	2007-12-12 14:14:12.000000000 -0700
@@ -1,196 +1,368 @@
-/* by yhlu 6.2005 */
-/* yhlu 2005.12 make it support HDT Memory Debuggers with Disassmbly, please select the PCI Bus mem for Phys Type*/
-/* yhlu 2006.3 copy data from cache to ram and reserve 0x1000 for global variables */
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2005-2007 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
+ */
+
 #define CacheSize DCACHE_RAM_SIZE
 #define CacheBase (0xd0000 - CacheSize)
+
 /* leave some space for global variable to pass to RAM stage */
 #define GlobalVarSize DCACHE_RAM_GLOBAL_VAR_SIZE
 
+#if CAR_FAM10 == 1
+#define CacheSizeAPStack 0x400 /* 1K */
+//#define CacheSizeAPStack 0x200 /* 512 */
+#endif
+
 #include <cpu/x86/mtrr.h>
 #include <cpu/amd/mtrr.h>
 
 	/* Save the BIST result */
-	movl    %eax, %ebp
-	
+	movl	%eax, %ebp
+
 	/*for normal part %ebx already contain cpu_init_detected from fallback call */
 
 cache_as_ram_setup:
+
+	movb	$0xA0, %al
+	outb	%al, $0x80
 
 	/* hope we can skip the double set for normal part */
-#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE==1)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==1))
+#if ((HAVE_FAILOVER_BOOT == 1) && (USE_FAILOVER_IMAGE == 1)) || ((HAVE_FAILOVER_BOOT == 0) && (USE_FALLBACK_IMAGE == 1))
+
 	/* check if cpu_init_detected */
 	movl	$MTRRdefType_MSR, %ecx
 	rdmsr
-	andl $0x00000800, %eax
-	movl %eax, %ebx  /* We store the status */
-	
+	andl	$(1 << 11), %eax
+	movl	%eax, %ebx	/* We store the status */
+
+#if CAR_FAM10 == 1
+	/* for GH, CAR need to set DRAM Base/Limit Registers to direct that to node0 */
+
+	/* Only BSP needed, for other nodes set during HT/memory init. */
+	/* So we need to check if it is BSP */
+	movl	$0x1b, %ecx
+	rdmsr
+	bt	$8, %eax /*BSC */
+	jnc	CAR_FAM10_out
+
+	/* Enable RT tables on BSP */
+	movl	$0x8000c06c, %eax
+	movw	$0xcf8, %dx
+	outl	%eax, %dx
+	addw	$4, %dx
+	inl	%dx, %eax
+	btr	$0, %eax
+	outl	%eax, %dx
+
+	/* Setup temporary DRAM map: [0,16M) bit 0-23 */
+	movl	$0x8000c144, %eax
+	movw	$0xcf8, %dx
+	outl	%eax, %dx
+	addw	$4, %dx
+	movl	$0, %eax
+	outl	%eax, %dx
+
+	movl	$0x8000c140, %eax
+	movw	$0xcf8, %dx
+	outl	%eax, %dx
+	addw	$4, %dx
+	movl	$3, %eax
+	outl	%eax, %dx
+
+CAR_FAM10_out:
+
+#endif
+
+#if CAR_FAM10 == 1
+	/* Errata 193: Disable clean copybacks to L3 cache to allow cached ROM.
+	   Re-enable it in after RAM is initialized and before CAR is disabled */
+	movl	$0xc001102a, %ecx
+	rdmsr
+	bts	$15, %eax
+	wrmsr
+#endif
+
 	/* Set MtrrFixDramModEn for clear fixed mtrr */
 enable_fixed_mtrr_dram_modify:
 	movl	$SYSCFG_MSR, %ecx
 	rdmsr
-	andl	$(~(SYSCFG_MSR_MtrrFixDramEn|SYSCFG_MSR_MtrrVarDramEn)), %eax
+	andl	$(~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrVarDramEn)), %eax
 	orl	$SYSCFG_MSR_MtrrFixDramModEn, %eax
 	wrmsr
 
-	/*Clear all MTRRs */
-
-	xorl    %edx, %edx
-	movl    $fixed_mtrr_msr, %esi
+	/* Clear all MTRRs */
+	xorl	%edx, %edx
+	movl	$fixed_mtrr_msr, %esi
+
 clear_fixed_var_mtrr:
-        lodsl   (%esi), %eax
-        testl   %eax, %eax
-        jz      clear_fixed_var_mtrr_out
-
-        movl    %eax, %ecx
-        xorl    %eax, %eax
-        wrmsr   
+	lodsl	(%esi), %eax
+	testl	%eax, %eax
+	jz		clear_fixed_var_mtrr_out
+
+	movl	%eax, %ecx
+	xorl	%eax, %eax
+	wrmsr
 
-        jmp     clear_fixed_var_mtrr
+	jmp		clear_fixed_var_mtrr
 clear_fixed_var_mtrr_out:
 
-#if CacheSize == 0x10000 
-        /* enable caching for 64K using fixed mtrr */
-        movl    $0x268, %ecx  /* fix4k_c0000*/
-        movl    $0x06060606, %eax /* WB IO type */
-	movl    %eax, %edx
-        wrmsr
+#if CacheSize == 0x10000
+	/* enable caching for 64K using fixed mtrr */
+	movl	$0x268, %ecx  /* fix4k_c0000*/
+ #if CAR_FAM10 == 1
+	movl	$0x1e1e1e1e, %edx /* WB MEM type */
+ #else
+	movl	$0x06060606, %edx /* WB IO type */
+ #endif
+
+	movl	%edx, %eax
+		wrmsr
 	movl	$0x269, %ecx
 	wrmsr
 #endif
 
 #if CacheSize == 0xc000
-        /* enable caching for 16K using fixed mtrr */
-        movl    $0x268, %ecx  /* fix4k_c4000*/
-        movl    $0x06060606, %edx /* WB IO type */
-        xorl    %eax, %eax
-        wrmsr
-        /* enable caching for 32K using fixed mtrr */
-        movl    $0x269, %ecx  /* fix4k_c8000*/
-        movl    $0x06060606, %eax /* WB IO type */
-        movl    %eax, %edx
-        wrmsr
-
+	/* enable caching for 16K using fixed mtrr */
+	movl	$0x268, %ecx  /* fix4k_c4000*/
+ #if CAR_FAM10 == 1
+	movl	$0x1e1e1e1e, %edx /* WB MEM type */
+ #else
+	movl	$0x06060606, %edx /* WB IO type */
+ #endif
+	xorl	%eax, %eax
+	wrmsr
+	/* enable caching for 32K using fixed mtrr */
+	movl	$0x269, %ecx  /* fix4k_c8000*/
+ #if CAR_FAM10 == 1
+	movl	$0x1e1e1e1e, %edx /* WB MEM type */
+ #else
+	movl	$0x06060606, %edx /* WB IO type */
+ #endif
+	movl	%edx, %eax
+	wrmsr
 #endif
 
 
 #if CacheSize == 0x8000
-        /* enable caching for 32K using fixed mtrr */
-        movl    $0x269, %ecx  /* fix4k_c8000*/
-        movl    $0x06060606, %eax /* WB IO type */
-	movl    %eax, %edx
+	/* enable caching for 32K using fixed mtrr */
+	movl	$0x269, %ecx  /* fix4k_c8000*/
+ #if CAR_FAM10 == 1
+	movl	$0x1e1e1e1e, %edx /* WB MEM type */
+ #else
+	movl	$0x06060606, %edx /* WB IO type */
+ #endif
+	movl	%edx, %eax
 	wrmsr
 #endif
 
 #if CacheSize < 0x8000
-        /* enable caching for 16K/8K/4K using fixed mtrr */
-        movl    $0x269, %ecx  /* fix4k_cc000*/
-    #if CacheSize == 0x4000
-        movl    $0x06060606, %edx /* WB IO type */
-    #endif
-    #if CacheSize == 0x2000
-        movl    $0x06060000, %edx /* WB IO type */
-    #endif
-    #if CacheSize == 0x1000
-        movl    $0x06000000, %edx /* WB IO type */
-    #endif
-	xorl    %eax, %eax
+	/* enable caching for 16K/8K/4K using fixed mtrr */
+	movl	$0x269, %ecx  /* fix4k_cc000*/
+ #if CacheSize == 0x4000
+  #if CAR_FAM10 == 1
+	movl	$0x1e1e1e1e, %edx /* WB MEM type */
+  #else
+	movl	$0x06060606, %edx /* WB IO type */
+  #endif
+ #endif
+ #if CacheSize == 0x2000
+  #if CAR_FAM10 == 1
+	movl	$0x1e1e0000, %edx /* WB MEM type */
+  #else
+	movl	$0x06060000, %edx /* WB IO type */
+  #endif
+ #endif
+ #if CacheSize == 0x1000
+  #if CAR_FAM10 == 1
+	movl	$0x1e000000, %edx /* WB MEM type */
+  #else
+	movl	$0x06000000, %edx /* WB IO type */
+  #endif
+ #endif
+	xorl	%eax, %eax
 	wrmsr
 #endif
 
-        /* enable memory access for first MBs using top_mem */
-        movl    $TOP_MEM, %ecx
-        xorl    %edx, %edx
-        movl    $(((CONFIG_LB_MEM_TOPK << 10) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax
-        wrmsr
+	/* enable memory access for first MBs using top_mem */
+	movl	$TOP_MEM, %ecx
+	xorl	%edx, %edx
+	movl	$(((CONFIG_LB_MEM_TOPK << 10) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax
+	wrmsr
 #endif /*  USE_FAILOVER_IMAGE == 1*/
 
 
-#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE == 0)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==0))
-        /* disable cache */
-        movl    %cr0, %eax
-        orl    $(0x1<<30),%eax
-        movl    %eax, %cr0
+#if ((HAVE_FAILOVER_BOOT == 1) && (USE_FAILOVER_IMAGE == 0)) || ((HAVE_FAILOVER_BOOT == 0) && (USE_FALLBACK_IMAGE == 0))
+	/* disable cache */
+	movl	%cr0, %eax
+	orl		$(1 << 30),%eax
+	movl	%eax, %cr0
 
-#endif 
+#endif
 
 #if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
-        /* enable write base caching so we can do execute in place
-         * on the flash rom.
-         */
-        movl    $0x202, %ecx
-        xorl    %edx, %edx
-        movl    $(XIP_ROM_BASE | MTRR_TYPE_WRBACK), %eax
-        wrmsr
-
-        movl    $0x203, %ecx
-        movl    $((1<<(CPU_ADDR_BITS-32))-1), %edx  /* AMD 40 bit */
-        movl    $(~(XIP_ROM_SIZE - 1) | 0x800), %eax
-        wrmsr
+	/* enable write base caching so we can do execute in place
+	 * on the flash rom.
+	 */
+	movl	$0x202, %ecx
+	xorl	%edx, %edx
+	movl	$(XIP_ROM_BASE | MTRR_TYPE_WRBACK), %eax
+	wrmsr
+
+	movl	$0x203, %ecx
+	movl	$((1 << (CPU_ADDR_BITS - 32)) - 1), %edx  /* AMD 40 bit for K8, 48 bit for GH */
+	movl	$(~(XIP_ROM_SIZE - 1) | 0x800), %eax
+	wrmsr
 #endif /* XIP_ROM_SIZE && XIP_ROM_BASE */
 
-#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE==1)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==1))
-        /* Set the default memory type and enable fixed and variable MTRRs */
-        movl    $MTRRdefType_MSR, %ecx
-        xorl    %edx, %edx
-        /* Enable Variable and Fixed MTRRs */
-        movl    $0x00000c00, %eax
-        wrmsr
-
-        /* Enable the MTRRs and IORRs in SYSCFG */
-        movl    $SYSCFG_MSR, %ecx
-        rdmsr
-        orl     $(SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn), %eax
-        wrmsr
-#endif
-
-        /* enable cache */
-        movl    %cr0, %eax
-        andl    $0x9fffffff,%eax
-        movl    %eax, %cr0
+#if ((HAVE_FAILOVER_BOOT == 1) && (USE_FAILOVER_IMAGE == 1)) || ((HAVE_FAILOVER_BOOT == 0) && (USE_FALLBACK_IMAGE == 1))
+	/* Set the default memory type and enable fixed and variable MTRRs */
+	movl	$MTRRdefType_MSR, %ecx
+	xorl	%edx, %edx
+	/* Enable Variable and Fixed MTRRs */
+	movl	$0x00000c00, %eax
+	wrmsr
+
+	/* Enable the MTRRs and IORRs in SYSCFG */
+	movl	$SYSCFG_MSR, %ecx
+	rdmsr
+	orl		$(SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn), %eax
+	wrmsr
+#endif
+
+	movb	$0xA1, %al
+	outb	%al, $0x80
+
+	/* enable cache */
+	movl	%cr0, %eax
+	andl	$0x9fffffff, %eax
+	movl	%eax, %cr0
 
-#if ((HAVE_FAILOVER_BOOT==1) && (USE_FAILOVER_IMAGE==1)) || ((HAVE_FAILOVER_BOOT==0) && (USE_FALLBACK_IMAGE==1))
 
-        /* Read the range with lodsl*/
+#if CAR_FAM10 == 1
+	/* So we need to check if it is BSP */
+	movl	$0x1b, %ecx
+	rdmsr
+	bt	$8, %eax /*BSC */
+	jnc	CAR_FAM10_ap
+#endif
+
+	movb	$0xA2, %al
+	outb	%al, $0x80
+
+#if ((HAVE_FAILOVER_BOOT == 1) && (USE_FAILOVER_IMAGE == 1)) || ((HAVE_FAILOVER_BOOT == 0) && (USE_FALLBACK_IMAGE == 1))
+		/* Read the range with lodsl*/
 	cld
-        movl    $CacheBase, %esi
-        movl    $(CacheSize>>2), %ecx
-        rep     
-		lodsl
-        /* Clear the range */
-        movl    $CacheBase, %edi
-        movl    $(CacheSize>>2), %ecx
-        xorl    %eax, %eax
-        rep     
-		stosl
+	movl	$CacheBase, %esi
+	movl	$(CacheSize >> 2), %ecx
+	rep		lodsl
+	/* Clear the range */
+	movl	$CacheBase, %edi
+	movl	$(CacheSize >> 2), %ecx
+	xorl	%eax, %eax
+	rep		stosl
 
 #endif /*USE_FAILOVER_IMAGE == 1*/
 
 	/* set up the stack pointer */
-	movl	$(CacheBase+CacheSize - GlobalVarSize), %eax 
-	movl    %eax, %esp
+	movl	$(CacheBase + CacheSize - GlobalVarSize), %eax
+	movl	%eax, %esp
+
+	movb	$0xA3, %al
+	outb	%al, $0x80
+
+#if CAR_FAM10 == 1
+
+	jmp	CAR_FAM10_ap_out
+CAR_FAM10_ap:
+	/* need to set stack pointer for AP */
+	/* it will be from CacheBase + (CacheSize - GlobalVarSize)/2 - (NodeID<<CoreIDbits + CoreID) * CacheSizeAPStack*/
+	/* So need to get the NodeID and CoreID at first */
+	/* If NB_CFG bit 54 is set just use initial apicid, otherwise need to reverse it */
+
+	/* store our init detected */
+	movl	%ebx, %esi
+
+	/* get the coreid bits at first */
+	movl	$0x80000008, %eax
+	cpuid
+	shrl	$12, %ecx
+	andl	$0x0f, %ecx
+	movl	%ecx, %edi
+
+	/* get the initial apic id */
+	movl	$1, %eax
+	cpuid
+	shrl	$24, %ebx
+
+	/* get the nb cfg bit 54 */
+	movl	$0xc001001f, %ecx /* NB_CFG_MSR */
+	rdmsr
+	movl	%edi, %ecx	/* CoreID bits */
+	bt	$(54-32), %edx
+	jc	roll_cfg
+	rolb	%cl, %bl
+roll_cfg:
+
+	/* calculate stack pointer */
+	movl	$CacheSizeAPStack, %eax
+	mull	%ebx
+	movl	$(CacheBase + (CacheSize - GlobalVarSize)/2), %esp
+	subl	%eax, %esp
+
+	/* retrive init detected */
+	movl	%esi, %ebx
+
+	movb	$0xA4, %al
+	outb	%al, $0x80
+
+CAR_FAM10_ap_out:
+#endif
+
+	movb	$0xA5, %al
+	outb	%al, $0x80
 
 	/* Restore the BIST result */
-	movl    %ebp, %eax
+	movl	%ebp, %eax
+
 	/* We need to set ebp ? No need */
 	movl	%esp, %ebp
-	pushl %ebx  /* init detected */
-	pushl %eax  /* bist */
-	call    cache_as_ram_main
+	pushl	%ebx  /* init detected */
+	pushl	%eax  /* bist */
+	call	cache_as_ram_main
 	/* We will not go back */
 
-fixed_mtrr_msr: 
-        .long   0x250, 0x258, 0x259
-        .long   0x268, 0x269, 0x26A
-        .long   0x26B, 0x26C, 0x26D
-        .long   0x26E, 0x26F
-var_mtrr_msr:   
-        .long   0x200, 0x201, 0x202, 0x203
-        .long   0x204, 0x205, 0x206, 0x207
-        .long   0x208, 0x209, 0x20A, 0x20B
-        .long   0x20C, 0x20D, 0x20E, 0x20F
-var_iorr_msr:   
-        .long   0xC0010016, 0xC0010017, 0xC0010018, 0xC0010019
+	movb	$0xAF, %al		/* Should never see this postcode */
+	outb	%al, $0x80
+
+fixed_mtrr_msr:
+	.long	0x250, 0x258, 0x259
+	.long	0x268, 0x269, 0x26A
+	.long	0x26B, 0x26C, 0x26D
+	.long	0x26E, 0x26F
+var_mtrr_msr:
+	.long	0x200, 0x201, 0x202, 0x203
+	.long	0x204, 0x205, 0x206, 0x207
+	.long	0x208, 0x209, 0x20A, 0x20B
+	.long	0x20C, 0x20D, 0x20E, 0x20F
+var_iorr_msr:
+	.long	0xC0010016, 0xC0010017, 0xC0010018, 0xC0010019
 mem_top:
-        .long   0xC001001A, 0xC001001D
-        .long   0x000 /* NULL, end of table */
+	.long	0xC001001A, 0xC001001D
+	.long	0x000 /* NULL, end of table */
+
 cache_as_ram_setup_out:
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/Config.lb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/Config.lb	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,40 @@
+#
+# This file is part of the LinuxBIOS project.
+#
+# Copyright (C) 2007 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
+#
+
+uses HAVE_INIT_TIMER
+uses HAVE_MOVNTI
+uses CPU_ADDR_BITS
+
+default HAVE_INIT_TIMER=1
+default HAVE_MOVNTI=1
+default CPU_ADDR_BITS=48
+dir /cpu/x86/tsc
+dir /cpu/x86/fpu
+dir /cpu/x86/mmx
+dir /cpu/x86/sse
+dir /cpu/x86/lapic
+dir /cpu/x86/cache
+dir /cpu/x86/pae
+dir /cpu/amd/mtrr
+dir /cpu/amd/quadcore
+dir /cpu/amd/microcode
+driver model_10xxx_init.o
+object update_microcode.o
+object apic_timer.o
+object pstate.o
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/fidvid.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/fidvid.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,455 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#if FAM10_SET_FIDVID == 1
+
+#define FAM10_SET_FIDVID_DEBUG 1
+
+// if we are tight of CAR stack, disable it
+#define FAM10_SET_FIDVID_STORE_AP_APICID_AT_FIRST 1
+
+static inline void print_debug_fv(const char *str, u32 val)
+{
+#if FAM10_SET_FIDVID_DEBUG == 1
+		printk_debug("%s%x\n", str, val);
+#endif
+}
+
+static inline void print_debug_fv_8(const char *str, u8 val)
+{
+#if FAM10_SET_FIDVID_DEBUG == 1
+		printk_debug("%s%02x\n", str, val);
+#endif
+}
+
+static inline void print_debug_fv_64(const char *str, u32 val, u32 val2)
+{
+#if FAM10_SET_FIDVID_DEBUG == 1
+		printk_debug("%s%x%x\n", str, val, val2);
+#endif
+}
+
+
+static void enable_fid_change(u8 fid)
+{
+	u32 dword;
+	u32 nodes;
+	device_t dev;
+	int i;
+
+	nodes = ((pci_read_config32(PCI_DEV(CBB, CDB, 0), 0x60) >> 4) & 7) + 1;
+
+	for(i = 0; i < nodes; i++) {
+		dev = NODE_PCI(i,3);
+		dword = pci_read_config32(dev, 0xd4);
+		dword &= ~0x1F;
+		dword |= (u32) fid & 0x1F;
+		dword |= 1 << 5;	// enable
+		pci_write_config32(dev, 0xd4, dword);
+		printk_debug("FID Change Node:%02x, F3xD4: %08x \n", i, dword);
+	}
+}
+
+static void prep_fid_change(void)
+{
+	u32 dword;
+	u32 nodes;
+	device_t dev;
+	int i;
+
+	/* This needs to be run before any Pstate changes are requested */
+
+	nodes = ((pci_read_config32(PCI_DEV(CBB, CDB, 0), 0x60) >> 4) & 7) + 1;
+
+	for(i = 0; i < nodes; i++) {
+		printk_debug("Node:%02x \n", i);
+		dev = NODE_PCI(i,3);
+
+		dword = pci_read_config32(dev, 0xa0);
+		dword &= ~(1<<29);
+		dword |= ((~dword >> 8) & 1) << 29; // SlamVidMode is the inverse to the PviMode
+		dword |= PLLLOCK_DFT_L; /* Force per BKDG */
+		pci_write_config32(dev, 0xa0, dword);
+		printk_debug("  F3xA0: %08x \n", dword);
+
+		dword = pci_read_config32(dev, 0xd8);
+		dword &= ~0x77;
+		dword |= (1<<4) | 6; // VSRampTime, and VSSlamTime
+		dword |= 3 << 24; // ReConDel set to 3 per BKDG
+		pci_write_config32(dev, 0xd8, dword);
+		printk_debug("  F3xD8: %08x \n", dword);
+
+		dword = pci_read_config32(dev, 0xd4);
+		dword &= 0x1F;
+		dword |= 0xC331AF00; // per BKDG
+		pci_write_config32(dev, 0xd4, dword);
+		printk_debug("  F3xD4: %08x \n", dword);
+
+		dword = pci_read_config32(dev, 0xdc);
+		dword |= 0x5 << 12; // NbsynPtrAdj set to 0x5 per BKDG (needs reset)
+		pci_write_config32(dev, 0xdc, dword);
+		printk_debug("  F3xDC: %08x \n", dword);
+
+		// Rev B settings - FIXME: support other revs.
+		dword = 0xA0E641E6;
+		pci_write_config32(dev, 0x84, dword);
+		printk_debug("  F3x84: %08x \n", dword);
+
+		dword = 0xE600A681;
+		pci_write_config32(dev, 0x80, dword);
+		printk_debug("  F3x80: %08x \n", dword);
+
+	}
+}
+
+
+#include "fidvid_common.c"
+
+
+
+static void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid)
+{
+
+	msr_t msr;
+	device_t dev;
+	u8 vid_max;
+	u8 fid_max;
+	u8 startup_pstate;
+	u8 nb_cof_vid_update;
+	u8 pvimode;
+	u32 reg1fc;
+	u32 dword;
+	u32 send;
+
+	printk_debug("FIDVID on AP: %02x\n", apicid);
+
+	/* Only support single plane system at this time. */
+	/* Steps 1-6 of BIOS NB COF and VID Configuration
+	 * for Single-Plane PVI Systems
+	 */
+	dev = NODE_PCI(nodeid,3);
+	reg1fc = pci_read_config32(dev, 0x1FC);
+	nb_cof_vid_update = reg1fc & 1;
+	if (nb_cof_vid_update) {
+		/* Get fused settings */
+		dword = pci_read_config32(dev, 0xa0);
+			pvimode = (dword >> 8) & 1;
+
+		vid_max = (reg1fc >> 7) & 0x7F;	// per node
+		fid_max = (reg1fc >> 2) & 0x1F;	// per system
+
+		if (pvimode) {
+		/* FIXME: support daul plane mode */
+			die("PVImode not supported\n");
+			/* fidmax = vidmax - (reg1fc >> 17) & 0x1F;
+			fidmax = fidmax + (reg1fc >> 14) & 0x03;
+			*/
+		}
+
+	} else {
+		/* Use current values */
+		msr = rdmsr(0xc0010071);
+		fid_max = ((msr.hi >> (59-32)) & 0x1f);		//max nb fid
+		vid_max = ((msr.hi >> (35-32)) & 0x7f);		//max vid
+	}
+
+	/* Note this is the single plane setup. Need to add dual plane path */
+	msr = rdmsr(0xc0010071);
+	startup_pstate = (msr.hi >> (32-32)) & 0x07;
+
+
+	/* Copy startup pstate to P1 and P0 MSRs. Set the maxvid for this node in P0.
+	   Then transition to P1 for corex and P0 for core0. */
+	msr = rdmsr(0xC0010064 + startup_pstate);
+	wrmsr(0xC0010065, msr);
+	wrmsr(0xC0010064, msr);
+
+	msr.lo &= ~0xFE000000;	// clear nbvid
+	msr.lo |= vid_max << 25;
+	wrmsr(0xC0010064, msr);
+
+	// Transition to P1 for all APs and P0 for core0.
+	msr = rdmsr(0xC0010062);
+	msr.lo = (msr.lo & ~0x07) | 1;
+	wrmsr(0xC0010062, msr);
+
+	// Wait for P1 to set.
+	do {
+		msr = rdmsr(0xC0010063);
+	} while (msr.lo != 1);
+
+	if (coreid == 0) {
+		msr.lo = msr.lo & ~0x07;
+		wrmsr(0xC0010062, msr);
+		// Wait for P0 to set.
+		do {
+			msr = rdmsr(0xC0010063);
+		} while (msr.lo != 0);
+	}
+
+
+	send = (nb_cof_vid_update << 16) | (fid_max << 8);
+	send |= (apicid << 24); // ap apicid
+
+	// Send signal to BSP about this AP max fid
+	// This also indicates this AP is ready for warm reset (if required).
+	lapic_write(LAPIC_MSG_REG, send | 1);
+}
+
+static u32 calc_common_fid(u32 fid_packed, u32 fid_packed_new)
+{
+	u32 fidmax;
+	u32 fidmax_new;
+
+	fidmax = (fid_packed >> 8) & 0xFF;
+
+	fidmax_new = (fid_packed_new >> 8) & 0xFF;
+
+	if(fidmax > fidmax_new) {
+		fidmax = fidmax_new;
+	}
+
+	fid_packed &= 0xFF << 16;
+	fid_packed |= (fidmax << 8);
+	fid_packed |= fid_packed_new & (0xFF << 16); // set nb_cof_vid_update
+
+	return fid_packed;
+}
+
+struct fidvid_st {
+	u32 common_fid;
+};
+
+static void init_fidvid_bsp_stage1(u32 ap_apicid, void *gp )
+{
+		u32 readback = 0;
+		u32 timeout = 1;
+
+		struct fidvid_st *fvp = gp;
+		int loop;
+
+		print_debug_fv("Wait for AP stage 1: ap_apicid = ", ap_apicid);
+
+		loop = 100000;
+		while(--loop > 0) {
+			if(lapic_remote_read(ap_apicid, LAPIC_MSG_REG, &readback) != 0) continue;
+			if((readback & 0x3f) == 1) {
+				timeout = 0;
+				break; //target ap is in stage 1
+			}
+		}
+
+		if(timeout) {
+			print_initcpu8("fidvid_bsp_stage1: time out while reading from ap ", ap_apicid);
+			return;
+		}
+
+		print_debug_fv("\treadback = ", readback);
+
+		fvp->common_fid = calc_common_fid(fvp->common_fid, readback);
+
+		print_debug_fv("\tcommon_fid(packed) = ", fvp->common_fid);
+
+}
+
+
+static void init_fidvid_stage2(u32 apicid, u32 nodeid)
+{
+	msr_t msr;
+	device_t dev;
+	u32 reg1fc;
+	u8 StartupPstate;
+	u8 nbvid;
+	int i;
+
+	/* After warm reset finish the fid/vid setup for all cores. */
+	dev = NODE_PCI(nodeid,3);
+	reg1fc = pci_read_config32(dev, 0x1FC);
+	nbvid = (reg1fc >> 7) & 0x7F;
+
+	if (reg1fc & 0x02) { // NbVidUpdateAll ?
+		for( i = 0; i < 5; i++) {
+			msr = rdmsr(0xC0010064 + i);
+			if ((msr.hi >> 31) & 1) { // PstateEn?
+				msr.lo &= ~(0x7F << 25);
+				msr.lo |= (nbvid & 0x7F) << 25;
+			}
+		}
+	} else {
+		for( i = 0; i < 5; i++) {
+			msr = rdmsr(0xC0010064 + i);
+			if (((msr.hi >> 31) & 1) && (((msr.lo >> 22) & 1) == 0)) { // PstateEn and PDid == 0?
+				msr.lo &= ~(0x7F << 25);
+				msr.lo |= (nbvid & 0x7F) << 25;
+			}
+		}
+	}
+
+	// For each processor in the system, transition all cores to StartupPstate
+	msr = rdmsr(0xC0010071);
+	StartupPstate = msr.hi >> (32-32) & 0x03;
+	msr = rdmsr(0xC0010062);
+	msr.lo = StartupPstate;
+	wrmsr(0xC0010062, msr);
+}
+
+
+#if FAM10_SET_FIDVID_STORE_AP_APICID_AT_FIRST == 1
+struct ap_apicid_st {
+	u32 num;
+	// it could use 256 bytes for 64 node quad core system
+	u8 apicid[NODE_NUMS * 4];
+};
+
+static void store_ap_apicid(unsigned ap_apicid, void *gp)
+{
+	struct ap_apicid_st *p = gp;
+
+	p->apicid[p->num++] = ap_apicid;
+
+}
+#endif
+
+
+static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes)
+{
+#if FAM10_SET_FIDVID_STORE_AP_APICID_AT_FIRST == 1
+	struct ap_apicid_st ap_apicidx;
+	u32 i;
+#endif
+	struct fidvid_st fv;
+	msr_t msr;
+	device_t dev;
+	u8 vid_max;
+	u8 fid_max;
+	u8 startup_pstate;
+	u8 nb_cof_vid_update;
+	u32 reg1fc;
+	u32 dword;
+	u8 pvimode;
+
+	printk_debug("FIDVID on BSP, APIC_id: %02x\n", bsp_apicid);
+
+	/* FIXME: Only support single plane system at this time. */
+	/* Steps 1-6 of BIOS NB COF and VID Configuration
+	 * for Single-Plane PVI Systems
+	 */
+	dev = NODE_PCI(0,3);	// nodeid for the BSP is 0
+	reg1fc = pci_read_config32(dev, 0x1FC);
+	nb_cof_vid_update = reg1fc & 1;
+	if (nb_cof_vid_update) {
+		/* Get fused settings */
+		dword = pci_read_config32(dev, 0xa0);
+			pvimode = (dword >> 8) & 1;
+
+		vid_max = (reg1fc >> 7) & 0x7F;	// per node
+		fid_max = (reg1fc >> 2) & 0x1F;	// per system
+
+		if (pvimode) {
+		/* FIXME: support daul plane mode */
+			die("PVImode not supported\n");
+			/* fidmax = vidmax - (reg1fc >> 17) & 0x1F;
+			fidmax = fidmax + (reg1fc >> 14) & 0x03;
+			*/
+		}
+
+	} else {
+		/* Use current values */
+		msr = rdmsr(0xc0010071);
+		fid_max = ((msr.hi >> (59-32)) & 0x1f);		//max nb fid
+		vid_max = ((msr.hi >> (35-32)) & 0x7f);		//max vid
+	}
+
+	/* Note this is the single plane setup. Need to add dual plane path */
+	msr = rdmsr(0xc0010071);
+	startup_pstate = (msr.hi >> (32-32)) & 0x07;
+
+
+	/* Copy startup pstate to P1 and P0 MSRs. Set the maxvid for this node in P0.
+	   Then transition to P1 for corex and P0 for core0. */
+	msr = rdmsr(0xC0010064 + startup_pstate);
+	wrmsr(0xC0010065, msr);
+	wrmsr(0xC0010064, msr);
+
+	msr.lo &= ~0xFE000000;	// clear nbvid
+	msr.lo |= vid_max << 25;
+	wrmsr(0xC0010064, msr);
+
+	// Transition to P1 and then P0 for core0.
+	msr = rdmsr(0xC0010062);
+	msr.lo = (msr.lo & ~0x07) | 1;
+	wrmsr(0xC0010062, msr);
+
+	// Wait for P1 to set.
+	do {
+		msr = rdmsr(0xC0010063);
+	} while (msr.lo != 1);
+
+	msr.lo = msr.lo & ~0x07;
+	wrmsr(0xC0010062, msr);
+	// Wait for P0 to set.
+	do {
+		msr = rdmsr(0xC0010063);
+	} while (msr.lo != 0);
+
+
+	fv.common_fid = (nb_cof_vid_update << 16) | (fid_max << 8) ;
+	print_debug_fv("BSP fid = ", fv.common_fid);
+
+#if FAM10_SET_FIDVID_STORE_AP_APICID_AT_FIRST == 1 && FAM10_SET_FIDVID_CORE0_ONLY == 0
+	/* For all APs (We know the APIC ID of all APs even when the APIC ID
+	   is lifted) remote read from AP LAPIC_MSG_REG about max fid.
+	   Then calculate the common max fid that can be used for all
+	   APs and BSP */
+	ap_apicidx.num = 0;
+
+	for_each_ap(bsp_apicid, FAM10_SET_FIDVID_CORE_RANGE, store_ap_apicid, &ap_apicidx);
+
+	for(i = 0; i < ap_apicidx.num; i++) {
+		init_fidvid_bsp_stage1(ap_apicidx.apicid[i], &fv);
+	}
+#else
+	for_each_ap(bsp_apicid, FAM10_SET_FIDVID_CORE0_ONLY, init_fidvid_bsp_stage1, &fv);
+#endif
+
+	print_debug_fv("common_fid = ", fv.common_fid);
+
+	if (fv.common_fid & ~(0xFF << 16)) {	// check nb_cof_vid_update
+
+		// Enable the common fid and other settings.
+		enable_fid_change((fv.common_fid >> 8) & 0x1F);
+
+		// nbfid change need warm reset, so reset at first
+		return 1;
+	}
+
+	return 0; // No FID/VID changes. Don't reset
+}
+static void set_p0(void)
+{
+	msr_t msr;
+
+	// Transition P0 for calling core.
+	msr = rdmsr(0xC0010062);
+	msr.lo = (msr.lo & ~0x07);
+	wrmsr(0xC0010062, msr);
+
+	// Don't bother to wait around for the P state to change.
+}
+#endif
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/fidvid_common.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/fidvid_common.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,312 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <cpu/x86/tsc.h>
+
+
+static u32 get_vstime(u32 nodeid, u32 slam)
+{
+	u32 val;
+	u32 v;
+	device_t dev;
+
+#if defined(__ROMCC__)
+	dev = NODE_PCI(nodeid, 3);
+#else
+	dev = get_node_pci(nodeid, 3);
+#endif
+
+	val = pci_read_config32(dev, 0xd8);
+
+	val >>= slam?0:4;
+	val &= 7;
+
+	switch (val) {
+	case 4: v = 60; break;
+	case 5: v = 100; break;
+	case 6: v = 200; break;
+	case 7: v = 500; break;
+	default:
+		v = (val+1)*10; // in us
+	}
+
+	return v;
+}
+
+static void udelay_tsc(u32 us)
+{
+	/* Use TSC to delay because it is fixed, ie. it will not changed with p-states.
+	 * Also, We use the APIC TIMER register is to hold flags for AP init.
+	 */
+	u32 dword;
+	tsc_t tsc, tsc1, tscd;
+	u32 d =  0x00000200; //800Mhz or 200Mhz or 1.6G or get the NBFID at first
+	u32 dn = 0x1000000/2; // howmany us need to use hi
+
+	tscd.hi = us/dn;
+	tscd.lo = (us - tscd.hi * dn) * d;
+
+	tsc1 = rdtsc();
+	dword = tsc1.lo + tscd.lo;
+	if((dword<tsc1.lo) || (dword<tscd.lo)) {
+		tsc1.hi++;
+	}
+	tsc1.lo = dword;
+	tsc1.hi+= tscd.hi;
+
+	do {
+		tsc = rdtsc();
+	} while ((tsc.hi>tsc1.hi) || ((tsc.hi==tsc1.hi) && (tsc.lo>tsc1.lo)));
+
+}
+
+#ifdef __ROMCC__
+void udelay(u32 usecs)
+{
+	udelay_tsc(usecs);
+}
+#endif
+
+static u32 set_vid(u32 newvid, u32 bit_offset, u32 nodeid, u32 coreid)
+{
+	u32 val;
+	msr_t msr;
+	u32 curvid;
+	u32 slam;
+	u32 delay;
+	u32 count = 3;
+	device_t dev;
+
+	msr = rdmsr(0xc0010071);//status
+	curvid = (msr.lo >> bit_offset) & 0x7f; // seven bits
+
+	if(newvid == curvid) return curvid;
+
+#if defined(__ROMCC__)
+	dev = NODE_PCI(nodeid, 3);
+#else
+	dev = get_node_pci(nodeid, 3);
+#endif
+
+	val = pci_read_config32(dev, 0xa0);
+
+	slam = (val >> 29) & 1;
+	delay = get_vstime(nodeid, slam);
+
+	if(!slam) {
+		if(curvid>newvid) {
+			count = (curvid - newvid) * 2;
+		} else {
+			count = (newvid - curvid) * 2;
+		}
+	}
+
+	while(count-->0) {
+		if(slam) {
+			curvid = newvid;
+		}
+		else { //ramp
+			if(curvid>newvid) {
+				curvid--;
+			} else {
+				curvid++;
+			}
+		}
+
+		msr = rdmsr(0xc0010070); //control
+		msr.lo &= ~(0x7f<<bit_offset);
+		msr.lo |= (curvid<<bit_offset);
+		wrmsr(0xc0010070, msr); // how about all copys, APIC or PCI conf space?
+
+		udelay_tsc(delay);
+
+		msr = rdmsr(0xc0010071);//status
+		curvid = (msr.lo >> bit_offset) & 0x7f; // seven bits
+
+		if(curvid == newvid) break;
+
+	}
+
+	return curvid;
+}
+
+
+static u32 set_nb_vid(u32 newvid, u32 nodeid, u32 coreid)
+{
+	return set_vid(newvid, 25, nodeid, coreid);
+}
+
+
+static u32 set_core_vid(u32 newvid, u32 nodeid, u32 coreid)
+{
+	return set_vid(newvid, 9, nodeid, coreid);
+}
+
+
+static unsigned set_cof(u32 val, u32 mask, u32 nodeid, u32 coreid)
+{
+	msr_t msr;
+	int count = 3;
+
+	val &= mask;
+
+	// FIXME: What is count for? Why 3 times? What about node and core id?
+	while(count-- > 0) {
+
+		msr = rdmsr(0xc0010071);
+		msr.lo &= mask;
+		if(msr.lo == val) break;
+
+		msr = rdmsr(0xc0010070);
+		msr.lo &= ~(mask);
+		msr.lo |= val;
+		wrmsr(0xc0010070, msr);
+	}
+
+	return msr.lo;
+}
+
+static u32 set_core_cof(u32 fid, u32 did, u32 nodeid, u32 coreid)
+{
+	u32 val;
+	u32 mask;
+
+	mask = (7<<6) | 0x3f;
+	val = ((did & 7)<<6) | (fid & 0x3f);
+
+	return set_cof(val, mask, nodeid, coreid);
+
+}
+
+
+static u32 set_nb_cof(u32 did, u32 nodeid, u32 coreid) // fid need warmreset
+{
+	u32 val;
+	u32 mask;
+
+	mask = 1<<22;
+	val = (did & 1)<<22;
+
+	return set_cof(val, mask, nodeid, coreid);
+
+}
+
+
+/* set vid and cof for core and nb after warm reset is not started by BIOS */
+static void set_core_nb_max_pstate_after_other_warm_reset(u32 nodeid, u32 coreid) // P0
+{
+	msr_t msr;
+	u32 val;
+	u32 vid;
+	u32 mask;
+	u32 did;
+	device_t dev;
+
+	msr = rdmsr(0xc0010064);
+
+#if defined(__ROMCC__)
+	dev = NODE_PCI(nodeid, 3);
+#else
+	dev = get_node_pci(nodeid, 3);
+#endif
+
+	val = pci_read_config32(dev, 0xa0);
+	if((val>>8) & 1) { // PVI
+		vid = (msr.lo >> 25) & 0x7f;
+	} else { //SVI
+		vid = (msr.lo >> 9) & 0x7f;
+	}
+	set_core_vid(vid, nodeid, coreid);
+
+	mask = (0x7<<6) | 0x3f;
+	val = msr.lo & mask;
+	set_cof(val, mask, nodeid, coreid);
+
+	//set nb cof and vid
+	did = (msr.lo >> 22) & 1;
+	vid = (msr.lo >> 25) & 0x7f;
+	if(did) {
+		 set_nb_cof(did, nodeid, coreid);
+		set_nb_vid(vid, nodeid, coreid);
+	} else {
+		set_nb_vid(vid, nodeid, coreid);
+		 set_nb_cof(did, nodeid, coreid);
+	}
+
+	//set the p state
+	msr.hi = 0;
+	msr.lo = 0;
+	wrmsr(0xc0010062, msr);
+
+}
+
+
+/* set vid and cof for core and nb after warm reset is not started by BIOS */
+static void  set_core_nb_min_pstate_after_other_warm_reset(u32 nodeid, u32 coreid) // Px
+{
+	msr_t msr;
+	u32 val;
+	u32 vid;
+	u32 mask;
+	u32 did;
+	u32 pstate;
+	device_t dev;
+
+#if defined(__ROMCC__)
+	dev = NODE_PCI(nodeid, 3);
+#else
+	dev = get_node_pci(nodeid, 3);
+#endif
+
+
+	val = pci_read_config32(dev, 0xdc); //PstateMaxVal
+
+	pstate = (val >> 8) & 0x7;
+
+	msr = rdmsr(0xc0010064 + pstate);
+
+	mask = (7<<6) | 0x3f;
+	val = msr.lo & mask;
+	set_cof(val, mask, nodeid, coreid);
+
+	val = pci_read_config32(dev, 0xa0);
+	if((val>>8) & 1) { // PVI
+		 vid = (msr.lo>>25) & 0x7f;
+	} else { //SVI
+		 vid = (msr.lo>>9) & 0x7f;
+	}
+	set_core_vid(vid, nodeid, coreid);
+
+	//set nb cof and vid
+	did = (msr.lo >> 22) & 1;
+	vid = (msr.lo >> 25) & 0x7f;
+	if(did) {
+		set_nb_cof(did, nodeid, coreid);
+		set_nb_vid(vid, nodeid, coreid);
+	} else {
+		set_nb_vid(vid, nodeid, coreid);
+		set_nb_cof(did, nodeid, coreid);
+	}
+
+	//set the p state
+	msr.hi = 0;
+	msr.lo = pstate;
+	wrmsr(0xc0010062, msr);
+}
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/init_cpus.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/init_cpus.c	2007-12-12 14:14:12.000000000 -0700
@@ -0,0 +1,553 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+//it takes the ENABLE_APIC_EXT_ID and APIC_ID_OFFSET and LIFT_BSP_APIC_ID
+#ifndef FAM10_SET_FIDVID
+	#define FAM10_SET_FIDVID 1
+#endif
+
+#ifndef FAM10_SET_FIDVID_CORE0_ONLY
+	/* MSR FIDVID_CTL and FIDVID_STATUS are shared by cores,
+	   Need to do every AP to set common FID/VID*/
+	#define FAM10_SET_FIDVID_CORE0_ONLY 0
+#endif
+
+
+static inline void print_initcpu8 (const char *strval, u8 val)
+{
+	printk_debug("%s%02x\n", strval, val);
+}
+
+static inline void print_initcpu8_nocr (const char *strval, u8 val)
+{
+	printk_debug("%s%02x", strval, val);
+}
+
+
+static inline void print_initcpu16 (const char *strval, u16 val)
+{
+	printk_debug("%s%04x\n", strval, val);
+}
+
+
+static inline void print_initcpu(const char *strval, u32 val)
+{
+	printk_debug("%s%08x\n", strval, val);
+}
+
+
+static void prep_fid_change(void);
+static void init_fidvid_stage2(u32 apicid, u32 nodeid);
+
+#if PCI_IO_CFG_EXT == 1
+static inline void set_EnableCf8ExtCfg(void)
+{
+	// set the NB_CFG[46]=1;
+	msr_t msr;
+	msr = rdmsr(NB_CFG_MSR);
+	// EnableCf8ExtCfg: We need that to access PCI_IO_CFG_EXT 4K range
+	msr.hi |= (1<<(46-32));
+	wrmsr(NB_CFG_MSR, msr);
+}
+#else
+static inline void set_EnableCf8ExtCfg(void) { }
+#endif
+
+
+/*[39:8] */
+#define PCI_MMIO_BASE 0xfe000000
+/* because we will use gs to store hi, so need to make sure lo can start
+   from 0, So PCI_MMIO_BASE & 0x00ffffff should be equal to 0*/
+
+static inline void set_pci_mmio_conf_reg(void)
+{
+#if MMCONF_SUPPORT
+	msr_t msr;
+	msr = rdmsr(0xc0010058);
+	msr.lo &= ~(0xfff00000 | (0xf << 2));
+	// 256 bus per segment, MMIO reg will be 4G , enable MMIO Config space
+	msr.lo |= ((8+PCI_BUS_SEGN_BITS) << 2) | (1 << 0);
+	msr.hi &= ~(0x0000ffff);
+	msr.hi |= (PCI_MMIO_BASE >> (32-8));
+	wrmsr(0xc0010058, msr); // MMIO Config Base Address Reg
+
+	//mtrr for that range?
+//	set_var_mtrr_x(7, PCI_MMIO_BASE<<8, PCI_MMIO_BASE>>(32-8), 0x00000000, 0x01, MTRR_TYPE_UNCACHEABLE);
+
+	set_wrap32dis();
+
+	msr.hi = (PCI_MMIO_BASE >> (32-8));
+	msr.lo = 0;
+	wrmsr(0xc0000101, msr); //GS_Base Reg
+
+
+
+#endif
+}
+
+
+typedef void (*process_ap_t)(u32 apicid, void *gp);
+
+//core_range = 0 : all cores
+//core range = 1 : core 0 only
+//core range = 2 : cores other than core0
+
+static void for_each_ap(u32 bsp_apicid, u32 core_range,
+				process_ap_t process_ap, void *gp)
+{
+	// here assume the OS don't change our apicid
+	u32 ap_apicid;
+
+	u32 nodes;
+	u32 siblings;
+	u32 disable_siblings;
+	u32 cores_found;
+	u32 nb_cfg_54;
+	int i,j;
+	u32 ApicIdCoreIdSize;
+
+	/* get_nodes define in ht_wrapper.c */
+	nodes = get_nodes();
+
+	disable_siblings = !CONFIG_LOGICAL_CPUS;
+
+#if CONFIG_LOGICAL_CPUS == 1
+	if(read_option(CMOS_VSTART_quad_core, CMOS_VLEN_quad_core, 0) != 0) { // 0 mean quad core
+		disable_siblings = 1;
+	}
+#endif
+
+	/* Assume that all node are same stepping, otherwise we can use use
+	   nb_cfg_54 from bsp for all nodes */
+	nb_cfg_54 = read_nb_cfg_54();
+
+	ApicIdCoreIdSize = (cpuid_ecx(0x80000008) >> 12 & 0xf);
+	if(ApicIdCoreIdSize) {
+		siblings = ((1 << ApicIdCoreIdSize) - 1);
+	} else {
+		siblings = 3; //quad core
+	}
+
+	for (i = 0; i < nodes; i++) {
+		cores_found = get_core_num_in_bsp(i);
+
+		u32 jstart, jend;
+
+		if (core_range == 2) {
+			jstart = 1;
+		} else {
+			jstart = 0;
+		}
+
+		if (disable_siblings || (core_range==1)) {
+			jend = 0;
+		} else {
+			jend = cores_found;
+		}
+
+
+		for (j = jstart; j <= jend; j++) {
+			ap_apicid = i * (nb_cfg_54 ? (siblings + 1):1) + j * (nb_cfg_54 ? 1:64);
+
+		#if (ENABLE_APIC_EXT_ID == 1) && (APIC_ID_OFFSET > 0)
+			#if LIFT_BSP_APIC_ID == 0
+			if( (i != 0) || (j != 0)) /* except bsp */
+			#endif
+				ap_apicid += APIC_ID_OFFSET;
+		#endif
+
+			if(ap_apicid == bsp_apicid) continue;
+
+			process_ap(ap_apicid, gp);
+
+		}
+	}
+}
+
+/* FIXME: Duplicate of what is in lapic.h? */
+static inline int lapic_remote_read(int apicid, int reg, u32 *pvalue)
+{
+	int timeout;
+	u32 status;
+	int result;
+	lapic_wait_icr_idle();
+	lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+	lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
+	timeout = 0;
+
+	do {
+		status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+	} while (status == LAPIC_ICR_BUSY && timeout++ < 1000);
+
+	timeout = 0;
+	do {
+		status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
+	} while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
+
+	result = -1;
+
+	if (status == LAPIC_ICR_RR_VALID) {
+		*pvalue = lapic_read(LAPIC_RRR);
+		result = 0;
+	}
+	return result;
+}
+
+
+/* Use the LAPIC timer count register to hold each cores init status */
+#define LAPIC_MSG_REG 0x380
+
+
+#if FAM10_SET_FIDVID == 1
+static void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid);
+#endif
+
+static inline __attribute__((always_inline)) void print_apicid_nodeid_coreid(u32 apicid, struct node_core_id id, const char *str)
+{
+		printk_debug("%s --- {	 APICID = %02x NODEID = %02x COREID = %02x} ---\n", str, apicid, id.nodeid, id.coreid);
+}
+
+
+static unsigned wait_cpu_state(u32 apicid, u32 state)
+{
+	u32 readback = 0;
+	u32 timeout = 1;
+	int loop = 4000000;
+	while (--loop > 0) {
+		if (lapic_remote_read(apicid, LAPIC_MSG_REG, &readback) != 0) continue;
+		if ((readback & 0x3f) == state) {
+			timeout = 0;
+			break; //target cpu is in stage started
+		}
+	}
+	if (timeout) {
+		if (readback) {
+			timeout = readback;
+		}
+	}
+
+	return timeout;
+}
+
+
+static void wait_ap_started(u32 ap_apicid, void *gp )
+{
+	u32 timeout;
+	timeout = wait_cpu_state(ap_apicid, 0x13); // started
+	if(timeout) {
+		print_initcpu8_nocr("* AP ", ap_apicid);
+		print_initcpu(" didn't start timeout:", timeout);
+	}
+	else {
+		print_initcpu8_nocr("AP started: ", ap_apicid);
+	}
+}
+
+
+static void wait_all_aps_started(u32 bsp_apicid)
+{
+	for_each_ap(bsp_apicid, 0 , wait_ap_started, (void *)0);
+}
+
+
+static void wait_all_other_cores_started(u32 bsp_apicid)
+{
+	// all aps other than core0
+	print_debug("started ap apicid: ");
+	for_each_ap(bsp_apicid, 2 , wait_ap_started, (void *)0);
+	print_debug("\n");
+}
+
+
+static void allow_all_aps_stop(u32 bsp_apicid)
+{
+	/* Called by the BSP to indicate AP can stop */
+
+	/* FIXME Do APs use this?
+	   Looks like wait_till_sysinfo_in_ram is used instead. */
+
+	// allow aps to stop use 6 bits for state
+	lapic_write(LAPIC_MSG_REG, (bsp_apicid << 24) | 0x14);
+}
+
+
+static void STOP_CAR_AND_CPU()
+{
+	disable_cache_as_ram(); // inline
+	stop_this_cpu();
+}
+
+
+#ifndef MEM_TRAIN_SEQ
+#define MEM_TRAIN_SEQ 0
+#endif
+
+#if RAMINIT_SYSINFO == 1
+static u32 init_cpus(u32 cpu_init_detectedx ,struct sys_info *sysinfo)
+#else
+static u32 init_cpus(u32 cpu_init_detectedx)
+#endif
+{
+	u32 bsp_apicid = 0;
+	u32 apicid;
+	struct node_core_id id;
+
+	/*
+	 * already set early mtrr in cache_as_ram.inc
+	 */
+
+	/* enable access pci conf via mmio*/
+	set_pci_mmio_conf_reg();
+
+	/* that is from initial apicid, we need nodeid and coreid
+	   later */
+	id = get_node_core_id_x();
+
+	/* NB_CFG MSR is shared between cores, so we need make sure
+	  core0 is done at first --- use wait_all_core0_started  */
+	if(id.coreid == 0) {
+		set_apicid_cpuid_lo(); /* only set it on core0 */
+		set_EnableCf8ExtCfg(); /* only set it on core0 */
+		#if (ENABLE_APIC_EXT_ID == 1)
+		enable_apic_ext_id(id.nodeid);
+		#endif
+	}
+
+	enable_lapic();
+
+
+#if (ENABLE_APIC_EXT_ID == 1) && (APIC_ID_OFFSET > 0)
+	u32 initial_apicid = get_initial_apicid();
+
+	#if LIFT_BSP_APIC_ID == 0
+	if( initial_apicid != 0 ) // other than bsp
+	#endif
+	{
+		/* use initial apic id to lift it */
+		u32 dword = lapic_read(LAPIC_ID);
+		dword &= ~(0xff << 24);
+		dword |= (((initial_apicid + APIC_ID_OFFSET) & 0xff) << 24);
+
+		lapic_write(LAPIC_ID, dword);
+	}
+
+	#if LIFT_BSP_APIC_ID == 1
+	bsp_apicid += APIC_ID_OFFSET;
+	#endif
+
+#endif
+
+	/* get the apicid, it may be lifted already */
+	apicid = lapicid();
+
+	// show our apicid, nodeid, and coreid
+	if( id.coreid==0 ) {
+		if (id.nodeid!=0) //all core0 except bsp
+			print_apicid_nodeid_coreid(apicid, id, " core0: ");
+	}
+	else { //all other cores
+		print_apicid_nodeid_coreid(apicid, id, " corex: ");
+	}
+
+
+	if (cpu_init_detectedx) {
+		print_apicid_nodeid_coreid(apicid, id, "\n\n\nINIT detected from ");
+		print_debug("\nIssuing SOFT_RESET...\n");
+		soft_reset();
+	}
+
+	if(id.coreid == 0) {
+		if(!(warm_reset_detect(id.nodeid))) //FIXME: INIT is checked above but check for more resets?
+			distinguish_cpu_resets(id.nodeid); // Also indicates we are started
+	}
+
+	// Mark the core as started.
+	lapic_write(LAPIC_MSG_REG, (apicid << 24) | 0x13);
+
+
+	if(apicid != bsp_apicid) {
+#if FAM10_SET_FIDVID == 1
+	#if (CONFIG_LOGICAL_CPUS == 1)  && (FAM10_SET_FIDVID_CORE0_ONLY == 1)
+		// Run on all AP for proper FID/VID setup.
+		if(id.coreid == 0 ) // only need set fid for core0
+	#endif
+		{
+		// check warm(bios) reset to call stage2 otherwise do stage1
+			if (warm_reset_detect(id.nodeid)) {
+				printk_debug("init_fidvid_stage2 apicid: %02x\n", apicid);
+				init_fidvid_stage2(apicid, id.nodeid);
+			} else {
+				printk_debug("init_fidvid_ap(stage1) apicid: %02x\n", apicid);
+				init_fidvid_ap(bsp_apicid, apicid, id.nodeid, id.coreid);
+			}
+		}
+#endif
+
+		/* AP is ready, Wait for the BSP to get memory configured */
+		/* FIXME: many cores spinning on node0 pci register seems to be bad.
+		 * Why do we need to wait? These APs are just going to go sit in a hlt.
+		 */
+		//wait_till_sysinfo_in_ram();
+
+		set_init_ram_access();
+
+		STOP_CAR_AND_CPU();
+		printk_debug("\nAP %02x should be halted but you are reading this....\n", apicid);
+	}
+
+	return bsp_apicid;
+}
+
+
+static u32 is_core0_started(u32 nodeid)
+{
+	u32 htic;
+	device_t device;
+	device = NODE_PCI(nodeid, 0);
+	htic = pci_read_config32(device, HT_INIT_CONTROL);
+	htic &= HTIC_ColdR_Detect;
+	return htic;
+}
+
+
+static void wait_all_core0_started(void)
+{
+	/* When core0 is started, it will distingush_cpu_resets
+	  . So wait for that to finish */
+	u32 i;
+	u32 nodes = get_nodes();
+
+	printk_debug("Wait all core0s started \n");
+	for(i=1;i<nodes;i++) { // skip bsp, because it is running on bsp
+		while(!is_core0_started(i)) {}
+		print_initcpu8("  Core0 started on node: ", i);
+	}
+	printk_debug("Wait all core0s started done\n");
+}
+#if CONFIG_MAX_PHYSICAL_CPUS > 1
+/**
+ * void start_node(u32 node)
+ *
+ *  start the core0 in node, so it can generate HT packet to feature code.
+ *
+ * This function starts the AP nodes core0s. wait_all_core0_started() in
+ * cache_as_ram_auto.c waits for all the AP to be finished before continuing
+ * system init.
+ */
+static void start_node(u8 node)
+{
+	u32 val;
+
+	/* Enable routing table */
+	printk_debug("Start node %02x", node);
+
+#if CAR_FAM10 == 1
+	/* For CAR_FAM10 support, we need to set Dram base/limit for the new node */
+	pci_write_config32(NODE_MP(node), 0x44, 0);
+	pci_write_config32(NODE_MP(node), 0x40, 3);
+#endif
+
+	/* Allow APs to make requests (ROM fetch) */
+	val=pci_read_config32(NODE_HT(node), 0x6c);
+	val &= ~(1 << 1);
+	pci_write_config32(NODE_HT(node), 0x6c, val);
+
+	printk_debug(" done.\n");
+}
+
+
+/**
+ * static void setup_remote_node(u32 node)
+ *
+ * Copy the BSP Adress Map to each AP.
+ */
+static void setup_remote_node(u8 node)
+{
+	/* There registers can be used with F1x114_x Address Map at the
+	   same time, So must set them even 32 node */
+	static const u16 pci_reg[] = {
+		/* DRAM Base/Limits Registers */
+		0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c,
+		0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78,
+		0x144, 0x14c, 0x154, 0x15c, 0x164, 0x16c, 0x174, 0x17c,
+		0x140, 0x148, 0x150, 0x158, 0x160, 0x168, 0x170, 0x178,
+		/* MMIO Base/Limits Registers */
+		0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc,
+		0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8,
+		/* IO Base/Limits Registers */
+		0xc4, 0xcc, 0xd4, 0xdc,
+		0xc0, 0xc8, 0xd0, 0xd8,
+		/* Configuration Map Registers */
+		0xe0, 0xe4, 0xe8, 0xec,
+	};
+	u16 i;
+
+	printk_debug("setup_remote_node: %02x", node);
+
+	/* copy the default resource map from node 0 */
+	for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) {
+		u32 value;
+		u16 reg;
+		reg = pci_reg[i];
+		value = pci_read_config32(NODE_MP(0), reg);
+		pci_write_config32(NODE_MP(node), reg, value);
+
+	}
+	printk_debug(" done\n");
+}
+#endif
+/**
+ * finalize_node_setup()
+ *
+ * Do any additional post HT init
+ *
+ * This could really be moved to cache_as_ram_auto.c since it really isn't HT init.
+ */
+void finalize_node_setup(struct sys_info *sysinfo)
+{
+	u8 i;
+	u8 nodes = get_nodes();
+	u32 reg;
+
+#if RAMINIT_SYSINFO == 1
+	/* read Node0 F0_0x64 bit [8:10] to find out SbLink # */
+	reg = pci_read_config32(NODE_HT(0), 0x64);
+	sysinfo->sblk = (reg>>8) & 7;
+	sysinfo->sbbusn = 0;
+	sysinfo->nodes = nodes;
+	sysinfo->sbdn = get_sbdn(sysinfo->sbbusn);
+#endif
+
+	setup_link_trans_cntrl();
+
+#if FAM10_SET_FIDVID == 1
+	// Prep each node for FID/VID setup.
+	prep_fid_change();
+#endif
+
+#if CONFIG_MAX_PHYSICAL_CPUS > 1
+	/* Skip the BSP, start at node 1 */
+	for(i=1; i<nodes; i++) {
+		setup_remote_node(i);
+		start_node(i);
+	}
+#endif
+}
+
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000018.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000018.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,163 @@
+/*
+ ============================================================
+ (c) Advanced Micro Devices, Inc., 2004-2005
+
+ The  enclosed microcode  is intended  to be  used  with AMD
+ Microprocessors.  You  may   copy,  view  and  install  the
+ enclosed microcode  only for development  and deployment of
+ firmware,  BIOS,  or  operating  system code  for  computer
+ systems   that  contain  AMD   processors.   You   are  not
+ authorized  to use  the  enclosed microcode  for any  other
+ purpose.
+
+ THE  MICROCODE IS PROVIDED  "AS IS"  WITHOUT ANY  EXPRESS OR
+ IMPLIED WARRANTY  OF ANY KIND, INCLUDING BUT  NOT LIMITED TO
+ WARRANTIES    OF    MERCHANTABILITY,   NON-    INFRINGEMENT,
+ TITLE,FITNESS  FOR  ANY  PARTICULAR PURPOSE,  OR  WARRANTIES
+ ARISING FROM CONDUCT, COURSE  OF DEALING, OR USAGE OF TRADE.
+ AMD does not assume  any responsibility for any errors which
+ may  appear   in  this   microcode  or  any   other  related
+ information provided  to you by  AMD, or result from  use of
+ this microcode.   AMD is not obligated  to furnish, support,
+ or  make   any  further  information,   software,  technical
+ information, know-how, or show-how available related to this
+ microcode.
+
+ The  microcode is provided  with "RESTRICTED  RIGHTS."  Use,
+ duplication, or disclosure by the U.S. Government is subject
+ to  the  restrictions as  set  forth  in  FAR 52.227-14  and
+ DFAR252.227-7013,  et seq.,  or its  successor.  Use  of the
+ microcode    by    the    U.S.     Government    constitutes
+ acknowledgement  of   AMD's  proprietary  rights   in  them.
+ ============================================================
+*/
+
+0x07, 0x20, 0x08, 0x02, 0x18, 0x00, 0x00, 0x01, 0x00, 0x80, 0x20, 0x00,
+0x66, 0x70, 0x30, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x44, 0x06, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0xa4, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x72, 0x09, 0x00, 0x00, 0x70, 0x09, 0x00, 0x00, 0x9b, 0x0b, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x7f, 0x00, 0xc3, 0x3f, 0x80, 0x37,
+0xfc, 0x07, 0xfe, 0x01, 0x0d, 0xff, 0x00, 0xfe, 0xf0, 0x1f, 0xf8, 0x07,
+0x37, 0xfc, 0x03, 0xf8, 0xc0, 0xff, 0xf7, 0x00, 0x80, 0xff, 0xc0, 0x3f,
+0x9b, 0xe1, 0x1f, 0xc0, 0x00, 0xfe, 0x03, 0xff, 0xff, 0x86, 0x7f, 0x00,
+0x03, 0xf8, 0x0f, 0xfc, 0xfc, 0x1b, 0xfe, 0x01, 0x00, 0x40, 0x37, 0x6b,
+0xff, 0xfb, 0xfd, 0xff, 0x57, 0x7d, 0xf0, 0xcd, 0xff, 0x1f, 0xb7, 0xfe,
+0xc0, 0xcf, 0xc3, 0x3f, 0xff, 0x01, 0xff, 0xf7, 0x00, 0x02, 0x07, 0xff,
+0x35, 0x00, 0x90, 0x8b, 0xf0, 0x0f, 0xe0, 0x3f, 0x07, 0xf0, 0x6f, 0xf8,
+0xc0, 0x3f, 0x80, 0xff, 0x1f, 0xc0, 0xbf, 0xe1, 0x03, 0xff, 0x00, 0xfe,
+0x7f, 0x00, 0xff, 0x86, 0xff, 0x1e, 0x00, 0xf8, 0x1f, 0xf8, 0x07, 0xf0,
+0xfc, 0x03, 0x78, 0x33, 0x7f, 0xe0, 0x1f, 0xc0, 0xf0, 0x0f, 0xe0, 0xdf,
+0xff, 0x81, 0x7f, 0x00, 0xc3, 0x3f, 0x80, 0x7f, 0xfc, 0x7f, 0x0f, 0x00,
+0xf8, 0x0f, 0xfc, 0x03, 0x19, 0xfe, 0x01, 0xbc, 0xe0, 0x3f, 0xf0, 0x0f,
+0x6f, 0xf8, 0x07, 0xf0, 0x80, 0xff, 0xc0, 0x3f, 0xbf, 0xe1, 0x1f, 0xc0,
+0x00, 0xb4, 0xb2, 0x06, 0xbf, 0xdf, 0xff, 0xff, 0xd5, 0x07, 0xdf, 0x7c,
+0x67, 0xb2, 0xe7, 0xf9, 0xfc, 0x3c, 0xfc, 0x03, 0x1f, 0xf0, 0x7f, 0xff,
+0x20, 0x70, 0xf0, 0x0f, 0x03, 0x00, 0xed, 0x58, 0xff, 0x00, 0xfe, 0x03,
+0x00, 0xff, 0x86, 0x7f, 0xfc, 0x03, 0xf8, 0x0f, 0x01, 0xfc, 0x1b, 0xfe,
+0xf0, 0x0f, 0xe0, 0x3f, 0x07, 0xf0, 0x6f, 0xf8, 0xef, 0x01, 0x80, 0xff,
+0xff, 0xff, 0x29, 0x2a, 0x5f, 0xd0, 0xc1, 0xc3, 0xff, 0xff, 0xb3, 0xdd,
+0xff, 0x7e, 0xfd, 0x0f, 0x1f, 0xf8, 0x57, 0xf6, 0xbc, 0x63, 0x2d, 0x3c,
+0x03, 0xd4, 0x00, 0x40, 0xff, 0xd7, 0xbf, 0xb7, 0xe1, 0xdf, 0xeb, 0xe7,
+0xef, 0xff, 0xff, 0x57, 0x87, 0x7f, 0xbf, 0xea, 0xfa, 0x0f, 0xfc, 0x03,
+0x1f, 0xbe, 0xf5, 0xfc, 0x80, 0x02, 0x4b, 0x00, 0x8a, 0xca, 0xff, 0x7f,
+0xf0, 0xf0, 0x17, 0x74, 0x6c, 0xf7, 0xff, 0xff, 0xff, 0xc3, 0xbf, 0x5f,
+0x95, 0xfd, 0x07, 0xfe, 0x0b, 0x0f, 0xef, 0x58, 0x00, 0xd0, 0x00, 0x35,
+0xab, 0xea, 0xff, 0xfb, 0x05, 0x78, 0xf4, 0x67, 0xff, 0xd5, 0xfb, 0xff,
+0xaf, 0xfa, 0xe1, 0xdf, 0xff, 0x80, 0xfe, 0x03, 0x3d, 0xff, 0x87, 0x6f,
+0x12, 0x00, 0xa0, 0xc0, 0xff, 0x0f, 0xf0, 0xaf, 0x03, 0xf8, 0x3f, 0xfc,
+0xff, 0x2f, 0xc0, 0xff, 0x2d, 0x65, 0xff, 0xf0, 0x0d, 0xfe, 0x04, 0xb6,
+0x2f, 0x03, 0xad, 0xc3, 0x51, 0x0d, 0x00, 0x8c, 0xff, 0xfe, 0x03, 0xf8,
+0xff, 0xb9, 0xc9, 0x19, 0x3f, 0xf0, 0x0f, 0xe0, 0xf8, 0x07, 0xf0, 0x6f,
+0xff, 0xc0, 0x3f, 0x80, 0xe1, 0x1f, 0xc0, 0xbf, 0xf2, 0xb9, 0x06, 0x00,
+0xfc, 0x07, 0xfe, 0x01, 0x0d, 0xff, 0x00, 0xfe, 0xf0, 0x1f, 0xf8, 0x07,
+0x37, 0xfc, 0x03, 0xf8, 0xc0, 0x7f, 0xe0, 0x1f, 0xdf, 0xf0, 0x0f, 0xe0,
+0x00, 0xff, 0xdf, 0x03, 0x00, 0xfe, 0x03, 0xff, 0xff, 0x86, 0x7f, 0x00,
+0x03, 0xf8, 0x0f, 0xfc, 0xfc, 0x1b, 0xfe, 0x01, 0x0f, 0xe0, 0x3f, 0xf0,
+0xf0, 0x6f, 0xf8, 0x07, 0x01, 0x80, 0xff, 0xef, 0x7f, 0x00, 0xff, 0x81,
+0x80, 0x7f, 0xc3, 0x3f, 0xfe, 0x01, 0xfc, 0x07, 0x00, 0xfe, 0x0d, 0xff,
+0xf8, 0x07, 0xf0, 0x1f, 0x03, 0xf8, 0x37, 0xfc, 0xd7, 0x00, 0x40, 0x34,
+0xc0, 0x3f, 0x80, 0xff, 0x1f, 0xc0, 0xbf, 0xe1, 0x03, 0xff, 0x00, 0xfe,
+0x7f, 0x00, 0xff, 0x86, 0x0f, 0xfc, 0x03, 0xf8, 0xfe, 0x01, 0xfc, 0x1b,
+0x9a, 0x6b, 0x00, 0x00, 0x7f, 0xe0, 0x1f, 0xc0, 0xf0, 0x0f, 0xe0, 0xdf,
+0xff, 0x81, 0x7f, 0x00, 0xc3, 0x3f, 0x80, 0x7f, 0xfc, 0x07, 0xfe, 0x01,
+0x0d, 0xff, 0x00, 0xfe, 0xf0, 0xff, 0x3d, 0x00, 0xf4, 0x3f, 0xf0, 0xaf,
+0x72, 0xf8, 0x55, 0xaa, 0xd2, 0x7b, 0xcf, 0x3f, 0xfc, 0xe1, 0x5b, 0xa9,
+0x80, 0xff, 0x93, 0xff, 0x81, 0x87, 0x7f, 0x00, 0x00, 0xf8, 0xff, 0x1e,
+0x67, 0xf2, 0x1f, 0xf8, 0xfc, 0x3c, 0xfc, 0x03, 0x1f, 0xc0, 0x7f, 0xe0,
+0xe0, 0xdf, 0xf0, 0x0f, 0x7f, 0x00, 0xff, 0x81, 0x80, 0x7f, 0xc3, 0x3f,
+0x0f, 0x00, 0xdc, 0x7f, 0xfe, 0x73, 0xfb, 0xff, 0xf4, 0x22, 0x1f, 0xde,
+0xc0, 0x9f, 0x40, 0x5d, 0x63, 0xc0, 0x75, 0xf8, 0xe5, 0x3f, 0xb5, 0xff,
+0xdd, 0xef, 0xf8, 0xe1, 0xbf, 0x07, 0x00, 0xfe, 0x7f, 0xff, 0x9d, 0xfc,
+0xff, 0x00, 0x3f, 0x0f, 0xfe, 0xff, 0x7f, 0xf2, 0xfc, 0x03, 0xfc, 0x3c,
+0xff, 0xff, 0x3f, 0xc0, 0xf0, 0xfd, 0x64, 0xf0, 0x08, 0x90, 0x00, 0x00,
+0xfe, 0xbf, 0xff, 0xdc, 0x87, 0x37, 0xae, 0x88, 0xfb, 0x0f, 0xfc, 0x33,
+0x1f, 0xfe, 0x98, 0x96, 0xcd, 0xff, 0xff, 0x5f, 0x7e, 0x78, 0xa7, 0xba,
+0x00, 0x04, 0x48, 0x00, 0x00, 0xff, 0x81, 0x7f, 0xf2, 0xc3, 0x3b, 0x13,
+0xfd, 0xfd, 0x37, 0xff, 0x3f, 0x0f, 0xff, 0x7e, 0xd6, 0xf7, 0xff, 0xfd,
+0xe5, 0x3b, 0xfc, 0x71, 0x00, 0x80, 0xff, 0xef, 0x3f, 0x80, 0xff, 0xc0,
+0xc0, 0xbf, 0xe1, 0x1f, 0xff, 0x00, 0xfe, 0x03, 0x00, 0xff, 0x86, 0x7f,
+0xfc, 0x03, 0xf8, 0x0f, 0x01, 0xfc, 0x1b, 0xfe, 0x7b, 0x00, 0xe0, 0xff,
+0xe0, 0x1f, 0xc0, 0x7f, 0x0f, 0xe0, 0xdf, 0xf0, 0x81, 0x7f, 0x00, 0xff,
+0x3f, 0x80, 0x7f, 0xc3, 0x07, 0xfe, 0x01, 0xfc, 0xff, 0x00, 0xfe, 0x0d,
+0xff, 0x3d, 0x00, 0xf0, 0x3f, 0xf0, 0x0f, 0xe0, 0xf8, 0x07, 0xf0, 0x6f,
+0xff, 0xc0, 0x3f, 0x80, 0xe1, 0x1f, 0xc0, 0xbf, 0xfe, 0x03, 0xff, 0x00,
+0x86, 0x7f, 0x00, 0xff, 0xf8, 0xff, 0x1e, 0x00, 0xf0, 0x1f, 0xf8, 0x07,
+0x37, 0xfc, 0x03, 0xf8, 0xc0, 0x7f, 0xe0, 0x1f, 0xdf, 0xf0, 0x0f, 0xe0,
+0x00, 0xff, 0x81, 0x7f, 0x7f, 0xc3, 0x3f, 0x80, 0x00, 0xfc, 0x7f, 0x0f,
+0x03, 0xf8, 0x0f, 0xfc, 0xfc, 0x1b, 0xfe, 0x01, 0x0f, 0xe0, 0x3f, 0xf0,
+0xf0, 0x6f, 0xf8, 0x07, 0x3f, 0x80, 0xff, 0xc0, 0xc0, 0xbf, 0xe1, 0x1f,
+0x07, 0x00, 0xfe, 0xbf, 0xfe, 0x01, 0xfc, 0x07, 0x00, 0xfe, 0x0d, 0xff,
+0xf8, 0x07, 0xf0, 0x1f, 0x03, 0xf8, 0x37, 0xfc, 0xe0, 0x1f, 0xc0, 0x7f,
+0x0f, 0xe0, 0xdf, 0xf0, 0xdf, 0x03, 0x00, 0xff, 0x03, 0xff, 0x00, 0xfe,
+0x7f, 0x00, 0xff, 0x86, 0x0f, 0xfc, 0x03, 0xf8, 0xfe, 0x01, 0xfc, 0x1b,
+0x3f, 0xf0, 0x0f, 0xe0, 0xf8, 0x07, 0xf0, 0x6f, 0xff, 0xef, 0x01, 0x80,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000020.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000020.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,163 @@
+/*
+ ============================================================
+ (c) Advanced Micro Devices, Inc., 2004-2005
+
+ The  enclosed microcode  is intended  to be  used  with AMD
+ Microprocessors.  You  may   copy,  view  and  install  the
+ enclosed microcode  only for development  and deployment of
+ firmware,  BIOS,  or  operating  system code  for  computer
+ systems   that  contain  AMD   processors.   You   are  not
+ authorized  to use  the  enclosed microcode  for any  other
+ purpose.
+
+ THE  MICROCODE IS PROVIDED  "AS IS"  WITHOUT ANY  EXPRESS OR
+ IMPLIED WARRANTY  OF ANY KIND, INCLUDING BUT  NOT LIMITED TO
+ WARRANTIES    OF    MERCHANTABILITY,   NON-    INFRINGEMENT,
+ TITLE,FITNESS  FOR  ANY  PARTICULAR PURPOSE,  OR  WARRANTIES
+ ARISING FROM CONDUCT, COURSE  OF DEALING, OR USAGE OF TRADE.
+ AMD does not assume  any responsibility for any errors which
+ may  appear   in  this   microcode  or  any   other  related
+ information provided  to you by  AMD, or result from  use of
+ this microcode.   AMD is not obligated  to furnish, support,
+ or  make   any  further  information,   software,  technical
+ information, know-how, or show-how available related to this
+ microcode.
+
+ The  microcode is provided  with "RESTRICTED  RIGHTS."  Use,
+ duplication, or disclosure by the U.S. Government is subject
+ to  the  restrictions as  set  forth  in  FAR 52.227-14  and
+ DFAR252.227-7013,  et seq.,  or its  successor.  Use  of the
+ microcode    by    the    U.S.     Government    constitutes
+ acknowledgement  of   AMD's  proprietary  rights   in  them.
+ ============================================================
+*/
+
+0x07, 0x20, 0x26, 0x03, 0x20, 0x00, 0x00, 0x01, 0x00, 0x80, 0x20, 0x00,
+0x66, 0x68, 0x30, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+0x00, 0x10, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x44, 0x06, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0xa4, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x72, 0x09, 0x00, 0x00, 0x70, 0x09, 0x00, 0x00, 0x9b, 0x0b, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x7f, 0x00, 0xc3, 0x3f, 0x80, 0x37,
+0xfc, 0x07, 0xfe, 0x01, 0x0d, 0xff, 0x00, 0xfe, 0xf0, 0x1f, 0xf8, 0x07,
+0x37, 0xfc, 0x03, 0xf8, 0xc0, 0xff, 0xf7, 0x00, 0x80, 0xff, 0xc0, 0x3f,
+0x9b, 0xe1, 0x1f, 0xc0, 0x00, 0xfe, 0x03, 0xff, 0xff, 0x86, 0x7f, 0x00,
+0x03, 0xf8, 0x0f, 0xfc, 0xfc, 0x1b, 0xfe, 0x01, 0x00, 0x40, 0x37, 0x6b,
+0xff, 0xfb, 0xfd, 0xff, 0x57, 0x7d, 0xf0, 0xcd, 0xff, 0x1f, 0xb7, 0xfe,
+0xc0, 0xcf, 0xc3, 0x3f, 0xff, 0x01, 0xff, 0xf7, 0x00, 0x02, 0x07, 0xff,
+0x35, 0x00, 0x90, 0x8b, 0xf0, 0x0f, 0xe0, 0x3f, 0x07, 0xf0, 0x6f, 0xf8,
+0xc0, 0x3f, 0x80, 0xff, 0x1f, 0xc0, 0xbf, 0xe1, 0x03, 0xff, 0x00, 0xfe,
+0x7f, 0x00, 0xff, 0x86, 0xff, 0x1e, 0x00, 0xf8, 0x1f, 0xf8, 0x07, 0xf0,
+0xfc, 0x03, 0x78, 0x33, 0x7f, 0xe0, 0x1f, 0xc0, 0xf0, 0x0f, 0xe0, 0xdf,
+0xff, 0x81, 0x7f, 0x00, 0xc3, 0x3f, 0x80, 0x7f, 0xfc, 0x7f, 0x0f, 0x00,
+0xf8, 0x0f, 0xfc, 0x03, 0x19, 0xfe, 0x01, 0xbc, 0xe0, 0x3f, 0xf0, 0x0f,
+0x6f, 0xf8, 0x07, 0xf0, 0x80, 0xff, 0xc0, 0x3f, 0xbf, 0xe1, 0x1f, 0xc0,
+0x00, 0xb4, 0xb2, 0x06, 0xbf, 0xdf, 0xff, 0xff, 0xd5, 0x07, 0xdf, 0x7c,
+0x67, 0xb2, 0xe7, 0xf9, 0xfc, 0x3c, 0xfc, 0x03, 0x1f, 0xf0, 0x7f, 0xff,
+0x20, 0x70, 0xf0, 0x0f, 0x03, 0x00, 0xed, 0x58, 0xff, 0x00, 0xfe, 0x03,
+0x00, 0xff, 0x86, 0x7f, 0xfc, 0x03, 0xf8, 0x0f, 0x01, 0xfc, 0x1b, 0xfe,
+0xf0, 0x0f, 0xe0, 0x3f, 0x07, 0xf0, 0x6f, 0xf8, 0xef, 0x01, 0x80, 0xff,
+0xff, 0xff, 0x29, 0x2a, 0x5f, 0xd0, 0xc1, 0xc3, 0xff, 0xff, 0xb3, 0xdd,
+0xff, 0x7e, 0xfd, 0x0f, 0x1f, 0xf8, 0x57, 0xf6, 0xbc, 0x63, 0x2d, 0x3c,
+0x03, 0xd4, 0x00, 0x40, 0xff, 0xd7, 0xbf, 0xb7, 0xe1, 0xdf, 0xeb, 0xe7,
+0xef, 0xff, 0xff, 0x57, 0x87, 0x7f, 0xbf, 0xea, 0xfa, 0x0f, 0xfc, 0x03,
+0x1f, 0xbe, 0xf5, 0xfc, 0x80, 0x02, 0x4b, 0x00, 0x8a, 0xca, 0xff, 0x7f,
+0xf0, 0xf0, 0x17, 0x74, 0x6c, 0xef, 0xff, 0xff, 0xff, 0xc3, 0xbf, 0x5f,
+0x95, 0xfd, 0x07, 0xfe, 0x0b, 0x0f, 0xef, 0x58, 0x00, 0xd0, 0x00, 0x35,
+0xab, 0xea, 0xff, 0xfb, 0x05, 0x78, 0xf4, 0x67, 0xff, 0xd5, 0xfb, 0xff,
+0xaf, 0xfa, 0xe1, 0xdf, 0xff, 0x80, 0xfe, 0x03, 0x3d, 0xff, 0x87, 0x6f,
+0x12, 0x00, 0xa0, 0xc0, 0xff, 0x0f, 0xf0, 0xaf, 0x03, 0xf8, 0x3f, 0xfc,
+0xff, 0x2f, 0xc0, 0xff, 0x2d, 0x65, 0xff, 0xf0, 0x0d, 0xfe, 0x04, 0xb6,
+0x2f, 0x03, 0xad, 0xc3, 0x51, 0x0d, 0x00, 0x8c, 0xff, 0xfe, 0x03, 0xf8,
+0xff, 0xb9, 0xc9, 0x19, 0x3f, 0xf0, 0x0f, 0xe0, 0xf8, 0x07, 0xf0, 0x6f,
+0xff, 0xc0, 0x3f, 0x80, 0xe1, 0x1f, 0xc0, 0xbf, 0xf2, 0xb9, 0x06, 0x00,
+0xfc, 0x07, 0xfe, 0x01, 0x0d, 0xff, 0x00, 0xfe, 0xf0, 0x1f, 0xf8, 0x07,
+0x37, 0xfc, 0x03, 0xf8, 0xc0, 0x7f, 0xe0, 0x1f, 0xdf, 0xf0, 0x0f, 0xe0,
+0x00, 0xff, 0xdf, 0x03, 0x00, 0xfe, 0x03, 0xff, 0xff, 0x86, 0x7f, 0x00,
+0x03, 0xf8, 0x0f, 0xfc, 0xfc, 0x1b, 0xfe, 0x01, 0x0f, 0xe0, 0x3f, 0xf0,
+0xf0, 0x6f, 0xf8, 0x07, 0x01, 0x80, 0xff, 0xef, 0x7f, 0x00, 0xff, 0x81,
+0x80, 0x7f, 0xc3, 0x3f, 0xfe, 0x01, 0xfc, 0x07, 0x00, 0xfe, 0x0d, 0xff,
+0xf8, 0x07, 0xf0, 0x1f, 0x03, 0xf8, 0x37, 0xfc, 0xd7, 0x00, 0x40, 0x34,
+0xc0, 0x3f, 0x80, 0xff, 0x1f, 0xc0, 0xbf, 0xe1, 0x03, 0xff, 0x00, 0xfe,
+0x7f, 0x00, 0xff, 0x86, 0x0f, 0xfc, 0x03, 0xf8, 0xfe, 0x01, 0xfc, 0x1b,
+0x9a, 0x6b, 0x00, 0x00, 0x7f, 0xe0, 0x1f, 0xc0, 0xf0, 0x0f, 0xe0, 0xdf,
+0xff, 0x81, 0x7f, 0x00, 0xc3, 0x3f, 0x80, 0x7f, 0xfc, 0x07, 0xfe, 0x01,
+0x0d, 0xff, 0x00, 0xfe, 0xf0, 0xff, 0x3d, 0x00, 0xf4, 0x3f, 0xf0, 0xaf,
+0x72, 0xf8, 0x55, 0xaa, 0xd2, 0x7b, 0xcf, 0x3f, 0xfc, 0xe1, 0x5b, 0xa9,
+0x80, 0xff, 0x93, 0xff, 0x81, 0x87, 0x7f, 0x00, 0x00, 0xf8, 0xff, 0x1e,
+0x67, 0xf2, 0x1f, 0xf8, 0xfc, 0x3c, 0xfc, 0x03, 0x1f, 0xc0, 0x7f, 0xe0,
+0xe0, 0xdf, 0xf0, 0x0f, 0x7f, 0x00, 0xff, 0x81, 0x80, 0x7f, 0xc3, 0x3f,
+0x0f, 0x00, 0xdc, 0x7f, 0xfe, 0x73, 0xfb, 0xff, 0xf4, 0x22, 0x1f, 0xde,
+0xc0, 0x9f, 0x40, 0x5d, 0x63, 0xc0, 0x75, 0xf8, 0xe5, 0x3f, 0xb5, 0xff,
+0xdd, 0xef, 0xf8, 0xe1, 0xbf, 0x07, 0x00, 0xfe, 0x7f, 0xff, 0x9d, 0xfc,
+0xff, 0x00, 0x3f, 0x0f, 0xfe, 0xff, 0x7f, 0xf2, 0xfc, 0x03, 0xfc, 0x3c,
+0xff, 0xff, 0x3f, 0xc0, 0xf0, 0xfd, 0x64, 0xf0, 0x08, 0x90, 0x00, 0x00,
+0xfe, 0xbf, 0xff, 0xdc, 0x87, 0x37, 0xae, 0x88, 0xfb, 0x0f, 0xfc, 0x33,
+0x1f, 0xfe, 0x98, 0x96, 0xcd, 0xff, 0xff, 0x5f, 0x7e, 0x78, 0xa7, 0xba,
+0x00, 0x04, 0x48, 0x00, 0x00, 0xff, 0x81, 0x7f, 0xf2, 0xc3, 0x3b, 0x13,
+0xfd, 0xfd, 0x37, 0xff, 0x3f, 0x0f, 0xff, 0x7e, 0xd6, 0xf7, 0xff, 0xfd,
+0xe5, 0x3b, 0xfc, 0x71, 0x00, 0x80, 0xff, 0xef, 0x3f, 0x80, 0xff, 0xc0,
+0xc0, 0xbf, 0xe1, 0x1f, 0xff, 0x00, 0xfe, 0x03, 0x00, 0xff, 0x86, 0x7f,
+0xfc, 0x03, 0xf8, 0x0f, 0x01, 0xfc, 0x1b, 0xfe, 0x7b, 0x00, 0xe0, 0xff,
+0xe0, 0x1f, 0xc0, 0x7f, 0x0f, 0xe0, 0xdf, 0xf0, 0x81, 0x7f, 0x00, 0xff,
+0x3f, 0x80, 0x7f, 0xc3, 0x07, 0xfe, 0x01, 0xfc, 0xff, 0x00, 0xfe, 0x0d,
+0xff, 0x3d, 0x00, 0xf0, 0x3f, 0xf0, 0x0f, 0xe0, 0xf8, 0x07, 0xf0, 0x6f,
+0xff, 0xc0, 0x3f, 0x80, 0xe1, 0x1f, 0xc0, 0xbf, 0xfe, 0x03, 0xff, 0x00,
+0x86, 0x7f, 0x00, 0xff, 0xf8, 0xff, 0x1e, 0x00, 0xf0, 0x1f, 0xf8, 0x07,
+0x37, 0xfc, 0x03, 0xf8, 0xc0, 0x7f, 0xe0, 0x1f, 0xdf, 0xf0, 0x0f, 0xe0,
+0x00, 0xff, 0x81, 0x7f, 0x7f, 0xc3, 0x3f, 0x80, 0x00, 0xfc, 0x7f, 0x0f,
+0x03, 0xf8, 0x0f, 0xfc, 0xfc, 0x1b, 0xfe, 0x01, 0x0f, 0xe0, 0x3f, 0xf0,
+0xf0, 0x6f, 0xf8, 0x07, 0x3f, 0x80, 0xff, 0xc0, 0xc0, 0xbf, 0xe1, 0x1f,
+0x07, 0x00, 0xfe, 0xbf, 0xfe, 0x01, 0xfc, 0x07, 0x00, 0xfe, 0x0d, 0xff,
+0xf8, 0x07, 0xf0, 0x1f, 0x03, 0xf8, 0x37, 0xfc, 0xe0, 0x1f, 0xc0, 0x7f,
+0x0f, 0xe0, 0xdf, 0xf0, 0xdf, 0x03, 0x00, 0xff, 0x03, 0xff, 0x00, 0xfe,
+0x7f, 0x00, 0xff, 0x86, 0x0f, 0xfc, 0x03, 0xf8, 0xfe, 0x01, 0xfc, 0x1b,
+0x3f, 0xf0, 0x0f, 0xe0, 0xf8, 0x07, 0xf0, 0x6f, 0xff, 0xef, 0x01, 0x80,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/model_10xxx_init.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/model_10xxx_init.c	2007-12-12 11:29:12.000000000 -0700
@@ -0,0 +1,463 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <console/console.h>
+#include <cpu/x86/msr.h>
+#include <cpu/amd/mtrr.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/pae.h>
+#include <pc80/mc146818rtc.h>
+#include <cpu/x86/lapic.h>
+
+#include "../../../northbridge/amd/amdfam10/amdfam10.h"
+
+#include <cpu/amd/model_10xxx_rev.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/mem.h>
+
+#include <cpu/amd/quadcore.h>
+
+#include <cpu/amd/model_10xxx_msr.h>
+
+extern void prep_pstates_all(void);
+extern void init_pstates(device_t dev, u32 nodeid, u32 coreid);
+extern device_t get_node_pci(u32 nodeid, u32 fn);
+
+
+
+void cpus_ready_for_init(void)
+{
+	prep_pstates_all();
+#if MEM_TRAIN_SEQ == 1
+	struct sys_info *sysinfox = (struct sys_info *)((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_GLOBAL_VAR_SIZE);
+	// wait for ap memory to trained
+	wait_all_core0_mem_trained(sysinfox);
+#endif
+}
+
+
+#define MCI_STATUS 0x401
+
+
+static inline msr_t rdmsr_amd(u32 index)
+{
+	 msr_t result;
+	 __asm__ __volatile__ (
+		 "rdmsr"
+		 : "=a" (result.lo), "=d" (result.hi)
+		 : "c" (index), "D" (0x9c5a203a)
+		 );
+	 return result;
+}
+
+
+static inline void wrmsr_amd(u32 index, msr_t msr)
+{
+	__asm__ __volatile__ (
+		"wrmsr"
+		: /* No outputs */
+		: "c" (index), "a" (msr.lo), "d" (msr.hi), "D" (0x9c5a203a)
+		);
+}
+
+
+#define MTRR_COUNT 8
+#define ZERO_CHUNK_KB 0x800UL /* 2M */
+#define TOLM_KB 0x400000UL
+
+struct mtrr {
+	msr_t base;
+	msr_t mask;
+};
+
+
+struct mtrr_state {
+	struct mtrr mtrrs[MTRR_COUNT];
+	msr_t top_mem, top_mem2;
+	msr_t def_type;
+};
+
+
+static void save_mtrr_state(struct mtrr_state *state)
+{
+	int i;
+	for(i = 0; i < MTRR_COUNT; i++) {
+		state->mtrrs[i].base = rdmsr(MTRRphysBase_MSR(i));
+		state->mtrrs[i].mask = rdmsr(MTRRphysMask_MSR(i));
+	}
+	state->top_mem	= rdmsr(TOP_MEM);
+	state->top_mem2 = rdmsr(TOP_MEM2);
+	state->def_type = rdmsr(MTRRdefType_MSR);
+}
+
+
+static void restore_mtrr_state(struct mtrr_state *state)
+{
+	int i;
+	disable_cache();
+
+	for(i = 0; i < MTRR_COUNT; i++) {
+		wrmsr(MTRRphysBase_MSR(i), state->mtrrs[i].base);
+		wrmsr(MTRRphysMask_MSR(i), state->mtrrs[i].mask);
+	}
+	wrmsr(TOP_MEM, state->top_mem);
+	wrmsr(TOP_MEM2, state->top_mem2);
+	wrmsr(MTRRdefType_MSR, state->def_type);
+
+	enable_cache();
+}
+
+
+#if 0
+static void print_mtrr_state(struct mtrr_state *state)
+{
+	int i;
+	for(i = 0; i < MTRR_COUNT; i++) {
+		printk_debug("var mtrr %d: %08x%08x mask: %08x%08x\n",
+			i,
+			state->mtrrs[i].base.hi, state->mtrrs[i].base.lo,
+			state->mtrrs[i].mask.hi, state->mtrrs[i].mask.lo);
+	}
+	printk_debug("top_mem:	%08x%08x\n",
+		state->top_mem.hi, state->top_mem.lo);
+	printk_debug("top_mem2: %08x%08x\n",
+		state->top_mem2.hi, state->top_mem2.lo);
+	printk_debug("def_type: %08x%08x\n",
+		state->def_type.hi, state->def_type.lo);
+}
+#endif
+
+
+static void set_init_ecc_mtrrs(void)
+{
+	msr_t msr;
+	int i;
+	disable_cache();
+
+	/* First clear all of the msrs to be safe */
+	for(i = 0; i < MTRR_COUNT; i++) {
+		msr_t zero;
+		zero.lo = zero.hi = 0;
+		wrmsr(MTRRphysBase_MSR(i), zero);
+		wrmsr(MTRRphysMask_MSR(i), zero);
+	}
+
+	/* Write back cache the first 1MB */
+	msr.hi = 0x00000000;
+	msr.lo = 0x00000000 | MTRR_TYPE_WRBACK;
+	wrmsr(MTRRphysBase_MSR(0), msr);
+	msr.hi = 0x000000ff;
+	msr.lo = ~((CONFIG_LB_MEM_TOPK << 10) - 1) | 0x800;
+	wrmsr(MTRRphysMask_MSR(0), msr);
+
+	/* Set the default type to write combining */
+	msr.hi = 0x00000000;
+	msr.lo = 0xc00 | MTRR_TYPE_WRCOMB;
+	wrmsr(MTRRdefType_MSR, msr);
+
+	/* Set TOP_MEM to 4G */
+	msr.hi = 0x00000001;
+	msr.lo = 0x00000000;
+	wrmsr(TOP_MEM, msr);
+
+	enable_cache();
+}
+
+
+static inline void clear_2M_ram(unsigned long basek, struct mtrr_state *mtrr_state)
+{
+		unsigned long limitk;
+		unsigned long size;
+		void *addr;
+
+		/* Report every 64M */
+		if ((basek % (64*1024)) == 0) {
+
+			/* Restore the normal state */
+			map_2M_page(0);
+			restore_mtrr_state(mtrr_state);
+			enable_lapic();
+
+			/* Print a status message */
+			printk_debug("%c", (basek >= TOLM_KB)?'+':'-');
+
+			/* Return to the initialization state */
+			set_init_ecc_mtrrs();
+			disable_lapic();
+
+		}
+
+		limitk = (basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1);
+
+		size = (limitk - basek) << 10;
+		addr = map_2M_page(basek >> 11);
+		if (addr == MAPPING_ERROR) {
+			printk_err("Cannot map page: %x\n", basek >> 11);
+			return;
+		}
+
+		/* clear memory 2M (limitk - basek) */
+		addr = (void *)(((u32)addr) | ((basek & 0x7ff) << 10));
+		clear_memory(addr, size);
+}
+
+
+static void init_ecc_memory(u32 node_id)
+{
+	unsigned long startk, begink, endk;
+	unsigned long hole_startk = 0;
+	unsigned long basek;
+	struct mtrr_state mtrr_state;
+
+	device_t f1_dev, f2_dev, f3_dev;
+	int enable_scrubbing;
+	u32 dcl;
+
+	f1_dev = get_node_pci(node_id, 1);
+
+	if (!f1_dev) {
+		die("Cannot find cpu function 1\n");
+	}
+	f2_dev = get_node_pci(node_id, 2);
+	if (!f2_dev) {
+		die("Cannot find cpu function 2\n");
+	}
+	f3_dev = get_node_pci(node_id, 3);
+	if (!f3_dev) {
+		die("Cannot find cpu function 3\n");
+	}
+
+	/* See if we scrubbing should be enabled */
+	enable_scrubbing = 1;
+	get_option(&enable_scrubbing, "hw_scrubber");
+
+	/* Enable cache scrubbing at the lowest possible rate */
+	if (enable_scrubbing) {
+		pci_write_config32(f3_dev, DRAM_SCRUB_RATE_CTRL,
+			(SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_NONE << 0));
+	} else {
+		pci_write_config32(f3_dev, DRAM_SCRUB_RATE_CTRL,
+			(SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0));
+		printk_debug("Scrubbing Disabled\n");
+	}
+
+
+	/* If ecc support is not enabled don't touch memory */
+	dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW);
+	if (!(dcl & DCL_DimmEccEn)) {
+		printk_debug("ECC Disabled\n");
+		return;
+	}
+
+	startk = (pci_read_config32(f1_dev, 0x40 + (node_id*8)) & 0xffff0000) >> 2;
+	endk   = ((pci_read_config32(f1_dev, 0x44 + (node_id*8)) & 0xffff0000) >> 2) + 0x4000;
+
+#if HW_MEM_HOLE_SIZEK != 0
+		u32 val;
+		val = pci_read_config32(f1_dev, 0xf0);
+		if(val & 1) {
+			hole_startk = ((val & (0xff<<24)) >> 10);
+		}
+#endif
+
+
+	/* Don't start too early */
+	begink = startk;
+	if (begink < CONFIG_LB_MEM_TOPK) {
+		begink = CONFIG_LB_MEM_TOPK;
+	}
+
+	printk_debug("Clearing memory %uK - %uK: ", begink, endk);
+
+	/* Save the normal state */
+	save_mtrr_state(&mtrr_state);
+
+	/* Switch to the init ecc state */
+	set_init_ecc_mtrrs();
+	disable_lapic();
+
+	/* Walk through 2M chunks and zero them */
+#if HW_MEM_HOLE_SIZEK != 0
+	/* here hole_startk can not be equal to begink, never. Also hole_startk is in 2M boundary, 64M? */
+	 if ( (hole_startk != 0) && ((begink < hole_startk) && (endk>(4*1024*1024)))) {
+			for(basek = begink; basek < hole_startk;
+				basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1)))
+			{
+				clear_2M_ram(basek, &mtrr_state);
+			}
+			for(basek = 4*1024*1024; basek < endk;
+				basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1)))
+			{
+				clear_2M_ram(basek, &mtrr_state);
+			}
+	} else
+#endif
+	for(basek = begink; basek < endk;
+		basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1))) {
+		clear_2M_ram(basek, &mtrr_state);
+	}
+
+
+	/* Restore the normal state */
+	map_2M_page(0);
+	restore_mtrr_state(&mtrr_state);
+	enable_lapic();
+
+	/* Set the scrub base address registers */
+	pci_write_config32(f3_dev, DRAM_SCRUB_ADDR_LOW,	 startk << 10);
+	pci_write_config32(f3_dev, DRAM_SCRUB_ADDR_HIGH, startk >> 22);
+
+	/* Enable the scrubber? */
+	if (enable_scrubbing) {
+		/* Enable scrubbing at the lowest possible rate */
+		pci_write_config32(f3_dev, DRAM_SCRUB_RATE_CTRL,
+			(SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0));
+	}
+
+	printk_debug(" done\n");
+}
+
+
+static inline void fam10_errata(void)
+{
+	msr_t msr;
+	/* FIXME: Is doing errata here too late? */
+
+	/* 298 : FIXME: Fixed in B3/C1 */
+/*	msr = rdmsr(0xC0010015);
+	msr.lo |= 1 << 3;
+	wrmsr(0xC0010015, msr);
+
+	msr = rdmsr(0xC0010023);
+	msr.lo |= 1 << 1;
+	wrmsr(0xC0010023, msr);
+*/
+}
+
+static void smash1Gpages(void)
+{
+	msr_t msr;
+
+	/* 1G pages are smashed and installed in the TLB as 2M pages.
+	   BIOS must set this bit for revision B. */
+	/* FIXME: What about RevC? */
+
+	msr = rdmsr(0xC001102A);
+	msr.lo |= 1 << 29;
+	wrmsr(0xC001102A, msr);
+
+}
+
+extern void update_microcode(u32 cpu_deviceid);
+
+
+void model_10xxx_init(device_t dev)
+{
+	unsigned long i;
+	msr_t msr;
+	struct node_core_id id;
+#if CONFIG_LOGICAL_CPUS == 1
+	unsigned siblings;
+#endif
+
+	/* Turn on caching if we haven't already */
+	x86_enable_cache();
+	amd_setup_mtrrs();
+	x86_mtrr_check();
+
+
+	/* Update the microcode */
+	update_microcode(dev->device);
+
+	disable_cache();
+
+	/* zero the machine check error status registers */
+	msr.lo = 0;
+	msr.hi = 0;
+	for(i=0; i < 5; i++) {
+		wrmsr(MCI_STATUS + (i * 4),msr);
+	}
+
+	fam10_errata();
+
+	enable_cache();
+
+	/* Enable the local cpu apics */
+	setup_lapic();
+
+#if CONFIG_LOGICAL_CPUS == 1
+	siblings = cpuid_ecx(0x80000008) & 0xff;
+
+	if (siblings > 0) {
+		msr = rdmsr_amd(CPU_ID_FEATURES_MSR);
+		msr.lo |= 1 << 28;
+		wrmsr_amd(CPU_ID_FEATURES_MSR, msr);
+
+		msr = rdmsr_amd(LOGICAL_CPUS_NUM_MSR);
+		msr.lo = (siblings+1)<<16;
+		wrmsr_amd(LOGICAL_CPUS_NUM_MSR, msr);
+
+		msr = rdmsr_amd(CPU_ID_EXT_FEATURES_MSR);
+		msr.hi |= 1<<(33-32);
+		wrmsr_amd(CPU_ID_EXT_FEATURES_MSR, msr);
+	}
+	printk_debug("siblings = %02d, ", siblings);
+#endif
+
+	id = get_node_core_id(read_nb_cfg_54()); // pre e0 nb_cfg_54 can not be set
+
+	printk_debug("nodeid = %02d, coreid = %02d\n", id.nodeid, id.coreid);
+
+	init_pstates(dev, id.nodeid, id.coreid); // is it a good place? some cores are clearing their ram
+
+	/* Is this a bad location?  In particular can another node prefecth
+	 * data from this node before we have initialized it?
+	 */
+	if (id.coreid == 0) init_ecc_memory(id.nodeid); // only do it for core 0
+
+#if CONFIG_LOGICAL_CPUS==1
+	 /* Start up my cpu siblings */
+//	if(id.coreid==0)  amd_sibling_init(dev); // Don't need core1 is already be put in the CPU BUS in bus_cpu_scan
+#endif
+
+	smash1Gpages();
+}
+
+static struct device_operations cpu_dev_ops = {
+	.init = model_10xxx_init,
+};
+static struct cpu_device_id cpu_table[] = {
+//AMD_GH_SUPPORT
+	{ X86_VENDOR_AMD, 0x100f00 },		/* SH-F0 L1 */
+	{ X86_VENDOR_AMD, 0x100f10 },		/* M2 */
+	{ X86_VENDOR_AMD, 0x100f20 },		/* S1g1 */
+	{ X86_VENDOR_AMD, 0x100f21 },
+	{ X86_VENDOR_AMD, 0x100f2A },
+	{ X86_VENDOR_AMD, 0x100f22 },
+	{ 0, 0 },
+};
+static struct cpu_driver model_10xxx __cpu_driver = {
+	.ops	  = &cpu_dev_ops,
+	.id_table = cpu_table,
+};
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/pstate.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/pstate.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,456 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <console/console.h>
+#include <cpu/x86/msr.h>
+#include <cpu/amd/mtrr.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/pae.h>
+#include <pc80/mc146818rtc.h>
+#include <cpu/x86/lapic.h>
+
+#include "../../../northbridge/amd/amdfam10/amdfam10.h"
+
+#include <cpu/amd/model_10xxx_rev.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/mem.h>
+
+#include <cpu/amd/quadcore.h>
+
+#include <cpu/amd/model_10xxx_msr.h>
+#include <cpu/amd/amdfam10_sysconf.h>
+
+extern device_t get_node_pci(u32 nodeid, u32 fn);
+
+#include "fidvid_common.c"
+
+#define PSTATES_DEBUG 0
+
+
+
+static void inline dump_msr_pstates(u32 nodes)
+{
+#if PSTATES_DEBUG==1
+	int i, j;
+	for(j=0; j<5; j++) {
+		printk_debug("P%d:", j);
+		for(i=0;i<nodes;i++)  {
+			printk_debug(" [%08x %08x] ", sysconf.msr_pstate[i*5+j].hi, sysconf.msr_pstate[i*5+j].lo);
+		}
+		printk_debug("\n");
+	}
+#endif
+}
+
+
+static void inline dump_p(const char *p_c, u32 nodes, u32 *p)
+{
+#if PSTATES_DEBUG==1
+	int i, j;
+		printk_debug(p_c);
+		printk_debug("p:");
+		for(i=0;i<nodes;i++)  {
+			printk_debug(" %d ", p[i]);
+		}
+		printk_debug("\n");
+
+#endif
+}
+
+
+//according the pstate and make it work conformed to mixed conf system
+static u32 get_pwrvalue(u32 val)
+{
+	u32 times;
+	switch((val>>8)&3) {
+	case 0: times = 1000; break;
+	case 1: times = 100;  break;
+	case 2: times = 10;   break;
+	default:
+		//error
+		times = 1;
+	}
+
+	return (val & 0xff) * times;
+
+}
+
+
+static u32 get_powerstep(u32 val)
+{
+	u32 time;
+	if(val<4) {time = (4 - val)*100;}
+	else if(val<8) { time = (9+4-val)*10;}
+	else { time = (10+8-val) * 5; }
+
+	return time;
+
+}
+
+
+static u32 get_plllocktime(u32 val)
+{
+	u32 time;
+	switch(val) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		time = val+1; break;
+	case 4: time = 8; break;
+	case 5: time = 16; break;
+	default:
+		//erro2
+		time = 1;
+	}
+	return time;
+}
+
+
+static void disable_pstate(u32 nodes, u32 *p)
+{
+	int i;
+
+	for(i=0;i<nodes; i++) {
+		sysconf.msr_pstate[i*5+p[i]].hi &= ~(1<<(63-32));
+	}
+}
+
+
+static void match_pstate(u32 nodes, u32 *p)
+{
+	int i;
+	u32 corecof_min, pwrvalue_max, pwrval_max;
+	u32 enable;
+	enable = (sysconf.msr_pstate[0*5+p[0]].hi >> 31);
+	if(!enable)  {
+		disable_pstate(nodes, p);
+		return;
+	}
+	corecof_min = ((sysconf.msr_pstate[0*5+p[0]].lo & 0x3f) + 0x10)>>((sysconf.msr_pstate[0*5+p[0]].lo>>6) & 7);
+	pwrval_max = sysconf.msr_pstate[0*5+p[0]].hi & 0x3ff;
+	pwrvalue_max = get_pwrvalue(pwrval_max);
+
+	for(i=1; i<nodes; i++) {
+		enable = (sysconf.msr_pstate[0*5+p[i]].hi >> 31);
+		if(!enable) {
+			disable_pstate(nodes, p);
+			return;
+		}
+
+		u32 coredid = ((sysconf.msr_pstate[i*5+p[i]].lo>>6) & 7);
+		u32 corecof = ((sysconf.msr_pstate[i*5+p[i]].lo & 0x3f) + 0x10)>>coredid;
+		if(corecof<corecof_min) corecof_min = corecof;
+		u32 pwrval, pwrvalue;
+		pwrval = sysconf.msr_pstate[i*5+p[i]].hi & 0x3ff;
+		pwrvalue = get_pwrvalue(pwrval);
+		if(pwrvalue>pwrvalue_max) {
+			pwrvalue_max = pwrvalue;
+			pwrval_max = pwrval;
+		}
+	}
+
+	for(i=0; i<nodes; i++) {
+		u32 coredid = ((sysconf.msr_pstate[i*5+p[i]].lo>>6) & 7);
+		u32 corefid = (corecof_min<<coredid);
+		while(corefid<0x10) {
+			coredid++;
+			corefid = (corecof_min<<coredid);
+		}
+		sysconf.msr_pstate[i*5+p[i]].lo &= ~(0x1ff);
+		sysconf.msr_pstate[i*5+p[i]].lo |= (corefid - 0x10) | (coredid << 6);
+		sysconf.msr_pstate[i*5+p[i]].hi &= ~(0x3ff);
+		sysconf.msr_pstate[i*5+p[i]].hi |= pwrval_max;
+	}
+}
+
+
+static void match_pstates(u32 nodes, u32 *p, u32 *px)
+{
+	int i;
+	int j;
+	u32 p_int[NODE_NUMS];
+
+	int jj=1;
+	u32 end = 0;
+	for(i=0;i<nodes; i++) {
+		p_int[i] = px[i];
+	}
+	while(1){
+		for(i=0;i<nodes; i++) {
+			if(px[i]<=(p[i]+jj)) {
+				end = 1;
+				break;
+			}
+		}
+		if(!end) {
+			for(i=0; i<nodes; i++) {
+				p_int[i] = px[i] - jj;
+			}
+			match_pstate(nodes, p_int);
+			dump_p("P int\n", nodes, p_int);
+			jj++;
+		}
+		else {
+			for(i=0;i<nodes; i++) {
+				for(j=p[i]+1; j<p_int[i]; j++) {
+					sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
+				}
+			}
+			break;
+		}
+	}
+}
+
+
+void prep_pstates_all(void)
+{
+	device_t f3_dev[NODE_NUMS], f4_dev[NODE_NUMS];
+	u32 p[NODE_NUMS];
+	u32 p_htc[NODE_NUMS];
+	u32 p_lowest[NODE_NUMS];
+	u32 htc_cap = 1;
+	u32 lowest_htc_equal = 0;
+
+	u32 nodes = sysconf.nodes;
+	int i;
+	int j;
+	u32 val;
+	u32 nbdid;
+	u32 nbvid0;
+	u32 nbvid1;
+
+	for(i=0;i<nodes; i++) { // get the value from F4x1F0:E0 or we can get that msr in CAR stage...
+		f3_dev[i] = get_node_pci(i, 3);
+		f4_dev[i] = get_node_pci(i, 4);
+	}
+
+	for(i=0;i<nodes; i++) { // get the value from F4x1F0:E0 or we can get that msr in CAR stage...
+		val = pci_read_config32(f4_dev[i], 0x1f4);
+		nbvid0 = val & 0x3f;
+		nbvid1 = (val>>7) & 0x3f;
+		for(j=0; j<5; j++) {
+			val = pci_read_config32(f4_dev[i], 0x1e0 + (j<<2));
+			nbdid = ((val>>16) & 1);
+			sysconf.msr_pstate[i*5+j].lo = (val & 0xffff)  | (nbdid<<22) | ((nbdid?nbvid1:nbvid0)<<25);
+			sysconf.msr_pstate[i*5+j].hi = (((val>>17) & 0x3ff) << (32-32)) | (((val>>27) & 1)<<(63-32));
+		}
+	}
+
+	dump_msr_pstates(nodes);
+
+	sysconf.needs_update_pstate_msrs = 0; // normal case for all sockets are installed same conf CPU
+
+	for(i=1; (i<nodes) && (!sysconf.needs_update_pstate_msrs); i++) {
+		for(j=0; j<5; j++) {
+			if((sysconf.msr_pstate[i*5+j].lo != sysconf.msr_pstate[0*5+j].lo) || (sysconf.msr_pstate[i*5+j].hi != sysconf.msr_pstate[0*5+j].hi)) {
+				sysconf.needs_update_pstate_msrs = 1;
+				break;
+			}
+		}
+	}
+
+	if(sysconf.needs_update_pstate_msrs) {
+
+		// update msr_pstate for mixed conf
+
+		//P0
+		/* Match P0 cpu cof for all cpu cores to the lowest P0 cpu cof value in the coherent fabric, and match P0 power for all cpu cores to the highest P0 power value */
+		for(i=0;i<nodes; i++) p[i] = 0;
+		match_pstate(nodes, p);
+		dump_p("P0\n", nodes, p);
+		 dump_msr_pstates(nodes);
+
+
+		//p_htc
+		for(i=0;i<nodes; i++) {
+			val = pci_read_config32(f3_dev[i], 0xe8); //htc cap
+			if(!(val & (1<<10))) {
+				htc_cap = 0;
+				break;
+			}
+
+			//HtcPstateLimit
+			val = pci_read_config32(f3_dev[i], 0x64);
+			p_htc[i] = (((val>>28) & 7));
+			if(p_htc[i] == 0) {
+				val |= 1<<28;
+				pci_write_config32(f3_dev[i], 0x64, val);
+				val = pci_read_config32(f3_dev[i], 0x68); //stc
+				val &= ~(7<<28);
+				val |= (1<<28);
+				pci_write_config32(f3_dev[i], 0x68, val);
+
+				p_htc[i] = 1;
+			}
+		}
+		if(htc_cap) {
+			match_pstate(nodes, p_htc);
+
+			dump_p("P_htc\n", nodes, p_htc);
+			dump_msr_pstates(nodes);
+		}
+
+		//p_lowest
+		for(i=0;i<nodes; i++) {
+			p_lowest[i] = 0;
+			for(j=1; j<5; j++) {
+				if(sysconf.msr_pstate[i*5+j].hi & (1<<(63-32)))	{
+					p_lowest[i] = j;
+				}
+			}
+			// PstateMaxVal
+			val = pci_read_config32(f3_dev[i], 0xdc);
+			if(p_lowest[i]>((val>>8) & 7)) {
+				val &= ~(7<<8);
+				val |= (p_lowest[i])<<8;
+				pci_write_config32(f3_dev[i], 0xdc, val);
+			}
+			else {
+				p_lowest[i] = (val>>8) & 7;
+			}
+		}
+		if(htc_cap) {
+			for(i=0;i<nodes; i++) {
+				if(p_lowest[i]==p_htc[i]){
+					lowest_htc_equal = 1;
+					break;
+				}
+			}
+		}
+		if(lowest_htc_equal) {
+			for(i=0;i<nodes; i++) {
+				// PstateMaxVal
+				val = pci_read_config32(f3_dev[i], 0xdc);
+				val &= ~(7<<8);
+				val |= p_htc[i];
+				pci_write_config32(f3_dev[i], 0xdc, val);
+				for(j=p_htc[i]+1; j<5; j++) {
+					sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
+				}
+			}
+		} else {
+			match_pstate(nodes, p_lowest);
+			for(i=0; i<nodes; i++) {
+				for(j=p_lowest[i]+1; j<5; j++) {
+				      sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
+				}
+			}
+
+		}
+
+		dump_p("Px\n", nodes, p_lowest);
+		dump_msr_pstates(nodes);
+
+
+		if(htc_cap) {
+			//p_up_int
+			match_pstates(nodes, p, p_htc);
+
+			dump_msr_pstates(nodes);
+
+			//p_lower_int
+			match_pstates(nodes, p_htc, p_lowest);
+		} else {
+			match_pstates(nodes, p, p_lowest);
+		}
+
+		dump_msr_pstates(nodes);
+
+	}
+
+	// fill data into p_state
+	for(i=0; i<nodes; i++) {
+		sysconf.p_state_num = 0;
+		u32 corefid_equal = 1;
+		u32 corefid;
+		corefid = (sysconf.msr_pstate[i*5+0].lo & 0x3f);
+		for(j=1; j<5; j++) {
+			msr_t *msr_pstate;
+			msr_pstate = &(sysconf.msr_pstate[i*5+j]);
+			if(!(msr_pstate->hi & (1<<(63-32)) )) continue;
+			if((msr_pstate->lo & 0x3f) != corefid) {
+				corefid_equal = 0;
+				break;
+			}
+		}
+		for(j=0; j<5; j++) {
+			struct p_state_t *p_state;
+			msr_t *msr_pstate;
+			msr_pstate = &sysconf.msr_pstate[i*5+j];
+			if(!(msr_pstate->hi & (1<<(63-32)) )) continue;
+			p_state = &sysconf.p_state[i*5+sysconf.p_state_num];
+			u32 coredid = ((msr_pstate->lo>>6) & 7);
+			u32 corecof = ((msr_pstate->lo & 0x3f) + 0x10)>>coredid;
+			p_state->corefreq = corecof;
+
+			u32 pwrval, pwrvalue;
+			pwrval = msr_pstate->hi & 0x3ff;
+			pwrvalue = get_pwrvalue(pwrval);
+			p_state->power = pwrvalue;
+
+			u32 lat;
+			val = pci_read_config32(f3_dev[i], 0xd4);
+			lat = 15 * (get_powerstep((val>>24)& 0xf)+get_powerstep((val>>20)& 0xf)) /1000;
+			if(!corefid_equal) {
+				val = pci_read_config32(f3_dev[i], 0xa0);
+				lat += get_plllocktime((val >> 11 ) & 7);
+			}
+			p_state->transition_lat = lat;
+			p_state->busmaster_lat = lat;
+
+			p_state->control = j;
+			p_state->status = j;
+
+			sysconf.p_state_num++;
+		}
+		// don't need look at other nodes
+		if(!sysconf.p_state_num) break;
+	}
+}
+
+
+//it will update pstates info from ram into MSR
+void init_pstates(device_t dev, u32 nodeid, u32 coreid)
+{
+	int j;
+	msr_t msr;
+
+	if(sysconf.needs_update_pstate_msrs) {
+		for(j=0; j < 5; j++) {
+			wrmsr(0xC0010064 + j, sysconf.msr_pstate[nodeid * 5 + j]);
+		}
+	}
+
+	/* Set TSC Freq Select: TSC increments at the rate of the core P-state 0 */
+	msr = rdmsr(0xC0010015);
+	msr.lo |= 1 << 24;
+	wrmsr(0xC0010015, msr);
+
+	// Enter the state P0
+	//FIXME I don't think that this works correctly. May depend on early fid/vid setup.
+	if(sysconf.p_state_num)
+		set_core_nb_max_pstate_after_other_warm_reset(nodeid, coreid);
+
+}
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/update_microcode.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/update_microcode.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#ifndef __ROMCC__
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+
+#include <cpu/amd/microcode.h>
+#endif
+
+static const u8 microcode_updates[] __attribute__ ((aligned(16))) = {
+
+#ifdef __ROMCC__
+
+	// Barcelona revAx
+//		#include "mc_patch_01000020.h"
+
+	// Barcelona revBx
+		#include "mc_patch_01000033.h"
+
+	// Barcelona rev Cx??
+//		#include "mc_patch_01000035.h"
+
+#endif
+	/*  Dummy terminator  */
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+};
+
+static u32 get_equivalent_processor_rev_id(u32 orig_id) {
+	static unsigned id_mapping_table[] = {
+		0x100f00, 0x1000,
+		0x100f01, 0x1000,
+		0x100f02, 0x1000,
+		0x100f20, 0x1020,
+		0x100f21, 0x1020,
+		0x100f2A, 0x1020,
+		0x100f22, 0x1022,
+	};
+
+	u32 new_id;
+	int i;
+
+	new_id = 0;
+
+	for (i = 0; i < sizeof(id_mapping_table); i += 2 ) {
+		if(id_mapping_table[i]==orig_id) {
+			new_id = id_mapping_table[i + 1];
+			break;
+		}
+	}
+
+	return new_id;
+
+}
+
+void update_microcode(u32 cpu_deviceid)
+{
+	u32 equivalent_processor_rev_id;
+
+	/* Update the microcode */
+	equivalent_processor_rev_id = get_equivalent_processor_rev_id(cpu_deviceid );
+	if (equivalent_processor_rev_id != 0) {
+		amd_update_microcode((void *) microcode_updates, equivalent_processor_rev_id);
+	} else {
+		printk_debug("microcode: rev id not found. Skipping microcode patch!\n");
+	}
+
+}
Index: LinuxBIOSv2/src/cpu/amd/quadcore/Config.lb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/quadcore/Config.lb	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,20 @@
+#
+# This file is part of the LinuxBIOS project.
+#
+# Copyright (C) 2007 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
+#
+
+object amd_sibling.o
Index: LinuxBIOSv2/src/cpu/amd/quadcore/amd_sibling.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/quadcore/amd_sibling.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <console/console.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/lapic.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <pc80/mc146818rtc.h>
+#include <smp/spinlock.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/amd/model_10xxx_msr.h>
+#include <cpu/amd/model_10xxx_rev.h>
+#include <cpu/amd/amdfam10_sysconf.h>
+
+extern device_t get_node_pci(u32 nodeid, u32 fn);
+
+#if 0
+static int first_time = 1;
+#endif
+
+#include "quadcore_id.c"
+
+static u32 get_max_siblings(u32 nodes)
+{
+	device_t dev;
+	u32 nodeid;
+	u32 siblings=0;
+
+	//get max siblings from all the nodes
+	for(nodeid=0; nodeid<nodes; nodeid++){
+		int j;
+		dev = get_node_pci(nodeid, 3);
+		j = (pci_read_config32(dev, 0xe8) >> 12) & 3;
+		if(siblings < j) {
+			siblings = j;
+		}
+	}
+
+	return siblings;
+}
+
+
+static void enable_apic_ext_id(u32 nodes)
+{
+	device_t dev;
+	u32 nodeid;
+
+	//enable APIC_EXIT_ID all the nodes
+	for(nodeid=0; nodeid<nodes; nodeid++){
+		u32 val;
+		dev = get_node_pci(nodeid, 0);
+		val = pci_read_config32(dev, 0x68);
+		val |= (1<<17)|(1<<18);
+		pci_write_config32(dev, 0x68, val);
+	}
+}
+
+
+u32 get_apicid_base(u32 ioapic_num)
+{
+	u32 apicid_base;
+	u32 siblings;
+	u32 nb_cfg_54;
+
+	u32 disable_siblings = !CONFIG_LOGICAL_CPUS;
+
+	get_option(&disable_siblings, "quad_core");
+
+	siblings = get_max_siblings(sysconf.nodes);
+
+	if(sysconf.bsp_apicid > 0) { // io apic could start from 0
+		return 0;
+	} else if (sysconf.enabled_apic_ext_id)	{ // enabled ext id but bsp = 0
+		return 1;
+	}
+
+	nb_cfg_54 = read_nb_cfg_54();
+
+
+	//contruct apicid_base
+
+	if((!disable_siblings) && (siblings>0) ) {
+		/* for 8 way dual core, we will used up apicid 16:16, actualy
+		   16 is not allowed by current kernel and the kernel will try
+		   to get one that is small than 16 to make io apic work. I don't
+		   know when the kernel can support 256 apic id.
+		   (APIC_EXT_ID is enabled) */
+
+		//4:10 for two way  8:12 for four way 16:16 for eight way
+		//Use CONFIG_MAX_PHYSICAL_CPUS instead of nodes for better consistency?
+		apicid_base = nb_cfg_54 ? (siblings+1) * sysconf.nodes :  8 * siblings + sysconf.nodes;
+
+	} else {
+		apicid_base = sysconf.nodes;
+	}
+
+	if((apicid_base+ioapic_num-1)>0xf) {
+		// We need to enable APIC EXT ID
+		printk_spew("if the IO APIC device doesn't support 256 apic id, \r\n you need to set ENABLE_APIC_EXT_ID in MB Option.lb so you can spare 16 id for ioapic\r\n");
+		enable_apic_ext_id(sysconf.nodes);
+	}
+
+	return apicid_base;
+}
Index: LinuxBIOSv2/src/cpu/amd/quadcore/quadcore.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/quadcore/quadcore.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#ifndef SET_NB_CFG_54
+	#define SET_NB_CFG_54 1
+#endif
+
+#include "cpu/amd/quadcore/quadcore_id.c"
+
+static inline u32 get_core_num_in_bsp(u32 nodeid)
+{
+	u32 dword;
+	dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
+	dword >>= 12;
+	dword &= 3;
+	return dword;
+}
+
+#if SET_NB_CFG_54 == 1
+static inline u8 set_apicid_cpuid_lo(void)
+{
+	// set the NB_CFG[54]=1; why the OS will be happy with that ???
+	msr_t msr;
+	msr = rdmsr(NB_CFG_MSR);
+	msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
+	wrmsr(NB_CFG_MSR, msr);
+
+	return 1;
+}
+#else
+
+static inline void set_apicid_cpuid_lo(void) { }
+
+#endif
+
+
+static inline void real_start_other_core(u32 nodeid, u32 cores)
+{
+	u32 dword;
+
+	printk_debug("Start other core - nodeid: %02x  cores: %02x\n", nodeid, cores);
+
+	/* set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4
+	   accesses and error logging to core0 */
+	dword = pci_read_config32(NODE_PCI(nodeid, 3), 0x44);
+	dword |= 1 << 27;	// NbMcaToMstCpuEn bit
+	pci_write_config32(NODE_PCI(nodeid, 3), 0x44, dword);
+	// set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
+	dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
+	dword |= 1 << 5;
+	pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);
+
+	if(cores > 1) {
+		dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
+		dword |= (1 << 0);	// core2
+		if(cores > 2) {		// core3
+			dword |= (1 << 1);
+		}
+		pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
+	}
+}
+
+//it is running on core0 of node0
+static inline void start_other_cores(void)
+{
+	u32 nodes;
+	u32 nodeid;
+
+	// disable quad_core
+	if (read_option(CMOS_VSTART_quad_core, CMOS_VLEN_quad_core, 0) != 0)  {
+		printk_debug("Skip additional core init\n");
+		return;
+	}
+
+	nodes = get_nodes();
+
+	for (nodeid = 0; nodeid < nodes; nodeid++) {
+		u32 cores = get_core_num_in_bsp(nodeid);
+		printk_debug("init node: %02x  cores: %02x \n", nodeid, cores);
+		if (cores > 0) {
+			real_start_other_core(nodeid, cores);
+		}
+	}
+
+}
Index: LinuxBIOSv2/src/cpu/amd/quadcore/quadcore_id.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/quadcore/quadcore_id.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <arch/cpu.h>
+#include <cpu/amd/quadcore.h>
+#ifdef __ROMCC__
+#include <cpu/amd/model_10xxx_msr.h>
+#endif
+
+//called by bus_cpu_scan too
+u32 read_nb_cfg_54(void)
+{
+	msr_t msr;
+	msr = rdmsr(NB_CFG_MSR);
+	return ( ( msr.hi >> (54-32)) & 1);
+}
+
+static inline u32 get_initial_apicid(void)
+{
+	return ((cpuid_ebx(1) >> 24) & 0xff);
+}
+
+//called by amd_siblings too
+#define CORE_ID_BIT 2
+#define NODE_ID_BIT 6
+struct node_core_id get_node_core_id(u32 nb_cfg_54)
+{
+	struct node_core_id id;
+	u32 core_id_bits;
+
+	u32 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
+	if(ApicIdCoreIdSize) {
+		core_id_bits = ApicIdCoreIdSize;
+	} else {
+		core_id_bits = CORE_ID_BIT; //quad core
+	}
+
+	// get the apicid via cpuid(1) ebx[31:24]
+	if( nb_cfg_54) {
+		// when NB_CFG[54] is set, nodeid = ebx[31:26], coreid = ebx[25:24]
+		id.coreid = (cpuid_ebx(1) >> 24) & 0xff;
+		id.nodeid = (id.coreid>>core_id_bits);
+		id.coreid &= ((1<<core_id_bits)-1);
+	} else {
+		// when NB_CFG[54] is clear, nodeid = ebx[29:24], coreid = ebx[31:30]
+		id.nodeid = (cpuid_ebx(1) >> 24) & 0xff;
+		id.coreid = (id.nodeid>>NODE_ID_BIT);
+		id.nodeid &= ((1<<NODE_ID_BIT)-1);
+	}
+	return id;
+}
+
+static inline u32 get_core_num(void)
+{
+	return (cpuid_ecx(0x80000008) & 0xff);
+}
+
+static inline struct node_core_id get_node_core_id_x(void) {
+
+	return get_node_core_id( read_nb_cfg_54() );
+}
+
Index: LinuxBIOSv2/src/config/Options.lb
===================================================================
--- LinuxBIOSv2.orig/src/config/Options.lb	2007-12-12 11:03:38.000000000 -0700
+++ LinuxBIOSv2/src/config/Options.lb	2007-12-12 14:16:22.000000000 -0700
@@ -291,6 +291,11 @@
 	export always
 	comment "Use data cache as temporary RAM if possible"
 end
+define CAR_FAM10
+	default 0
+	export always
+	comment "AMD family 10 CAR need set more"
+end
 define DCACHE_RAM_BASE
 	default 0xc0000
 	format "0x%x"
@@ -937,6 +942,12 @@
 	comment "enable mmconfig for pci conf"
 end
 
+define MMCONF_SUPPORT_DEFAULT
+	default 0
+	export always
+	comment "enable mmconfig for pci conf"
+end
+
 define HW_MEM_HOLE_SIZEK
         default 0
         export always
@@ -949,6 +960,12 @@
         comment "Opteron E0 later memory hole size auto increase to avoid hole startk equal to basek"
 end
 
+define CONFIG_VAR_MTRR_HOLE
+	default 1
+	export always
+	comment "using hole in MTRR instead of increasing method"
+end
+
 define K8_HT_FREQ_1G_SUPPORT
 	default 0 
 	export always
@@ -973,6 +990,24 @@
 	comment "Opteron cpu device num base"
 end
 
+define HT3_SUPPORT
+	default 0
+	export always
+	comment "Hypertransport 3 support, include ac HT and unganged sublink feature"
+end
+
+define EXT_RT_TBL_SUPPORT
+	default 0
+	export always
+	comment "support AMD family 10 extended routing table via F0x158, normally is enabled when node nums is greater than 8"
+end
+
+define EXT_CONF_SUPPORT
+	default 0
+	export always
+	comment "support AMD family 10 extended config space for ram, bus, io, mmio via F1x110, normally is enabled when HT3 is enabled and non ht chain nums is greater than 4"
+end
+
 define DIMM_SUPPORT
         default 0x0108
 	format "0x%x"
@@ -989,7 +1024,7 @@
 define CPU_ADDR_BITS
 	default 36
 	export always
-	comment "CPU hardware address lines num, for AMD K8 could be 40, and GH could be 48"
+	comment "CPU hardware address lines num, for AMD K8 could be 40, and AMD family 10 could be 48"
 end
 
 define CONFIG_PCI_ROM_RUN
@@ -1004,10 +1039,10 @@
         comment "allow PCI device get 4G above Region as pref mem"
 end
 
-define CONFIG_AGESA
+define CONFIG_AMDMCT
 	default 0
 	export always
-	comment "use AMD AGESA to init RAM instead of native code"
+	comment "use AMD MCT to init RAM instead of native code"
 end
 
 define CONFIG_VIDEO_MB
Index: LinuxBIOSv2/src/cpu/amd/socket_F_1207/Config.lb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/socket_F_1207/Config.lb	2007-12-12 14:14:12.000000000 -0700
@@ -0,0 +1,57 @@
+#
+# This file is part of the LinuxBIOS project.
+#
+# Copyright (C) 2007 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
+#
+
+uses CONFIG_CHIP_NAME
+uses PCI_IO_CFG_EXT
+uses MMCONF_SUPPORT
+uses HT3_SUPPORT
+uses EXT_RT_TBL_SUPPORT
+uses EXT_CONF_SUPPORT
+uses DIMM_SUPPORT
+uses CPU_SOCKET_TYPE
+uses CBB
+uses CDB
+uses PCI_BUS_SEGN_BITS
+uses CAR_FAM10
+
+if CONFIG_CHIP_NAME
+	config chip.h
+end
+
+default PCI_IO_CFG_EXT=1
+
+default HT3_SUPPORT=1
+default EXT_RT_TBL_SUPPORT=0
+default EXT_CONF_SUPPORT=0
+default DIMM_SUPPORT=0x0104  #DDR2 and REG
+default CPU_SOCKET_TYPE=0x10
+
+default CAR_FAM10=1
+
+if EXT_RT_TBL_SUPPORT
+	default CBB=0xff
+	default CDB=0
+end
+
+#default MMCONF_SUPPORT=1
+#default MMCONF_SUPPORT_DEFAULT=1
+
+object socket_F_1207.o
+
+dir /cpu/amd/model_10xxx
Index: LinuxBIOSv2/src/cpu/amd/socket_F_1207/chip.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/socket_F_1207/chip.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,23 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+extern struct chip_operations cpu_amd_socket_F_1207_ops;
+
+struct cpu_amd_socket_F_1207_config {
+};
Index: LinuxBIOSv2/src/cpu/amd/socket_F_1207/socket_F_1207.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/socket_F_1207/socket_F_1207.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <device/device.h>
+#include "chip.h"
+
+struct chip_operations cpu_amd_socket_F_1207_ops = {
+	CHIP_NAME("socket F_1207")
+};
Index: LinuxBIOSv2/src/include/cpu/amd/model_10xxx_msr.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/include/cpu/amd/model_10xxx_msr.h	2007-12-12 12:14:20.000000000 -0700
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef CPU_AMD_MODEL_10XXX_MSR_H
+#define CPU_AMD_MODEL_10XXX_MSR_H
+
+#define HWCR_MSR			0xC0010015
+#define NB_CFG_MSR			0xC001001f
+#define LS_CFG_MSR			0xC0011020
+#define IC_CFG_MSR			0xC0011021
+#define DC_CFG_MSR			0xC0011022
+#define BU_CFG_MSR			0xC0011023
+
+#define CPU_ID_FEATURES_MSR		0xC0011004
+#define CPU_ID_HYPER_EXT_FEATURES	0xC001100d
+#define LOGICAL_CPUS_NUM_MSR		0xC001100d
+#define CPU_ID_EXT_FEATURES_MSR	0xC0011005
+
+#endif /* CPU_AMD_MODEL_10XXX_MSR_H */
Index: LinuxBIOSv2/src/include/cpu/amd/model_10xxx_rev.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/include/cpu/amd/model_10xxx_rev.h	2007-12-12 12:11:59.000000000 -0700
@@ -0,0 +1,22 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <arch/cpu.h>
+
+/* place holder for Family 10 revision code */
Index: LinuxBIOSv2/src/include/cpu/amd/quadcore.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/include/cpu/amd/quadcore.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef CPU_AMD_QUADCORE_H
+#define CPU_AMD_QUADCORE_H
+
+#if defined(__GNUC__)
+unsigned int read_nb_cfg_54(void);
+#endif
+
+struct node_core_id {
+	u32 nodeid;
+	u32 coreid;
+};
+
+#if defined(__GNUC__)
+// it can be used to get unitid and coreid it running only
+struct node_core_id get_node_core_id(u32 nb_cfg_54);
+#endif
+
+#ifndef __ROMCC__
+struct device;
+u32 get_apicid_base(u32 ioapic_num);
+void amd_sibling_init(struct device *cpu);
+#endif
+
+#endif /* CPU_AMD_QUADCORE_H */
Index: LinuxBIOSv2/src/cpu/amd/microcode/microcode.c
===================================================================
--- LinuxBIOSv2.orig/src/cpu/amd/microcode/microcode.c	2007-12-12 11:03:38.000000000 -0700
+++ LinuxBIOSv2/src/cpu/amd/microcode/microcode.c	2007-12-12 11:19:15.000000000 -0700
@@ -1,43 +1,24 @@
-/*============================================================================
-Copyright 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
-This software and any related documentation (the "Materials") are the
-confidential proprietary information of AMD. Unless otherwise provided in a
-software agreement specifically licensing the Materials, the Materials are
-provided in confidence and may not be distributed, modified, or reproduced in
-whole or in part by any means.
-LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY
-EXPRESS OR IMPLIED WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO
-WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY
-PARTICULAR PURPOSE, OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR
-USAGE OF TRADE. IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY
-DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS,
-BUSINESS INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR
-INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION
-OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE
-LIMITATION MAY NOT APPLY TO YOU.
-AMD does not assume any responsibility for any errors which may appear in the
-Materials nor any responsibility to support or update the Materials. AMD
-retains the right to modify the Materials at any time, without notice, and is
-not obligated to provide such modified Materials to you.
-NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any
-further information, software, technical information, know-how, or show-how
-available to you.
-U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with "RESTRICTED
-RIGHTS." Use, duplication, or disclosure by the Government is subject to the
-restrictions as set forth in FAR 52.227-14 and DFAR 252.227-7013, et seq., or
-its successor. Use of the Materials by the Government constitutes
-acknowledgement of AMD's proprietary rights in them.
-============================================================================*/
-//@DOC
-// microcode.c
 /*
-$1.0$
-*/
-// Description: microcode patch support for k8
-// by yhlu
-//
-//============================================================================
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef __ROMCC__
+
 #include <stdint.h>
 #include <console/console.h>
 #include <cpu/cpu.h>
@@ -45,69 +26,74 @@
 #include <cpu/amd/microcode.h>
 #include <cpu/x86/cache.h>
 
+#endif
+
 struct microcode {
-	uint32_t date_code;
-	uint32_t patch_id;
+	u32 date_code;
+	u32 patch_id;
+
+	u16 m_patch_data_id;
+	u8 m_patch_data_len;
+	u8 init_flag;
+
+	u32 m_patch_data_cksum;
+
+	u32 nb_dev_id;
+	u32 ht_io_hub_dev_id;
+
+	u16 processor_rev_id;
+	u8 ht_io_hub_rev_id;
+	u8 nb_rev_id;
+
+	u8 bios_api_rev;
+	u8 resv1[3];
 
-	uint16_t m_patch_data_id;
-	uint8_t m_patch_data_len;
-	uint8_t init_flag;
-	
-	uint32_t m_patch_data_cksum;
-	
-	uint32_t nb_dev_id;
-	uint32_t ht_io_hub_dev_id;
-
-	uint16_t processor_rev_id;
-	uint8_t ht_io_hub_rev_id;
-	uint8_t nb_rev_id;
-
-	uint8_t bios_api_rev;
-	uint8_t resv1[3];
-
-	uint32_t match_reg[8];
-
-	uint8_t m_patch_data[896];
-	uint8_t resv2[896];
-	
-	uint8_t x86_code_present;
-	uint8_t x86_code_entry[191];
+	u32 match_reg[8];
+
+	u8 m_patch_data[896];
+	u8 resv2[896];
+
+	u8 x86_code_present;
+	u8 x86_code_entry[191];
 };
 
-static int need_apply_patch(struct microcode *m, unsigned equivalent_processor_rev_id)
+static int need_apply_patch(struct microcode *m, u32 equivalent_processor_rev_id)
 {
 
-        if (m->processor_rev_id != equivalent_processor_rev_id) return 0;
+	if (m->processor_rev_id != equivalent_processor_rev_id) {
+		printk_debug("microcode: rev id does not match this patch.\n");
+		printk_debug("microcode: Not updated! Fix microcode_updates[] \n");
+		return 0;
+	}
+	if (m->nb_dev_id) {
+		  //look at the device id, if not found return;
+		  //if(m->nb_rev_id != installed_nb_rev_id) return 0;
+	}
+
+	if (m->ht_io_hub_dev_id) {
+		  //look at the device id, if not found return;
+		  //if(m->ht_io_hub_rev_id != installed_ht_io_bub_rev_id) return 0;
+	}
 
-        if (m->nb_dev_id) {
-                 //look at the device id, if not found return;
-                 //if(m->nb_rev_id != installed_nb_rev_id) return 0;
-        }
-
-        if (m->ht_io_hub_dev_id) {
-                 //look at the device id, if not found return;
-                 //if(m->ht_io_hub_rev_id != installed_ht_io_bub_rev_id) return 0;
-        }
-
-        if (m->x86_code_present) {
-                 //if(!x86_code_execute()) return 0;
-        }
+	if (m->x86_code_present) {
+		  //if(!x86_code_execute()) return 0;
+	}
 
 	return 1;
 }
 
 
-void amd_update_microcode(void *microcode_updates, unsigned equivalent_processor_rev_id)
+void amd_update_microcode(void *microcode_updates, u32 equivalent_processor_rev_id)
 {
-	unsigned int patch_id, new_patch_id;
+	u32 patch_id, new_patch_id;
 	struct microcode *m;
 	char *c;
 	msr_t msr;
-	
+
 	msr = rdmsr(0x8b);
 	patch_id = msr.lo;
 
-	printk_debug("microcode: equivalent processor rev id  = 0x%04x, patch id = 0x%08x\n", equivalent_processor_rev_id, patch_id);
+	printk_debug("microcode: equivalent rev id  = 0x%04x, current patch id = 0x%08x\n", equivalent_processor_rev_id, patch_id);
 
 	m = microcode_updates;
 
@@ -117,17 +103,17 @@
 			//apply patch
 
 			msr.hi = 0;
-			msr.lo = (uint32_t)m;
+			msr.lo = (u32)m;
 
 			wrmsr(0xc0010020, msr);
 
-			printk_debug("microcode: patch id that want to apply= 0x%08x\n", m->patch_id);
+			printk_debug("microcode: patch id to apply = 0x%08x\n", m->patch_id);
 
-                        //read the patch_id again
-                        msr = rdmsr(0x8b);
-                        new_patch_id = msr.lo;
+			//read the patch_id again
+			msr = rdmsr(0x8b);
+			new_patch_id = msr.lo;
 
-			printk_debug("microcode: updated to patch id = 0x%08x %s\r\n", new_patch_id , (new_patch_id == m->patch_id)?" success":" fail" );
+			printk_debug("microcode: updated to patch id = 0x%08x %s\n", new_patch_id , (new_patch_id == m->patch_id)?" success\n":" fail\n" );
 			break;
 		}
 		c += 2048;
Index: LinuxBIOSv2/src/include/cpu/amd/amdfam10_sysconf.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/include/cpu/amd/amdfam10_sysconf.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef AMDFAM10_SYSCONF_H
+#define AMDFAM10_SYSCONF_H
+
+#include "../../../northbridge/amd/amdfam10/amdfam10_nums.h"
+
+#include <cpu/x86/msr.h>
+
+struct p_state_t {
+	unsigned corefreq;
+	unsigned power;
+	unsigned transition_lat;
+	unsigned busmaster_lat;
+	unsigned control;
+	unsigned status;
+};
+
+struct amdfam10_sysconf_t {
+	//ht
+	unsigned hc_possible_num;
+	unsigned pci1234[HC_POSSIBLE_NUM];
+	unsigned hcdn[HC_POSSIBLE_NUM];
+	unsigned hcid[HC_POSSIBLE_NUM]; //record ht chain type
+	unsigned sbdn;
+	unsigned sblk;
+
+	unsigned nodes;
+	unsigned ht_c_num; // we only can have 32 ht chain at most
+	unsigned ht_c_conf_bus[HC_NUMS]; // 4-->32: 4:segn, 8:bus_max, 8:bus_min, 4:linkn, 6: nodeid, 2: enable
+	unsigned io_addr_num;
+	unsigned conf_io_addr[HC_NUMS];
+	unsigned conf_io_addrx[HC_NUMS];
+	unsigned mmio_addr_num;
+	unsigned conf_mmio_addr[HC_NUMS*2]; // mem and pref mem
+	unsigned conf_mmio_addrx[HC_NUMS*2];
+	unsigned segbit;
+	unsigned hcdn_reg[HC_NUMS]; // it will be used by get_pci1234
+
+	msr_t msr_pstate[NODE_NUMS * 5]; // quad cores all cores in one node should be the same, and p0,..p5
+	unsigned needs_update_pstate_msrs;
+	struct p_state_t p_state[NODE_NUMS * 5];
+	unsigned p_state_num;
+
+	unsigned bsp_apicid;
+	int enabled_apic_ext_id;
+	unsigned lift_bsp_apicid;
+	int apicid_offset;
+
+	void *mb; // pointer for mb releated struct
+
+};
+
+extern struct amdfam10_sysconf_t sysconf;
+
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdht/AsPsDefs.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/AsPsDefs.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#ifndef ASPSDEFS_H
+#define ASPSDEFS_H
+
+/* AMD Platform Types */
+#define AMD_PTYPE_DSK 1
+#define AMD_PTYPE_MOB 2
+#define AMD_PTYPE_SVR 4
+#define AMD_PTYPE_DC 8
+#define AMD_PTYPE_MC 0x10
+#define AMD_PTYPE_UMA 0x20
+
+#define APIC_BAR 0x1b			/* APIC_BAR register */
+#define APIC_BAR_BP 0x100		/* APIC_BAR BSP bit */
+
+#define PS_LIM_REG 0xC0010061		/* P-state Current Limit Register */
+#define PS_CUR_LIM_SHFT 4		/* P-state Current Limit shift position */
+
+#define PS_CTL_REG 0xC0010062		/* P-state Control Register */
+#define PS_CMD_MASK_OFF 0xfffffff8	/* P-state Control Register CMD Mask OFF */
+
+#define PS_STS_REG 0xC0010063		/* P-state Status Register */
+#define PS_STS_MASK 0x7		/* P-state Status Mask */
+
+#define PS_REG_BASE 0xC0010064		/* P-state Register base */
+#define PS_MAX_REG 0xC0010068		/* Maximum P-State Register */
+#define PS_MIN_REG 0xC0010064		/* Mimimum P-State Register */
+
+/* P-state register offset */
+#define PS_REG0 0			/* offset for P0 */
+#define PS_REG1 1			/* offset for P1 */
+#define PS_REG2 2			/* offset for P2 */
+#define PS_REG3 3			/* offset for P3 */
+#define PS_REG4 4			/* offset for P4 */
+
+#define PS_PSDIS_MASK	0x7fffffff	/* disable P-state register */
+#define PS_EN_MASK  0x80000000		/* P-state register enable mask */
+#define PS_NB_DID_MASK 0x400000	/* P-state Reg[NbDid] Mask */
+#define PS_NB_VID_M_OFF 0x01ffffff	/* P-state Reg[NbVid] Mask OFF */
+#define PS_CPU_VID_M_ON 0x0fe00	/* P-state Reg[CpuVid] Mask On */
+#define PS_NB_VID_M_ON 0x0fe000000	/* P-state Reg[NbVid] Mask On */
+#define PS_CPU_VID_SHFT 9		/* P-state bit shift for CpuVid */
+#define PS_NB_VID_SHFT 25		/* P-state bit shift for NbVid */
+#define PS_BOTH_VID_OFF 0x01ff01ff	/* Mask NbVid & CpuVid */
+#define PS_CPU_NB_VID_SHFT 16		/* P-state bit shift from CpuVid to NbVid */
+#define PS_NB_VID_SHFT 25		/* P-state NBVID shift */
+#define PS_DIS 0x7fffffff		/* disable P-state reg */
+#define PS_EN 0x80000000		/* enable P-state reg */
+#define PS_CURDIV_SHFT 8		/* P-state Current Divisor shift position */
+#define PS_CPUDID_SHIFT 6		/* P-state CPU DID shift position */
+
+/* for unfused parts */
+#define PS_NB_VID_110V 0x48000000
+#define PS_NB_VID_1175V 0x3c000000
+/* NB VID 1.100V =0x12[PVI]=0x24[SVI] = 0100100b 7-bit code */
+
+#define PS_NB_DID0 0			/* NB DID 0 */
+#define PS_NB_DID1 0x400000		/* NB DID 1 */
+#define PS_CPU_VID_110V 0x4800		/* CPU VID 1.100V */
+#define PS_CPU_VID_1175V 0x3c00	/* CPU VID 1.175V */
+#define PS_CPU_DID 0x40		/* CPU DID 1 = divisor of 2 */
+#define PS_CPU_DID0 0			/* CPU DID 0 = divisor of 1 */
+#define PS_CPU_FID_16G 0x00		/* CPU FID of 00 = 1.6GHz */
+#define PS_CPU_FID_16G1 0x10		/* CPU FId of 16 COF = 16+16/2 = 16 */
+#define PS_CPU_FID_18G 20		/* CPU FId of 20 COF = 20+16/2 = 18 */
+#define PS_CPU_FID_19G 22		/* CPU FId of 20 COF = 22+16/2 = 19 */
+#define PS_CPU_FID_20G 24		/* CPU FId of 20 COF = 24+16/2 = 20 */
+#define PS_CPU_FID_22G 28		/* CPU FId of 2C COF = 28+16/2 = 22 */
+#define PS_CPU_FID_30G 44		/* CPU FId of 2C COF = 44+16/2 = 30 */
+
+
+
+#define PCI_DEV_BASE 24		/* System PCI device ID base */
+#define LOCAL_APIC_ID_SHIFT 24		/* Local APCI ID shift bit # */
+#define APIC_CID_SIZE_SHIFT 12		/* ApicCoreIdSize shift bit # */
+#define FN_0 0				/* Function 0 */
+#define FN_1 1				/* Function 1 */
+#define FN_2 2				/* Function 2 */
+#define FN_3 3				/* Function 3 */
+#define FN_4 4				/* Function 4 */
+#define FN_5 5				/* Function 5 */
+#define FN_80000000 0x80000000		/* Function 8000_0000 */
+#define FN_80000001 0x80000001		/* Function 8000_0001 */
+#define FN_80000008 0x80000008		/* Function 8000_0008 */
+
+#define LNK_INIT_REG 0x6C		/* F0x6C link initialization control register */
+#define WARM_RESET_BIT 0x10		/* bit 4 =1 : warm reset */
+
+#define HTC_REG 0x64			/* hardware thermal control reg */
+#define HTC_PS_LMT_MASK 0x8fffffff	/* HtcPstateLimit mask off */
+#define PS_LIMIT_POS 28		/* PstateLimit position for HTC & STC */
+
+#define STC_REG 0x68			/* software thermal control reg */
+#define STC_PS_LMT_MASK 0x8fffffff	/* StcPstateLimit mask off */
+
+#define CPTC0 0x0d4			/* Clock Power/Timing Control0 Register*/
+#define CPTC0_MASK 0x000c0fff		/* Reset mask for this register */
+#define CPTC0_NBFID_MASK 0xffffffe0	/* NbFid mask off for this register */
+#define CPTC0_NBFID_MON 0x1f		/* NbFid mask on for this register */
+#define NB_FID_EN 0x20			/* NbFidEn bit ON */
+#define NB_CLKDID_ALL 0x80000000	/* NbClkDidApplyAll bit ON */
+#define NB_CLKDID     0x40000000	/* NbClkDid value set by BIOS */
+#define PW_STP_UP50   0x08000000	/* PowerStepUp 50nS(1000b) */
+#define PW_STP_DN50   0x00800000	/* PowerStepDown 50nS (1000b)*/
+#define PW_STP_UP100  0x03000000	/* PowerStepUp 100nS(0011b) */
+#define PW_STP_DN100  0x00300000	/* PowerStepDown 100nS (0011b)*/
+#define PW_STP_UP200  0x02000000	/* PowerStepUp 200nS(0010b) */
+#define PW_STP_DN200  0x00200000	/* PowerStepDown 200nS (0010b)*/
+#define PW_STP_UP400  0x00000000	/* PowerStepUp 400nS(0000b) */
+#define PW_STP_DN400  0x00000000	/* PowerStepDown 400nS (0000b)*/
+
+
+#define LNK_PLL_LOCK  0x00010000	/* LnkPllLock value set (01b) by BIOS */
+
+
+
+#define PSTATE_CTL 0xC0010070		/* P-state Control Register */
+#define NB_VID_POS 25			/* NbVid bit shift for position */
+#define NB_VID_MASK_OFF 0x01ffffff	/* NbVid bits mask off */
+#define NB_VID_MASK_ON 0xfe000000	/* NbVid bits mask on */
+#define CPU_VID_POS 0x9		/* CpuVid bit shift for position */
+#define CPU_VID_MASK_OFF 0xffff01ff	/* CpuVid bits mask off */
+#define CPU_VID_MASK_ON 0x0000fe00	/* CpuVid bits mask on */
+#define CPU_FID_DID_M_ON 0x000001ff	/* CpuFid & CpuDid mask on */
+#define CPU_FID_DID_M_OFF 0xfffffe00	/* CpuFid & CpuDid mask off */
+#define NB_DID_VID_M_ON 0xfe400000	/* NbDid & NbVid mask on */
+#define NB_DID_M_ON 0x00400000		/* NbDid mask on */
+#define NB_DID_M_OFF 0xffbfffff	/* NbDid mask off */
+#define NB_DID_POS 22			/* NbDid bit shift for position */
+#define PS_M_OFF 0xfff8ffff		/* Cur Pstate mask off */
+#define PS_1 0x00010000		/* P-state 1 */
+#define PS_2 0x00020000		/* P-state 2 */
+#define PS_CPU_DID_1 0x40		/* Cpu Did 1 */
+
+
+
+
+#define PSTATE_STS 0xC0010071		/* P-state Status Register */
+#define STARTUP_PS_MASK 0x7		/* StartupPstate Mask */
+
+/* define for NB VID & CPU VID transition functions */
+#define IS_NB 1
+#define IS_CPU 0
+
+/* F3xD8 Clock Power/Timing Control 1 Register */
+#define CPTC1 0xd8			/* Clock Power/Timing Control1 Register*/
+#define VSRAMP_SLAM_MASK 0xffffff88	/* MaskOff [VSRampTime]&[VSSlamTime] */
+#define VSRAMP_SLAM_VALUE 0x16		/* [VSRampTime]=001b&[VSSlamTime]=110b */
+#define VS_RAMP_T 4			/* VSRampTime bit position */
+#define PWR_PLN_SHIFT 28		/* PwrPlanes bit shift */
+#define PWR_PLN_ON 0x10000000		/* PwrPlanes bit ON */
+#define PWR_PLN_OFF 0x0efffffff	/* PwrPlanes bit OFF */
+
+
+
+/* Northbridge Capability Register */
+#define NB_CAP 0xe8			/* Northbridge Cap Reg */
+#define CMP_CAP_SHFT 12		/* CMP CAP - number of enabled cores */
+
+/* F3xDC Clock Power/Timing Control 2 Register */
+#define CPTC2 0xdc			/* Clock Power/Timing Control2 Register*/
+#define PS_MAX_VAL_POS 8		/* PstateMaxValue bit shift */
+#define PS_MAX_VAL_MASK 0xfffff8ff	/* PstateMaxValue Mask off */
+
+#define PRCT_INFO 0x1fc		/* Product Info Register */
+#define UNI_NB_FID_BIT 2		/* UniNbFid bit position */
+#define UNI_NB_VID_BIT 7		/* UniNbVid bit position */
+#define SPLT_NB_FID_OFFSET 14		/* SpltNbFidOffset value bit position */
+#define SPLT_NB_VID_OFFSET 17		/* SpltNbVidOffset value bit position */
+#define NB_CV_UPDATE 0x01		/* F3x1FC[NbCofVidUpdated] bit mask */
+#define NB_VID_UPDATE_ALL 0x02		/* F3x1FC[NbVidUpdatedAll] bit mask */
+#define C_FID_DID_M_OFF  0xfffffe00	/* mask off Core FID & DID */
+
+#define PW_CTL_MISC 0x0a0		/* Power Control Miscellaneous Register */
+#define COF_VID_PROG_BIT 0x80000000	/* CofVidProg bit. 0= unfused part */
+#define DUAL_VDD_BIT 0x40000000	/* DualVdd bit. */
+#define NB_COFVID_UPDATE_BIT 0x01	/* NbCOFVIDUpdated bit */
+#define PVI_MODE 0x100			/* PviMode bit mask */
+#define VID_SLAM_OFF 0x0dfffffff	/* set VidSlamMode OFF */
+#define VID_SLAM_ON 0x020000000	/* set VidSlamMode ON */
+#define PLLLOCK_OFF 0x0ffffc7ff	/* PllLockTime Mask OFF */
+#define PLLLOCK_DFT 0x00001800		/* PllLockTime default value = 011b */
+#define PLLLOCK_DFT_L 0x00002800	/* PllLockTime long value = 101b */
+
+/* P-state Specification register base in PCI sapce */
+#define PS_SPEC_REG 0x1e0		/* PS Spec register base address */
+#define PCI_REG_LEN 4			/* PCI register length */
+#define NB_DID_MASK 0x10000		/* NbDid bit mask */
+#define NB_DID_2 2			/* NbDid = 2 */
+#define NB_DID_1 1			/* NbDid = 1 */
+#define SPEC_PWRDIV_M_ON 0x06000000	/* PwrDiv mask on */
+#define SPEC_PWRVAL_M_ON 0x01e00000	/* PwrValue mask on */
+#define SPEC_PWRDIV_SHFT 25		/* PwrDiv shift */
+#define SPEC_PWRVAL_SHFT 17		/* PwrValue shift */
+
+/* F4x1F4 Northbridge P-state spec register */
+#define NB_PS_SPEC_REG 0x1f4		/* Nb PS spec reg */
+
+#define NM_PS_REG 5			/* number of P-state MSR registers */
+
+/* sFidVidInit.outFlags defines */
+#define PWR_CK_OK 0			/* System board check OK */
+#define PWR_CK_NO_PS 1			/* All P-state registers are over
+					   the limit */
+
+/* bit mask */
+#define BIT_MASK_1 0x1
+#define BIT_MASK_2 0x3
+#define BIT_MASK_3 0x7
+#define BIT_MASK_4 0x0f
+#define BIT_MASK_5 0x1f
+#define BIT_MASK_6 0x3f
+#define BIT_MASK_7 0x7f
+#define BIT_MASK_8 0x0ff
+
+/* VID Code */
+#define VID_1_100V 0x12		/* 1.100V */
+#define VID_1_175V 0x1E		/* 1.175V */
+
+
+/* Nb Fid Code */
+#define NB_FID_800M 0x00		/* 800MHz */
+
+/* Nb DID Code */
+#define NB_DID_0 0
+#define NB_DID_1 1
+
+/* GH Logical ID */
+
+#define GH_REV_A2 0x4			/* GH Rev A2 logical ID, Upper half */
+
+
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdht/AsPsNb.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/AsPsNb.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ *
+ *----------------------------------------------------------------------------
+ */
+#undef FILECODE
+#define FILECODE 0xCCCC
+#include "comlib.h"
+#include "AsPsDefs.h"
+#include "AsPsNb.h"
+
+
+/*----------------------------------------------------------------------------
+ *			PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+u8 getNumOfNodeNb(void);
+u8 translateNodeIdToDeviceIdNb(u8 nodeId);
+
+
+/*----------------------------------------------------------------------------
+ * FUNCTION: getMinNbCOF
+ * INPUT: None
+ * OUTPUT: minNbCOF (in multiple of half of CLKIN, 100MHz)
+ * DESCRIPTION:
+ * This function returns the minimum possible NbCOF (in 100MHz)
+ * for the system .
+ * This function can be run on any core and is used by the HT & Memory init code
+ * in Phase 1.
+ * ----------------------------------------------------------------------------
+ */
+u8 getMinNbCOF(void)
+{
+	u8 numOfNode, i, j, deviceId, nbDid, nbFid, nextNbFid;
+	u32 dtemp;
+
+	nbDid = 0;
+	nbFid = 0;
+
+	/* get number of node in the system */
+	numOfNode = getNumOfNodeNb();
+
+	/* go through each node for the minimum NbCOF (in multiple of CLKIN/2) */
+	for(i=0; i < numOfNode; i++)
+	{
+		/* stub function for APIC ID virtualization for large MP system later */
+		deviceId = translateNodeIdToDeviceIdNb(i);
+
+		/* read all P-state spec registers for NbDid=1 */
+		for(j=0; j < 5; j++)
+		{
+			AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_4,PS_SPEC_REG+(j*PCI_REG_LEN)), &dtemp); /*F4x1E0 + j*4 */
+			/* get NbDid */
+			if(dtemp & NB_DID_MASK)
+				nbDid = 1;
+		}
+		/* if F3x1FC[NbCofVidUpdate]=0, NbFid =  default value */
+		AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PRCT_INFO), &dtemp); /*F3x1FC*/
+		if(!(dtemp & NB_CV_UPDATE)) /* F3x1FC[NbCofVidUpdated]=0, use default VID */
+		{
+			AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,CPTC0), &dtemp); /*F3xD4*/
+			nextNbFid = (u8) (dtemp & BIT_MASK_5);
+			if(nbDid)
+				nextNbFid = (u8) (nextNbFid >> 1);
+		}
+		else
+		{
+			/* check PVI/SPI */
+			AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PW_CTL_MISC), &dtemp); /*F3xA0*/
+			if(dtemp & PVI_MODE) /* PVI */
+			{
+				AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PRCT_INFO), &dtemp); /*F3x1FC*/
+				nextNbFid = (u8) (dtemp >> UNI_NB_FID_BIT);
+				nextNbFid &= BIT_MASK_5;
+				/* if(nbDid)
+					nextNbFid = nextNbFid  >> 1; */
+			}
+			else /* SVI */
+			{
+				AmdPCIRead(MAKE_SBDFO(0,0,deviceId,FN_3,PRCT_INFO), &dtemp); /*F3x1FC*/
+				nextNbFid = (u8) ((dtemp >> UNI_NB_FID_BIT) & BIT_MASK_5);
+				nextNbFid = (u8) (nextNbFid + ((dtemp >> SPLT_NB_FID_OFFSET) & BIT_MASK_3));
+				/* if(nbDid)
+					nextNbFid = nextNbFid >> 1; */
+			}
+		}
+		if( i == 0)
+			nbFid = nextNbFid;
+		else if( nbFid > nextNbFid )
+		nbFid = nextNbFid;
+	}
+
+	/* add the base and convert to 100MHz divide by 2 if DID=1 */
+	if(nbDid)
+		nbFid = (u8) (nbFid + 4);
+	else
+		nbFid = (u8) ((nbFid + 4) << 1);
+	return nbFid;
+}
+
+u8 getNumOfNodeNb(void)
+{
+	u32 dtemp;
+
+	AmdPCIRead(MAKE_SBDFO(0,0,24,0,0x60), &dtemp);
+	dtemp = (dtemp >> 4) & BIT_MASK_3;
+	dtemp++;
+	return (u8)dtemp;
+}
+
+/*----------------------------------------------------------------------------
+ * FUNCTION: translateNodeIdToDeviceId
+ * INPUT: u8 nodeId - node ID of the node
+ * OUTPUT: u8 - PCI device ID of the node
+ * DESCRIPTION:
+ * This function return the PCI device ID for PCI access using node ID.
+ * This function may need to chnage node ID to device ID in big MP systems.
+ * ----------------------------------------------------------------------------
+ */
+u8 translateNodeIdToDeviceIdNb(u8 nodeId)
+{
+	return (u8) (nodeId+PCI_DEV_BASE);
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdht/AsPsNb.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/AsPsNb.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#ifndef ASPSNB_H
+#define ASPSNB_H
+
+u8 getMinNbCOF(void);
+
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdht/comlib.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/comlib.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,290 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#undef FILECODE
+#define FILECODE 0xCCCC
+#include "comlib.h"
+
+/*
+ *---------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void CALLCONV AmdPCIReadBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
+{
+	ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0);
+
+	AmdPCIRead(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);
+}
+
+
+void CALLCONV AmdPCIWriteBits(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;
+
+	AmdPCIRead(loc, &temp);
+	temp &= ~(mask << lowbit);
+	temp |= (*pValue & mask) << lowbit;
+	AmdPCIWrite(loc, &temp);
+}
+
+
+/*
+ *  Given a SBDFO this routine will find the next PCI capabilities list entry.
+ *   If the end of the list of reached, or if a problem is detected, then
+ *   ILLEGAL_SBDFO is returned.
+ *
+ *   To start a new search from the beginning of head of the list, specify a
+ *   SBDFO with a offset of zero.
+ */
+void CALLCONV AmdPCIFindNextCap(SBDFO *pCurrent)
+{
+	SBDFO base;
+	u32 offset;
+	u32 temp;
+
+	if (*pCurrent == ILLEGAL_SBDFO)
+		return;
+
+	offset = SBDFO_OFF(*pCurrent);
+	base = *pCurrent - offset;
+	*pCurrent = ILLEGAL_SBDFO;
+
+	/* Verify that the SBDFO points to a valid PCI device SANITY CHECK */
+	AmdPCIRead(base, &temp);
+	if (temp == 0xFFFFFFFF)
+		return; /* There is no device at this address */
+
+	/* Verify that the device supports a capability list */
+	AmdPCIReadBits(base + 0x04, 20, 20, &temp);
+	if (temp == 0)
+		return; /* This PCI device does not support capability lists */
+
+	if (offset != 0)
+	{
+		/* If we are continuing on an existing list */
+		AmdPCIReadBits(base + offset, 15, 8, &temp);
+	}
+	else
+	{
+		/* We are starting on a new list */
+		AmdPCIReadBits(base + 0x34, 7, 0, &temp);
+	}
+
+	if (temp == 0)
+		return; /* We have reached the end of the capabilties list */
+
+	/* Error detection and recovery- The statement below protects against
+		PCI devices with broken PCI capabilities lists.	 Detect a pointer
+		that is not u32 aligned, points into the first 64 reserved DWORDs
+		or points back to itself.
+	*/
+	if (((temp & 3) != 0) || (temp == offset) || (temp < 0x40))
+		return;
+
+	*pCurrent = base + temp;
+	return;
+}
+
+
+void CALLCONV Amdmemcpy(void *pDst, const void *pSrc, u32 length)
+{
+	ASSERT(length <= 32768);
+	ASSERT(pDst != NULL);
+	ASSERT(pSrc != NULL);
+
+	while (length--){
+	//	*(((u8*)pDst)++) = *(((u8*)pSrc)++);
+		*((u8*)pDst) = *((u8*)pSrc);
+		pDst++;
+		pSrc++;
+	}
+}
+
+
+void CALLCONV Amdmemset(void *pBuf, u8 val, u32 length)
+{
+	ASSERT(length <= 32768);
+	ASSERT(pBuf != NULL);
+
+	while (length--){
+		//*(((u8*)pBuf)++) = val;
+		*(((u8*)pBuf)) = val;
+		pBuf++;
+	}
+}
+
+
+u8 CALLCONV AmdBitScanReverse(u32 value)
+{
+	u8 i;
+
+	for (i = 31; i != 0xFF; i--)
+	{
+		if (value & ((u32)1 << i))
+			break;
+	}
+
+	return i;
+}
+
+
+u32 CALLCONV AmdRotateRight(u32 value, u8 size, u32 count)
+{
+	u32 msb, mask;
+	ASSERT(size > 0 && size <= 32);
+
+	msb = (u32)1 << (size-1);
+	mask = ((msb-1) << 1) + 1;
+
+	value = value & mask;
+
+	while (count--)
+	{
+		if (value & 1)
+			value = (value >> 1) | msb;
+		else
+			value = value >> 1;
+	}
+
+	return value;
+}
+
+
+u32 CALLCONV AmdRotateLeft(u32 value, u8 size, u32 count)
+{
+	u32 msb, mask;
+	ASSERT(size > 0 && size <= 32);
+
+	msb = (u32)1 << (size-1);
+	mask = ((msb-1) << 1) + 1;
+
+	value = value & mask;
+
+	while (count--)
+	{
+		if (value & msb)
+			value = ((value << 1) & mask) | (u32)1;
+		else
+			value = ((value << 1) & mask);
+	}
+
+	return value;
+}
+
+
+void CALLCONV AmdPCIRead(SBDFO loc, u32 *Value)
+{
+	/* Use LinuxBIOS PCI functions */
+	*Value = pci_read_config32((loc & 0xFFFFF000), SBDFO_OFF(loc));
+}
+
+
+void CALLCONV AmdPCIWrite(SBDFO loc, u32 *Value)
+{
+	/* Use LinuxBIOS PCI functions */
+	pci_write_config32((loc & 0xFFFFF000), SBDFO_OFF(loc), *Value);
+}
+
+
+void CALLCONV AmdMSRRead(uint32 Address, uint64 *Value)
+{
+	msr_t msr;
+
+	msr = rdmsr(Address);
+	Value->lo = msr.lo;
+	Value->hi = msr.hi;
+}
+
+
+void CALLCONV AmdMSRWrite(uint32 Address, uint64 *Value)
+{
+	msr_t msr;
+
+	msr.lo = Value->lo;
+	msr.hi = Value->hi;
+	wrmsr(Address, msr);
+}
+
+
+void ErrorStop(u32 value)
+{
+	printk_debug("Error: %08x ", value);
+
+}
+
+/*;----------------------------------------------------------------------------
+; void __pascal ErrorStop(DWORD Value);
+;
+; This implementation provides a rotating display of the error code on the
+; a port 80h POST display card.  The rotation is used to make it easier to
+; view the error on both a 16-bit as well as a 32-bit display card.
+;
+; For use with SimNow the unrotated error code is also written to port 84h
+ErrorStop   PROC FAR PASCAL PUBLIC Value:DWORD
+        pushad
+        mov     eax, Value
+        mov     bx, 0DEADh
+        out     84h, eax
+
+ErrorStopTop:
+        out     80h, eax
+
+        mov     cx, 4           ; Rotate the display by one nibble
+@@:
+        bt      bx, 15
+        rcl     eax, 1
+        rcl     bx, 1
+        loop    @B
+
+
+        push    eax             ; Delay a few hundred milliseconds
+        push    ebx
+        mov     ecx, 10h        ; TSC
+        db      00Fh, 032h      ; RDMSR
+        mov     ebx, eax
+@@:
+        db      00Fh, 032h      ; RDMSR
+        sub     eax, ebx
+        cmp     eax, 500000000
+        jb      @B
+        pop     ebx
+        pop     eax
+
+        jmp     ErrorStopTop
+
+        popad
+        ret
+ErrorStop   ENDP
+*/
Index: LinuxBIOSv2/src/northbridge/amd/amdht/comlib.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/comlib.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef COMLIB_H
+#define COMLIB_H
+
+#ifndef FILECODE
+#error "FILECODE was not defined, should be #define'd to 0xFxxx"
+#endif
+
+#include "porting.h"
+
+/* include LinuxBIOS pci functions */
+#include <device/pci_def.h>
+#include <device/pci_ids.h>
+
+#ifdef AMD_DEBUG
+    #define ASSERT(x) ((x) ? 0 : ErrorStop(((uint32)FILECODE)*0x10000 + ((__LINE__)%10) + (((__LINE__/10)%10)*0x10) + (((__LINE__/100)%10)*0x100) +(((__LINE__/1000)%10)*0x1000)))
+#else
+    #define ASSERT(x)
+#endif
+
+#ifdef AMD_DEBUG_ERROR_STOP
+    /* Macro to aid debugging, causes program to halt and display the line number of the halt in decimal */
+    #define STOP_HERE ErrorStop(((uint32)FILECODE)*0x10000 + ((__LINE__)%10) + (((__LINE__/10)%10)*0x10) + (((__LINE__/100)%10)*0x100) +(((__LINE__/1000)%10)*0x1000))
+#else
+    /* Macro to aid debugging, causes program to halt and display the line number of the halt in decimal */
+    /* #define STOP_HERE STOP_HERE_OnlyForDebugUse */
+    #define STOP_HERE
+#endif
+
+void CALLCONV AmdPCIReadBits(SBDFO loc, uint8 highbit, uint8 lowbit, uint32 *value);
+void CALLCONV AmdPCIWriteBits(SBDFO loc, uint8 highbit, uint8 lowbit, uint32 *value);
+void CALLCONV AmdPCIFindNextCap(SBDFO *current);
+
+void CALLCONV Amdmemcpy(void *dst, const void *src, uint32 length);
+void CALLCONV Amdmemset(void *buf, uint8 val, uint32 length);
+
+uint8 CALLCONV AmdBitScanReverse(uint32 value);
+uint32 CALLCONV AmdRotateRight(uint32 value, uint8 size, uint32 count);
+uint32 CALLCONV AmdRotateLeft(uint32 value, uint8 size, uint32 count);
+
+#endif
Index: LinuxBIOSv2/src/northbridge/amd/amdht/h3ffeat.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/h3ffeat.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,177 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+#ifndef H3FFEAT_H
+#define H3FFEAT_H
+
+/*----------------------------------------------------------------------------
+ *	Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ *			DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#define MAX_NODES 8
+#define MAX_LINKS 8
+#define MAX_PLATFORM_LINKS 64 /* 8x8 fully connected (28) + 4 chains with two HT devices */
+
+/* These following are internal definitions */
+#define ROUTETOSELF 0x0F
+#define INVALID_LINK 0xCC     /* Used in port list data structure to mark unused data entries.
+				  Can also be used for no link found in a port list search */
+
+/* definitions for working with the port list structure */
+#define PORTLIST_TYPE_CPU 0
+#define PORTLIST_TYPE_IO  1
+
+/*
+ * Hypertransport Capability definitions and macros
+ *
+ */
+
+/* HT Host Capability */
+/* bool isHTHostCapability(u32 reg) */
+#define IS_HT_HOST_CAPABILITY(reg) \
+	((reg & (u32)0xE00000FF) == (u32)0x20000008)
+
+#define HT_HOST_CAP_SIZE			0x20
+
+/* Host CapabilityRegisters */
+#define HTHOST_LINK_CAPABILITY_REG		0x00
+#define HTHOST_LINK_CONTROL_REG		0x04
+#define HTHOST_FREQ_REV_REG			0x08
+	#define HT_HOST_REV_REV3		0x60
+#define HTHOST_FEATURE_CAP_REG			0x0C
+#define HTHOST_BUFFER_COUNT_REG		0x10
+#define HTHOST_ISOC_REG			0x14
+#define HTHOST_LINK_TYPE_REG			0x18
+	#define HTHOST_TYPE_COHERENT		3
+	#define HTHOST_TYPE_NONCOHERENT	7
+	#define HTHOST_TYPE_MASK		0x1F
+
+/* HT Slave Capability (HT1 compat) */
+#define IS_HT_SLAVE_CAPABILITY(reg) \
+	((reg & (u32)0xE00000FF) == (u32)0x00000008)
+#define HTSLAVE_LINK01_OFFSET			4
+#define HTSLAVE_LINK_CONTROL_0_REG		4
+#define HTSLAVE_FREQ_REV_0_REG			0xC
+
+/* HT3 gen Capability */
+#define IS_HT_GEN3_CAPABILITY(reg) \
+	((reg & (u32)0xF80000FF) == (u32)0xD0000008)
+#define HTGEN3_LINK01_OFFSET			0x10
+#define HTGEN3_LINK_TRAINING_0_REG		0x10
+
+/* HT3 Retry Capability */
+#define IS_HT_RETRY_CAPABILITY(reg) \
+	((reg & (u32)0xF80000FF) == (u32)0xC0000008)
+
+#define HTRETRY_CONTROL_REG			4
+
+/* Unit ID Clumping Capability */
+#define IS_HT_UNITID_CAPABILITY(reg) \
+	((reg & (u32)0xF80000FF) == (u32)0x90000008)
+
+#define HTUNIT_SUPPORT_REG			4
+#define HTUNIT_ENABLE_REG			8
+
+/*----------------------------------------------------------------------------
+ *			    TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+typedef struct cNorthBridge cNorthBridge;
+
+/* A pair consists of a source node, a link to the destination node, the
+ * destination node, and its link back to source node.	 The even indices are
+ * the source nodes and links, and the odd indices are for the destination
+ * nodes and links.
+ */
+typedef struct
+{
+	/* This section is where the link is in the system and how to find it */
+	u8 Type; /* 0 = CPU, 1 = Device, all others reserved */
+	u8 Link; /* 0-1 for devices, 0-7 for CPUs */
+	u8 NodeID; /* The node, or a pointer to the devices parent node */
+	u8 HostLink, HostDepth; /* Link of parent node + depth in chain.  Only used by devices */
+	SBDFO Pointer; /* A pointer to the device's slave HT capability, so we don't have to keep searching */
+
+	/* This section is for the final settings, which are written to hardware */
+	BOOL SelRegang; /* Only used for CPU->CPU links */
+	u8 SelWidthIn;
+	u8 SelWidthOut;
+	u8 SelFrequency;
+
+	/* This section is for keeping track of capabilities and possible configurations */
+	BOOL RegangCap;
+	u16 PrvFrequencyCap;
+	u8 PrvWidthInCap;
+	u8 PrvWidthOutCap;
+	u16 CompositeFrequencyCap;
+
+} sPortDescriptor;
+
+
+/*
+ * Our global state data structure
+ */
+typedef struct {
+	AMD_HTBLOCK *HtBlock;
+
+	u8 NodesDiscovered;	 /* One less than the number of nodes found in the system */
+	u8 TotalLinks;
+	u8 sysMpCap;		 /* The maximum number of nodes that all processors are capable of */
+
+	/* Two ports for each link
+	 * Note: The Port pair 2*N and 2*N+1 are connected together to form a link
+	 * (e.g. 0,1 and 8,9 are ports on either end of an HT link) The lower number
+	 * port (2*N) is the source port.	The device that owns the source port is
+	 * always the device closer to the BSP. (i.e. nearer the CPU in a
+	 * non-coherent chain, or the CPU with the lower NodeID).
+	 */
+	sPortDescriptor PortList[MAX_PLATFORM_LINKS*2];
+
+	/* The number of coherent links comming off of each node (i.e. the 'Degree' of the node) */
+	u8 sysDegree[MAX_NODES];
+	/* The systems adjency (sysMatrix[i][j] is true if Node_i has a link to Node_j) */
+	BOOL sysMatrix[MAX_NODES][MAX_NODES];
+
+	/* Same as above, but for the currently selected database entry */
+	u8 dbDegree[MAX_NODES];
+	BOOL dbMatrix[MAX_NODES][MAX_NODES];
+
+	u8 Perm[MAX_NODES];	 /* The node mapping from the database to the system */
+	u8 ReversePerm[MAX_NODES];	 /* The node mapping from the system to the database */
+
+	/* Data for non-coherent initilization */
+	u8 AutoBusCurrent;
+	u8 UsedCfgMapEntires;
+
+	/* 'This' pointer for northbridge */
+	cNorthBridge *nb;
+} sMainData;
+
+#endif	 /* H3FFEAT_H */
Index: LinuxBIOSv2/src/northbridge/amd/amdht/h3finit.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/h3finit.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,1678 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#undef FILECODE
+#define FILECODE 0xF001
+
+#include "comlib.h"
+#include "h3finit.h"
+#include "h3ffeat.h"
+#include "h3ncmn.h"
+#include "h3gtopo.h"
+#include "AsPsNb.h"
+/* this is pre-ram so include the required C files here */
+#include "comlib.c"
+#include "AsPsNb.c"
+#include "h3ncmn.c"
+
+/*----------------------------------------------------------------------------
+ *			DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#undef FILECODE
+#define FILECODE 0xF001
+
+/* APIC defines from amdgesa.inc, which can't be included in to c code. */
+#define APIC_Base_BSP	8
+#define APIC_Base	0x1b
+
+/*----------------------------------------------------------------------------
+ *			TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *			PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *			EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *			LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifndef HT_BUILD_NC_ONLY
+/*
+ **************************************************************************
+ *			Routing table decompressor
+ **************************************************************************
+ */
+
+/*
+ **************************************************************************
+ *	Graph Support routines
+ * These routines provide support for dealing with the graph representation
+ * of the topologies, along with the routing table information for that topology.
+ * The routing information is compressed and these routines currently decompress
+ * 'on the fly'.  A graph is represented as a set of routes. All the edges in the
+ * graph are routes; a direct route from node i to node j exists in the graph IFF
+ * there is an edge directly connecting node i to node j.  All other routes designate
+ * the edge which the route to that node initially takes, by designating a node
+ * to which a direct connection exists.  That is, the route to non-adjacent node j
+ * from node i specifies node k where node i directly connects to node k.
+ *
+ *
+ * pseudo definition of compressed graph:
+ * typedef struct
+ * {
+ *	BIT  broadcast[8];
+ *	uint4 responseRoute;
+ *	uint4 requestRoute;
+ * } sRoute;
+ * typedef struct
+ * {
+ *	u8 size;
+ *	sRoute graph[size][size];
+ * } sGraph;
+ *
+ **************************************************************************
+ */
+
+/*----------------------------------------------------------------------------------------
+ * int
+ * graphHowManyNodes(u8 *graph)
+ *
+ *  Description:
+ *	 Returns the number of nodes in the compressed graph
+ *
+ *  Parameters:
+ *	@param[in] u8 graph = a compressed graph
+ *	@param[out] u8 results = the number of nodes in the graph
+ * ---------------------------------------------------------------------------------------
+ */
+int graphHowManyNodes(u8 *graph)
+{
+	return graph[0];
+}
+
+/*----------------------------------------------------------------------------------------
+ * BOOL
+ * graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB)
+ *
+ *  Description:
+ * Returns true if NodeA is directly connected to NodeB, false otherwise
+ * (if NodeA == NodeB also returns false)
+ * Relies on rule that directly connected nodes always route requests directly.
+ *
+ *  Parameters:
+ *	@param[in]    u8    graph   = the graph to examine
+ *	@param[in]    u8    nodeA   = the node number of the first node
+ *	@param[in]    u8    nodeB   = the node number of the second node
+ *	@param[out]   BOOL    results  = true if nodeA connects to nodeB false if not
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB)
+{
+	u8 size = graph[0];
+	ASSERT(size <= MAX_NODES);
+	ASSERT((nodeA < size) && (nodeB < size));
+	return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F) == nodeB;
+}
+
+/*----------------------------------------------------------------------------------------
+ * u8
+ * graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB)
+ *
+ *  Description:
+ *	Returns the graph node used by nodeA to route responses targeted at nodeB.
+ *	This will be a node directly connected to nodeA (possibly nodeB itself),
+ *	or "Route to Self" if nodeA and nodeB are the same node.
+ *	Note that all node numbers are abstract node numbers of the topology graph,
+ *	it is the responsibility of the caller to apply any permutation needed.
+ *
+ *  Parameters:
+ *	@param[in]    u8    graph   = the graph to examine
+ *	@param[in]    u8    nodeA   = the node number of the first node
+ *	@param[in]    u8    nodeB   = the node number of the second node
+ *	@param[out]   u8    results = The response route node
+ * ---------------------------------------------------------------------------------------
+ */
+u8 graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB)
+{
+	u8 size = graph[0];
+	ASSERT(size <= MAX_NODES);
+	ASSERT((nodeA < size) && (nodeB < size));
+	return (graph[1+(nodeA*size+nodeB)*2+1] & 0xF0)>>4;
+}
+
+/*----------------------------------------------------------------------------------------
+ * u8
+ * graphGetReq(u8 *graph, u8 nodeA, u8 nodeB)
+ *
+ *  Description:
+ *	 Returns the graph node used by nodeA to route requests targeted at nodeB.
+ *	This will be a node directly connected to nodeA (possibly nodeB itself),
+ *	or "Route to Self" if nodeA and nodeB are the same node.
+ *	Note that all node numbers are abstract node numbers of the topology graph,
+ *	it is the responsibility of the caller to apply any permutation needed.
+ *
+ *  Parameters:
+ *	@param[in]    u8    graph   = the graph to examine
+ *	@param[in]    u8    nodeA   = the node number of the first node
+ *	@param[in]    u8    nodeB   = the node number of the second node
+ *	@param[out]   u8    results = The request route node
+ * ---------------------------------------------------------------------------------------
+ */
+u8 graphGetReq(u8 *graph, u8 nodeA, u8 nodeB)
+{
+	int size = graph[0];
+	ASSERT(size <= MAX_NODES);
+	ASSERT((nodeA < size) && (nodeB < size));
+	return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F);
+}
+
+/*----------------------------------------------------------------------------------------
+ * u8
+ * graphGetBc(unsigned char *graph, int nodeA, int nodeB)
+ *
+ *  Description:
+ *	 Returns a bit vector of nodes that nodeA should forward a broadcast from
+ *	 nodeB towards
+ *
+ *  Parameters:
+ *	@param[in]    u8    graph   = the graph to examine
+ *	@param[in]    u8    nodeA   = the node number of the first node
+ *	@param[in]    u8    nodeB   = the node number of the second node
+ *	OU    u8    results = the broadcast routes for nodeA from nodeB
+ * ---------------------------------------------------------------------------------------
+ */
+u8 graphGetBc(unsigned char *graph, int nodeA, int nodeB)
+{
+	int size = graph[0];
+	ASSERT(size <= MAX_NODES);
+	ASSERT((nodeA < size) && (nodeB < size));
+	return graph[1+(nodeA*size+nodeB)*2];
+}
+
+
+/***************************************************************************
+ ***		GENERIC HYPERTRANSPORT DISCOVERY CODE			***
+ ***************************************************************************/
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat)
+ *
+ *  Description:
+ *	 Ensure a request / response route from target node to bsp.  Since target node is
+ *	 always a predecessor of actual target node, each node gets a route to actual target
+ *	 on the link that goes to target.  The routing produced by this routine is adequate
+ *	 for config access during discovery, but NOT for coherency.
+ *
+ *  Parameters:
+ *	@param[in]    u8    targetNode   = the path to actual target goes through target
+ *	@param[in]    u8    actualTarget = the ultimate target being routed to
+ *	@param[in]    sMainData*  pDat   = our global state, port config info
+ * ---------------------------------------------------------------------------------------
+ */
+void routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat)
+{
+	u8 predecessorNode, predecessorLink, currentPair;
+
+	if (targetNode == 0)
+		return;  // BSP has no predecessor, stop
+
+	// Search for the link that connects targetNode to its predecessor
+	currentPair = 0;
+	while (pDat->PortList[currentPair*2+1].NodeID != targetNode)
+	{
+		currentPair++;
+		ASSERT(currentPair < pDat->TotalLinks);
+	}
+
+	predecessorNode = pDat->PortList[currentPair*2].NodeID;
+	predecessorLink = pDat->PortList[currentPair*2].Link;
+
+	// Recursively call self to ensure the route from the BSP to the Predecessor
+	// Node is established
+	routeFromBSP(predecessorNode, actualTarget, pDat);
+
+	pDat->nb->writeRoutingTable(predecessorNode, actualTarget, predecessorLink, pDat->nb);
+}
+
+/*----------------------------------------------------------------------------------------
+ * u8
+ * convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat)
+ *
+ *  Description:
+ *	 Return the link on source node which connects to target node
+ *
+ *  Parameters:
+ *	@param[in]    u8    srcNode    = the source node
+ *	@param[in]    u8    targetNode = the target node to find the link to
+ *	@param[in]    sMainData*  pDat = our global state
+ *	@param[out]   u8    results    = the link on source which connects to target
+ * ---------------------------------------------------------------------------------------
+ */
+u8 convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat)
+{
+	u8 targetlink = INVALID_LINK;
+	u8 k;
+
+	for (k = 0; k < pDat->TotalLinks*2; k += 2)
+	{
+		if ((pDat->PortList[k+0].NodeID == srcNode) && (pDat->PortList[k+1].NodeID == targetNode))
+		{
+			targetlink = pDat->PortList[k+0].Link;
+			break;
+		}
+		else if ((pDat->PortList[k+1].NodeID == srcNode) && (pDat->PortList[k+0].NodeID == targetNode))
+		{
+			targetlink = pDat->PortList[k+1].Link;
+			break;
+		}
+	}
+	ASSERT(targetlink != INVALID_LINK);
+
+	return targetlink;
+}
+
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * htDiscoveryFloodFill(sMainData *pDat)
+ *
+ *  Description:
+ *	 Discover all coherent devices in the system, initializing some basics like node IDs
+ *	 and total nodes found in the process. As we go we also build a representation of the
+ *	 discovered system which we will use later to program the routing tables.  During this
+ *	 step, the routing is via default link back to BSP and to each new node on the link it
+ *	 was discovered on (no coherency is active yet).
+ *
+ *  Parameters:
+ *	@param[in]    sMainData*  pDat = our global state
+ * ---------------------------------------------------------------------------------------
+ */
+void htDiscoveryFloodFill(sMainData *pDat)
+{
+	u8 currentNode = 0;
+	u8 currentLink;
+
+	/* Entries are always added in pairs, the even indices are the 'source'
+	 * side closest to the BSP, the odd indices are the 'destination' side
+	 */
+
+	while (currentNode <= pDat->NodesDiscovered)
+	{
+		u32 temp;
+
+		if (currentNode != 0)
+		{
+			/* Set path from BSP to currentNode */
+			routeFromBSP(currentNode, currentNode, pDat);
+
+			/* Set path from BSP to currentNode for currentNode+1 if
+			 * currentNode+1 != MAX_NODES
+			 */
+			if (currentNode+1 != MAX_NODES)
+				routeFromBSP(currentNode, currentNode+1, pDat);
+
+			/* Configure currentNode to route traffic to the BSP through its
+			 * default link
+			 */
+			pDat->nb->writeRoutingTable(currentNode, 0, pDat->nb->readDefLnk(currentNode, pDat->nb), pDat->nb);
+		}
+
+		/* Set currentNode's NodeID field to currentNode */
+		pDat->nb->writeNodeID(currentNode, currentNode, pDat->nb);
+
+		/* Enable routing tables on currentNode*/
+		pDat->nb->enableRoutingTables(currentNode, pDat->nb);
+
+		for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++)
+		{
+			BOOL linkfound;
+			u8 token;
+
+			if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(currentNode, currentLink))
+				continue;
+
+			if (pDat->nb->readTrueLinkFailStatus(currentNode, currentLink, pDat, pDat->nb))
+				continue;
+
+			/* Make sure that the link is connected, coherent, and ready */
+			if (!pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb))
+				continue;
+
+
+			/* Test to see if the currentLink has already been explored */
+			linkfound = FALSE;
+			for (temp = 0; temp < pDat->TotalLinks; temp++)
+			{
+				if ((pDat->PortList[temp*2+1].NodeID == currentNode) &&
+				   (pDat->PortList[temp*2+1].Link == currentLink))
+				{
+					linkfound = TRUE;
+					break;
+				}
+			}
+			if (linkfound)
+			{
+				/* We had already expored this link */
+				continue;
+			}
+
+			if (pDat->nb->handleSpecialLinkCase(currentNode, currentLink, pDat, pDat->nb))
+			{
+				continue;
+			}
+
+			/* Modify currentNode's routing table to use currentLink to send
+			 * traffic to currentNode+1
+			 */
+			pDat->nb->writeRoutingTable(currentNode, currentNode+1, currentLink, pDat->nb);
+
+			/* Check the northbridge of the node we just found, to make sure it is compatible
+			 * before doing anything else to it.
+			 */
+			if (!pDat->nb->isCompatible(currentNode+1, pDat->nb))
+			{
+				u8 nodeToKill;
+
+				/* Notify BIOS of event (while variables are still the same) */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					sHtEventCohFamilyFeud evt = {sizeof(sHtEventCohFamilyFeud),
+								currentNode,
+								currentLink,
+								pDat->NodesDiscovered};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
+									HT_EVENT_COH_FAMILY_FEUD,
+									(u8 *)&evt);
+				}
+
+				/* If node is not compatible, force boot to 1P
+				 * If they are not compatible stop cHT init and:
+				 *	1. Disable all cHT links on the BSP
+				 *	2. Configure the BSP routing tables as a UP.
+				 *	3. Notify main BIOS.
+				 */
+				pDat->NodesDiscovered = 0;
+				currentNode = 0;
+				pDat->TotalLinks = 0;
+				/* Abandon our coherent link data structure.  At this point there may
+				 * be coherent links on the BSP that are not yet in the portList, and
+				 * we have to turn them off anyway.  So depend on the hardware to tell us.
+				 */
+				for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++)
+				{
+					/* Stop all links which are connected, coherent, and ready */
+					if (pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb))
+						pDat->nb->stopLink(currentNode, currentLink, pDat->nb);
+				}
+
+				for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++)
+				{
+					pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
+				}
+
+				/* End Coherent Discovery */
+				STOP_HERE;
+				break;
+			}
+
+			/* Read token from Current+1 */
+			token = pDat->nb->readToken(currentNode+1, pDat->nb);
+			ASSERT(token <= pDat->NodesDiscovered);
+			if (token == 0)
+			{
+				pDat->NodesDiscovered++;
+				ASSERT(pDat->NodesDiscovered < pDat->nb->maxNodes);
+				/* Check the capability of northbridges against the currently known configuration */
+				if (!pDat->nb->isCapable(currentNode+1, pDat, pDat->nb))
+				{
+					u8 nodeToKill;
+
+					/* Notify BIOS of event  */
+					if (pDat->HtBlock->AMD_CB_EventNotify)
+					{
+						sHtEventCohMpCapMismatch evt = {sizeof(sHtEventCohMpCapMismatch),
+									currentNode,
+									currentLink,
+									pDat->sysMpCap,
+									pDat->NodesDiscovered};
+
+						pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
+									HT_EVENT_COH_MPCAP_MISMATCH,
+									(u8 *)&evt);
+					}
+
+					pDat->NodesDiscovered = 0;
+					currentNode = 0;
+					pDat->TotalLinks = 0;
+
+					for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++)
+					{
+						pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
+					}
+
+					/* End Coherent Discovery */
+					STOP_HERE;
+					break;
+				}
+
+				token = pDat->NodesDiscovered;
+				pDat->nb->writeToken(currentNode+1, token, pDat->nb);
+				/* Inform that we have discovered a node, so that logical id to
+				 * socket mapping info can be recorded.
+				 */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					sHtEventCohNodeDiscovered evt = {sizeof(sHtEventCohNodeDiscovered),
+								currentNode,
+								currentLink,
+								token};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,
+								HT_EVENT_COH_NODE_DISCOVERED,
+								(u8 *)&evt);
+				}
+			}
+
+			if (pDat->TotalLinks == MAX_PLATFORM_LINKS)
+			{
+				/*
+				 * Exceeded our capacity to describe all coherent links found in the system.
+				 * Error strategy:
+				 * Auto recovery is not possible because data space is already all used.
+				 * If the callback is not implemented or returns we will continue to initialize
+				 * the fabric we are capable of representing, adding no more nodes or links.
+				 * This should yield a bootable topology, but likely not the one intended.
+				 * We cannot continue discovery, there may not be any way to route a new
+				 * node back to the BSP if we can't add links to our representation of the system.
+				 */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					sHtEventCohLinkExceed evt = {sizeof(sHtEventCohLinkExceed),
+								currentNode,
+								currentLink,
+								token,
+								pDat->NodesDiscovered,
+								pDat->nb->maxLinks};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
+									HT_EVENT_COH_LINK_EXCEED,
+									(u8 *)&evt);
+				}
+				/* Force link and node loops to halt */
+				STOP_HERE;
+				currentNode = pDat->NodesDiscovered;
+				break;
+			}
+
+			pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
+			pDat->PortList[pDat->TotalLinks*2].Link = currentLink;
+			pDat->PortList[pDat->TotalLinks*2].NodeID = currentNode;
+
+			pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_CPU;
+			pDat->PortList[pDat->TotalLinks*2+1].Link = pDat->nb->readDefLnk(currentNode+1, pDat->nb);
+			pDat->PortList[pDat->TotalLinks*2+1].NodeID = token;
+
+			pDat->TotalLinks++;
+
+			if ( !pDat->sysMatrix[currentNode][token] )
+			{
+				pDat->sysDegree[currentNode]++;
+				pDat->sysDegree[token]++;
+				pDat->sysMatrix[currentNode][token] = TRUE;
+				pDat->sysMatrix[token][currentNode] = TRUE;
+			}
+		}
+		currentNode++;
+	}
+}
+
+
+/***************************************************************************
+ ***		ISOMORPHISM BASED ROUTING TABLE GENERATION CODE		***
+ ***************************************************************************/
+
+/*----------------------------------------------------------------------------------------
+ * BOOL
+ * isoMorph(u8 i, sMainData *pDat)
+ *
+ *  Description:
+ *	 Is graphA isomorphic to graphB?
+ *	 if this function returns true, then Perm will contain the permutation
+ *	 required to transform graphB into graphA.
+ *	 We also use the degree of each node, that is the number of connections it has, to
+ *	 speed up rejection of non-isomorphic graphs (if there is a node in graphA with n
+ *	 connections, there must be at least one unmatched in graphB with n connections).
+ *
+ *  Parameters:
+ *	@param[in] u8 i   = the discovered node which we are trying to match
+ *		    with a permutation the topology
+ *	@param[in]/@param[out] sMainData* pDat  = our global state, degree and adjacency matrix,
+ *				  output a permutation if successful
+ *	@param[out] BOOL results = the graphs are (or are not) isomorphic
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL isoMorph(u8 i, sMainData *pDat)
+{
+	u8 j, k;
+	u8 nodecnt;
+
+	/* We have only been called if nodecnt == pSelected->size ! */
+	nodecnt = pDat->NodesDiscovered+1;
+
+	if (i != nodecnt)
+	{
+		// Keep building the permutation
+		for (j = 0; j < nodecnt; j++)
+		{
+			// Make sure the degree matches
+			if (pDat->sysDegree[i] != pDat->dbDegree[j])
+				continue;
+
+			// Make sure that j hasn't been used yet (ought to use a "used"
+			// array instead, might be faster)
+			for (k = 0; k < i; k++)
+			{
+				if (pDat->Perm[k] == j)
+					break;
+			}
+			if (k != i)
+				continue;
+			pDat->Perm[i] = j;
+			if (isoMorph(i+1, pDat))
+				return TRUE;
+		}
+		return FALSE;
+	} else {
+		// Test to see if the permutation is isomorphic
+		for (j = 0; j < nodecnt; j++)
+		{
+			for (k = 0; k < nodecnt; k++)
+			{
+				if ( pDat->sysMatrix[j][k] !=
+				   pDat->dbMatrix[pDat->Perm[j]][pDat->Perm[k]] )
+					return FALSE;
+			}
+		}
+		return TRUE;
+	}
+}
+
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * lookupComputeAndLoadRoutingTables(sMainData *pDat)
+ *
+ *  Description:
+ *	 Using the description of the fabric topology we discovered, try to find a match
+ *	 among the supported topologies.  A supported topology description matches
+ *	 the discovered fabric if the nodes can be matched in such a way that all the nodes connected
+ *	 in one set are exactly the nodes connected in the other (formally, that the graphs are
+ *	 isomorphic).  Which links are used is not really important to matching.  If the graphs
+ *	 match, then there is a permutation of one that translates the node positions and linkages
+ *	 to the other.
+ *
+ *	 In order to make the isomorphism test efficient, we test for matched number of nodes
+ *	 (a 4 node fabric is not isomorphic to a 2 node topology), and provide degrees of nodes
+ *	 to the isomorphism test.
+ *
+ *	 The generic routing table solution for any topology is predetermined and represented
+ *	 as part of the topology.  The permutation we computed tells us how to interpret the
+ *	 routing onto the fabric we discovered.	 We do this working backward from the last
+ *	 node discovered to the BSP, writing the routing tables as we go.
+ *
+ *  Parameters:
+ *	@param[in]    sMainData* pDat = our global state, the discovered fabric,
+ *	@param[out]			degree matrix, permutation
+ * ---------------------------------------------------------------------------------------
+ */
+void lookupComputeAndLoadRoutingTables(sMainData *pDat)
+{
+	u8 **pTopologyList;
+	u8 *pSelected;
+
+	int i, j, k, size;
+
+	size = pDat->NodesDiscovered + 1;
+	/* Use the provided topology list or the internal, default one. */
+	pTopologyList = pDat->HtBlock->topolist;
+	if (pTopologyList == NULL)
+	{
+		getAmdTopolist(&pTopologyList);
+	}
+
+	pSelected = *pTopologyList;
+	while (pSelected != NULL)
+	{
+		if (graphHowManyNodes(pSelected) == size)
+		{
+			// Build Degree vector and Adjency Matrix for this entry
+			for (i = 0; i < size; i++)
+			{
+				pDat->dbDegree[i] = 0;
+				for (j = 0; j < size; j++)
+				{
+					if (graphIsAdjacent(pSelected, i, j))
+					{
+						pDat->dbMatrix[i][j] = 1;
+						pDat->dbDegree[i]++;
+					}
+					else
+					{
+						pDat->dbMatrix[i][j] = 0;
+					}
+				}
+			}
+			if (isoMorph(0, pDat))
+				break;	 // A matching topology was found
+		}
+
+		pTopologyList++;
+		pSelected = *pTopologyList;
+	}
+
+	if (pSelected != NULL)
+	{
+		// Compute the reverse Permutation
+		for (i = 0; i < size; i++)
+		{
+			pDat->ReversePerm[pDat->Perm[i]] = i;
+		}
+
+		// Start with the last discovered node, and move towards the BSP
+		for (i = size-1; i >= 0; i--)
+		{
+			for (j = 0; j < size; j++)
+			{
+				u8 ReqTargetLink, RspTargetLink;
+				u8 ReqTargetNode, RspTargetNode;
+
+				u8 AbstractBcTargetNodes = graphGetBc(pSelected, pDat->Perm[i], pDat->Perm[j]);
+				u32 BcTargetLinks = 0;
+
+				for (k = 0; k < MAX_NODES; k++)
+				{
+					if (AbstractBcTargetNodes & ((u32)1<<k))
+					{
+						BcTargetLinks |= (u32)1 << convertNodeToLink(i, pDat->ReversePerm[k], pDat);
+					}
+				}
+
+				if (i == j)
+				{
+					ReqTargetLink = ROUTETOSELF;
+					RspTargetLink = ROUTETOSELF;
+				}
+				else
+				{
+					ReqTargetNode = graphGetReq(pSelected, pDat->Perm[i], pDat->Perm[j]);
+					ReqTargetLink = convertNodeToLink(i, pDat->ReversePerm[ReqTargetNode], pDat);
+
+					RspTargetNode = graphGetRsp(pSelected, pDat->Perm[i], pDat->Perm[j]);
+					RspTargetLink = convertNodeToLink(i, pDat->ReversePerm[RspTargetNode], pDat);
+				}
+
+				pDat->nb->writeFullRoutingTable(i, j, ReqTargetLink, RspTargetLink, BcTargetLinks, pDat->nb);
+			}
+			/* Clean up discovery 'footprint' that otherwise remains in the routing table.  It didn't hurt
+			 * anything, but might cause confusion during debug and validation.  Do this by setting the
+			 * route back to all self routes. Since it's the node that would be one more than actually installed,
+			 * this only applies if less than maxNodes were found.
+			 */
+			if (size < pDat->nb->maxNodes)
+			{
+				pDat->nb->writeFullRoutingTable(i, size, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
+			}
+		}
+
+	}
+	else
+	{
+		/*
+		 * No Matching Topology was found
+		 * Error Strategy:
+		 * Auto recovery doesn't seem likely, Force boot as 1P.
+		 * For reporting, logging, provide number of nodes
+		 * If not implemented or returns, boot as BSP uniprocessor.
+		 */
+		if (pDat->HtBlock->AMD_CB_EventNotify)
+		{
+			sHtEventCohNoTopology evt = {sizeof(sHtEventCohNoTopology),
+							pDat->NodesDiscovered};
+
+			pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
+						HT_EVENT_COH_NO_TOPOLOGY,
+						(u8 *)&evt);
+		}
+		STOP_HERE;
+		/* Force 1P */
+		pDat->NodesDiscovered = 0;
+		pDat->TotalLinks = 0;
+		pDat->nb->enableRoutingTables(0, pDat->nb);
+	}
+}
+#endif /* HT_BUILD_NC_ONLY */
+
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * finializeCoherentInit(sMainData *pDat)
+ *
+ *  Description:
+ *	 Find the total number of cores and update the number of nodes and cores in all cpus.
+ *	 Limit cpu config access to installed cpus.
+ *
+ *  Parameters:
+ *	@param[in] sMainData* pDat = our global state, number of nodes discovered.
+ * ---------------------------------------------------------------------------------------
+ */
+void finializeCoherentInit(sMainData *pDat)
+{
+	u8 curNode;
+
+	u8 totalCores = 0;
+	for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
+	{
+		totalCores += pDat->nb->getNumCoresOnNode(curNode, pDat->nb);
+	}
+
+	for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
+	{
+		pDat->nb->setTotalNodesAndCores(curNode, pDat->NodesDiscovered+1, totalCores, pDat->nb);
+	}
+
+	for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
+	{
+		pDat->nb->limitNodes(curNode, pDat->nb);
+	}
+
+}
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * coherentInit(sMainData *pDat)
+ *
+ *  Description:
+ *	 Perform discovery and initialization of the coherent fabric.
+ *
+ *  Parameters:
+ *	@param[in] sMainData* pDat = our global state
+ * ---------------------------------------------------------------------------------------
+ */
+void coherentInit(sMainData *pDat)
+{
+	int i, j;
+
+#ifdef HT_BUILD_NC_ONLY
+	/* Replace discovery process with:
+	 * No other nodes, no coherent links
+	 * Enable routing tables on currentNode, for power on self route
+	 */
+	pDat->NodesDiscovered = 0;
+	pDat->TotalLinks = 0;
+	pDat->nb->enableRoutingTables(0, pDat->nb);
+#else
+	pDat->NodesDiscovered = 0;
+	pDat->TotalLinks = 0;
+	for (i = 0; i < MAX_NODES; i++)
+	{
+		pDat->sysDegree[i] = 0;
+		for (j = 0; j < MAX_NODES; j++)
+		{
+			pDat->sysMatrix[i][j] = 0;
+		}
+	}
+
+	htDiscoveryFloodFill(pDat);
+	lookupComputeAndLoadRoutingTables(pDat);
+#endif
+	finializeCoherentInit(pDat);
+}
+
+/***************************************************************************
+ ***			    Non-coherent init code			  ***
+ ***				  Algorithms				  ***
+ ***************************************************************************/
+/*----------------------------------------------------------------------------------------
+ * void
+ * processLink(u8 node, u8 link, sMainData *pDat)
+ *
+ *  Description:
+ *	 Process a non-coherent link, enabling a range of bus numbers, and setting the device
+ *	 ID for all devices found
+ *
+ *  Parameters:
+ *	@param[in] u8 node = Node on which to process nc init
+ *	@param[in] u8 link = The non-coherent link on that node
+ *	@param[in] sMainData* pDat = our global state
+ * ---------------------------------------------------------------------------------------
+ */
+void processLink(u8 node, u8 link, sMainData *pDat)
+{
+	u8 secBus, subBus;
+	u32 currentBUID;
+	u32 temp;
+	u32 unitIDcnt;
+	SBDFO currentPtr;
+	u8 depth;
+	u8 *pSwapPtr;
+
+	SBDFO lastSBDFO = ILLEGAL_SBDFO;
+	u8 lastLink = 0;
+
+	ASSERT(node < pDat->nb->maxNodes && link < pDat->nb->maxLinks);
+
+	if ((pDat->HtBlock->AMD_CB_OverrideBusNumbers == NULL)
+	   || !pDat->HtBlock->AMD_CB_OverrideBusNumbers(node, link, &secBus, &subBus))
+	{
+		/* Assign Bus numbers */
+		if (pDat->AutoBusCurrent >= pDat->HtBlock->AutoBusMax)
+		{
+			/* If we run out of Bus Numbers notify, if call back unimplemented or if it
+			 * returns, skip this chain
+			 */
+			if (pDat->HtBlock->AMD_CB_EventNotify)
+			{
+				sHTEventNcohBusMaxExceed evt = {sizeof(sHTEventNcohBusMaxExceed), node, link, pDat->AutoBusCurrent};
+
+				pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUS_MAX_EXCEED,(u8 *)&evt);
+			}
+			STOP_HERE;
+			return;
+		}
+
+		if (pDat->UsedCfgMapEntires >= 4)
+		{
+			/* If we have used all the PCI Config maps we can't add another chain.
+			 * Notify and if call back is unimplemented or returns, skip this chain.
+			 */
+			if (pDat->HtBlock->AMD_CB_EventNotify)
+			{
+				sHtEventNcohCfgMapExceed evt = {sizeof(sHtEventNcohCfgMapExceed), node, link};
+
+				pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
+							HT_EVENT_NCOH_CFG_MAP_EXCEED,
+							(u8 *)&evt);
+			}
+			STOP_HERE;
+			return;
+		}
+
+		secBus = pDat->AutoBusCurrent;
+		subBus = secBus + pDat->HtBlock->AutoBusIncrement-1;
+		pDat->AutoBusCurrent += pDat->HtBlock->AutoBusIncrement;
+	}
+
+	pDat->nb->setCFGAddrMap(pDat->UsedCfgMapEntires, secBus, subBus, node, link, pDat, pDat->nb);
+	pDat->UsedCfgMapEntires++;
+
+	if ((pDat->HtBlock->AMD_CB_ManualBUIDSwapList != NULL)
+	 && pDat->HtBlock->AMD_CB_ManualBUIDSwapList(node, link, &pSwapPtr))
+	{
+		/* Manual non-coherent BUID assignment */
+
+		/* Assign BUID's per manual override */
+		while (*pSwapPtr != 0xFF)
+		{
+			currentPtr = MAKE_SBDFO(0, secBus, *pSwapPtr, 0, 0);
+			pSwapPtr++;
+
+			do
+			{
+				AmdPCIFindNextCap(&currentPtr);
+				ASSERT(currentPtr != ILLEGAL_SBDFO);
+				AmdPCIRead(currentPtr, &temp);
+			} while (!IS_HT_SLAVE_CAPABILITY(temp));
+
+			currentBUID = *pSwapPtr;
+			pSwapPtr++;
+			AmdPCIWriteBits(currentPtr, 20, 16, &currentBUID);
+		}
+
+		/* Build chain of devices */
+		depth = 0;
+		pSwapPtr++;
+		while (*pSwapPtr != 0xFF)
+		{
+			pDat->PortList[pDat->TotalLinks*2].NodeID = node;
+			if (depth == 0)
+			{
+				pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
+				pDat->PortList[pDat->TotalLinks*2].Link = link;
+			}
+			else
+			{
+				pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO;
+				pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink;
+				pDat->PortList[pDat->TotalLinks*2].HostLink = link;
+				pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1;
+				pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO;
+			}
+
+			pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO;
+			pDat->PortList[pDat->TotalLinks*2+1].NodeID = node;
+			pDat->PortList[pDat->TotalLinks*2+1].HostLink = link;
+			pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth;
+
+			currentPtr = MAKE_SBDFO(0, secBus, (*pSwapPtr & 0x3F), 0, 0);
+			do
+			{
+				AmdPCIFindNextCap(&currentPtr);
+				ASSERT(currentPtr != ILLEGAL_SBDFO);
+				AmdPCIRead(currentPtr, &temp);
+			} while (!IS_HT_SLAVE_CAPABILITY(temp));
+			pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr;
+			lastSBDFO = currentPtr;
+
+			/* Bit 6 indicates whether orientation override is desired.
+			 * Bit 7 indicates the upstream link if overriding.
+			 */
+			/* assert catches at least the one known incorrect setting */
+			ASSERT ((*pSwapPtr & 0x40) || (!(*pSwapPtr & 0x80)));
+			if (*pSwapPtr & 0x40)
+			{
+				/* Override the device's orientation */
+				lastLink = *pSwapPtr >> 7;
+			}
+			else
+			{
+				/* Detect the device's orientation */
+				AmdPCIReadBits(currentPtr, 26, 26, &temp);
+				lastLink = (u8)temp;
+			}
+			pDat->PortList[pDat->TotalLinks*2+1].Link = lastLink;
+
+			depth++;
+			pDat->TotalLinks++;
+			pSwapPtr++;
+		}
+	}
+	else
+	{
+		/* Automatic non-coherent device detection */
+		depth = 0;
+		currentBUID = 1;
+		while (1)
+		{
+			currentPtr = MAKE_SBDFO(0, secBus, 0, 0, 0);
+
+			AmdPCIRead(currentPtr, &temp);
+			if (temp == 0xFFFFFFFF)
+				/* No device found at currentPtr */
+				break;
+
+			if (pDat->TotalLinks == MAX_PLATFORM_LINKS)
+			{
+				/*
+				 * Exceeded our capacity to describe all non-coherent links found in the system.
+				 * Error strategy:
+				 * Auto recovery is not possible because data space is already all used.
+				 */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					sHtEventNcohLinkExceed evt = {sizeof(sHtEventNcohLinkExceed),
+							node,
+							link,
+							depth,
+							pDat->nb->maxLinks};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
+								HT_EVENT_NCOH_LINK_EXCEED,
+								(u8 *)&evt);
+				}
+				/* Force link loop to halt */
+				STOP_HERE;
+				break;
+			}
+
+			pDat->PortList[pDat->TotalLinks*2].NodeID = node;
+			if (depth == 0)
+			{
+				pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
+				pDat->PortList[pDat->TotalLinks*2].Link = link;
+			}
+			else
+			{
+				pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO;
+				pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink;
+				pDat->PortList[pDat->TotalLinks*2].HostLink = link;
+				pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1;
+				pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO;
+			}
+
+			pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO;
+			pDat->PortList[pDat->TotalLinks*2+1].NodeID = node;
+			pDat->PortList[pDat->TotalLinks*2+1].HostLink = link;
+			pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth;
+
+			do
+			{
+				AmdPCIFindNextCap(&currentPtr);
+				ASSERT(currentPtr != ILLEGAL_SBDFO);
+				AmdPCIRead(currentPtr, &temp);
+			} while (!IS_HT_SLAVE_CAPABILITY(temp));
+
+			AmdPCIReadBits(currentPtr, 25, 21, &unitIDcnt);
+			if ((unitIDcnt + currentBUID > 31) || ((secBus == 0) && (unitIDcnt + currentBUID > 24)))
+			{
+				/* An error handler for the case where we run out of BUID's on a chain */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					sHtEventNcohBuidExceed evt = {sizeof(sHtEventNcohBuidExceed),
+								node, link, depth, (u8)currentBUID, (u8)unitIDcnt};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUID_EXCEED,(u8 *)&evt);
+				}
+				STOP_HERE;
+				break;
+			}
+			AmdPCIWriteBits(currentPtr, 20, 16, &currentBUID);
+
+
+			currentPtr += MAKE_SBDFO(0, 0, currentBUID, 0, 0);
+			AmdPCIReadBits(currentPtr, 20, 16, &temp);
+			if (temp != currentBUID)
+			{
+				/* An error handler for this critical error */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					sHtEventNcohDeviceFailed evt = {sizeof(sHtEventNcohDeviceFailed),
+							node, link, depth, (u8)currentBUID};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_DEVICE_FAILED,(u8 *)&evt);
+				}
+				STOP_HERE;
+				break;
+			}
+
+			AmdPCIReadBits(currentPtr, 26, 26, &temp);
+			pDat->PortList[pDat->TotalLinks*2+1].Link = (u8)temp;
+			pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr;
+
+			lastLink = (u8)temp;
+			lastSBDFO = currentPtr;
+
+			depth++;
+			pDat->TotalLinks++;
+			currentBUID += unitIDcnt;
+		}
+		if (pDat->HtBlock->AMD_CB_EventNotify)
+		{
+			/* Provide information on automatic device results */
+			sHtEventNcohAutoDepth evt = {sizeof(sHtEventNcohAutoDepth), node, link, (depth - 1)};
+
+			pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,HT_EVENT_NCOH_AUTO_DEPTH,(u8 *)&evt);
+		}
+	}
+}
+
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * ncInit(sMainData *pDat)
+ *
+ *  Description:
+ *	 Initialize the non-coherent fabric. Begin with the compat link on the BSP, then
+ *	 find and initialize all other non-coherent chains.
+ *
+ *  Parameters:
+ *	@param[in]  sMainData*  pDat = our global state
+ * ---------------------------------------------------------------------------------------
+ */
+void ncInit(sMainData *pDat)
+{
+	u8 node, link;
+	u8 compatLink;
+
+	compatLink = pDat->nb->readSbLink(pDat->nb);
+	processLink(0, compatLink, pDat);
+
+	for (node = 0; node <= pDat->NodesDiscovered; node++)
+	{
+		for (link = 0; link < pDat->nb->maxLinks; link++)
+		{
+			if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(node, link))
+				continue;   // Skip the link
+
+			if (node == 0 && link == compatLink)
+				continue;
+
+			if (pDat->nb->readTrueLinkFailStatus(node, link, pDat, pDat->nb))
+				continue;
+
+			if (pDat->nb->verifyLinkIsNonCoherent(node, link, pDat->nb))
+				processLink(node, link, pDat);
+		}
+	}
+}
+
+/***************************************************************************
+ ***				Link Optimization			  ***
+ ***************************************************************************/
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * regangLinks(sMainData *pDat)
+ *
+ *  Description:
+ *	 Test the sublinks of a link to see if they qualify to be reganged.  If they do,
+ *	 update the port list data to indicate that this should be done.  Note that no
+ *	 actual hardware state is changed in this routine.
+ *
+ *  Parameters:
+ *	@param[in,out] sMainData*  pDat = our global state
+ * ---------------------------------------------------------------------------------------
+ */
+void regangLinks(sMainData *pDat)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u8 i, j;
+	for (i = 0; i < pDat->TotalLinks*2; i += 2)
+	{
+		ASSERT(pDat->PortList[i].Type < 2 && pDat->PortList[i].Link < pDat->nb->maxLinks);  // Data validation
+		ASSERT(pDat->PortList[i+1].Type < 2 && pDat->PortList[i+1].Link < pDat->nb->maxLinks); // data validation
+		ASSERT(!(pDat->PortList[i].Type == PORTLIST_TYPE_IO && pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU));  // ensure src is closer to the bsp than dst
+
+		/* Regang is false unless we pass all conditions below */
+		pDat->PortList[i].SelRegang = FALSE;
+		pDat->PortList[i+1].SelRegang = FALSE;
+
+		if ( (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[i+1].Type != PORTLIST_TYPE_CPU))
+			continue;	 // Only process cpu to cpu links
+
+		for (j = i+2; j < pDat->TotalLinks*2; j += 2)
+		{
+			if ( (pDat->PortList[j].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[j+1].Type != PORTLIST_TYPE_CPU) )
+				continue;   // Only process cpu to cpu links
+
+			if (pDat->PortList[i].NodeID != pDat->PortList[j].NodeID)
+				continue;   // Links must be from the same source
+
+			if (pDat->PortList[i+1].NodeID != pDat->PortList[j+1].NodeID)
+				continue;   // Link must be to the same target
+
+			if ((pDat->PortList[i].Link & 3) != (pDat->PortList[j].Link & 3))
+				continue;   // Ensure same source base port
+
+			if ((pDat->PortList[i+1].Link & 3) != (pDat->PortList[j+1].Link & 3))
+				continue;   // Ensure same destination base port
+
+			if ((pDat->PortList[i].Link & 4) != (pDat->PortList[i+1].Link & 4))
+				continue;   // Ensure sublink0 routes to sublink0
+
+			ASSERT((pDat->PortList[j].Link & 4) == (pDat->PortList[j+1].Link & 4)); // (therefore sublink1 routes to sublink1)
+
+			if (pDat->HtBlock->AMD_CB_SkipRegang &&
+			    pDat->HtBlock->AMD_CB_SkipRegang(pDat->PortList[i].NodeID,
+							pDat->PortList[i].Link & 0x03,
+							pDat->PortList[i+1].NodeID,
+							pDat->PortList[i+1].Link & 0x03))
+			{
+				continue;   // Skip regang
+			}
+
+
+			pDat->PortList[i].Link &= 0x03; // Force to point to sublink0
+			pDat->PortList[i+1].Link &= 0x03;
+			pDat->PortList[i].SelRegang = TRUE; // Enable link reganging
+			pDat->PortList[i+1].SelRegang = TRUE;
+			pDat->PortList[i].PrvWidthOutCap = HT_WIDTH_16_BITS;
+			pDat->PortList[i+1].PrvWidthOutCap = HT_WIDTH_16_BITS;
+			pDat->PortList[i].PrvWidthInCap = HT_WIDTH_16_BITS;
+			pDat->PortList[i+1].PrvWidthInCap = HT_WIDTH_16_BITS;
+
+			// Delete PortList[j, j+1], slow but easy to debug implementation
+			pDat->TotalLinks--;
+			Amdmemcpy(&(pDat->PortList[j]), &(pDat->PortList[j+2]), sizeof(sPortDescriptor)*(pDat->TotalLinks*2-j));
+			Amdmemset(&(pDat->PortList[pDat->TotalLinks*2]), INVALID_LINK, sizeof(sPortDescriptor)*2);
+
+			////High performance, but would make debuging harder due to 'shuffling' of the records
+			////Amdmemcpy(PortList[TotalPorts-2], PortList[j], SIZEOF(sPortDescriptor)*2);
+			////TotalPorts -=2;
+
+			break; // Exit loop, advance to PortList[i+2]
+		}
+	}
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * selectOptimalWidthAndFrequency(sMainData *pDat)
+ *
+ *  Description:
+ *	 For all links:
+ *	 Examine both sides of a link and determine the optimal frequency and width,
+ *	 taking into account externally provided limits and enforcing any other limit
+ *	 or matching rules as applicable except sublink balancing.   Update the port
+ *	 list date with the optimal settings.
+ *	 Note no hardware state changes in this routine.
+ *
+ *  Parameters:
+ *	@param[in,out]  sMainData*  pDat = our global state, port list data
+ * ---------------------------------------------------------------------------------------
+ */
+void selectOptimalWidthAndFrequency(sMainData *pDat)
+{
+	u8 i, j;
+	u32 temp;
+	u16 cbPCBFreqLimit;
+	u8 cbPCBABDownstreamWidth;
+	u8 cbPCBBAUpstreamWidth;
+
+	for (i = 0; i < pDat->TotalLinks*2; i += 2)
+	{
+		cbPCBFreqLimit = 0xFFFF;
+		cbPCBABDownstreamWidth = 16;
+		cbPCBBAUpstreamWidth = 16;
+
+		if ( (pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU))
+		{
+			if (pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits)
+			{
+				pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits(
+						pDat->PortList[i].NodeID,
+						pDat->PortList[i].Link,
+						pDat->PortList[i+1].NodeID,
+						pDat->PortList[i+1].Link,
+						&cbPCBABDownstreamWidth,
+						&cbPCBBAUpstreamWidth, &cbPCBFreqLimit
+						);
+			}
+		}
+		else
+		{
+			if (pDat->HtBlock->AMD_CB_IOPCBLimits)
+			{
+				pDat->HtBlock->AMD_CB_IOPCBLimits(
+						pDat->PortList[i+1].NodeID,
+						pDat->PortList[i+1].HostLink,
+						pDat->PortList[i+1].HostDepth,
+						&cbPCBABDownstreamWidth,
+						 &cbPCBBAUpstreamWidth, &cbPCBFreqLimit
+						);
+			}
+		}
+
+
+		temp = pDat->PortList[i].PrvFrequencyCap;
+		temp &= pDat->PortList[i+1].PrvFrequencyCap;
+		temp &= cbPCBFreqLimit;
+		pDat->PortList[i].CompositeFrequencyCap = (u16)temp;
+		pDat->PortList[i+1].CompositeFrequencyCap = (u16)temp;
+
+		ASSERT (temp != 0);
+		for (j = 15; ; j--)
+		{
+			if (temp & ((u32)1 << j))
+				break;
+		}
+
+		pDat->PortList[i].SelFrequency = j;
+		pDat->PortList[i+1].SelFrequency = j;
+
+		temp = pDat->PortList[i].PrvWidthOutCap;
+		if (pDat->PortList[i+1].PrvWidthInCap < temp)
+			temp = pDat->PortList[i+1].PrvWidthInCap;
+		if (cbPCBABDownstreamWidth < temp)
+			temp = cbPCBABDownstreamWidth;
+		pDat->PortList[i].SelWidthOut = (u8)temp;
+		pDat->PortList[i+1].SelWidthIn = (u8)temp;
+
+		temp = pDat->PortList[i].PrvWidthInCap;
+		if (pDat->PortList[i+1].PrvWidthOutCap < temp)
+			temp = pDat->PortList[i+1].PrvWidthOutCap;
+		if (cbPCBBAUpstreamWidth < temp)
+			temp = cbPCBBAUpstreamWidth;
+		pDat->PortList[i].SelWidthIn = (u8)temp;
+		pDat->PortList[i+1].SelWidthOut = (u8)temp;
+
+	}
+}
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * hammerSublinkFixup(sMainData *pDat)
+ *
+ *  Description:
+ *	 Iterate through all links, checking the frequency of each sublink pair.  Make the
+ *	 adjustment to the port list data so that the frequencies are at a valid ratio,
+ *	 reducing frequency as needed to achieve this. (All links support the minimum 200 MHz
+ *	 frequency.)  Repeat the above until no adjustments are needed.
+ *	 Note no hardware state changes in this routine.
+ *
+ *  Parameters:
+ *	@param[in,out] sMainData* pDat = our global state, link state and port list
+ * ---------------------------------------------------------------------------------------
+ */
+void hammerSublinkFixup(sMainData *pDat)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u8 i, j, k;
+	BOOL changes, downgrade;
+
+	u8 hiIndex;
+	u8 hiFreq, loFreq;
+
+	u32 temp;
+
+	do
+	{
+		changes = FALSE;
+		for (i = 0; i < pDat->TotalLinks*2; i++)
+		{
+			if (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) // Must be a CPU link
+				continue;
+			if (pDat->PortList[i].Link < 4) // Only look for for sublink1's
+				continue;
+
+			for (j = 0; j < pDat->TotalLinks*2; j++)
+			{
+				// Step 1. Find the matching sublink0
+				if (pDat->PortList[j].Type != PORTLIST_TYPE_CPU)
+					continue;
+				if (pDat->PortList[j].NodeID != pDat->PortList[i].NodeID)
+					continue;
+				if (pDat->PortList[j].Link != (pDat->PortList[i].Link & 0x03))
+					continue;
+
+				// Step 2. Check for an illegal frequency ratio
+				if (pDat->PortList[i].SelFrequency >= pDat->PortList[j].SelFrequency)
+				{
+					hiIndex = i;
+					hiFreq = pDat->PortList[i].SelFrequency;
+					loFreq = pDat->PortList[j].SelFrequency;
+				}
+				else
+				{
+					hiIndex = j;
+					hiFreq = pDat->PortList[j].SelFrequency;
+					loFreq = pDat->PortList[i].SelFrequency;
+				}
+
+				if (hiFreq == loFreq)
+					break; // The frequencies are 1:1, no need to do anything
+
+				downgrade = FALSE;
+
+				if (hiFreq == 13)
+				{
+					if ((loFreq != 7) &&  //{13, 7} 2400MHz / 1200MHz 2:1
+					    (loFreq != 4) &&  //{13, 4} 2400MHz / 600MHz 4:1
+					    (loFreq != 2) )   //{13, 2} 2400MHz / 400MHz 6:1
+						downgrade = TRUE;
+				}
+				else if (hiFreq == 11)
+				{
+					if ((loFreq != 6))	//{11, 6} 2000MHz / 1000MHz 2:1
+						downgrade = TRUE;
+				}
+				else if (hiFreq == 9)
+				{
+					if ((loFreq != 5) &&  //{ 9, 5} 1600MHz / 800MHz 2:1
+					    (loFreq != 2) &&  //{ 9, 2} 1600MHz / 400MHz 4:1
+					    (loFreq != 0) )   //{ 9, 0} 1600MHz / 200Mhz 8:1
+						downgrade = TRUE;
+				}
+				else if (hiFreq == 7)
+				{
+					if ((loFreq != 4) &&  //{ 7, 4} 1200MHz / 600MHz 2:1
+					    (loFreq != 0) )   //{ 7, 0} 1200MHz / 200MHz 6:1
+						downgrade = TRUE;
+				}
+				else if (hiFreq == 5)
+				{
+					if ((loFreq != 2) &&  //{ 5, 2}  800MHz / 400MHz 2:1
+					    (loFreq != 0) )   //{ 5, 0}  800MHz / 200MHz 4:1
+						downgrade = TRUE;
+				}
+				else if (hiFreq == 2)
+				{
+					if ((loFreq != 0))	   //{ 2, 0}  400MHz / 200MHz 2:1
+						downgrade = TRUE;
+				}
+				else
+				{
+					downgrade = TRUE; // no legal ratios for hiFreq
+				}
+
+				// Step 3. Downgrade the higher of the two frequencies, and set nochanges to FALSE
+				if (downgrade)
+				{
+					// Although the problem was with the port specified by hiIndex, we need to
+					// downgrade both ends of the link.
+					hiIndex = hiIndex & 0xFE; // Select the 'upstream' (i.e. even) port
+
+					temp = pDat->PortList[hiIndex].CompositeFrequencyCap;
+
+					// Remove hiFreq from the list of valid frequencies
+					temp = temp & ~((u32)1 << hiFreq);
+					ASSERT (temp != 0);
+					pDat->PortList[hiIndex].CompositeFrequencyCap = (u16)temp;
+					pDat->PortList[hiIndex+1].CompositeFrequencyCap = (u16)temp;
+
+					for (k = 15; ; k--)
+					{
+						if (temp & ((u32)1 << k))
+							break;
+					}
+
+					pDat->PortList[hiIndex].SelFrequency = k;
+					pDat->PortList[hiIndex+1].SelFrequency = k;
+
+					changes = TRUE;
+				}
+			}
+		}
+	} while (changes); // Repeat until a valid configuration is reached
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * linkOptimization(sMainData *pDat)
+ *
+ *  Description:
+ *	 Based on link capabilities, apply optimization rules to come up with the real best
+ *	 settings, including several external limit decision from call backs. This includes
+ *	 handling of sublinks.	Finally, after the port list data is updated, set the hardware
+ *	 state for all links.
+ *
+ *  Parameters:
+ *	@param[in]  sMainData* pDat = our global state
+ * ---------------------------------------------------------------------------------------
+ */
+void linkOptimization(sMainData *pDat)
+{
+	pDat->nb->gatherLinkData(pDat, pDat->nb);
+	regangLinks(pDat);
+	selectOptimalWidthAndFrequency(pDat);
+	hammerSublinkFixup(pDat);
+	pDat->nb->setLinkData(pDat, pDat->nb);
+}
+
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * trafficDistribution(sMainData *pDat)
+ *
+ *  Description:
+ *	 In the case of a two node system with both sublinks used, enable the traffic
+ *	 distribution feature.
+ *
+ *  Parameters:
+ *	  @param[in]	    sMainData*	  pDat		 = our global state, port list data
+ * ---------------------------------------------------------------------------------------
+ */
+void trafficDistribution(sMainData *pDat)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 links01, links10;
+	u8 linkCount;
+	u8 i;
+
+	// Traffic Distribution is only used when there are exactly two nodes in the system
+	if (pDat->NodesDiscovered+1 != 2)
+		return;
+
+	links01 = 0;
+	links10 = 0;
+	linkCount = 0;
+	for (i = 0; i < pDat->TotalLinks*2; i += 2)
+	{
+		if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU))
+		{
+			links01 |= (u32)1 << pDat->PortList[i].Link;
+			links10 |= (u32)1 << pDat->PortList[i+1].Link;
+			linkCount++;
+		}
+	}
+	ASSERT(linkCount != 0);
+	if (linkCount == 1)
+		return; // Don't setup Traffic Distribution if only one link is being used
+
+	pDat->nb->writeTrafficDistribution(links01, links10, pDat->nb);
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * tuning(sMainData *pDat)
+ *
+ *  Description:
+ *	 Handle system and performance tunings, such as traffic distribution, fifo and
+ *	 buffer tuning, and special config tunings.
+ *
+ *  Parameters:
+ *	@param[in] sMainData* pDat = our global state, port list data
+ * ---------------------------------------------------------------------------------------
+ */
+void tuning(sMainData *pDat)
+{
+	u8 i;
+
+	/* See if traffic distribution can be done and do it if so
+	 * or allow system specific customization
+	 */
+	if ((pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution == NULL)
+		|| !pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution())
+	{
+		trafficDistribution(pDat);
+	}
+
+	/* For each node, invoke northbridge specific buffer tunings or
+	 * system specific customizations.
+	 */
+	for (i=0; i < pDat->NodesDiscovered + 1; i++)
+	{
+		if ((pDat->HtBlock->AMD_CB_CustomizeBuffers == NULL)
+		   || !pDat->HtBlock->AMD_CB_CustomizeBuffers(i))
+		{
+			pDat->nb->bufferOptimizations(i, pDat, pDat->nb);
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------------------
+ * BOOL
+ * isSanityCheckOk()
+ *
+ *  Description:
+ *	 Perform any general sanity checks which should prevent HT from running if they fail.
+ *	 Currently only the "Must run on BSP only" check.
+ *
+ *  Parameters:
+ *	@param[out] result BOOL  = true if check is ok, false if it failed
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL isSanityCheckOk()
+{
+	uint64 qValue;
+
+	AmdMSRRead(APIC_Base, &qValue);
+
+	return ((qValue.lo & ((u32)1 << APIC_Base_BSP)) != 0);
+}
+
+/***************************************************************************
+ ***				 HT Initialize				   ***
+ ***************************************************************************/
+
+/*----------------------------------------------------------------------------------------
+ * void
+ * htInitialize(AMD_HTBLOCK *pBlock)
+ *
+ *  Description:
+ *	 This is the top level external interface for Hypertransport Initialization.
+ *	 Create our initial internal state, initialize the coherent fabric,
+ *	 initialize the non-coherent chains, and perform any required fabric tuning or
+ *	 optimization.
+ *
+ *  Parameters:
+ *	@param[in] AMD_HTBLOCK*  pBlock = Our Initial State including possible
+ *				  topologies and routings, non coherent bus
+ *				  assignment info, and actual
+ *				  wrapper or OEM call back routines.
+ * ---------------------------------------------------------------------------------------
+ */
+void amdHtInitialize(AMD_HTBLOCK *pBlock)
+{
+	sMainData pDat;
+	cNorthBridge nb;
+
+	if (isSanityCheckOk())
+	{
+		newNorthBridge(0, &nb);
+
+		pDat.HtBlock = pBlock;
+		pDat.nb = &nb;
+		pDat.sysMpCap = nb.maxNodes;
+		nb.isCapable(0, &pDat, pDat.nb);
+		coherentInit(&pDat);
+
+		pDat.AutoBusCurrent = pBlock->AutoBusStart;
+		pDat.UsedCfgMapEntires = 0;
+		ncInit(&pDat);
+		linkOptimization(&pDat);
+		tuning(&pDat);
+	}
+}
Index: LinuxBIOSv2/src/northbridge/amd/amdht/h3finit.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/h3finit.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,613 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef H3FINIT_H
+#define H3FINIT_H
+
+/*----------------------------------------------------------------------------
+ *	Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ *			DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/* Width equates for call backs */
+#define HT_WIDTH_8_BITS	8
+#define HT_WIDTH_16_BITS	16
+#define HT_WIDTH_4_BITS	4
+#define HT_WIDTH_2_BITS	2
+
+/* Frequency equates for call backs which take an actual frequency setting */
+#define HT_FREQUENCY_200M	0
+#define HT_FREQUENCY_400M	2
+#define HT_FREQUENCY_600M	4
+#define HT_FREQUENCY_800M	5
+#define HT_FREQUENCY_1000M	6
+#define HT_FREQUENCY_1200M	7
+#define HT_FREQUENCY_1400M	8
+#define HT_FREQUENCY_1600M	9
+#define HT_FREQUENCY_1800M	10
+#define HT_FREQUENCY_2000M	11
+#define HT_FREQUENCY_2200M	12
+#define HT_FREQUENCY_2400M	13
+#define HT_FREQUENCY_2600M	14
+
+/* Frequency Limit equates for call backs which take a frequency supported mask. */
+#define HT_FREQUENCY_LIMIT_200M	1
+#define HT_FREQUENCY_LIMIT_400M	7
+#define HT_FREQUENCY_LIMIT_600M	0x1F
+#define HT_FREQUENCY_LIMIT_800M	0x3F
+#define HT_FREQUENCY_LIMIT_1000M	0x7F
+#define HT_FREQUENCY_LIMIT_HT1_ONLY	0x7F
+#define HT_FREQUENCY_LIMIT_1200M	0xFF
+#define HT_FREQUENCY_LIMIT_1400M	0x1FF
+#define HT_FREQUENCY_LIMIT_1600M	0x3FF
+#define HT_FREQUENCY_LIMIT_1800M	0x7FF
+#define HT_FREQUENCY_LIMIT_2000M	0xFFF
+#define HT_FREQUENCY_LIMIT_2200M	0x1FFF
+#define HT_FREQUENCY_LIMIT_2400M	0x3FFF
+#define HT_FREQUENCY_LIMIT_2600M	0x7FFF
+
+/*
+ * Event Notify definitions
+ */
+
+/* Event Class definitions */
+#define HT_EVENT_CLASS_CRITICAL	1
+#define HT_EVENT_CLASS_ERROR		2
+#define HT_EVENT_CLASS_HW_FAULT	3
+#define HT_EVENT_CLASS_WARNING		4
+#define HT_EVENT_CLASS_INFO		5
+
+/* Event definitions. */
+
+/* Coherent subfunction events */
+#define HT_EVENT_COH_EVENTS		0x1000
+#define HT_EVENT_COH_NO_TOPOLOGY	0x1001
+#define HT_EVENT_COH_LINK_EXCEED	0x1002
+#define HT_EVENT_COH_FAMILY_FEUD	0x1003
+#define HT_EVENT_COH_NODE_DISCOVERED	0x1004
+#define HT_EVENT_COH_MPCAP_MISMATCH	0x1005
+
+/* Non-coherent subfunction events */
+#define HT_EVENT_NCOH_EVENTS		0x2000
+#define HT_EVENT_NCOH_BUID_EXCEED	0x2001
+#define HT_EVENT_NCOH_LINK_EXCEED	0x2002
+#define HT_EVENT_NCOH_BUS_MAX_EXCEED	0x2003
+#define HT_EVENT_NCOH_CFG_MAP_EXCEED	0x2004
+#define HT_EVENT_NCOH_DEVICE_FAILED	0x2005
+#define HT_EVENT_NCOH_AUTO_DEPTH	0x2006
+
+/* Optimization subfunction events */
+#define HT_EVENT_OPT_EVENTS			0x3000
+#define HT_EVENT_OPT_REQUIRED_CAP_RETRY	0x3001
+#define HT_EVENT_OPT_REQUIRED_CAP_GEN3		0x3002
+
+/* HW Fault events */
+#define HT_EVENT_HW_EVENTS	0x4000
+#define HT_EVENT_HW_SYNCHFLOOD	0x4001
+#define HT_EVENT_HW_HTCRC	0x4002
+
+/* The bbHT component (hb*) uses 0x5000 for events.
+ * For consistency, we avoid that range here.
+ */
+
+/*----------------------------------------------------------------------------
+ *			TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+typedef struct {
+	u8 **topolist;
+	u8 AutoBusStart;
+	/* Note: This should always be the form AutoBusCurrent+N*AutoBusIncrement, also bus 253-255 are reserved */
+	u8 AutoBusMax;
+	u8 AutoBusIncrement;
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * BOOL
+	 * AMD_CB_IgnoreLink(u8 Node, u8 Link)
+	 *
+	 * Description:
+	 *	This routine is called every time a coherent link is found and then every
+	 *	time a non-coherent link from a CPU is found.
+	 *	Any coherent or non-coherent link from a CPU can be ignored and not used
+	 *	for discovery or initialization.  Useful for connection based systems.
+	 *	(Note: not called for IO device to IO Device links.)
+	 *
+	 * Parameters:
+	 *	@param[in]   u8   node   = The node on which this link is located
+	 *	@param[in]   u8   link   = The link about to be initialized
+	 *	@param[out]  BOOL result = true to ignore this link and skip it
+	 *				   false to initialize the link normally
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	BOOL (*AMD_CB_IgnoreLink)(u8 Node, u8 Link);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * BOOL
+	 * AMD_CB_OverrideBusNumbers(u8 Node, u8 Link, u8 *SecBus, u8 *SubBus)
+	 *
+	 * Description:
+	 *	This routine is called every time a non-coherent chain is processed.
+	 *	If a system can not use the auto Bus numbering feature for non-coherent chain bus
+	 *	assignments, this routine can provide explicit control.  For each chain, provide
+	 *	the bus number range to use.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8   node   = The node on which this chain is located
+	 *	@param[in]  u8   link   = The link on the host for this chain
+	 *	@param[out] u8   secBus = Secondary Bus number for this non-coherent chain
+	 *	@param[out] u8*  subBus = Subordinate Bus number
+	 *	@param[out] BOOL result = true this routine is supplying the bus numbers
+	 *				  false use auto Bus numbering
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	BOOL (*AMD_CB_OverrideBusNumbers)(u8 Node, u8 Link, u8 *SecBus, u8 *SubBus);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * BOOL
+	 * AMD_CB_ManualBUIDSwapList(u8 Node, u8 Link, u8 **List)
+	 *
+	 * Description:
+	 *	This routine is called every time a non-coherent chain is processed.
+	 *	BUID assignment may be controlled explicitly on a non-coherent chain. Provide a
+	 *	swap list. The first part of the list controls the BUID assignment and the
+	 *	second part of the list provides the device to device linking.  Device orientation
+	 *	can be detected automatically, or explicitly.  See documentation for more details.
+	 *
+	 *	Automatic non-coherent init assigns BUIDs starting at 1 and incrementing sequentially
+	 *	based on each device's unit count.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8  node    = The node on which this chain is located
+	 *	@param[in]  u8  link    = The link on the host for this chain
+	 *	@param[out] u8** list   = supply a pointer to a list
+	 *	@param[out] BOOL result = true to use a manual list
+	 *				  false to initialize the link automatically
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	BOOL (*AMD_CB_ManualBUIDSwapList)(u8 Node, u8 Link, u8 **List);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * void
+	 * AMD_CB_DeviceCapOverride(u8 HostNode, u8 HostLink, u8 Depth, u8 Segment,
+	 *				  u8 Bus, u8 Dev, u32 DevVenID, u8 Link,
+	 *				  u8 *LinkWidthIn, u8 *LinkWidthOut, u16 *FreqCap)
+	 *
+	 * Description:
+	 *	This routine is called once for every link on every IO device.
+	 *	Update the width and frequency capability if needed for this device.
+	 *	This is used along with device capabilities, the limit call backs, and northbridge
+	 *	limits to compute the default settings.  The components of the device's PCI config
+	 *	address are provided, so its settings can be consulted if need be. The input width
+	 *	and frequency are the reported device capabilities.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8  hostNode  = The node on which this chain is located
+	 *	@param[in]  u8  hostLink  = The link on the host for this chain
+	 *	@param[in]  u8  Depth     = The depth in the I/O chain from the Host
+	 *	@param[in]  u8  Segment   = The Device's PCI Bus Segment number
+	 *	@param[in]  u8  Bus       = The Device's PCI Bus number
+	 *	@param[in]  u8  Dev       = The Device's PCI device Number
+	 *	@param[in]  u32 DevVenID  = The Device's PCI Vendor + Device ID (offset 0x00)
+	 *	@param[in]  u8  Link      = The Device's link number (0 or 1)
+	 *	@param[in,out] u8*  LinkWidthIn  = modify to change the Link Witdh In
+	 *	@param[in,out] u8*  LinkWidthOut  = modify to change the Link Witdh Out
+	 *	@param[in,out] u16* FreqCap = modify to change the link's frequency capability
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	void (*AMD_CB_DeviceCapOverride)(
+		u8 HostNode,
+		u8 HostLink,
+		u8 Depth,
+		u8 Segment,
+		u8 Bus,
+		u8 Dev,
+		u32 DevVenID,
+		u8 Link,
+		u8 *LinkWidthIn,
+		u8 *LinkWidthOut,
+		u16 *FreqCap
+	);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * void
+	 * AMD_CB_Cpu2CpuPCBLimits(u8 NodeA, u8 LinkA, u8 NodeB, u8 LinkB,
+	 *				 u8 *ABLinkWidthLimit, u8 *BALinkWidthLimit, u16 *PCBFreqCap)
+	 *
+	 * Description:
+	 *	For each coherent connection this routine is called once.
+	 *	Update the frequency and width if needed for this link (usually based on board
+	 *	restriction).  This is used with CPU device capabilities and northbridge limits
+	 *	to compute the default settings.  The input width and frequency are valid, but do
+	 *	not necessarily reflect the minimum setting that will be chosen.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8  nodeA  = One node on which this link is located
+	 *	@param[in]  u8  linkA  = The link on this node
+	 *	@param[in]  u8  nodeB  = The other node on which this link is located
+	 *	@param[in]  u8  linkB  = The link on that node
+	 *	@param[in,out]  u8*  ABLinkWidthLimit = modify to change the Link Witdh In
+	 *	@param[in,out]  u8*  BALinkWidthLimit = modify to change the Link Witdh Out
+	 *	@param[in,out]  u16* PCBFreqCap  = modify to change the link's frequency capability
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	void (*AMD_CB_Cpu2CpuPCBLimits)(
+		u8 NodeA,
+		u8 LinkA,
+		u8 NodeB,
+		u8 LinkB,
+		u8 *ABLinkWidthLimit,
+		u8 *BALinkWidthLimit,
+		u16 *PCBFreqCap
+	);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * void
+	 * AMD_CB_IOPCBLimits(u8 HostNode, u8 HostLink, u8 Depth, u8 *DownstreamLinkWidthLimit,
+	 *			    u8 *UpstreamLinkWidthLimit, u16 *PCBFreqCap)
+	 *
+	 * Description:
+	 *	For each non-coherent connection this routine is called once.
+	 *	Update the frequency and width if needed for this link (usually based on board
+	 *	restriction).  This is used with device capabilities, device overrides, and northbridge limits
+	 *	to compute the default settings. The input width and frequency are valid, but do
+	 *	not necessarily reflect the minimum setting that will be chosen.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8  hostNode  = The node on which this link is located
+	 *	@param[in]  u8  hostLink  = The link about to be initialized
+	 *	@param[in]  u8  Depth  = The depth in the I/O chain from the Host
+	 *	@param[in,out]  u8* DownstreamLinkWidthLimit = modify to change the Link Witdh In
+	 *	@param[in,out]  u8* UpstreamLinkWidthLimit  = modify to change the Link Witdh Out
+	 *	@param[in,out]  u16* PCBFreqCap = modify to change the link's frequency capability
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	void (*AMD_CB_IOPCBLimits)(
+		u8 HostNode,
+		u8 HostLink,
+		u8 Depth,
+		u8 *DownstreamLinkWidthLimit,
+		u8 *UpstreamLinkWidthLimit,
+		u16 *PCBFreqCap
+	);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * BOOL
+	 * AMD_CB_SkipRegang(u8 NodeA, u8 LinkA, u8 NodeB, u8 LinkB)
+	 *
+	 * Description:
+	 *	This routine is called whenever two sublinks are both connected to the same CPUs.
+	 *	Normally, unganged subsinks between the same two CPUs are reganged.
+	 *	Return true from this routine to leave the links unganged.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8  nodeA   = One node on which this link is located
+	 *	@param[in]  u8  linkA   = The link on this node
+	 *	@param[in]  u8  nodeB   = The other node on which this link is located
+	 *	@param[in]  u8  linkB   = The link on that node
+	 *	@param[out] BOOL result = true to leave link unganged
+	 *				  false to regang link automatically
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	BOOL (*AMD_CB_SkipRegang)(
+		u8 NodeA,
+		u8 LinkA,
+		u8 NodeB,
+		u8 LinkB
+	);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * BOOL
+	 * AMD_CB_CustomizeTrafficDistribution()
+	 *
+	 * Description:
+	 *	Near the end of HT initialization, this routine is called once.
+	 *	If this routine will handle traffic distribution in a proprietary way,
+	 *	after detecting which links to distribute traffic on and configuring the system,
+	 *	return true. Return false to let the HT code detect and do traffic distribution
+	 *	This routine can also be used to simply turn this feature off, or to pre-process
+	 *	the system before normal traffic distribution.
+	 *
+	 * Parameters:
+	 *	@param[out]  BOOL result  = true skip traffic distribution
+	 *				    false do normal traffic distribution
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	BOOL (*AMD_CB_CustomizeTrafficDistribution)();
+
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * BOOL
+	 * AMD_CB_CustomizeBuffers(u8 Node)
+	 *
+	 * Description:
+	 *	Near the end of HT initialization, this routine is called once per CPU node.
+	 *	Implement proprietary buffer tuning and return true, or return false for normal tuning.
+	 *	This routine can also be used to simply turn this feature off, or to pre-process
+	 *	the system before normal tuning.
+	 *
+	 * Parameters:
+	 *	@param[in] u8 node  = buffer allocation may apply to this node
+	 *	@param[out] BOOL  result  = true skip buffer allocation on this node
+	 *				    false tune buffers normally
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	BOOL (*AMD_CB_CustomizeBuffers)( u8 node );
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * void
+	 * AMD_CB_OverrideDevicePort(u8 HostNode, u8 HostLink, u8 Depth, u8 *LinkWidthIn,
+	 *				   u8 *LinkWidthOut, u16 *LinkFrequency)
+	 *
+	 * Description:
+	 *	Called once for each active link on each IO device.
+	 *	Provides an opportunity to directly control the frequency and width,
+	 *	intended for test and debug.  The input frequency and width will be used
+	 *	if not overridden.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8   hostNode  = The node on which this link is located
+	 *	@param[in]  u8   hostLink  = The link about to be initialized
+	 *	@param[in]  u8   Depth     = The depth in the I/O chain from the Host
+	 *	@param[in]  u8   Link      = the link on the device (0 or 1)
+	 *	@param[in,out]  u8*   LinkWidthIn    = modify to change the Link Witdh In
+	 *	@param[in,out]  u8*   LinkWidthOut   = modify to change the Link Witdh Out
+	 *	@param[in,out]  u16*   LinkFrequency = modify to change the link's frequency capability
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	void (*AMD_CB_OverrideDevicePort)(
+		u8 HostNode,
+		u8 HostLink,
+		u8 Depth,
+		u8 Link,
+		u8 *LinkWidthIn,
+		u8 *LinkWidthOut,
+		u8 *LinkFrequency
+	);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * void
+	 * AMD_CB_OverrideCpuPort(u8 Node, u8 Link, u8 *LinkWidthIn, u8 *LinkWidthOut,
+	 *				u16 *LinkFrequency)
+	 *
+	 * Description:
+	 *	Called once for each active link on each CPU.
+	 *	Provides an opportunity to directly control the frequency and width,
+	 *	intended for test and debug. The input frequency and width will be used
+	 *	if not overridden.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8  node  = One node on which this link is located
+	 *	@param[in]  u8  link  = The link on this node
+	 *	@param[in,out]  u8*  LinkWidthIn = modify to change the Link Witdh In
+	 *	@param[in,out]  u8*  LinkWidthOut = modify to change the Link Witdh Out
+	 *	@param[in,out]  u16*  LinkFrequency  = modify to change the link's frequency capability
+	 *
+	 *---------------------------------------------------------------------------------------
+	 */
+	void (*AMD_CB_OverrideCpuPort)(
+		u8 Node,
+		u8 Link,
+		u8 *LinkWidthIn,
+		u8 *LinkWidthOut,
+		u8 *LinkFrequency
+	);
+
+	/**----------------------------------------------------------------------------------------
+	 *
+	 * void
+	 * AMD_CB_EventNotify(u8 evtClass, u16 event, const u8 *pEventData0)
+	 *
+	 * Description:
+	 *	Errors, events, faults, warnings, and useful information are provided by
+	 *	calling this routine as often as necessary, once for each notification.
+	 *	See elsewhere in this file for class, event, and event data definitions.
+	 *	See the documentation for more details.
+	 *
+	 * Parameters:
+	 *	@param[in]  u8  evtClass = What level event is this
+	 *	@param[in]  u16 event = A unique ID of this event
+	 *	@param[in]  u8* pEventData0 = useful data associated with the event.
+	 *
+	 * ---------------------------------------------------------------------------------------
+	 */
+	void (*AMD_CB_EventNotify) (
+		u8 evtClass,
+		u16 event,
+		const u8 *pEventData0
+	);
+
+} AMD_HTBLOCK;
+
+/*
+ * Event Notification Structures
+ * These structures are passed to AMD_CB_EventNotify as *pEventData0.
+ */
+
+/* For event HT_EVENT_HW_SYNCHFLOOD */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+} sHtEventHWSynchFlood;
+
+/* For event HT_EVENT_HW_HTCRC */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 laneMask;
+} sHtEventHWHtCrc;
+
+/* For event HT_EVENT_NCOH_BUS_MAX_EXCEED */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 bus;
+} sHTEventNcohBusMaxExceed;
+
+/* For event HT_EVENT_NCOH_LINK_EXCEED */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 depth;
+	u8 maxLinks;
+} sHtEventNcohLinkExceed;
+
+/* For event HT_EVENT_NCOH_CFG_MAP_EXCEED */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+} sHtEventNcohCfgMapExceed;
+
+/* For event HT_EVENT_NCOH_BUID_EXCEED */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 depth;
+	u8 currentBUID;
+	u8 unitCount;
+} sHtEventNcohBuidExceed;
+
+/* For event HT_EVENT_NCOH_DEVICE_FAILED */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 depth;
+	u8 attemptedBUID;
+} sHtEventNcohDeviceFailed;
+
+/* For event HT_EVENT_NCOH_AUTO_DEPTH */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 depth;
+} sHtEventNcohAutoDepth;
+
+/* For event HT_EVENT_OPT_REQUIRED_CAP_RETRY,
+ *	      HT_EVENT_OPT_REQUIRED_CAP_GEN3
+ */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 depth;
+} sHtEventOptRequiredCap;
+
+/* For event HT_EVENT_COH_NO_TOPOLOGY */
+typedef struct
+{
+	u8 eSize;
+	u8 totalNodes;
+} sHtEventCohNoTopology;
+
+/* For event HT_EVENT_COH_LINK_EXCEED */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 targetNode;
+	u8 totalNodes;
+	u8 maxLinks;
+} sHtEventCohLinkExceed;
+
+/* For event HT_EVENT_COH_FAMILY_FEUD */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 totalNodes;
+} sHtEventCohFamilyFeud;
+
+/* For event HT_EVENT_COH_NODE_DISCOVERED */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 newNode;
+} sHtEventCohNodeDiscovered;
+
+/* For event HT_EVENT_COH_MPCAP_MISMATCH */
+typedef struct
+{
+	u8 eSize;
+	u8 node;
+	u8 link;
+	u8 sysMpCap;
+	u8 totalNodes;
+} sHtEventCohMpCapMismatch;
+
+/*----------------------------------------------------------------------------
+ *			FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+void amdHtInitialize(AMD_HTBLOCK *pBlock);
+
+
+#endif	 /* H3FINIT_H */
+
+
Index: LinuxBIOSv2/src/northbridge/amd/amdht/h3gtopo.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/h3gtopo.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,358 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef HTTOPO_H
+#define HTTOPO_H
+
+/*----------------------------------------------------------------------------
+ *   Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ *			DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *			TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*
+ *   0
+ */
+static u8 const amdHtTopologySingleNode[] = {
+	0x01,
+	0x00, 0xFF	// Node 0
+};
+
+/*
+ *   0---1
+ */
+static u8 const amdHtTopologyDualNode[] = {
+	0x02,
+	0x02, 0xFF, 0x00, 0x11,	// Node 0
+	0x00, 0x00, 0x01, 0xFF	// Node 1
+};
+
+/*
+ *   2
+ *   |
+ *   |
+ *   0---1
+ */
+static u8 const amdHtTopologyThreeLine[] = {
+	0x03,
+	0x06, 0xFF, 0x04, 0x11, 0x02, 0x22,	// Node 0
+	0x00, 0x00, 0x01, 0xFF, 0x00, 0x00,	// Node 1
+	0x00, 0x00, 0x00, 0x00, 0x01, 0xFF	// Node 2
+};
+
+/*
+ *   2
+ *   |\
+ *   |  \
+ *   0---1
+ */
+static u8 const amdHtTopologyTriangle[] = {
+	0x03,
+	0x06, 0xFF, 0x00, 0x11, 0x00, 0x22,	// Node 0
+	0x00, 0x00, 0x05, 0xFF, 0x00, 0x22,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0x03, 0xFF	// Node 2
+};
+
+/*
+ *   2   3
+ *   |\  |
+ *   |  \|
+ *   0---1
+ */
+static u8 const amdHtTopologyFourDegenerate[] = {
+	0x04,
+	0x06, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x11,	// Node 0
+	0x08, 0x00, 0x0D, 0xFF, 0x08, 0x22, 0x05, 0x33,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0x03, 0xFF, 0x00, 0x11,	// Node 2
+	0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x02, 0xFF	// Node 3
+};
+
+/*
+ *   2---3
+ *   |\ /|
+ *   |/ \|
+ *   0---1
+ */
+static u8 const amdHtTopologyFourFully[] = {
+	0x04,
+	0x0E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33,	// Node 0
+	0x00, 0x00, 0x0D, 0xFF, 0x00, 0x22, 0x00, 0x33,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0x0B, 0xFF, 0x00, 0x33,	// Node 2
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x07, 0xFF	// Node 3
+};
+
+
+/*
+ *   2---3
+ *   |\  |
+ *   |  \|
+ *   0---1
+ */
+static u8 const amdHtTopologyFourKite[] = {
+	0x04,
+	0x06, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x11,	// Node 0
+	0x08, 0x00, 0x0D, 0xFF, 0x00, 0x22, 0x00, 0x33,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0x0B, 0xFF, 0x01, 0x33,	// Node 2
+	0x00, 0x22, 0x00, 0x11, 0x00, 0x22, 0x06, 0xFF	// Node 3
+};
+
+
+/*
+ *   2   3
+ *   |   |
+ *   |   |
+ *   0---1
+ */
+static u8 const amdHtTopologyFourLine[] = {
+	0x04,
+	0x06, 0xFF, 0x04, 0x11, 0x02, 0x22, 0x04, 0x11,	// Node 0
+	0x08, 0x00, 0x09, 0xFF, 0x08, 0x00, 0x01, 0x33,	// Node 1
+	0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00,	// Node 2
+	0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x02, 0xFF	// Node 3
+};
+
+
+/*
+ *   2---3
+ *   |   |
+ *   |   |
+ *   0---1
+ */
+static u8 const amdHtTopologyFourSquare[] = {
+	0x04,
+	0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x22,	// Node 0
+	0x00, 0x00, 0x09, 0xFF, 0x00, 0x33, 0x01, 0x33,	// Node 1
+	0x08, 0x00, 0x00, 0x00, 0x09, 0xFF, 0x00, 0x33,	// Node 2
+	0x00, 0x11, 0x04, 0x11, 0x00, 0x22, 0x06, 0xFF,	// Node 3
+};
+
+
+/*
+ *   2---3
+ *   |\
+ *   |  \
+ *   0   1
+ */
+static u8 const amdHtTopologyFourStar[] = {
+	0x04,
+	0x04, 0xFF, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22,	// Node 0
+	0x00, 0x22, 0x04, 0xFF, 0x00, 0x22, 0x00, 0x22,	// Node 1
+	0x0A, 0x00, 0x09, 0x11, 0x0B, 0xFF, 0x03, 0x33,	// Node 2
+	0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x04, 0xFF,	// Node 3
+};
+
+
+static u8 const amdHtTopologyFiveFully[] = {
+	0x05,
+	0x1E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44,	// Node 0
+	0x00, 0x00, 0x1D, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0x1B, 0xFF, 0x00, 0x33, 0x00, 0x44,	// Node 2
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x17, 0xFF, 0x00, 0x44,	// Node 3
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x0F, 0xFF	// Node 4
+};
+
+
+/*
+ *
+ *  4
+ *  |\
+ *  |  \
+ *  2   3
+ *  |   |
+ *  0---1
+ */
+static u8 const amdHtTopologyFiveTwistedLadder[] = {
+	0x05,
+	0x06, 0xFF, 0x04, 0x11, 0x02, 0x22, 0x00, 0x11, 0x00, 0x22,	// Node0
+	0x08, 0x00, 0x09, 0xFF, 0x08, 0x00, 0x01, 0x33, 0x00, 0x30,	// Node1
+	0x10, 0x00, 0x10, 0x00, 0x11, 0xFF, 0x00, 0x40, 0x01, 0x44,	// Node2
+	0x00, 0x11, 0x00, 0x11, 0x00, 0x14, 0x12, 0xFF, 0x02, 0x44,	// Node3
+	0x00, 0x22, 0x00, 0x23, 0x00, 0x22, 0x04, 0x33, 0x0C, 0xFF	// Node4
+};
+
+
+static u8 const amdHtTopologySixFully[] = {
+	0x06,
+	0x3E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55,	// Node 0
+	0x00, 0x00, 0x3D, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0x3B, 0xFF, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55,	// Node 2
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x37, 0xFF, 0x00, 0x44, 0x00, 0x55,	// Node 3
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x2F, 0xFF, 0x00, 0x55,	// Node 4
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x1F, 0xFF	// Node 5
+};
+
+/*
+ *
+ *  4   5
+ *  |\ /|
+ *  |/ \|
+ *  2   3
+ *  |   |
+ *  0---1
+ */
+static u8 const amdHtTopologySixTwistedLadder[] = {
+	0x06,
+	0x06, 0xFF, 0x04, 0x11, 0x02, 0x22, 0x00, 0x11, 0x02, 0x22, 0x00, 0x12,	// Node0
+	0x08, 0x00, 0x09, 0xFF, 0x00, 0x00, 0x01, 0x33, 0x00, 0x03, 0x01, 0x33,	// Node1
+	0x30, 0x00, 0x00, 0x00, 0x31, 0xFF, 0x00, 0x54, 0x21, 0x44, 0x00, 0x55,	// Node2
+	0x00, 0x11, 0x30, 0x11, 0x00, 0x45, 0x32, 0xFF, 0x00, 0x44, 0x12, 0x55,	// Node3
+	0x00, 0x22, 0x00, 0x32, 0x08, 0x22, 0x00, 0x33, 0x0C, 0xFF, 0x00, 0x32,	// Node4
+	0x00, 0x23, 0x00, 0x33, 0x00, 0x22, 0x04, 0x33, 0x00, 0x23, 0x0C, 0xFF	// Node5
+};
+
+
+static u8 const amdHtTopologySevenFully[] = {
+	0x07,
+	0x7E, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66,	// Node 0
+	0x00, 0x00, 0x7D, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0x7B, 0xFF, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66,	// Node 2
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x77, 0xFF, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66,	// Node 3
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x6F, 0xFF, 0x00, 0x55, 0x00, 0x66,	// Node 4
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x5F, 0xFF, 0x00, 0x66,	// Node 5
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x3F, 0xFF,	// Node 6
+};
+
+
+/*  6
+ *  |
+ *  4   5
+ *  |\ /|
+ *  |/ \|
+ *  2   3
+ *  |   |
+ *  0---1
+ */
+static u8 const amdHtTopologySevenTwistedLadder[] = {
+	0x07,
+	0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x12, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22,	// Node0
+	0x00, 0x00, 0x09, 0xFF, 0x00, 0x03, 0x01, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,	// Node1
+	0x30, 0x00, 0x00, 0x50, 0x31, 0xFF, 0x00, 0x54, 0x21, 0x44, 0x01, 0x55, 0x21, 0x44,	// Node2
+	0x00, 0x41, 0x30, 0x11, 0x00, 0x45, 0x32, 0xFF, 0x02, 0x44, 0x12, 0x55, 0x02, 0x44,	// Node3
+	0x48, 0x22, 0x40, 0x33, 0x48, 0x22, 0x40, 0x33, 0x4C, 0xFF, 0x40, 0x32, 0x0C, 0x66,	// Node4
+	0x00, 0x22, 0x04, 0x33, 0x00, 0x22, 0x04, 0x33, 0x00, 0x23, 0x0C, 0xFF, 0x00, 0x23,	// Node5
+	0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x10, 0xFF 	// Node6
+};
+
+
+/*
+ *   5--4
+ *  /####\
+ * 6######3
+ * |######|
+ * 7######2
+ *  \####/
+ *   0--1
+ */
+static u8 const amdHtTopologyEightFully [] = {
+	0x08,
+	0xFE, 0xFF, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77,	// Node 0
+	0x00, 0x00, 0xFD, 0xFF, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77,	// Node 1
+	0x00, 0x00, 0x00, 0x11, 0xFB, 0xFF, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77,	// Node 2
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0xF7, 0xFF, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77,	// Node 3
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0xEF, 0xFF, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77,	// Node 4
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0xDF, 0xFF, 0x00, 0x66, 0x00, 0x77,	// Node 5
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0xBF, 0xFF, 0x00, 0x77,	// Node 6
+	0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x7F, 0xFF	// Node 7
+};
+
+
+/*  6---7
+ *  |   |
+ *  4---5
+ *  |   |
+ *  2---3
+ *  |   |
+ *  0---1
+ */
+static u8 const amdHtTopologyEightStraightLadder[] = {
+	0x08,
+	0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x22, 0x02, 0x22, 0x00, 0x22, 0x02, 0x22, 0x00, 0x22,	// Node0
+	0x00, 0x00, 0x09, 0xFF, 0x00, 0x33, 0x01, 0x33, 0x00, 0x33, 0x01, 0x33, 0x00, 0x33, 0x01, 0x33,	// Node1
+	0x18, 0x00, 0x00, 0x00, 0x19, 0xFF, 0x00, 0x33, 0x09, 0x44, 0x00, 0x44, 0x09, 0x44, 0x00, 0x44,	// Node2
+	0x00, 0x11, 0x24, 0x11, 0x00, 0x22, 0x26, 0xFF, 0x00, 0x55, 0x06, 0x55, 0x00, 0x55, 0x06, 0x55,	// Node3
+	0x60, 0x22, 0x00, 0x22, 0x60, 0x22, 0x00, 0x22, 0x64, 0xFF, 0x00, 0x55, 0x24, 0x66, 0x00, 0x66,	// Node4
+	0x00, 0x33, 0x90, 0x33, 0x00, 0x33, 0x90, 0x33, 0x00, 0x44, 0x98, 0xFF, 0x00, 0x77, 0x18, 0x77,	// Node5
+	0x80, 0x44, 0x00, 0x44, 0x80, 0x44, 0x00, 0x44, 0x80, 0x44, 0x00, 0x44, 0x90, 0xFF, 0x00, 0x77,	// Node6
+	0x00, 0x55, 0x40, 0x55, 0x00, 0x55, 0x40, 0x55, 0x00, 0x55, 0x40, 0x55, 0x00, 0x66, 0x60, 0xFF	// Node7
+};
+
+
+/*  6---7
+ *  |   |
+ *  4   5
+ *  |\ /|
+ *  |/ \|
+ *  2   3
+ *  |   |
+ *  0---1
+ */
+static u8 const amdHtTopologyEightTwistedLadder[] = {
+	0x08,
+	0x06, 0xFF, 0x00, 0x11, 0x02, 0x22, 0x00, 0x12, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22,	// Node0
+	0x00, 0x00, 0x09, 0xFF, 0x00, 0x03, 0x01, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,	// Node1
+	0x30, 0x00, 0x00, 0x50, 0x31, 0xFF, 0x00, 0x54, 0x21, 0x44, 0x01, 0x55, 0x21, 0x44, 0x01, 0x55,	// Node2
+	0x00, 0x41, 0x30, 0x11, 0x00, 0x45, 0x32, 0xFF, 0x02, 0x44, 0x12, 0x55, 0x02, 0x44, 0x12, 0x55,	// Node3
+	0x48, 0x22, 0x40, 0x33, 0x48, 0x22, 0x40, 0x33, 0x4C, 0xFF, 0x00, 0x32, 0x0C, 0x66, 0x00, 0x36,	// Node4
+	0x80, 0x22, 0x84, 0x33, 0x80, 0x22, 0x84, 0x33, 0x00, 0x23, 0x8C, 0xFF, 0x00, 0x27, 0x0C, 0x77,	// Node5
+	0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x80, 0x44, 0x00, 0x74, 0x90, 0xFF, 0x00, 0x77,	// Node6
+	0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x65, 0x40, 0x55, 0x00, 0x66, 0x60, 0xFF	// Node7
+};
+
+static const u8 * const amd_topo_list[] = {
+	amdHtTopologySingleNode,
+	amdHtTopologyDualNode,
+	amdHtTopologyThreeLine,
+	amdHtTopologyTriangle,
+	amdHtTopologyFourLine,
+	amdHtTopologyFourStar,
+	amdHtTopologyFourDegenerate,
+	amdHtTopologyFourSquare,
+	amdHtTopologyFourKite,
+	amdHtTopologyFourFully,
+	amdHtTopologyFiveFully,
+	amdHtTopologySixFully,
+	amdHtTopologySevenFully,
+	amdHtTopologyEightFully,
+	amdHtTopologyEightTwistedLadder,
+	amdHtTopologyEightStraightLadder,
+	NULL			// NULL to mark end of list
+};
+
+/*----------------------------------------------------------------------------
+ *			FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+void getAmdTopolist(u8 ***p);
+
+
+#endif	 /* HTTOPO_H */
+
Index: LinuxBIOSv2/src/northbridge/amd/amdht/h3ncmn.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/h3ncmn.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,2214 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#undef FILECODE
+#define FILECODE 0xF002
+#include "h3finit.h"
+#include "h3ffeat.h"
+#include "h3ncmn.h"
+#include "AsPsNb.h"
+
+
+/*----------------------------------------------------------------------------
+ *			DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* CPU Northbridge Functions */
+#define CPU_HTNB_FUNC_00		0
+#define CPU_HTNB_FUNC_04		4
+#define CPU_ADDR_FUNC_01		1
+#define CPU_NB_FUNC_03			3
+
+/* Function 0 registers */
+#define REG_ROUTE0_0X40		0x40
+#define REG_ROUTE1_0X44		0x44
+#define REG_NODE_ID_0X60		0x60
+#define REG_UNIT_ID_0X64		0x64
+#define REG_LINK_TRANS_CONTROL_0X68	0x68
+#define REG_LINK_INIT_CONTROL_0X6C	0x6C
+#define REG_HT_CAP_BASE_0X80		0x80
+#define REG_HT_LINK_RETRY0_0X130	0x130
+#define REG_HT_TRAFFIC_DIST_0X164	0x164
+#define REG_HT_LINK_EXT_CONTROL0_0X170	0x170
+
+#define HT_CONTROL_CLEAR_CRC		(~(3 << 8))
+
+/* Function 1 registers */
+#define REG_ADDR_CONFIG_MAP0_1XE0	0xE0
+#define CPU_ADDR_NUM_CONFIG_MAPS	4
+
+/* Function 3 registers */
+#define REG_NB_SRI_XBAR_BUF_3X70	0x70
+#define REG_NB_MCT_XBAR_BUF_3X78	0x78
+#define REG_NB_FIFOPTR_3XDC		0xDC
+#define REG_NB_CAPABILITY_3XE8		0xE8
+#define REG_NB_CPUID_3XFC		0xFC
+#define REG_NB_LINK_XCS_TOKEN0_3X148	0x148
+#define REG_NB_DOWNCORE_3X190		0x190
+
+/* Function 4 registers */
+
+
+/*----------------------------------------------------------------------------
+ *			TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+/*----------------------------------------------------------------------------
+ *			PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/***************************************************************************
+ ***			FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS		***
+ ***************************************************************************/
+
+/**----------------------------------------------------------------------------------------
+ *
+ * SBDFO
+ * makeLinkBase(u8 currentNode, u8 currentLink)
+ *
+ *  Description:
+ *	Private to northbridge implementation. Return the HT Host capability base
+ *	PCI config address for a link.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node    = the node this link is on
+ *	@param[in]  u8  link    = the link
+ *	@param[out] SBDFO  result  = the pci config address
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+static SBDFO makeLinkBase(u8 node, u8 link)
+{
+	SBDFO linkBase;
+
+	/* With rev F can not be called with a 4th link or with the sublinks */
+	if (link < 4)
+		linkBase = MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_00,
+				REG_HT_CAP_BASE_0X80 + link*HT_HOST_CAP_SIZE);
+	else
+		linkBase = MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_04,
+				REG_HT_CAP_BASE_0X80 + (link-4)*HT_HOST_CAP_SIZE);
+	return linkBase;
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue)
+ *
+ *  Description:
+ *	Private to northbridge implementation. Provide a common routine for accessing the
+ *	HT Link Control registers (84, a4, c4, e4), to enforce not clearing the
+ *	HT CRC error bits.  Replaces direct use of AmdPCIWriteBits().
+ *	NOTE: This routine is called for IO Devices as well as CPUs!
+ *
+ *  Parameters:
+ *	@param[in]  SBDFO  reg    = the PCI config address the control register
+ *	@param[in]  u8  hiBit  = the high bit number
+ *	@param[in]  u8  loBit  = the low bit number
+ *	@param[in]  u8  pValue = the value to write to that bit range. Bit 0 => loBit.
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+static void setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue)
+{
+	u32 temp, mask;
+
+	ASSERT((hiBit < 32) && (loBit < 32) && (hiBit >= loBit) && ((reg & 0x3) == 0));
+	ASSERT((hiBit < 8) || (loBit > 9));
+
+	/* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
+	if ((hiBit-loBit) != 31)
+		mask = (((u32)1 << (hiBit-loBit+1))-1);
+	else
+		mask = (u32)0xFFFFFFFF;
+
+	AmdPCIRead(reg, &temp);
+	temp &= ~(mask << loBit);
+	temp |= (*pValue & mask) << loBit;
+	temp &= (u32)HT_CONTROL_CLEAR_CRC;
+	AmdPCIWrite(reg, &temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * writeRoutingTable(u8 node, u8 target, u8 Link, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 This routine will modify the routing tables on the
+ *	 SourceNode to cause it to route both request and response traffic to the
+ *	 targetNode through the specified Link.
+ *
+ *	 NOTE: This routine is to be used for early discovery and initialization.  The
+ *	 final routing tables must be loaded some other way because this
+ *	 routine does not address the issue of probes, or independent request
+ *	 response paths.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node    = the node that will have it's routing tables modified.
+ *	@param[in]  u8  target  = For routing to node target
+ *	@param[in]  u8  Link    =  Link from node to target
+ *	@param[in]  cNorthBridge *nb   = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+
+void writeRoutingTable(u8 node, u8 target, u8 link, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 temp = (nb->selfRouteResponseMask | nb->selfRouteRequestMask) << (link + 1);
+	ASSERT((node < nb->maxNodes) && (target < nb->maxNodes) && (link < nb->maxLinks));
+	AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node),
+			makePCIBusFromNode(node),
+			makePCIDeviceFromNode(node),
+			CPU_HTNB_FUNC_00,
+			REG_ROUTE0_0X40 + target*4),
+			&temp);
+#else
+	STOP_HERE;
+#endif
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Modifies the NodeID register on the target node
+ *
+ *  Parameters:
+ *	@param[in] u8  node    = the node that will have its NodeID altered.
+ *	@param[in] u8  nodeID  = the new value for NodeID
+ *	@param[in] cNorthBridge *nb = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+
+void writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
+{
+	u32 temp = nodeID;
+	ASSERT((node < nb->maxNodes) && (nodeID < nb->maxNodes));
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_00,
+				REG_NODE_ID_0X60),
+				2, 0, &temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * readDefLnk(u8 node, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Read the DefLnk (the source link of the current packet)
+ *	 from node
+ *
+ *  Parameters:
+ *	@param[in] u8    node    = the node that will have its NodeID altered.
+ *	@param[in] cNorthBridge *nb = this northbridge
+ *	@param[out] u8    result = The HyperTransport link where the request to
+ *				read the default link came from.  Since this
+ *				code is running on the BSP, this should be the link
+ *				pointing back towards the BSP.
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+
+u8 readDefLnk(u8 node, cNorthBridge *nb)
+{
+	u32 deflink = 0;
+	SBDFO licr;
+	u32 temp;
+
+	licr = MAKE_SBDFO(makePCISegmentFromNode(node),
+			makePCIBusFromNode(node),
+			makePCIDeviceFromNode(node),
+			CPU_HTNB_FUNC_00,
+			REG_LINK_INIT_CONTROL_0X6C);
+
+	ASSERT((node < nb->maxNodes));
+	AmdPCIReadBits(licr, 3, 2, &deflink);
+	AmdPCIReadBits(licr, 8, 8, &temp);	/* on rev F, this bit is reserved == 0 */
+	deflink |= temp << 2;
+	return (u8)deflink;
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * enableRoutingTables(u8 node, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Turns routing tables on for a given node
+ *
+ *  Parameters:
+ *	@param[in]  u8    node     = the node that will have it's routing tables enabled
+ *	@param[in]  cNorthBridge *nb  = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+
+void enableRoutingTables(u8 node, cNorthBridge *nb)
+{
+	u32 temp = 0;
+	ASSERT((node < nb->maxNodes));
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_00,
+				REG_LINK_INIT_CONTROL_0X6C),
+				0, 0, &temp);
+}
+
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * verifyLinkIsCoherent(u8 node, u8 Link, cNorthBridge *nbk)
+ *
+ *  Description:
+ *	Verify that the link is coherent, connected, and ready
+ *
+ *  Parameters:
+ *	@param[in]   u8  node      = the node that will be examined
+ *	@param[in]   u8  link      = the link on that Node to examine
+ *	@param[in]   cNorthBridge *nb = this northbridge
+ *	@param[out]  u8  result    = true - The link has the following status
+ *				  linkCon=1,	       Link is connected
+ *				  InitComplete=1,      Link initialization is complete
+ *				  NC=0,		       Link is coherent
+ *				  UniP-cLDT=0,	       Link is not Uniprocessor cLDT
+ *				  LinkConPend=0	       Link connection is not pending
+ *				  false- The link has some other status
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+
+BOOL verifyLinkIsCoherent(u8 node, u8 link, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+
+	u32 linkType;
+	SBDFO linkBase;
+
+	ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
+
+	linkBase = makeLinkBase(node, link);
+
+	// FN0_98/A4/C4 = LDT Type Register
+	AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType);
+
+	// Verify LinkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0
+	return (linkType & HTHOST_TYPE_MASK) ==  HTHOST_TYPE_COHERENT;
+#else
+	return 0;
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * bool
+ * readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Return the LinkFailed status AFTER an attempt is made to clear the bit.
+ *	Also, call event notify if a Hardware Fault caused a synch flood on a previous boot.
+ *
+ *	The table below summarizes correct responses of this routine.
+ *	Family	  before    after    unconnected    Notify?    return
+ *	  0F         0       0          0             No         0
+ *	  0F         1       0          0             Yes        0
+ *	  0F         1       1          X             No         1
+ *	  10         0       0          0             No         0
+ *	  10         1       0          0             Yes        0
+ *	  10         1       0          3             No         1
+ *
+ *  Parameters:
+ *	@param[in]    u8  node      = the node that will be examined
+ *	@param[in]    u8  link      = the link on that node to examine
+ *	@param[in]    u8  sMainData = access to call back routine
+ *	@param[in]    cNorthBridge *nb = this northbridge
+ *	@param[out]   u8  result    = true - the link is not connected or has hard error
+ *					false- if the link is connected
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb)
+{
+	u32 before, after, unconnected, crc;
+	SBDFO linkBase;
+
+	ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
+
+	linkBase = makeLinkBase(node, link);
+
+	/* Save the CRC status before doing anything else.
+	 * Read, Clear, the Re-read the error bits in the Link Control Register
+	 * FN0_84/A4/C4[4] = LinkFail bit
+	 * and the connection status, TransOff and EndOfChain
+	 */
+	AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 9, 8, &crc);
+	AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before);
+	setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before);
+	AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &after);
+	AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &unconnected);
+
+	if (before != after)
+	{
+		if (!unconnected)
+		{
+			if (crc != 0)
+			{
+				/* A synch flood occurred due to HT CRC */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					/* Pass the node and link on which the generic synch flood event occurred. */
+					sHtEventHWHtCrc evt = {sizeof(sHtEventHWHtCrc), node, link, (u8)crc};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
+									HT_EVENT_HW_HTCRC,
+									(u8 *)&evt);
+				}
+			}
+			else
+			{
+				/* Some synch flood occurred */
+				if (pDat->HtBlock->AMD_CB_EventNotify)
+				{
+					/* Pass the node and link on which the generic synch flood event occurred. */
+					sHtEventHWSynchFlood evt = {sizeof(sHtEventHWSynchFlood), node, link};
+
+					pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
+									HT_EVENT_HW_SYNCHFLOOD,
+									(u8 *)&evt);
+				}
+			}
+		}
+	}
+	return ((after != 0) || unconnected);
+}
+
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u8
+ * readToken(u8 node, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Read the token stored in the scratchpad register
+ *	NOTE: The location used to store the token is arbitrary.  The only
+ *	requirement is that the location warm resets to zero, and that
+ *	using it will have no ill-effects during HyperTransport initialization.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node      = the node that will be examined
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u8  result    = the Token read from the node
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u8 readToken(u8 node, cNorthBridge *nb)
+{
+	u32 temp;
+
+	ASSERT((node < nb->maxNodes));
+	/* Use CpuCnt as a scratch register */
+	/* Limiting use to 4 bits makes code GH to rev F compatible. */
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_00,
+				REG_NODE_ID_0X60),
+				19, 16, &temp);
+
+	return (u8)temp;
+}
+
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * writeToken(u8 node, u8 Value, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Write the token stored in the scratchpad register
+ *	NOTE: The location used to store the token is arbitrary.  The only
+ *	requirement is that the location warm resets to zero, and that
+ *	using it will have no ill-effects during HyperTransport initialization.
+ *	Limiting use to 4 bits makes code GH to rev F compatible.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node  = the node that will be examined
+ *	@param[in]  cNorthBridge *nb  = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void writeToken(u8 node, u8 value, cNorthBridge *nb)
+{
+	u32 temp = value;
+	ASSERT((node < nb->maxNodes));
+	/* Use CpuCnt as a scratch register */
+	/* Limiting use to 4 bits makes code GH to rev F compatible. */
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+					makePCIBusFromNode(node),
+					makePCIDeviceFromNode(node),
+					CPU_HTNB_FUNC_00,
+					REG_NODE_ID_0X60),
+					19, 16, &temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u8
+ * fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Return the number of cores (1 based count) on node.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node      = the node that will be examined
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u8  result    = the number of cores
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u8 fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
+{
+	u32 temp;
+
+	ASSERT((node < nb->maxNodes));
+	/* Read CmpCap */
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+			makePCIBusFromNode(node),
+			makePCIDeviceFromNode(node),
+			CPU_NB_FUNC_03,
+			REG_NB_CAPABILITY_3XE8),
+			13, 12, &temp);
+
+	/* and add one */
+	return (u8)(temp+1);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u8
+ * fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Return the number of cores (1 based count) on node.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node      = the node that will be examined
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u8  result    = the number of cores
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
+{
+	u32 temp, leveling, cores;
+	u8 i;
+
+	ASSERT((node < nb->maxNodes));
+	/* Read CmpCap */
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_NB_FUNC_03,
+				REG_NB_CAPABILITY_3XE8),
+				13, 12, &temp);
+
+	/* Support Downcoring */
+	cores = temp + 1;
+	AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
+					makePCIBusFromNode(node),
+					makePCIDeviceFromNode(node),
+					CPU_NB_FUNC_03,
+					REG_NB_DOWNCORE_3X190),
+					3, 0, &leveling);
+	for (i=0; i<cores; i++)
+	{
+		if (leveling & ((u32) 1 << i))
+		{
+			temp--;
+		}
+	}
+	return (u8)(temp+1);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Write the total number of cores and nodes to the node
+ *
+ *  Parameters:
+ *	@param[in]  u8  node   = the node that will be examined
+ *	@param[in]  u8  totalNodes  = the total number of nodes
+ *	@param[in]  u8  totalCores  = the total number of cores
+ *	@param[in]  cNorthBridge *nb   = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
+{
+	SBDFO nodeIDReg;
+	u32 temp;
+
+	ASSERT((node < nb->maxNodes) && (totalNodes <= nb->maxNodes));
+	nodeIDReg = MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_00,
+				REG_NODE_ID_0X60);
+
+	temp = totalCores-1;
+	/* Rely on max number of nodes:cores for rev F and GH to make
+	 * this code work, even though we write reserved bit 20 on rev F it will be
+	 * zero in that case.
+	 */
+	AmdPCIWriteBits(nodeIDReg, 20, 16, &temp);
+	temp = totalNodes-1;
+	AmdPCIWriteBits(nodeIDReg, 6,  4, &temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * limitNodes(u8 node, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Limit coherent config accesses to cpus as indicated by nodecnt.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node  = the node that will be examined
+ *	@param[in]  cNorthBridge *nb  = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void limitNodes(u8 node, cNorthBridge *nb)
+{
+	u32 temp = 1;
+	ASSERT((node < nb->maxNodes));
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_00,
+				REG_LINK_TRANS_CONTROL_0X68),
+				15, 15, &temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 BClinks, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Write the routing table entry for node to target, using the request link, response
+ *	link, and broadcast links provided.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node   = the node that will be examined
+ *	@param[in]  u8  target   = the target node for these routes
+ *	@param[in]  u8  reqLink  = the link for requests to target
+ *	@param[in]  u8  rspLink  = the link for responses to target
+ *	@param[in]  u32 bClinks  = the broadcast links
+ *	@param[in]  cNorthBridge *nb  = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 bClinks, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 value = 0;
+
+	ASSERT((node < nb->maxNodes) && (target < nb->maxNodes));
+	if (reqLink == ROUTETOSELF)
+		value |= nb->selfRouteRequestMask;
+	else
+		value |= nb->selfRouteRequestMask << (reqLink+1);
+
+	if (rspLink == ROUTETOSELF)
+		value |= nb->selfRouteResponseMask;
+	else
+		value |= nb->selfRouteResponseMask << (rspLink+1);
+
+	/* Allow us to accept a Broadcast ourselves, then set broadcasts for routes */
+	value |= (u32)1 << nb->broadcastSelfBit;
+	value |= (u32)bClinks << (nb->broadcastSelfBit + 1);
+
+	AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_HTNB_FUNC_00,
+				REG_ROUTE0_0X40 + target*4), &value);
+#else
+	STOP_HERE;
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * static u32
+ * makeKey(u8 currentNode)
+ *
+ *  Description:
+ *	Private routine to northbridge code.
+ *	Determine whether a node is compatible with the discovered configuration so
+ *	far.  Currently, that means the family, extended family of the new node are the
+ *	same as the BSP's.
+ *
+ *  Parameters:
+ *	@param[in]  u8   node   = the node
+ *	@param[out] u32  result = the key value
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+static u32 makeKey(u8 node)
+{
+	u32 extFam, baseFam;
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_NB_FUNC_03,
+				REG_NB_CPUID_3XFC),
+				27, 20, &extFam);
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_NB_FUNC_03,
+				REG_NB_CPUID_3XFC),
+				11, 8, &baseFam);
+	return ((u32)(baseFam << 8) | extFam);
+}
+
+
+/**----------------------------------------------------------------------------------------
+ *
+ * BOOL
+ * isCompatible(u8 currentNode, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Determine whether a node is compatible with the discovered configuration so
+ *	far.  Currently, that means the family, extended family of the new node are the
+ *	same as the BSP's.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node   = the node
+ *	@param[in]  cNorthBridge *nb  = this northbridge
+ *	@param[out] BOOL   result = true: the new is compatible, false: it is not
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL isCompatible(u8 node, cNorthBridge *nb)
+{
+	return (makeKey(node) == nb->compatibleKey);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * BOOL
+ * fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Get node capability and update the minimum supported system capability.
+ *	Return whether the current configuration exceeds the capability.
+ *
+ *  Parameters:
+ *	@param[in] u8  node      = the node
+ *	@param[in,out]  sMainData *pDat = sysMpCap (updated) and NodesDiscovered
+ *	@param[in] cNorthBridge *nb = this northbridge
+ *	@param[out] BOOL  result    = true: system is capable of current config.
+ *			      false: system is not capable of current config.
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 temp;
+	u8 maxNodes;
+
+	ASSERT(node < nb->maxNodes);
+
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_NB_FUNC_03,
+				REG_NB_CAPABILITY_3XE8),
+				2, 1, &temp);
+	if (temp > 1)
+	{
+		maxNodes = 8;
+	} else {
+		if (temp == 1)
+		{
+			maxNodes = 2;
+		} else {
+			maxNodes = 1;
+		}
+	}
+	if (pDat->sysMpCap > maxNodes)
+	{
+		 pDat->sysMpCap = maxNodes;
+	}
+	/* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
+	return (pDat->sysMpCap > pDat->NodesDiscovered);
+#else
+	return 1;
+#endif
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * BOOL
+ * fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Get node capability and update the minimum supported system capability.
+ *	Return whether the current configuration exceeds the capability.
+ *
+ *  Parameters:
+ *	@param[in] u8  node   = the node
+ *	@param[in,out] sMainData *pDat = sysMpCap (updated) and NodesDiscovered
+ *	@param[in]  cNorthBridge *nb   = this northbridge
+ *	@param[out] BOOL  result = true: system is capable of current config.
+ *			   false: system is not capable of current config.
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 temp;
+	u8 maxNodes;
+
+	ASSERT(node < nb->maxNodes);
+
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_NB_FUNC_03,
+				REG_NB_CAPABILITY_3XE8),
+				18, 16, &temp);
+
+	if (temp != 0)
+	{
+		maxNodes = (1 << (~temp & 0x3));  /* That is, 1, 2, 4, or 8 */
+	}
+	else
+	{
+		maxNodes = 8;
+	}
+
+	if (pDat->sysMpCap > maxNodes)
+	{
+		pDat->sysMpCap = maxNodes;
+	}
+	/* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
+	return (pDat->sysMpCap > pDat->NodesDiscovered);
+#else
+	return 1;
+#endif
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Disable a cHT link on node by setting F0x[E4, C4, A4, 84][TransOff, EndOfChain]=1
+ *
+ *  Parameters:
+ *	@param[in]  u8  node      = the node this link is on
+ *	@param[in]  u8  link      = the link to stop
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void fam0fStopLink(u8 node, u8 link, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 temp;
+	SBDFO linkBase;
+
+	ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
+
+	linkBase = makeLinkBase(node, link);
+
+	/* Set TransOff, EndOfChain */
+	temp = 3;
+	setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &temp);
+#endif
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * commonVoid()
+ *
+ *  Description:
+ *	Nothing.
+ *
+ *  Parameters:
+ *		None.
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void commonVoid()
+{
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * BOOL
+ * commonReturnFalse()
+ *
+ *  Description:
+ *	Return False.
+ *
+ *  Parameters:
+ *	     @param[out]    BOOL     result	   = false
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL commonReturnFalse()
+{
+	return 0;
+}
+
+/***************************************************************************
+ ***			Non-coherent init code				  ***
+ ***			Northbridge access routines			  ***
+ ***************************************************************************/
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u8
+ * readSbLink(cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Return the link to the Southbridge
+ *
+ *  Parameters:
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u8    results = the link to the southbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u8 readSbLink(cNorthBridge *nb)
+{
+	u32 temp;
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(0),
+				makePCIBusFromNode(0),
+				makePCIDeviceFromNode(0),
+				CPU_HTNB_FUNC_00,
+				REG_UNIT_ID_0X64),
+				10, 8, &temp);
+	return (u8)temp;
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * BOOL
+ * verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Verify that the link is non-coherent, connected, and ready
+ *
+ *  Parameters:
+ *	@param[in]  u8  node   = the node that will be examined
+ *	@param[in]  u8  link   = the Link on that node to examine
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u8  results   = true - The link has the following status
+ *					LinkCon=1,     Link is connected
+ *					InitComplete=1,Link initilization is complete
+ *					NC=1,          Link is coherent
+ *					UniP-cLDT=0,   Link is not Uniprocessor cLDT
+ *					LinkConPend=0  Link connection is not pending
+ *					false- The link has some other status
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+BOOL verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
+{
+	u32 linkType;
+	SBDFO linkBase;
+
+	ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
+
+	linkBase = makeLinkBase(node, link);
+
+	/* FN0_98/A4/C4 = LDT Type Register */
+	AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType);
+
+	/* Verify linkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0 */
+	return (linkType & HTHOST_TYPE_MASK) ==  HTHOST_TYPE_NONCOHERENT;
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Configure and enable config access to a non-coherent chain for the given bus range.
+ *
+ *  Parameters:
+ *	@param[in] u8 cfgRouteIndex = the map entry to set
+ *	@param[in] u8 secBus      = The secondary bus number to use
+ *	@param[in] u8 subBus      = The subordinate bus number to use
+ *	@param[in] u8 targetNode  = The node  that shall be the recipient of the traffic
+ *	@param[in] u8 targetLink  = The link that shall be the recipient of the traffic
+ *	@param[in] sMainData* pDat   = our global state
+ *	@param[in] cNorthBridge *nb  = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void  ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
+{
+	u8 curNode;
+	SBDFO linkBase;
+	u32 temp;
+
+	linkBase = makeLinkBase(targetNode, targetLink);
+
+	ASSERT(secBus <= subBus);
+	temp = secBus;
+	AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
+
+	/* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
+	 * set to indicate a sublink.  For node, we are currently not supporting Extended
+	 * routing tables.
+	 */
+	temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
+		+ ((u32)targetNode << 4) + (u32)3;
+	for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
+		AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
+					makePCIBusFromNode(curNode),
+					makePCIDeviceFromNode(curNode),
+					CPU_ADDR_FUNC_01,
+					REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
+					&temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Configure and enable config access to a non-coherent chain for the given bus range.
+ *
+ *  Parameters:
+ *	@param[in] u8  cfgMapIndex = the map entry to set
+ *	@param[in] u8  secBus      = The secondary bus number to use
+ *	@param[in] u8  subBus      = The subordinate bus number to use
+ *	@param[in] u8  targetNode  = The node  that shall be the recipient of the traffic
+ *	@param[in] u8  targetLink  = The link that shall be the recipient of the traffic
+ *	@param[in] sMainData*  pDat   = our global state
+ *	@param[in] cNorthBridge *nb   = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
+{
+	u8 curNode;
+	SBDFO linkBase;
+	u32 temp;
+
+	linkBase = makeLinkBase(targetNode, targetLink);
+
+	ASSERT(secBus <= subBus);
+	temp = secBus;
+	AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
+
+	temp = subBus;
+	AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 23, 16, &temp);
+
+	/* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
+	 * set to indicate a sublink.  For node, we are currently not supporting Extended
+	 * routing tables.
+	 */
+	temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
+		+ ((u32)targetNode << 4) + (u32)3;
+	for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
+		 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
+					makePCIBusFromNode(curNode),
+					makePCIDeviceFromNode(curNode),
+					CPU_ADDR_FUNC_01,
+					REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
+					&temp);
+}
+
+/***************************************************************************
+ ***				 Link Optimization			  ***
+ ***************************************************************************/
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u8
+ * convertBitsToWidth(u8 value, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Given the bits set in the register field, return the width it represents
+ *
+ *  Parameters:
+ *	@param[in]  u8  value   = The bits for the register
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u8  results = The width
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u8 convertBitsToWidth(u8 value, cNorthBridge *nb)
+{
+	if (value == 1) {
+		return 16;
+	} else if (value == 0) {
+		return 8;
+	} else if (value == 5) {
+		return 4;
+	} else if (value == 4) {
+		return 2;
+	}
+	STOP_HERE; // This is an error internal condition
+
+	return 0xFF;	// make the compiler happy.
+
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u8
+ * convertWidthToBits(u8 value, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Translate a desired width setting to the bits to set in the register field
+ *
+ *  Parameters:
+ *	@param[in]  u8  value     = The width
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u8  results   = The bits for the register
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u8 convertWidthToBits(u8 value, cNorthBridge *nb)
+{
+	if (value == 16) {
+		return 1;
+	} else if (value == 8) {
+		return 0;
+	} else if (value == 4) {
+		return 5;
+	} else if (value == 2) {
+		return 4;
+	}
+	STOP_HERE; // This is an internal error condition
+
+	return 0xFF;	// make the compiler happy.
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u16
+ * ht1NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Return a mask that eliminates HT frequencies that cannot be used due to a slow
+ *	northbridge frequency.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node      = Result could (later) be for a specific node
+ *	@param[in]  cNorthBridge *nb = this northbridge
+ *	@param[out] u16 results   = Frequency mask
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u16 ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
+{
+	/* only up to HT1 speeds */
+	return (HT_FREQUENCY_LIMIT_HT1_ONLY);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * u16
+ * fam10NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
+ *
+ *  Description:
+ *	Return a mask that eliminates HT frequencies that cannot be used due to a slow
+ *	northbridge frequency.
+ *
+ *  Parameters:
+ *	@param[in]  u8    node     = Result could (later) be for a specific node
+ *	@param[in]  cNorthBridge *nb  = this northbridge
+ *	@param[out] u16   results  = Frequency mask
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+u16 fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
+{
+	u8 nbCOF;
+	u16 supported;
+
+	nbCOF = getMinNbCOF();
+	/*
+	 * nbCOF is minimum northbridge speed in hundreds of MHz.
+	 * HT can not go faster than the minimum speed of the northbridge.
+	 */
+	if ((nbCOF >= 6) && (nbCOF <= 26))
+	{
+		/* Convert frequency to bit and all less significant bits,
+		 * by setting next power of 2 and subtracting 1.
+		 */
+		supported = ((u16)1 << ((nbCOF >> 1) + 2)) - 1;
+	}
+	else if (nbCOF > 26)
+	{
+		supported = HT_FREQUENCY_LIMIT_2600M;
+	}
+	/* unlikely cases, but include as a defensive measure, also avoid trick above */
+	else if (nbCOF == 4)
+	{
+		supported = HT_FREQUENCY_LIMIT_400M;
+	}
+	else if (nbCOF == 2)
+	{
+		supported = HT_FREQUENCY_LIMIT_200M;
+	}
+	else
+	{
+		STOP_HERE;
+		supported = HT_FREQUENCY_LIMIT_200M;
+	}
+
+	return (fixEarlySampleFreqCapability(supported));
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * gatherLinkData(sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 For all discovered links, populate the port list with the frequency and width
+ *	 capabilities.
+ *
+ *  Parameters:
+ *	@param[in,out] sMainData*  pDat = our global state, port list
+ *	@param[in]     cNorthBridge *nb = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void gatherLinkData(sMainData *pDat, cNorthBridge *nb)
+{
+	u8 i;
+	SBDFO linkBase;
+	u32 temp;
+
+	for (i = 0; i < pDat->TotalLinks*2; i++)
+	{
+		if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
+		{
+			linkBase = makeLinkBase(pDat->PortList[i].NodeID, pDat->PortList[i].Link);
+
+			pDat->PortList[i].Pointer = linkBase;
+
+			AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 22, 20, &temp);
+			pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb);
+
+			AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 18, 16, &temp);
+			pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb);
+
+			AmdPCIReadBits(linkBase + HTHOST_FREQ_REV_REG, 31, 16, &temp);
+			pDat->PortList[i].PrvFrequencyCap = (u16)temp & 0x7FFF
+				 & nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb); // Mask off bit 15, reserved value
+		}
+		else
+		{
+			linkBase = pDat->PortList[i].Pointer;
+			if (pDat->PortList[i].Link == 1)
+			 linkBase += HTSLAVE_LINK01_OFFSET;
+
+			AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp);
+			pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb);
+
+			AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 18, 16, &temp);
+			pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb);
+
+			AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 16, &temp);
+			pDat->PortList[i].PrvFrequencyCap = (u16)temp;
+
+			if (pDat->HtBlock->AMD_CB_DeviceCapOverride)
+			{
+				linkBase &= 0xFFFFF000;
+				AmdPCIRead(linkBase, &temp);
+
+				pDat->HtBlock->AMD_CB_DeviceCapOverride(
+					pDat->PortList[i].NodeID,
+					pDat->PortList[i].HostLink,
+					pDat->PortList[i].HostDepth,
+					(u8)SBDFO_SEG(pDat->PortList[i].Pointer),
+					(u8)SBDFO_BUS(pDat->PortList[i].Pointer),
+					(u8)SBDFO_DEV(pDat->PortList[i].Pointer),
+					temp,
+					pDat->PortList[i].Link,
+					&(pDat->PortList[i].PrvWidthInCap),
+					&(pDat->PortList[i].PrvWidthOutCap),
+					&(pDat->PortList[i].PrvFrequencyCap));
+			}
+		}
+	}
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * setLinkData(sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Change the hardware state for all links according to the now optimized data in the
+ *	 port list data structure.
+ *
+ *  Parameters:
+ *	  @param[in]	    sMainData*	  pDat		 = our global state, port list
+ *	  @param[in]	    cNorthBridge *nb   = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void setLinkData(sMainData *pDat, cNorthBridge *nb)
+{
+	u8 i;
+	SBDFO linkBase;
+	u32 temp, widthin, widthout, bits;
+
+	for (i = 0; i < pDat->TotalLinks*2; i++)
+	{
+
+		ASSERT(pDat->PortList[i&0xFE].SelWidthOut == pDat->PortList[(i&0xFE)+1].SelWidthIn);
+		ASSERT(pDat->PortList[i&0xFE].SelWidthIn == pDat->PortList[(i&0xFE)+1].SelWidthOut);
+		ASSERT(pDat->PortList[i&0xFE].SelFrequency == pDat->PortList[(i&0xFE)+1].SelFrequency);
+
+		if (pDat->PortList[i].SelRegang)
+		{
+			ASSERT(pDat->PortList[i].Type == PORTLIST_TYPE_CPU);
+			ASSERT(pDat->PortList[i].Link < 4);
+			temp = 1;
+			AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
+					makePCIBusFromNode(pDat->PortList[i].NodeID),
+					makePCIDeviceFromNode(pDat->PortList[i].NodeID),
+					CPU_HTNB_FUNC_00,
+					REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
+					0, 0, &temp);
+		}
+
+		if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
+		{
+			if (pDat->HtBlock->AMD_CB_OverrideCpuPort)
+				pDat->HtBlock->AMD_CB_OverrideCpuPort(pDat->PortList[i].NodeID,
+						pDat->PortList[i].Link,
+						&(pDat->PortList[i].SelWidthIn),
+						&(pDat->PortList[i].SelWidthOut),
+						&(pDat->PortList[i].SelFrequency));
+		}
+		else
+		{
+			if (pDat->HtBlock->AMD_CB_OverrideDevicePort)
+				pDat->HtBlock->AMD_CB_OverrideDevicePort(pDat->PortList[i].NodeID,
+							pDat->PortList[i].HostLink,
+							pDat->PortList[i].HostDepth,
+							pDat->PortList[i].Link,
+							&(pDat->PortList[i].SelWidthIn),
+							&(pDat->PortList[i].SelWidthOut),
+							&(pDat->PortList[i].SelFrequency));
+		}
+
+		linkBase = pDat->PortList[i].Pointer;
+		if ((pDat->PortList[i].Type == PORTLIST_TYPE_IO) && (pDat->PortList[i].Link == 1))
+			linkBase += HTSLAVE_LINK01_OFFSET;
+
+		/* Some IO devices don't work properly when setting widths, so write them in a single operation,
+		 * rather than individually.
+		 */
+		widthout = convertWidthToBits(pDat->PortList[i].SelWidthOut, pDat->nb);
+		ASSERT(widthout == 1 || widthout == 0 || widthout == 5 || widthout == 4);
+		widthin = convertWidthToBits(pDat->PortList[i].SelWidthIn, pDat->nb);
+		ASSERT(widthin == 1 || widthin == 0 || widthin == 5 || widthin == 4);
+
+		temp = (widthin & 7) | ((widthout & 7) << 4);
+		setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 31, 24, &temp);
+
+		temp = pDat->PortList[i].SelFrequency;
+		if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
+		{
+			ASSERT((temp >= HT_FREQUENCY_600M && temp <= HT_FREQUENCY_2600M)
+				|| (temp == HT_FREQUENCY_200M) || (temp == HT_FREQUENCY_400M));
+			AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, &temp);
+			if (temp > HT_FREQUENCY_1000M) // Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz
+			{
+				/* Enable  for Gen3 frequencies */
+				temp = 1;
+			}
+			else
+			{
+				/* Disable  for Gen1 frequencies */
+				temp = 0;
+			}
+				/* HT3 retry mode enable / disable */
+				AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
+							makePCIBusFromNode(pDat->PortList[i].NodeID),
+							makePCIDeviceFromNode(pDat->PortList[i].NodeID),
+							CPU_HTNB_FUNC_00,
+							REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link),
+							0, 0, &temp);
+				/* and Scrambling enable / disable */
+				AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
+						makePCIBusFromNode(pDat->PortList[i].NodeID),
+						makePCIDeviceFromNode(pDat->PortList[i].NodeID),
+						CPU_HTNB_FUNC_00,
+						REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
+						3, 3, &temp);
+		}
+		else
+		{
+			SBDFO currentPtr;
+			BOOL isFound;
+
+			ASSERT(temp <= HT_FREQUENCY_2600M);
+			/* Write the frequency setting */
+			AmdPCIWriteBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 11, 8, &temp);
+
+			/* Handle additional HT3 frequency requirements, if needed,
+			 * or clear them if switching down to ht1 on a warm reset.
+			 * Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz
+			 *
+			 * Even though we assert if debugging, we need to check that the capability was found
+			 * always, since this is an unknown hardware device, also we are taking
+			 * unqualified frequency from the call backs
+			 * (could be trying to do ht3 on an ht1 IO device).
+			 */
+
+			if (temp > HT_FREQUENCY_1000M)
+			{
+				/* Enabling features if gen 3 */
+				bits = 1;
+			}
+			else
+			{
+				/* Disabling features if gen 1 */
+				bits = 0;
+			}
+
+			/* Retry Enable */
+			isFound = FALSE;
+			currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
+			do
+			{
+				AmdPCIFindNextCap(&currentPtr);
+				if (currentPtr != ILLEGAL_SBDFO)
+				{
+					AmdPCIRead(currentPtr, &temp);
+					/* HyperTransport Retry Capability? */
+					if (IS_HT_RETRY_CAPABILITY(temp))
+					{
+						ASSERT(pDat->PortList[i].Link < 2);
+						AmdPCIWriteBits(currentPtr + HTRETRY_CONTROL_REG,
+								pDat->PortList[i].Link*16,
+								pDat->PortList[i].Link*16,
+								&bits);
+						isFound = TRUE;
+					}
+				/* Some other capability, keep looking */
+				}
+				else
+				{
+					/* If we are turning it off, that may mean the device was only ht1 capable,
+					 * so don't complain that we can't do it.
+					 */
+					if (bits != 0)
+					{
+						if (pDat->HtBlock->AMD_CB_EventNotify)
+						{
+							sHtEventOptRequiredCap evt ={sizeof(sHtEventOptRequiredCap),
+										pDat->PortList[i].NodeID,
+										pDat->PortList[i].HostLink,
+										pDat->PortList[i].HostDepth};
+
+							pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
+										HT_EVENT_OPT_REQUIRED_CAP_RETRY,
+										(u8 *)&evt);
+						}
+						STOP_HERE;
+					}
+					isFound = TRUE;
+				}
+			} while (!isFound);
+
+			/* Scrambling enable */
+			isFound = FALSE;
+			currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
+			do
+			{
+				AmdPCIFindNextCap(&currentPtr);
+				if (currentPtr != ILLEGAL_SBDFO)
+				{
+					AmdPCIRead(currentPtr, &temp);
+					/* HyperTransport Gen3 Capability? */
+					if (IS_HT_GEN3_CAPABILITY(temp))
+					{
+						ASSERT(pDat->PortList[i].Link < 2);
+						AmdPCIWriteBits((currentPtr +
+							HTGEN3_LINK_TRAINING_0_REG +
+							pDat->PortList[i].Link*HTGEN3_LINK01_OFFSET),
+							3, 3, &bits);
+						isFound = TRUE;
+					}
+					/* Some other capability, keep looking */
+					}
+					else
+					{
+					/* If we are turning it off, that may mean the device was only ht1 capable,
+					 * so don't complain that we can't do it.
+					 */
+					if (bits != 0)
+					{
+						if (pDat->HtBlock->AMD_CB_EventNotify)
+						{
+							sHtEventOptRequiredCap evt ={sizeof(sHtEventOptRequiredCap),
+									pDat->PortList[i].NodeID,
+									pDat->PortList[i].HostLink,
+									pDat->PortList[i].HostDepth};
+
+							pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
+										HT_EVENT_OPT_REQUIRED_CAP_GEN3,
+										(u8 *)&evt);
+						}
+						STOP_HERE;
+					}
+					isFound = TRUE;
+				}
+			} while (!isFound);
+		}
+	}
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
+ *
+ *  Description:
+ *	Set the command buffer allocations in the buffer count register for the node and link.
+ *	The command buffer settings in the low 16 bits are the same on both
+ *	family 10h and family 0fh northbridges.
+ *
+ *  Parameters:
+ *	@param[in]  u8 node = The node to set allocations on
+ *	@param[in]  u8 link = the link to set allocations on
+ *	@param[in]  u8 req  = non-posted Request Command Buffers
+ *	@param[in]  u8 preq = Posted Request Command Buffers
+ *	@param[in]  u8 rsp  = Response Command Buffers
+ *	@param[in]  u8 prb  = Probe Command Buffers
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+static void fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
+{
+	u32 temp;
+	SBDFO currentPtr;
+
+	currentPtr = makeLinkBase(node, link);
+	currentPtr += HTHOST_BUFFER_COUNT_REG;
+
+	/* non-posted Request Command Buffers */
+	temp = req;
+	AmdPCIWriteBits(currentPtr, 3, 0, &temp);
+	/* Posted Request Command Buffers */
+	temp = preq;
+	AmdPCIWriteBits(currentPtr, 7, 4, &temp);
+	/* Response Command Buffers */
+	temp = rsp;
+	AmdPCIWriteBits(currentPtr, 11, 8, &temp);
+	/* Probe Command Buffers */
+	temp = prb;
+	AmdPCIWriteBits(currentPtr, 15, 12, &temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
+ *
+ *  Description:
+ *	 Set the data buffer allocations in the buffer count register for the node and link.
+ *	 The command buffer settings in the high 16 bits are not the same on both
+ *	 family 10h and family 0fh northbridges.
+ *
+ *  Parameters:
+ *	@param[in] u8 node  = The node to set allocations on
+ *	@param[in] u8 link  = the link to set allocations on
+ *	@param[in] u8 reqD  = non-posted Request Data Buffers
+ *	@param[in] u8 preqD = Posted Request Data Buffers
+ *	@param[in] u8 rspD  = Response Data Buffers
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+static void fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
+{
+	u32 temp;
+	SBDFO currentPtr;
+
+	currentPtr = makeLinkBase(node, link);
+	currentPtr += HTHOST_BUFFER_COUNT_REG;
+
+	/* Request Data Buffers */
+	temp = reqD;
+	AmdPCIWriteBits(currentPtr, 18, 16, &temp);
+	/* Posted Request Data Buffers */
+	temp = preqD;
+	AmdPCIWriteBits(currentPtr, 22, 20, &temp);
+	/* Response Data Buffers */
+	temp = rspD;
+	AmdPCIWriteBits(currentPtr, 26, 24, &temp);
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Set the traffic distribution register for the links provided.
+ *
+ *  Parameters:
+ *	@param[in] u32 links01   = coherent links from node 0 to 1
+ *	@param[in] u32 links10   = coherent links from node 1 to 0
+ *	@param[in] cNorthBridge* nb = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 temp;
+
+	/* Node 0 */
+	/* DstLnk */
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
+			makePCIBusFromNode(0),
+			makePCIDeviceFromNode(0),
+			CPU_HTNB_FUNC_00,
+			REG_HT_TRAFFIC_DIST_0X164),
+			23, 16, &links01);
+	/* DstNode = 1, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
+	temp = 0x0107;
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
+			makePCIBusFromNode(0),
+			makePCIDeviceFromNode(0),
+			CPU_HTNB_FUNC_00,
+			REG_HT_TRAFFIC_DIST_0X164),
+			15, 0, &temp);
+
+	/* Node 1 */
+	/* DstLnk */
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
+			makePCIBusFromNode(1),
+			makePCIDeviceFromNode(1),
+			CPU_HTNB_FUNC_00,
+			REG_HT_TRAFFIC_DIST_0X164),
+			23, 16, &links10);
+	/* DstNode = 0, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
+	temp = 0x0007;
+	AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
+			makePCIBusFromNode(1),
+			makePCIDeviceFromNode(1),
+			CPU_HTNB_FUNC_00,
+			REG_HT_TRAFFIC_DIST_0X164),
+			15, 0, &temp);
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Traffic distribution is more complex in this case as the routing table must be
+ *	 adjusted to use one link for requests and the other for responses.  Also,
+ *	 perform the buffer tunings on the links required for this config.
+ *
+ *  Parameters:
+ *	@param[in]  u32  links01  = coherent links from node 0 to 1
+ *	@param[in]  u32  links01  = coherent links from node 1 to 0
+ *	@param[in]  cNorthBridge* nb = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u32 route01, route10;
+	u8 req0, req1, rsp0, rsp1, nclink;
+
+	/*
+	 * Get the current request route for 0->1 and 1->0.  This will indicate which of the links
+	 * in links01 are connected to which links in links10.  Since we have to route to distribute
+	 * traffic, we need to know that.	The link used by htinit will become the request, probe link.
+	 * the other link will be used for responses.
+	 */
+
+	/* Get the routes, and hang on to them, we will write them back updated. */
+	AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(0),
+				makePCIBusFromNode(0),
+				makePCIDeviceFromNode(0),
+				CPU_HTNB_FUNC_00,
+				REG_ROUTE1_0X44),
+				&route01);
+	AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(1),
+				makePCIBusFromNode(1),
+				makePCIDeviceFromNode(1),
+				CPU_HTNB_FUNC_00,
+				REG_ROUTE0_0X40),
+				&route10);
+
+	/* Convert the request routes to a link number.  Note "0xE" is ht1 nb specific.
+	 * Find the response link numbers.
+	*/
+	ASSERT((route01 & 0xE) && (route10 & 0xE));    /* no route! error! */
+	req0 = (u8)AmdBitScanReverse((route01 & 0xE)) - 1;
+	req1 = (u8)AmdBitScanReverse((route10 & 0xE)) - 1;
+	/* Now, find the other link for the responses */
+	rsp0 = (u8)AmdBitScanReverse((links01 & ~((u32)1 << req0)));
+	rsp1 = (u8)AmdBitScanReverse((links10 & ~((u32)1 << req1)));
+
+	/* ht1 nb restriction, must have exactly two links */
+	ASSERT(((((links01 & ~((u32)1 << req0)) & ~((u32)1 << rsp0))) == 0)
+		&& ((((links10 & ~((u32)1 << req1)) & ~((u32)1 << rsp1))) == 0));
+
+	route01 = (route01 & ~0x0E00) | ((u32)0x0100<<(rsp0 + 1));
+	route10 = (route10 & ~0x0E00) | ((u32)0x0100<<(rsp1 + 1));
+
+	AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(0),
+				makePCIBusFromNode(0),
+				makePCIDeviceFromNode(0),
+				CPU_HTNB_FUNC_00,
+				REG_ROUTE1_0X44),
+				&route01);
+
+	AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(1),
+				makePCIBusFromNode(1),
+				makePCIDeviceFromNode(1),
+				CPU_HTNB_FUNC_00,
+				REG_ROUTE0_0X40),
+				&route10);
+
+	/* While we otherwise do buffer tunings elsewhere, for the dual cHT DP case with
+	 * ht1 northbridges like family 0Fh, do the tunings here where we have all the
+	 * link and route info at hand and don't need to recalculate it.
+	 */
+
+	/* Node 0, Request / Probe Link (note family F only has links < 4) */
+	fam0fWriteHTLinkCmdBufferAlloc(0, req0, 6, 3, 1, 6);
+	fam0fWriteHTLinkDatBufferAlloc(0, req0, 4, 3, 1);
+	/* Node 0, Response Link (note family F only has links < 4) */
+	fam0fWriteHTLinkCmdBufferAlloc(0, rsp0, 1, 0, 15, 0);
+	fam0fWriteHTLinkDatBufferAlloc(0, rsp0, 1, 1, 6);
+	/* Node 1, Request / Probe Link (note family F only has links < 4) */
+	fam0fWriteHTLinkCmdBufferAlloc(1, req1, 6, 3, 1, 6);
+	fam0fWriteHTLinkDatBufferAlloc(1, req1, 4, 3, 1);
+	/* Node 1, Response Link (note family F only has links < 4) */
+	fam0fWriteHTLinkCmdBufferAlloc(1, rsp1, 1, 0, 15, 0);
+	fam0fWriteHTLinkDatBufferAlloc(1, rsp1, 1, 1, 6);
+
+	/* Node 0, is the third link non-coherent? */
+	nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req0) & ~((u32)1 << rsp0)));
+	if (nb->verifyLinkIsNonCoherent(0, nclink, nb))
+	{
+		fam0fWriteHTLinkCmdBufferAlloc(0, nclink, 6, 5, 2, 0);
+	}
+
+	/* Node 1, is the third link non-coherent? */
+	nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req1) & ~((u32)1 << rsp1)));
+	if (nb->verifyLinkIsNonCoherent(1, nclink, nb))
+	{
+		fam0fWriteHTLinkCmdBufferAlloc(1, nclink, 6, 5, 2, 0);
+	}
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Buffer tunings are inherently northbridge specific. Check for specific configs
+ *	 which require adjustments and apply any standard workarounds to this node.
+ *
+ *  Parameters:
+ *	@param[in]  u8  node      = the node to
+ *	@param[in]  sMainData *pDat  = coherent links from node 0 to 1
+ *	@param[in]  cNorthBridge* nb = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
+{
+#ifndef HT_BUILD_NC_ONLY
+	u8 i;
+	u32 temp;
+	SBDFO currentPtr;
+
+	ASSERT(node < nb->maxNodes);
+
+	/* Fix the FIFO pointer register before changing speeds */
+	currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
+				makePCIBusFromNode(node),
+				makePCIDeviceFromNode(node),
+				CPU_NB_FUNC_03,
+				REG_NB_FIFOPTR_3XDC);
+	for (i=0; i < nb->maxLinks; i++)
+	{
+		temp = 0;
+		if (nb->verifyLinkIsCoherent(node, i, nb))
+		{
+			temp = 0x26;
+			ASSERT(i<3);
+			AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
+		}
+		else
+		{
+			if (nb->verifyLinkIsNonCoherent(node, i, nb))
+			{
+				temp = 0x25;
+				ASSERT(i<3);
+				AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
+			}
+		}
+	}
+	/*
+	 * 8P Buffer tuning.
+	 * Either apply the BKDG tunings or, if applicable, apply the more restrictive errata 153
+	 * workaround.
+	 * If 8 nodes, Check this node for 'inner' or 'outer'.
+	 * Tune each link based on coherent or non-coherent
+	 */
+	if (pDat->NodesDiscovered >= 6)
+	{
+		u8 j;
+		BOOL isOuter;
+		BOOL isErrata153;
+
+		/* This is for family 0Fh, so assuming dual core max then 7 or 8 nodes are required
+		 * to be in the situation of 14 or more cores.	 We checked nodes above, cross check
+		 * that the number of cores is 14 or more. We want both 14 cores with at least 7 or 8 nodes
+		 * not one condition alone, to apply the errata 153 workaround.  Otherwise, 7 or 8 rev F
+		 * nodes use the BKDG tuning.
+		 */
+
+		isErrata153 = 0;
+
+		AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(0),
+					makePCIBusFromNode(0),
+					makePCIDeviceFromNode(0),
+					CPU_HTNB_FUNC_00,
+					REG_NODE_ID_0X60),
+					19, 16, &temp);
+
+		if (temp >= 14)
+		{
+			/* Check whether we need to do errata 153 tuning or BKDG tuning.
+			 * Errata 153 applies to JH-1, JH-2 and older.  It is fixed in JH-3
+			 * (and, one assumes, from there on).
+			 */
+			for (i=0; i < (pDat->NodesDiscovered +1); i++)
+			{
+				AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(i),
+						makePCIBusFromNode(i),
+						makePCIDeviceFromNode(i),
+						CPU_NB_FUNC_03,
+						REG_NB_CPUID_3XFC),
+						7, 0, &temp);
+				if (((u8)temp & ~0x40) < 0x13)
+				{
+					isErrata153 = 1;
+					break;
+				}
+			}
+		}
+
+		for (i=0; i < CPU_ADDR_NUM_CONFIG_MAPS; i++)
+		{
+			isOuter = FALSE;
+			/* Check for outer node by scanning the config maps on node 0 for one
+			 * which is assigned to this node.
+			 */
+			currentPtr = MAKE_SBDFO(makePCISegmentFromNode(0),
+						makePCIBusFromNode(0),
+						makePCIDeviceFromNode(0),
+						CPU_ADDR_FUNC_01,
+						REG_ADDR_CONFIG_MAP0_1XE0 + (4 * i));
+			AmdPCIReadBits (currentPtr, 1, 0, &temp);
+			/* Make sure this config map is valid, if it is it will be enabled for read/write */
+			if (temp == 3)
+			{
+				/* It's valid, get the node (that node is an outer node) */
+				AmdPCIReadBits (currentPtr, 6, 4, &temp);
+				/* Is the node we're working on now? */
+				if (node == (u8)temp)
+				{
+					/* This is an outer node.	Tune it appropriately. */
+					for (j=0; j < nb->maxLinks; j++)
+					{
+						if (isErrata153)
+						{
+							if (nb->verifyLinkIsCoherent(node, j, nb))
+							{
+								fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 6, 4);
+							}
+							else
+							{
+								if (nb->verifyLinkIsNonCoherent(node, j, nb))
+								{
+									fam0fWriteHTLinkCmdBufferAlloc(node, j, 5, 4, 1, 0);
+								}
+							}
+						}
+						else
+						{
+							if (nb->verifyLinkIsCoherent(node, j, nb))
+							{
+								fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 8, 5);
+							}
+						}
+					}
+					/*
+					 * SRI to XBAR Buffer Counts are correct for outer node at power on defaults.
+					 */
+					isOuter = TRUE;
+					break;
+				}
+			}
+			/* We fill config maps in ascending order, so if we didn't use this one, we're done. */
+			else break;
+		}
+		if (!isOuter)
+		{
+			if (isErrata153)
+			{
+				/* Tuning for inner node coherent links */
+				for (j=0; j < nb->maxLinks; j++)
+				{
+					if (nb->verifyLinkIsCoherent(node, j, nb))
+					{
+						fam0fWriteHTLinkCmdBufferAlloc(node, j, 2, 1, 5, 4);
+					}
+
+				}
+				/* SRI to XBAR Buffer Count for inner nodes, zero DReq and DPReq */
+				temp = 0;
+				AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
+							makePCIBusFromNode(node),
+							makePCIDeviceFromNode(node),
+							CPU_NB_FUNC_03,
+							REG_NB_SRI_XBAR_BUF_3X70),
+							31, 28, &temp);
+			}
+		}
+
+		/*
+		 * Tune MCT to XBAR Buffer Count the same an all nodes, 2 Probes, 5 Response
+		 */
+		if (isErrata153)
+		{
+			temp = 0x25;
+			AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
+						makePCIBusFromNode(node),
+						makePCIDeviceFromNode(node),
+						CPU_NB_FUNC_03,
+						REG_NB_MCT_XBAR_BUF_3X78),
+						14, 8, &temp);
+		}
+	}
+#endif /* HT_BUILD_NC_ONLY */
+}
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Buffer tunings are inherently northbridge specific. Check for specific configs
+ *	 which require adjustments and apply any standard workarounds to this node.
+ *
+ *  Parameters:
+ *	@param[in] u8 node       = the node to tune
+ *	@param[in] sMainData *pDat  = global state
+ *	@param[in] cNorthBridge* nb = this northbridge
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
+{
+	u32 temp;
+	SBDFO currentPtr;
+	u8 i;
+
+	ASSERT(node < nb->maxNodes);
+
+	/*
+	 * Link to XCS Token Count Tuning
+	 *
+	 * For each active link that we reganged (so this unfortunately can't go into the PCI reg
+	 * table), we have to switch the Link to XCS Token Counts to the ganged state.
+	 * We do this here for the non-uma case, which is to write the values that would have
+	 * been power on defaults if the link was ganged at cold reset.
+	 */
+	for (i = 0; i < pDat->TotalLinks*2; i++)
+	{
+		if ((pDat->PortList[i].NodeID == node) && (pDat->PortList[i].Type == PORTLIST_TYPE_CPU))
+		{
+			/* If the link is greater than 4, this is a sublink 1, so it is not reganged. */
+			if (pDat->PortList[i].Link < 4)
+			{
+				currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
+						makePCIBusFromNode(node),
+						makePCIDeviceFromNode(node),
+						CPU_NB_FUNC_03,
+						REG_NB_LINK_XCS_TOKEN0_3X148 + 4*pDat->PortList[i].Link);
+				if (pDat->PortList[i].SelRegang)
+				{
+					/* Handle all the regang Token count adjustments */
+
+					/* Sublink 0: [Probe0tok] = 2 [Rsp0tok] = 2 [PReq0tok] = 2 [Req0tok] = 2 */
+					temp = 0xAA;
+					AmdPCIWriteBits(currentPtr, 7, 0, &temp);
+					/* Sublink 1: [Probe1tok] = 0 [Rsp1tok] = 0 [PReq1tok] = 0 [Req1tok] = 0 */
+					temp = 0;
+					AmdPCIWriteBits(currentPtr, 23, 16, &temp);
+					/* [FreeTok] = 3 */
+					temp = 3;
+					AmdPCIWriteBits(currentPtr, 15, 14, &temp);
+				}
+				else
+				{
+					/* Read the regang bit in hardware */
+					AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
+							makePCIBusFromNode(pDat->PortList[i].NodeID),
+							makePCIDeviceFromNode(pDat->PortList[i].NodeID),
+							CPU_HTNB_FUNC_00,
+							REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
+							0, 0, &temp);
+					if (temp == 1)
+					{
+						/* handle a minor adjustment for stapped ganged links.	 If SelRegang is false we
+						 * didn't do the regang, so if the bit is on then it's hardware strapped.
+						 */
+
+						/* [FreeTok] = 3 */
+						temp = 3;
+						AmdPCIWriteBits(currentPtr, 15, 14, &temp);
+					}
+				}
+			}
+		}
+	}
+}
+
+/*
+ * North Bridge 'constructor'.
+ *
+ */
+
+/**----------------------------------------------------------------------------------------
+ *
+ * void
+ * newNorthBridge(u8 node, cNorthBridge *nb)
+ *
+ *  Description:
+ *	 Construct a new northbridge.  This routine encapsulates knowledge of how to tell
+ *	 significant differences between families of supported northbridges and what routines
+ *	 can be used in common and which are unique.  A fully populated northbridge interface
+ *	 is provided by nb.
+ *
+ *  Parameters:
+ *	  @param[in]	    node	  u8		 = create a northbridge interface for this node.
+ *	  @param[out]	    cNorthBridge* nb		 = the caller's northbridge structure to initialize.
+ *
+ * ---------------------------------------------------------------------------------------
+ */
+void newNorthBridge(u8 node, cNorthBridge *nb)
+{
+	u32 match;
+	u32 extFam, baseFam, model;
+
+	cNorthBridge fam10 =
+	{
+#ifdef HT_BUILD_NC_ONLY
+		8,
+		1,
+		12,
+#else
+		8,
+		8,
+		64,
+#endif /* HT_BUILD_NC_ONLY*/
+		writeRoutingTable,
+		writeNodeID,
+		readDefLnk,
+		enableRoutingTables,
+		verifyLinkIsCoherent,
+		readTrueLinkFailStatus,
+		readToken,
+		writeToken,
+		fam10GetNumCoresOnNode,
+		setTotalNodesAndCores,
+		limitNodes,
+		writeFullRoutingTable,
+		isCompatible,
+		fam10IsCapable,
+		(void (*)(u8, u8, cNorthBridge*))commonVoid,
+		(BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
+		readSbLink,
+		verifyLinkIsNonCoherent,
+		ht3SetCFGAddrMap,
+		convertBitsToWidth,
+		convertWidthToBits,
+		fam10NorthBridgeFreqMask,
+		gatherLinkData,
+		setLinkData,
+		ht3WriteTrafficDistribution,
+		fam10BufferOptimizations,
+		0x00000001,
+		0x00000200,
+		18,
+		0x00000f01
+	};
+
+	cNorthBridge fam0f =
+	{
+#ifdef HT_BUILD_NC_ONLY
+		3,
+		1,
+		12,
+#else
+		3,
+		8,
+		32,
+#endif /* HT_BUILD_NC_ONLY*/
+		writeRoutingTable,
+		writeNodeID,
+		readDefLnk,
+		enableRoutingTables,
+		verifyLinkIsCoherent,
+		readTrueLinkFailStatus,
+		readToken,
+		writeToken,
+		fam0FGetNumCoresOnNode,
+		setTotalNodesAndCores,
+		limitNodes,
+		writeFullRoutingTable,
+		isCompatible,
+		fam0fIsCapable,
+		fam0fStopLink,
+		(BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
+		readSbLink,
+		verifyLinkIsNonCoherent,
+		ht1SetCFGAddrMap,
+		convertBitsToWidth,
+		convertWidthToBits,
+		ht1NorthBridgeFreqMask,
+		gatherLinkData,
+		setLinkData,
+		ht1WriteTrafficDistribution,
+		fam0fBufferOptimizations,
+		0x00000001,
+		0x00000100,
+		16,
+		0x00000f00
+	};
+
+	/* Start with enough of the key to identify the northbridge interface */
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+			makePCIBusFromNode(node),
+			makePCIDeviceFromNode(node),
+			CPU_NB_FUNC_03,
+			REG_NB_CPUID_3XFC),
+			27, 20, &extFam);
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+			makePCIBusFromNode(node),
+			makePCIDeviceFromNode(node),
+			CPU_NB_FUNC_03,
+			REG_NB_CPUID_3XFC),
+			11, 8, &baseFam);
+	AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+			makePCIBusFromNode(node),
+			makePCIDeviceFromNode(node),
+			CPU_NB_FUNC_03,
+			REG_NB_CPUID_3XFC),
+			7, 4, &model);
+	match = (u32)((baseFam << 8) | extFam);
+
+	/* Test each in turn looking for a match.	Init the struct if found */
+	if (match == fam10.compatibleKey)
+	{
+		Amdmemcpy((void *)nb, (const void *)&fam10, (u32) sizeof(cNorthBridge));
+	}
+	else
+	{
+		if (match == fam0f.compatibleKey)
+		{
+			Amdmemcpy((void *)nb, (const void *)&fam0f, (u32) sizeof(cNorthBridge));
+		}
+		else
+		{
+		STOP_HERE;
+		}
+	}
+
+	/* Update the initial limited key to the real one, which may include other matching info */
+	nb->compatibleKey = makeKey(node);
+}
+
Index: LinuxBIOSv2/src/northbridge/amd/amdht/h3ncmn.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/h3ncmn.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef H3NCMN_H
+#define H3NCMN_H
+
+/*----------------------------------------------------------------------------
+ *   Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ *			DEFINITIONS AND MACROS
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/* Use a macro to convert a node number to a PCI device.  If some future port of
+ * this code needs to, this can easily be replaced by a function call:
+ * u8 makePCIDeviceFromNode(u8 node);
+ */
+#define makePCIDeviceFromNode(node) \
+	((u8)(24 + node))
+
+/* Use a macro to convert a node number to a PCI bus.	If some future port of
+ * this code needs to, this can easily be replaced by a function call:
+ * u8 makePCIBusFromNode(u8 node);
+ */
+#define makePCIBusFromNode(node) \
+	((u8)(0))
+
+/* Use a macro to convert a node number to a PCI Segment.  If some future port of
+ * this code needs to, this can easily be replaced by a function call:
+ * u8 makePCISegmentFromNode(u8 node);
+ */
+#define makePCISegmentFromNode(node) \
+	((u8)(0))
+
+/* Macros to fix support issues that come up with early sample processors, which
+ * sometimes do things like report capabilities that are actually unsupported.
+ * Use the build flag, HT_BUILD_EARLY_SAMPLE_CPU_SUPPORT, to enable this support.
+ *
+ * It's not envisioned this would be replaced by an external function, but the prototype is
+ * u16 fixEarlySampleFreqCapability(u16 fc);
+ */
+#ifndef HT_BUILD_EARLY_SAMPLE_CPU_SUPPORT
+#define fixEarlySampleFreqCapability(fc) \
+	((u16)fc)
+#else
+#define fixEarlySampleFreqCapability(fc) \
+	((u16)fc & HT_FREQUENCY_LIMIT_HT1_ONLY)
+#endif
+
+/*----------------------------------------------------------------------------
+ *			    TYPEDEFS, STRUCTURES, ENUMS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+struct cNorthBridge
+{
+	/* Public data, clients of northbridge can access */
+	u8 maxLinks;
+	u8 maxNodes;
+	u8 maxPlatformLinks;
+
+	/* Public Interfaces for northbridge clients, coherent init*/
+	void (*writeRoutingTable)(u8 node, u8 target, u8 link, cNorthBridge *nb);
+	void (*writeNodeID)(u8 node, u8 nodeID, cNorthBridge *nb);
+	u8 (*readDefLnk)(u8 node, cNorthBridge *nb);
+	void (*enableRoutingTables)(u8 node, cNorthBridge *nb);
+	BOOL (*verifyLinkIsCoherent)(u8 node, u8 link, cNorthBridge *nb);
+	BOOL (*readTrueLinkFailStatus)(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb);
+	u8 (*readToken)(u8 node, cNorthBridge *nb);
+	void (*writeToken)(u8 node, u8 value, cNorthBridge *nb);
+	u8 (*getNumCoresOnNode)(u8 node, cNorthBridge *nb);
+	void (*setTotalNodesAndCores)(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb);
+	void (*limitNodes)(u8 node, cNorthBridge *nb);
+	void (*writeFullRoutingTable)(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 bClinks, cNorthBridge *nb);
+	BOOL (*isCompatible)(u8 node, cNorthBridge *nb);
+	BOOL (*isCapable)(u8 node, sMainData *pDat, cNorthBridge *nb);
+	void (*stopLink)(u8 node, u8 link, cNorthBridge *nb);
+	BOOL (*handleSpecialLinkCase)(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb);
+
+	/* Public Interfaces for northbridge clients, noncoherent init */
+	u8 (*readSbLink)(cNorthBridge *nb);
+	BOOL (*verifyLinkIsNonCoherent)(u8 node, u8 link, cNorthBridge *nb);
+	void (*setCFGAddrMap)(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb);
+
+	/* Public Interfaces for northbridge clients, Optimization */
+	u8 (*convertBitsToWidth)(u8 value, cNorthBridge *nb);
+	u8 (*convertWidthToBits)(u8 value, cNorthBridge *nb);
+	u16 (*northBridgeFreqMask)(u8 node, cNorthBridge *nb);
+	void (*gatherLinkData)(sMainData *pDat, cNorthBridge *nb);
+	void (*setLinkData)(sMainData *pDat, cNorthBridge *nb);
+
+	/* Public Interfaces for northbridge clients, System and performance Tuning. */
+	void (*writeTrafficDistribution)(u32 links01, u32 links10, cNorthBridge *nb);
+	void (*bufferOptimizations)(u8 node, sMainData *pDat, cNorthBridge *nb);
+
+	/* Private Data for northbridge implementation use only */
+	u32 selfRouteRequestMask;
+	u32 selfRouteResponseMask;
+	u8 broadcastSelfBit;
+	u32 compatibleKey;
+} ;
+
+/*----------------------------------------------------------------------------
+ *			FUNCTIONS PROTOTYPE
+ *
+ *----------------------------------------------------------------------------
+ */
+void newNorthBridge(u8 node, cNorthBridge *nb);
+
+#endif	 /* H3NCMN_H */
Index: LinuxBIOSv2/src/northbridge/amd/amdht/ht_wrapper.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/ht_wrapper.c	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+
+/*----------------------------------------------------------------------------
+ *			TYPEDEFS, DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* Single CPU system? */
+#if (CONFIG_MAX_PHYSICAL_CPUS == 1)
+	#define HT_BUILD_NC_ONLY 1
+#endif
+
+/* Debugging Options */
+#define AMD_DEBUG 1
+//#define AMD_DEBUG_ERROR_STOP 1
+
+/*----------------------------------------------------------------------------
+ *				MODULES USED
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#undef FILECODE
+#define FILECODE 0xFF01
+#include "comlib.h"
+#include "h3gtopo.h"
+#include "h3finit.h"
+
+/* include the main HT source file */
+#include "h3finit.c"
+
+
+/*----------------------------------------------------------------------------
+ *			LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* FIXME: Find a better place for these pre-ram functions. */
+#define NODE_HT(x) NODE_PCI(x,0)
+#define NODE_MP(x) NODE_PCI(x,1)
+#define NODE_MC(x) NODE_PCI(x,3)
+#define NODE_LC(x) NODE_PCI(x,4)
+static  u32 get_nodes(void)
+{
+	device_t dev;
+	u32 nodes;
+
+	dev = PCI_DEV(CBB, CDB, 0);
+	nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) ;
+#if CONFIG_MAX_PHYSICAL_CPUS > 8
+	nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
+#endif
+	nodes++;
+
+	return nodes;
+}
+
+static void enable_apic_ext_id(u32 node)
+{
+	u32 val;
+	val = pci_read_config32(NODE_HT(node), 0x68);
+	val |= (HTTC_APIC_EXT_SPUR | HTTC_APIC_EXT_ID | HTTC_APIC_EXT_BRD_CST);
+	pci_write_config32(NODE_HT(node), 0x68, val);
+}
+
+
+static void setup_link_trans_cntrl()
+{
+	/* FIXME: Not sure that this belongs here but it is HT related */
+	u32 val;
+	val = pci_read_config32(NODE_HT(0), 0x68);
+	val |= 0x00206800;	// DSNpReqLimit, LimitCldtCfg, BufRefPri, RespPassPW per BKDG;
+	pci_write_config32(NODE_HT(0), 0x68, val);
+}
+
+
+
+
+/**
+ * void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0)
+ *
+ *  Needs to be fixed to output the debug structures.
+ *
+ */
+void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0)
+{
+	printk_debug("AMD_CB_EventNotify()\n");
+	printk_debug("event class: %02x event: %04x\n", evtClass, event);
+
+}
+
+/**
+ * void getAmdTopolist(u8 ***p)
+ *
+ *  point to the stock topo list array
+ *
+ */
+void getAmdTopolist(u8 ***p)
+{
+	*p = (u8 **)amd_topo_list;
+}
+
+
+/**
+ * void amd_ht_init(struct sys_info *sysinfo)
+ *
+ *  AMD HT init LinuxBIOS wrapper
+ *
+ */
+void amd_ht_init(struct sys_info *sysinfo)
+{
+	AMD_HTBLOCK ht_wrapper = {
+		NULL,	// u8 **topolist;
+		0,	// u8 AutoBusStart;
+		32,	// u8 AutoBusMax;
+		6,	// u8 AutoBusIncrement;
+		NULL,	// BOOL (*AMD_CB_IgnoreLink)();
+		NULL,	// BOOL (*AMD_CB_OverrideBusNumbers)();
+		NULL,	// BOOL (*AMD_CB_ManualBUIDSwapList)();
+		NULL,	// void (*AMD_CB_DeviceCapOverride)();
+		NULL,	// void (*AMD_CB_Cpu2CpuPCBLimits)();
+		NULL,	// void (*AMD_CB_IOPCBLimits)();
+		NULL,	// BOOL (*AMD_CB_SkipRegang)();
+		NULL,	// BOOL (*AMD_CB_CustomizeTrafficDistribution)();
+		NULL,	// BOOL (*AMD_CB_CustomizeBuffers)();
+		NULL,	// void (*AMD_CB_OverrideDevicePort)();
+		NULL,	// void (*AMD_CB_OverrideCpuPort)();
+		AMD_CB_EventNotify	// void (*AMD_CB_EventNotify) ();
+	};
+
+	printk_debug("Enter amd_ht_init()\n");
+	amdHtInitialize(&ht_wrapper);
+	printk_debug("Exit amd_ht_init()\n");
+
+
+}
+
+
+
+
Index: LinuxBIOSv2/src/northbridge/amd/amdht/porting.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/northbridge/amd/amdht/porting.h	2007-12-12 14:21:12.000000000 -0700
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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
+ */
+
+#ifndef PORTING_H
+#define PORTING_H
+
+
+/* For AMD64 or 32-bit GCC */
+typedef int int32;
+typedef unsigned int uint32;
+typedef short int16;
+typedef unsigned short uint16;
+typedef char int8;
+typedef unsigned char  uint8;
+
+/* Create the Boolean type */
+#define TRUE  1
+#define FALSE 0
+typedef unsigned char BOOL;
+
+/* Force tight packing of structures */
+#pragma pack(1)
+
+#define CALLCONV
+
+
+typedef struct _uint64
+{
+	uint32 lo;
+	uint32 hi;
+}uint64;
+
+
+/*
+ *   SBDFO - Segment Bus Device Function Offset
+ *   31:28   Segment (4-bits)
+ *   27:20   Bus     (8-bits)
+ *   19:15   Device  (5-bits)
+ *   14:12   Function(3-bits)
+ *   11:00   Offset  (12-bits)
+ */
+typedef uint32 SBDFO;
+
+#define MAKE_SBDFO(seg,bus,dev,fun,off) ((((uint32)(seg))<<28) | (((uint32)(bus))<<20) | \
+		    (((uint32)(dev))<<15) | (((uint32)(fun))<<12) | ((uint32)(off)))
+#define SBDFO_SEG(x) (((uint32)(x)>>28) & 0x0F)
+#define SBDFO_BUS(x) (((uint32)(x)>>20) & 0xFF)
+#define SBDFO_DEV(x) (((uint32)(x)>>15) & 0x1F)
+#define SBDFO_FUN(x) (((uint32)(x)>>12) & 0x07)
+#define SBDFO_OFF(x) (((uint32)(x)) & 0xFFF)
+#define ILLEGAL_SBDFO 0xFFFFFFFF
+
+void CALLCONV AmdMSRRead(uint32 Address, uint64 *Value);
+void CALLCONV AmdMSRWrite(uint32 Address, uint64 *Value);
+void CALLCONV AmdIORead(uint8 IOSize, uint16 Address, uint32 *Value);
+void CALLCONV AmdIOWrite(uint8 IOSize, uint16 Address, uint32 *Value);
+void CALLCONV AmdMemRead(uint8 MemSize, uint64 *Address, uint32 *Value);
+void CALLCONV AmdMemWrite(uint8 MemSize, uint64 *Address, uint32 *Value);
+void CALLCONV AmdPCIRead(SBDFO loc, uint32 *Value);
+void CALLCONV AmdPCIWrite(SBDFO loc, uint32 *Value);
+void CALLCONV AmdCPUIDRead(uint32 Address, uint32 Regs[4]);
+void CALLCONV ErrorStop(uint32 Value);
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define BYTESIZE 1
+#define WORDSIZE 2
+#define DWORDSIZE 4
+
+#endif /* PORTING_H */
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000033.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000033.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,163 @@
+/*
+ ============================================================
+ (c) Advanced Micro Devices, Inc., 2004-2005
+
+ The  enclosed microcode  is intended  to be  used  with AMD
+ Microprocessors.  You  may   copy,  view  and  install  the
+ enclosed microcode  only for development  and deployment of
+ firmware,  BIOS,  or  operating  system code  for  computer
+ systems   that  contain  AMD   processors.   You   are  not
+ authorized  to use  the  enclosed microcode  for any  other
+ purpose.
+
+ THE  MICROCODE IS PROVIDED  "AS IS"  WITHOUT ANY  EXPRESS OR
+ IMPLIED WARRANTY  OF ANY KIND, INCLUDING BUT  NOT LIMITED TO
+ WARRANTIES    OF    MERCHANTABILITY,   NON-    INFRINGEMENT,
+ TITLE,FITNESS  FOR  ANY  PARTICULAR PURPOSE,  OR  WARRANTIES
+ ARISING FROM CONDUCT, COURSE  OF DEALING, OR USAGE OF TRADE.
+ AMD does not assume  any responsibility for any errors which
+ may  appear   in  this   microcode  or  any   other  related
+ information provided  to you by  AMD, or result from  use of
+ this microcode.   AMD is not obligated  to furnish, support,
+ or  make   any  further  information,   software,  technical
+ information, know-how, or show-how available related to this
+ microcode.
+
+ The  microcode is provided  with "RESTRICTED  RIGHTS."  Use,
+ duplication, or disclosure by the U.S. Government is subject
+ to  the  restrictions as  set  forth  in  FAR 52.227-14  and
+ DFAR252.227-7013,  et seq.,  or its  successor.  Use  of the
+ microcode    by    the    U.S.     Government    constitutes
+ acknowledgement  of   AMD's  proprietary  rights   in  them.
+ ============================================================
+*/
+
+0x07, 0x20, 0x27, 0x06, 0x33, 0x00, 0x00, 0x01, 0x00, 0x80, 0x20, 0x00,
+0xDE, 0x76, 0xD5, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x20, 0x10, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0x70, 0x09, 0x00, 0x00,
+0x49, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0x08, 0x00, 0x00,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0xFF, 0xFF, 0x29, 0xC3, 0x5F, 0xD0, 0xC1,
+0xBD, 0xFF, 0xFF, 0xB3, 0x0F, 0xFF, 0x7E, 0xFD, 0xF6, 0x1F, 0xF8, 0x57,
+0x3C, 0xBC, 0x63, 0x2D, 0x80, 0x96, 0xD6, 0x00, 0xAA, 0xFF, 0xEF, 0xAF,
+0xE0, 0xD1, 0x9F, 0x15, 0x57, 0xEF, 0xFF, 0xFF, 0xEA, 0x87, 0x7F, 0xBF,
+0x03, 0xFA, 0x0F, 0xFC, 0xFC, 0x1F, 0xBE, 0xF5, 0x00, 0xE0, 0x4A, 0x4B,
+0x7F, 0xC8, 0xFF, 0xF7, 0xB4, 0xF8, 0xF0, 0x2F, 0xFF, 0x1F, 0xC5, 0xFE,
+0xC0, 0xCF, 0xC3, 0x3F, 0xFF, 0x03, 0xD4, 0xFF, 0x40, 0xC8, 0x0F, 0xEF,
+0x3D, 0x00, 0xF0, 0xFF, 0xFB, 0xAF, 0xE5, 0xBF, 0xD7, 0xFA, 0x3F, 0xF8,
+0xEB, 0x3F, 0x97, 0xFF, 0x9F, 0xEB, 0xFF, 0xE0, 0x97, 0xFF, 0x5E, 0xFE,
+0x7F, 0xAE, 0xFA, 0x83, 0xC9, 0x1A, 0x00, 0x08, 0x9F, 0xFC, 0x07, 0xF0,
+0x7C, 0x7B, 0xD9, 0x1F, 0x7F, 0xE0, 0x1F, 0xC0, 0xF0, 0x0F, 0xE0, 0xDF,
+0xFF, 0x81, 0x7F, 0x00, 0xC3, 0x3F, 0x80, 0x7F, 0xFC, 0x7F, 0x0F, 0x00,
+0xF8, 0x0F, 0xFC, 0x03, 0x1B, 0xFE, 0x01, 0xFC, 0xE0, 0x3F, 0xF0, 0x0F,
+0x6F, 0xF8, 0x07, 0xF0, 0x80, 0xFF, 0xC0, 0x3F, 0xBF, 0xE1, 0x1F, 0xC0,
+0x00, 0xFE, 0xBF, 0x07, 0x01, 0xFC, 0x67, 0xEB, 0x00, 0x07, 0xFE, 0xDE,
+0xFF, 0x02, 0x00, 0xE0, 0xFD, 0x3F, 0xBC, 0x63, 0xFF, 0x8B, 0xFF, 0xFF,
+0xF5, 0x7F, 0xF0, 0xEF, 0x03, 0x00, 0x3D, 0x57, 0xFF, 0x58, 0xFE, 0xBF,
+0xAC, 0x7C, 0x83, 0x3F, 0xFF, 0x7F, 0xF9, 0xE2, 0x01, 0x7E, 0x1E, 0xFE,
+0x1B, 0x0F, 0xE0, 0xBF, 0xF7, 0xF6, 0x3A, 0xF0, 0xAF, 0x01, 0x80, 0xB4,
+0x81, 0x7F, 0x00, 0xFF, 0x3F, 0x80, 0x7F, 0xC3, 0x07, 0xFE, 0x01, 0xFC,
+0xFF, 0x00, 0xFE, 0x0D, 0x1F, 0xF8, 0x07, 0xF0, 0xFC, 0x03, 0xF8, 0x37,
+0xFF, 0xF7, 0x00, 0xC0, 0xFF, 0xC0, 0x3F, 0x80, 0xE1, 0x1F, 0xC0, 0xBF,
+0xFE, 0x03, 0xFF, 0x00, 0x86, 0x7F, 0x00, 0xFF, 0xF8, 0x0F, 0xFC, 0x03,
+0x1B, 0xFE, 0x01, 0xFC, 0xE0, 0xFF, 0x7B, 0x00, 0xC0, 0x7F, 0xE0, 0x1F,
+0xDF, 0xF0, 0x0F, 0xE0, 0x00, 0xFF, 0x81, 0x7F, 0x7F, 0xC3, 0x3F, 0x80,
+0x01, 0xFC, 0x07, 0xFE, 0xFE, 0x0D, 0xFF, 0x00, 0x00, 0xF0, 0xFF, 0x3D,
+0x0F, 0xE0, 0x3F, 0xF0, 0xF0, 0x6F, 0xF8, 0x07, 0x3F, 0x80, 0xFF, 0xC0,
+0xC0, 0xBF, 0xE1, 0x1F, 0xFF, 0x00, 0xFE, 0x03, 0x00, 0xFF, 0x86, 0x7F,
+0x1E, 0x00, 0xF8, 0xFF, 0xF8, 0x07, 0xF0, 0x1F, 0x03, 0xF8, 0x37, 0xFC,
+0xE0, 0x1F, 0xC0, 0x7F, 0x0F, 0xE0, 0xDF, 0xF0, 0x81, 0x7F, 0x00, 0xFF,
+0x3F, 0x80, 0x7F, 0xC3, 0x7F, 0x0F, 0x00, 0xFC, 0x0F, 0xFC, 0x03, 0xF8,
+0xFE, 0x01, 0xFC, 0x1B, 0x3F, 0xF0, 0x0F, 0xE0, 0xF8, 0x07, 0xF0, 0x6F,
+0xFF, 0xC0, 0x3F, 0x80, 0xE1, 0x1F, 0xC0, 0xBF, 0xFE, 0xBF, 0x07, 0x00,
+0xFC, 0x07, 0xFE, 0x01, 0x0D, 0xFF, 0x00, 0xFE, 0xF0, 0x1F, 0xF8, 0x07,
+0x37, 0xFC, 0x03, 0xF8, 0xC0, 0x7F, 0xE0, 0x1F, 0xDF, 0xF0, 0x0F, 0xE0,
+0x00, 0xFF, 0xDF, 0x03, 0x00, 0xFE, 0x03, 0xFF, 0xFF, 0x86, 0x7F, 0x00,
+0x03, 0xF8, 0x0F, 0xFC, 0xFC, 0x1B, 0xFE, 0x01, 0x0F, 0xE0, 0x3F, 0xF0,
+0xF0, 0x6F, 0xF8, 0x07, 0x01, 0x80, 0xFF, 0xEF, 0x7F, 0x00, 0xFF, 0x81,
+0x80, 0x7F, 0xC3, 0x3F, 0xFE, 0x01, 0xFC, 0x07, 0x00, 0xFE, 0x0D, 0xFF,
+0xF8, 0x07, 0xF0, 0x1F, 0x03, 0xF8, 0x37, 0xFC, 0xD7, 0x00, 0x40, 0x34,
+0xC0, 0x3F, 0x80, 0xFF, 0x1F, 0xC0, 0xBF, 0xE1, 0x03, 0xFF, 0x00, 0xFE,
+0x7F, 0x00, 0xFF, 0x86, 0x0F, 0xFC, 0x03, 0xF8, 0xFE, 0x01, 0xFC, 0x1B,
+0x9A, 0x6B, 0x00, 0x00, 0x7F, 0xE0, 0x1F, 0xC0, 0xF0, 0x0F, 0xE0, 0xDF,
+0xFF, 0x81, 0x7F, 0x00, 0xC3, 0x3F, 0x80, 0x7F, 0xFC, 0x07, 0xFE, 0x01,
+0x0D, 0xFF, 0x00, 0xFE, 0xF0, 0xFF, 0x3D, 0x00, 0xE0, 0x3F, 0xF0, 0x0F,
+0x6F, 0xF8, 0x07, 0xF0, 0x80, 0xFF, 0xC0, 0x3F, 0xBF, 0xE1, 0x1F, 0xC0,
+0x00, 0xFE, 0x03, 0xFF, 0xFF, 0x86, 0x7F, 0x00, 0x00, 0xF8, 0xFF, 0x1E,
+0x07, 0xF0, 0x1F, 0xF8, 0xF8, 0x37, 0xFC, 0x03, 0x1F, 0xC0, 0x7F, 0xE0,
+0xE0, 0xDF, 0xF0, 0x0F, 0x7F, 0x00, 0xFF, 0x81, 0x80, 0x7F, 0xC3, 0x3F,
+0x0F, 0x00, 0xFC, 0x7F, 0xFC, 0x03, 0xF8, 0x0F, 0x01, 0xFC, 0x1B, 0xFE,
+0xF0, 0x0F, 0xE0, 0x3F, 0x07, 0xF0, 0x6F, 0xF8, 0xC0, 0x3F, 0x80, 0xFF,
+0x1F, 0xC0, 0xBF, 0xE1, 0xBF, 0x07, 0x00, 0xFE, 0x07, 0xFE, 0x01, 0xFC,
+0xFF, 0x00, 0xFE, 0x0D, 0x1F, 0xF8, 0x07, 0xF0, 0xFC, 0x03, 0xF8, 0x37,
+0x7F, 0xE0, 0x1F, 0xC0, 0xF0, 0x0F, 0xE0, 0xDF, 0xFF, 0xDF, 0x03, 0x00,
+0xFE, 0x03, 0xFF, 0x00, 0x86, 0x7F, 0x00, 0xFF, 0xF8, 0x0F, 0xFC, 0x03,
+0x1B, 0xFE, 0x01, 0xFC, 0xE0, 0x3F, 0xF0, 0x0F, 0x6F, 0xF8, 0x07, 0xF0,
+0x80, 0xFF, 0xEF, 0x01, 0x00, 0xFF, 0x81, 0x7F, 0x7F, 0xC3, 0x3F, 0x80,
+0x01, 0xFC, 0x07, 0xFE, 0xFE, 0x0D, 0xFF, 0x00, 0x07, 0xF0, 0x1F, 0xF8,
+0xF8, 0x37, 0xFC, 0x03, 0x00, 0xC0, 0xFF, 0xF7, 0x3F, 0x80, 0xFF, 0xC0,
+0xC0, 0xBF, 0xE1, 0x1F, 0xFF, 0x00, 0xFE, 0x03, 0x00, 0xFF, 0x86, 0x7F,
+0xFC, 0x03, 0xF8, 0x0F, 0x01, 0xFC, 0x1B, 0xFE, 0x7B, 0x00, 0xE0, 0xFF,
+0xE0, 0x1F, 0xC0, 0x7F, 0x0F, 0xE0, 0xDF, 0xF0, 0x81, 0x7F, 0x00, 0xFF,
+0x3F, 0x80, 0x7F, 0xC3, 0x07, 0xFE, 0x01, 0xFC, 0xFF, 0x00, 0xFE, 0x0D,
+0xFF, 0x3D, 0x00, 0xF0, 0x3F, 0xF0, 0x0F, 0xE0, 0xF8, 0x07, 0xF0, 0x6F,
+0xFF, 0xC0, 0x3F, 0x80, 0xE1, 0x1F, 0xC0, 0xBF, 0xFE, 0x03, 0xFF, 0x00,
+0x86, 0x7F, 0x00, 0xFF, 0xF8, 0xFF, 0x1E, 0x00, 0xF0, 0x1F, 0xF8, 0x07,
+0x37, 0xFC, 0x03, 0xF8, 0xC0, 0x7F, 0xE0, 0x1F, 0xDF, 0xF0, 0x0F, 0xE0,
+0x00, 0xFF, 0x81, 0x7F, 0x7F, 0xC3, 0x3F, 0x80, 0x00, 0xFC, 0x7F, 0x0F,
+0x03, 0xF8, 0x0F, 0xFC, 0xFC, 0x1B, 0xFE, 0x01, 0x0F, 0xE0, 0x3F, 0xF0,
+0xF0, 0x6F, 0xF8, 0x07, 0x3F, 0x80, 0xFF, 0xC0, 0xC0, 0xBF, 0xE1, 0x1F,
+0x07, 0x00, 0xFE, 0xBF, 0xFE, 0x01, 0xFC, 0x07, 0x00, 0xFE, 0x0D, 0xFF,
+0xF8, 0x07, 0xF0, 0x1F, 0x03, 0xF8, 0x37, 0xFC, 0xE0, 0x1F, 0xC0, 0x7F,
+0x0F, 0xE0, 0xDF, 0xF0, 0xDF, 0x03, 0x00, 0xFF, 0x03, 0xFF, 0x00, 0xFE,
+0x7F, 0x00, 0xFF, 0x86, 0x0F, 0xFC, 0x03, 0xF8, 0xFE, 0x01, 0xFC, 0x1B,
+0x3F, 0xF0, 0x0F, 0xE0, 0xF8, 0x07, 0xF0, 0x6F, 0xFF, 0xEF, 0x01, 0x80,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000035.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/mc_patch_01000035.h	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,163 @@
+/*
+ ============================================================
+ (c) Advanced Micro Devices, Inc., 2004-2005
+
+ The  enclosed microcode  is intended  to be  used  with AMD
+ Microprocessors.  You  may   copy,  view  and  install  the
+ enclosed microcode  only for development  and deployment of
+ firmware,  BIOS,  or  operating  system code  for  computer
+ systems   that  contain  AMD   processors.   You   are  not
+ authorized  to use  the  enclosed microcode  for any  other
+ purpose.
+
+ THE  MICROCODE IS PROVIDED  "AS IS"  WITHOUT ANY  EXPRESS OR
+ IMPLIED WARRANTY  OF ANY KIND, INCLUDING BUT  NOT LIMITED TO
+ WARRANTIES    OF    MERCHANTABILITY,   NON-    INFRINGEMENT,
+ TITLE,FITNESS  FOR  ANY  PARTICULAR PURPOSE,  OR  WARRANTIES
+ ARISING FROM CONDUCT, COURSE  OF DEALING, OR USAGE OF TRADE.
+ AMD does not assume  any responsibility for any errors which
+ may  appear   in  this   microcode  or  any   other  related
+ information provided  to you by  AMD, or result from  use of
+ this microcode.   AMD is not obligated  to furnish, support,
+ or  make   any  further  information,   software,  technical
+ information, know-how, or show-how available related to this
+ microcode.
+
+ The  microcode is provided  with "RESTRICTED  RIGHTS."  Use,
+ duplication, or disclosure by the U.S. Government is subject
+ to  the  restrictions as  set  forth  in  FAR 52.227-14  and
+ DFAR252.227-7013,  et seq.,  or its  successor.  Use  of the
+ microcode    by    the    U.S.     Government    constitutes
+ acknowledgement  of   AMD's  proprietary  rights   in  them.
+ ============================================================
+*/
+
+0x07, 0x20, 0x23, 0x07, 0x35, 0x00, 0x00, 0x01, 0x00, 0x80, 0x20, 0x00,
+0xDE, 0x76, 0xD5, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x22, 0x10, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0x70, 0x09, 0x00, 0x00,
+0x49, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0x08, 0x00, 0x00,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0xFF, 0xFF, 0x29, 0xC3, 0x5F, 0xD0, 0xC1,
+0xBD, 0xFF, 0xFF, 0xB3, 0x0F, 0xFF, 0x7E, 0xFD, 0xF6, 0x1F, 0xF8, 0x57,
+0x3C, 0xBC, 0x63, 0x2D, 0x80, 0x96, 0xD6, 0x00, 0xAA, 0xFF, 0xEF, 0xAF,
+0xE0, 0xD1, 0x9F, 0x15, 0x57, 0xEF, 0xFF, 0xFF, 0xEA, 0x87, 0x7F, 0xBF,
+0x03, 0xFA, 0x0F, 0xFC, 0xFC, 0x1F, 0xBE, 0xF5, 0x00, 0xE0, 0x4A, 0x4B,
+0x7F, 0xC8, 0xFF, 0xF7, 0xB4, 0xF8, 0xF0, 0x2F, 0xFF, 0x1F, 0xC5, 0xFE,
+0xC0, 0xCF, 0xC3, 0x3F, 0xFF, 0x03, 0xD4, 0xFF, 0x40, 0xC8, 0x0F, 0xEF,
+0x3D, 0x00, 0xF0, 0xFF, 0xFB, 0xAF, 0xE5, 0xBF, 0xD7, 0xFA, 0x3F, 0xF8,
+0xEB, 0x3F, 0x97, 0xFF, 0x9F, 0xEB, 0xFF, 0xE0, 0x97, 0xFF, 0x5E, 0xFE,
+0x7F, 0xAE, 0xFA, 0x83, 0xC9, 0x1A, 0x00, 0x08, 0x9F, 0xFC, 0x07, 0xF0,
+0x7C, 0x7B, 0xD9, 0x1F, 0x7F, 0xE0, 0x1F, 0xC0, 0xF0, 0x0F, 0xE0, 0xDF,
+0xFF, 0x81, 0x7F, 0x00, 0xC3, 0x3F, 0x80, 0x7F, 0xFC, 0x7F, 0x0F, 0x00,
+0xF8, 0x0F, 0xFC, 0x03, 0x1B, 0xFE, 0x01, 0xFC, 0xE0, 0x3F, 0xF0, 0x0F,
+0x6F, 0xF8, 0x07, 0xF0, 0x80, 0xFF, 0xC0, 0x3F, 0xBF, 0xE1, 0x1F, 0xC0,
+0x00, 0xFE, 0xBF, 0x07, 0x01, 0xFC, 0x67, 0xEB, 0x00, 0x07, 0xFE, 0xDE,
+0xFF, 0x02, 0x00, 0xE0, 0xFD, 0x3F, 0xBC, 0x63, 0xFF, 0x8B, 0xFF, 0xFF,
+0xF5, 0x7F, 0xF0, 0xEF, 0x03, 0x00, 0x3D, 0x57, 0xFF, 0x58, 0xFE, 0xBF,
+0xAC, 0x7C, 0x83, 0x3F, 0xFF, 0x7F, 0xF9, 0xE2, 0x01, 0x7E, 0x1E, 0xFE,
+0x1B, 0x0F, 0xE0, 0xBF, 0xF7, 0xF6, 0x3A, 0xF0, 0xAF, 0x01, 0x80, 0xB4,
+0x81, 0x7F, 0x00, 0xFF, 0x3F, 0x80, 0x7F, 0xC3, 0x07, 0xFE, 0x01, 0xFC,
+0xFF, 0x00, 0xFE, 0x0D, 0x1F, 0xF8, 0x07, 0xF0, 0xFC, 0x03, 0xF8, 0x37,
+0xFF, 0xF7, 0x00, 0xC0, 0xFF, 0xC0, 0x3F, 0x80, 0xE1, 0x1F, 0xC0, 0xBF,
+0xFE, 0x03, 0xFF, 0x00, 0x86, 0x7F, 0x00, 0xFF, 0xF8, 0x0F, 0xFC, 0x03,
+0x1B, 0xFE, 0x01, 0xFC, 0xE0, 0xFF, 0x7B, 0x00, 0xC0, 0x7F, 0xE0, 0x1F,
+0xDF, 0xF0, 0x0F, 0xE0, 0x00, 0xFF, 0x81, 0x7F, 0x7F, 0xC3, 0x3F, 0x80,
+0x01, 0xFC, 0x07, 0xFE, 0xFE, 0x0D, 0xFF, 0x00, 0x00, 0xF0, 0xFF, 0x3D,
+0x0F, 0xE0, 0x3F, 0xF0, 0xF0, 0x6F, 0xF8, 0x07, 0x3F, 0x80, 0xFF, 0xC0,
+0xC0, 0xBF, 0xE1, 0x1F, 0xFF, 0x00, 0xFE, 0x03, 0x00, 0xFF, 0x86, 0x7F,
+0x1E, 0x00, 0xF8, 0xFF, 0xF8, 0x07, 0xF0, 0x1F, 0x03, 0xF8, 0x37, 0xFC,
+0xE0, 0x1F, 0xC0, 0x7F, 0x0F, 0xE0, 0xDF, 0xF0, 0x81, 0x7F, 0x00, 0xFF,
+0x3F, 0x80, 0x7F, 0xC3, 0x7F, 0x0F, 0x00, 0xFC, 0x0F, 0xFC, 0x03, 0xF8,
+0xFE, 0x01, 0xFC, 0x1B, 0x3F, 0xF0, 0x0F, 0xE0, 0xF8, 0x07, 0xF0, 0x6F,
+0xFF, 0xC0, 0x3F, 0x80, 0xE1, 0x1F, 0xC0, 0xBF, 0xFE, 0xBF, 0x07, 0x00,
+0xFC, 0x07, 0xFE, 0x01, 0x0D, 0xFF, 0x00, 0xFE, 0xF0, 0x1F, 0xF8, 0x07,
+0x37, 0xFC, 0x03, 0xF8, 0xC0, 0x7F, 0xE0, 0x1F, 0xDF, 0xF0, 0x0F, 0xE0,
+0x00, 0xFF, 0xDF, 0x03, 0x00, 0xFE, 0x03, 0xFF, 0xFF, 0x86, 0x7F, 0x00,
+0x03, 0xF8, 0x0F, 0xFC, 0xFC, 0x1B, 0xFE, 0x01, 0x0F, 0xE0, 0x3F, 0xF0,
+0xF0, 0x6F, 0xF8, 0x07, 0x01, 0x80, 0xFF, 0xEF, 0x7F, 0x00, 0xFF, 0x81,
+0x80, 0x7F, 0xC3, 0x3F, 0xFE, 0x01, 0xFC, 0x07, 0x00, 0xFE, 0x0D, 0xFF,
+0xF8, 0x07, 0xF0, 0x1F, 0x03, 0xF8, 0x37, 0xFC, 0xD7, 0x00, 0x40, 0x34,
+0xC0, 0x3F, 0x80, 0xFF, 0x1F, 0xC0, 0xBF, 0xE1, 0x03, 0xFF, 0x00, 0xFE,
+0x7F, 0x00, 0xFF, 0x86, 0x0F, 0xFC, 0x03, 0xF8, 0xFE, 0x01, 0xFC, 0x1B,
+0x9A, 0x6B, 0x00, 0x00, 0x7F, 0xE0, 0x1F, 0xC0, 0xF0, 0x0F, 0xE0, 0xDF,
+0xFF, 0x81, 0x7F, 0x00, 0xC3, 0x3F, 0x80, 0x7F, 0xFC, 0x07, 0xFE, 0x01,
+0x0D, 0xFF, 0x00, 0xFE, 0xF0, 0xFF, 0x3D, 0x00, 0xE0, 0x3F, 0xF0, 0x0F,
+0x6F, 0xF8, 0x07, 0xF0, 0x80, 0xFF, 0xC0, 0x3F, 0xBF, 0xE1, 0x1F, 0xC0,
+0x00, 0xFE, 0x03, 0xFF, 0xFF, 0x86, 0x7F, 0x00, 0x00, 0xF8, 0xFF, 0x1E,
+0x07, 0xF0, 0x1F, 0xF8, 0xF8, 0x37, 0xFC, 0x03, 0x1F, 0xC0, 0x7F, 0xE0,
+0xE0, 0xDF, 0xF0, 0x0F, 0x7F, 0x00, 0xFF, 0x81, 0x80, 0x7F, 0xC3, 0x3F,
+0x0F, 0x00, 0xFC, 0x7F, 0xFC, 0x03, 0xF8, 0x0F, 0x01, 0xFC, 0x1B, 0xFE,
+0xF0, 0x0F, 0xE0, 0x3F, 0x07, 0xF0, 0x6F, 0xF8, 0xC0, 0x3F, 0x80, 0xFF,
+0x1F, 0xC0, 0xBF, 0xE1, 0xBF, 0x07, 0x00, 0xFE, 0x07, 0xFE, 0x01, 0xFC,
+0xFF, 0x00, 0xFE, 0x0D, 0x1F, 0xF8, 0x07, 0xF0, 0xFC, 0x03, 0xF8, 0x37,
+0x7F, 0xE0, 0x1F, 0xC0, 0xF0, 0x0F, 0xE0, 0xDF, 0xFF, 0xDF, 0x03, 0x00,
+0xFE, 0x03, 0xFF, 0x00, 0x86, 0x7F, 0x00, 0xFF, 0xF8, 0x0F, 0xFC, 0x03,
+0x1B, 0xFE, 0x01, 0xFC, 0xE0, 0x3F, 0xF0, 0x0F, 0x6F, 0xF8, 0x07, 0xF0,
+0x80, 0xFF, 0xEF, 0x01, 0x00, 0xFF, 0x81, 0x7F, 0x7F, 0xC3, 0x3F, 0x80,
+0x01, 0xFC, 0x07, 0xFE, 0xFE, 0x0D, 0xFF, 0x00, 0x07, 0xF0, 0x1F, 0xF8,
+0xF8, 0x37, 0xFC, 0x03, 0x00, 0xC0, 0xFF, 0xF7, 0x3F, 0x80, 0xFF, 0xC0,
+0xC0, 0xBF, 0xE1, 0x1F, 0xFF, 0x00, 0xFE, 0x03, 0x00, 0xFF, 0x86, 0x7F,
+0xFC, 0x03, 0xF8, 0x0F, 0x01, 0xFC, 0x1B, 0xFE, 0x7B, 0x00, 0xE0, 0xFF,
+0xE0, 0x1F, 0xC0, 0x7F, 0x0F, 0xE0, 0xDF, 0xF0, 0x81, 0x7F, 0x00, 0xFF,
+0x3F, 0x80, 0x7F, 0xC3, 0x07, 0xFE, 0x01, 0xFC, 0xFF, 0x00, 0xFE, 0x0D,
+0xFF, 0x3D, 0x00, 0xF0, 0x3F, 0xF0, 0x0F, 0xE0, 0xF8, 0x07, 0xF0, 0x6F,
+0xFF, 0xC0, 0x3F, 0x80, 0xE1, 0x1F, 0xC0, 0xBF, 0xFE, 0x03, 0xFF, 0x00,
+0x86, 0x7F, 0x00, 0xFF, 0xF8, 0xFF, 0x1E, 0x00, 0xF0, 0x1F, 0xF8, 0x07,
+0x37, 0xFC, 0x03, 0xF8, 0xC0, 0x7F, 0xE0, 0x1F, 0xDF, 0xF0, 0x0F, 0xE0,
+0x00, 0xFF, 0x81, 0x7F, 0x7F, 0xC3, 0x3F, 0x80, 0x00, 0xFC, 0x7F, 0x0F,
+0x03, 0xF8, 0x0F, 0xFC, 0xFC, 0x1B, 0xFE, 0x01, 0x0F, 0xE0, 0x3F, 0xF0,
+0xF0, 0x6F, 0xF8, 0x07, 0x3F, 0x80, 0xFF, 0xC0, 0xC0, 0xBF, 0xE1, 0x1F,
+0x07, 0x00, 0xFE, 0xBF, 0xFE, 0x01, 0xFC, 0x07, 0x00, 0xFE, 0x0D, 0xFF,
+0xF8, 0x07, 0xF0, 0x1F, 0x03, 0xF8, 0x37, 0xFC, 0xE0, 0x1F, 0xC0, 0x7F,
+0x0F, 0xE0, 0xDF, 0xF0, 0xDF, 0x03, 0x00, 0xFF, 0x03, 0xFF, 0x00, 0xFE,
+0x7F, 0x00, 0xFF, 0x86, 0x0F, 0xFC, 0x03, 0xF8, 0xFE, 0x01, 0xFC, 0x1B,
+0x3F, 0xF0, 0x0F, 0xE0, 0xF8, 0x07, 0xF0, 0x6F, 0xFF, 0xEF, 0x01, 0x80,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
Index: LinuxBIOSv2/src/cpu/amd/model_10xxx/apic_timer.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LinuxBIOSv2/src/cpu/amd/model_10xxx/apic_timer.c	2007-12-12 11:19:15.000000000 -0700
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 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 <stdint.h>
+#include <delay.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/lapic.h>
+
+/* NOTE: We use the APIC TIMER register is to hold flags for AP init during
+ * pre-memory init (ROMCC). Don't use init_timer() and  udelay is redirected
+ * to udelay_tsc().
+ */
+
+
+void init_timer(void)
+{
+	/* Set the apic timer to no interrupts and periodic mode */
+	lapic_write(LAPIC_LVTT, (1 << 17)|(1<< 16)|(0 << 12)|(0 << 0));
+
+	/* Set the divider to 1, no divider */
+	lapic_write(LAPIC_TDCR, LAPIC_TDR_DIV_1);
+
+	/* Set the initial counter to 0xffffffff */
+	lapic_write(LAPIC_TMICT, 0xffffffff);
+
+}
+
+
+void udelay(u32 usecs)
+{
+	u32 start, value, ticks;
+	/* Calculate the number of ticks to run, our FSB runs a 200Mhz */
+	ticks = usecs * 200;
+	start = lapic_read(LAPIC_TMCCT);
+	do {
+		value = lapic_read(LAPIC_TMCCT);
+	} while((start - value) < ticks);
+
+}
