summaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdht
diff options
context:
space:
mode:
authorMarc Jones <marc.jones@amd.com>2007-12-19 01:32:08 +0000
committerMarc Jones <marc.jones@amd.com>2007-12-19 01:32:08 +0000
commit8ae8c8822068ef1722c08073ffa4ecc25633cbee (patch)
tree8c7bbf2f7b791081e486439a9b7ffb2fd6e649ac /src/northbridge/amd/amdht
parent2006b38fed2f5f3680de1736f7fc878823f2f93b (diff)
downloadcoreboot-8ae8c8822068ef1722c08073ffa4ecc25633cbee.tar.xz
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> Acked-by: Myles Watson <myles@pel.cs.byu.edu> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3014 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/amd/amdht')
-rw-r--r--src/northbridge/amd/amdht/AsPsDefs.h252
-rw-r--r--src/northbridge/amd/amdht/AsPsNb.c145
-rw-r--r--src/northbridge/amd/amdht/AsPsNb.h26
-rw-r--r--src/northbridge/amd/amdht/comlib.c290
-rw-r--r--src/northbridge/amd/amdht/comlib.h59
-rw-r--r--src/northbridge/amd/amdht/h3ffeat.h177
-rw-r--r--src/northbridge/amd/amdht/h3finit.c1678
-rw-r--r--src/northbridge/amd/amdht/h3finit.h613
-rw-r--r--src/northbridge/amd/amdht/h3gtopo.h358
-rw-r--r--src/northbridge/amd/amdht/h3ncmn.c2214
-rw-r--r--src/northbridge/amd/amdht/h3ncmn.h132
-rw-r--r--src/northbridge/amd/amdht/ht_wrapper.c160
-rw-r--r--src/northbridge/amd/amdht/porting.h88
13 files changed, 6192 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdht/AsPsDefs.h b/src/northbridge/amd/amdht/AsPsDefs.h
new file mode 100644
index 0000000000..2a5a908c71
--- /dev/null
+++ b/src/northbridge/amd/amdht/AsPsDefs.h
@@ -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
diff --git a/src/northbridge/amd/amdht/AsPsNb.c b/src/northbridge/amd/amdht/AsPsNb.c
new file mode 100644
index 0000000000..8f79cd107f
--- /dev/null
+++ b/src/northbridge/amd/amdht/AsPsNb.c
@@ -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);
+}
diff --git a/src/northbridge/amd/amdht/AsPsNb.h b/src/northbridge/amd/amdht/AsPsNb.h
new file mode 100644
index 0000000000..c7ac180b3e
--- /dev/null
+++ b/src/northbridge/amd/amdht/AsPsNb.h
@@ -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
diff --git a/src/northbridge/amd/amdht/comlib.c b/src/northbridge/amd/amdht/comlib.c
new file mode 100644
index 0000000000..47c538b19e
--- /dev/null
+++ b/src/northbridge/amd/amdht/comlib.c
@@ -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
+*/
diff --git a/src/northbridge/amd/amdht/comlib.h b/src/northbridge/amd/amdht/comlib.h
new file mode 100644
index 0000000000..08c6d111f1
--- /dev/null
+++ b/src/northbridge/amd/amdht/comlib.h
@@ -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
diff --git a/src/northbridge/amd/amdht/h3ffeat.h b/src/northbridge/amd/amdht/h3ffeat.h
new file mode 100644
index 0000000000..d415fee108
--- /dev/null
+++ b/src/northbridge/amd/amdht/h3ffeat.h
@@ -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 */
diff --git a/src/northbridge/amd/amdht/h3finit.c b/src/northbridge/amd/amdht/h3finit.c
new file mode 100644
index 0000000000..dd3e3813bd
--- /dev/null
+++ b/src/northbridge/amd/amdht/h3finit.c
@@ -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);
+ }
+}
diff --git a/src/northbridge/amd/amdht/h3finit.h b/src/northbridge/amd/amdht/h3finit.h
new file mode 100644
index 0000000000..8da1bd2e8c
--- /dev/null
+++ b/src/northbridge/amd/amdht/h3finit.h
@@ -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 */
+
+
diff --git a/src/northbridge/amd/amdht/h3gtopo.h b/src/northbridge/amd/amdht/h3gtopo.h
new file mode 100644
index 0000000000..a724618763
--- /dev/null
+++ b/src/northbridge/amd/amdht/h3gtopo.h
@@ -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 */
+
diff --git a/src/northbridge/amd/amdht/h3ncmn.c b/src/northbridge/amd/amdht/h3ncmn.c
new file mode 100644
index 0000000000..f03139f914
--- /dev/null
+++ b/src/northbridge/amd/amdht/h3ncmn.c
@@ -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);
+}
+
diff --git a/src/northbridge/amd/amdht/h3ncmn.h b/src/northbridge/amd/amdht/h3ncmn.h
new file mode 100644
index 0000000000..51f82bff6f
--- /dev/null
+++ b/src/northbridge/amd/amdht/h3ncmn.h
@@ -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 */
diff --git a/src/northbridge/amd/amdht/ht_wrapper.c b/src/northbridge/amd/amdht/ht_wrapper.c
new file mode 100644
index 0000000000..6892c63e45
--- /dev/null
+++ b/src/northbridge/amd/amdht/ht_wrapper.c
@@ -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");
+
+
+}
+
+
+
+
diff --git a/src/northbridge/amd/amdht/porting.h b/src/northbridge/amd/amdht/porting.h
new file mode 100644
index 0000000000..534e742fd5
--- /dev/null
+++ b/src/northbridge/amd/amdht/porting.h
@@ -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 */