summaryrefslogtreecommitdiff
path: root/src/northbridge/amd
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd')
-rw-r--r--src/northbridge/amd/amdk8/incoherent_ht.c141
1 files changed, 108 insertions, 33 deletions
diff --git a/src/northbridge/amd/amdk8/incoherent_ht.c b/src/northbridge/amd/amdk8/incoherent_ht.c
index 55b37cc4a8..c5f7f2da6f 100644
--- a/src/northbridge/amd/amdk8/incoherent_ht.c
+++ b/src/northbridge/amd/amdk8/incoherent_ht.c
@@ -12,8 +12,7 @@ static unsigned ht_lookup_slave_capability(device_t dev)
hdr_type &= 0x7f;
if ((hdr_type == PCI_HEADER_TYPE_NORMAL) ||
- (hdr_type == PCI_HEADER_TYPE_BRIDGE))
- {
+ (hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
pos = PCI_CAPABILITY_LIST;
}
if (pos > PCI_CAP_LIST_NEXT) {
@@ -39,18 +38,26 @@ static unsigned ht_lookup_slave_capability(device_t dev)
static void ht_collapse_previous_enumeration(unsigned bus)
{
device_t dev;
+ uint32_t id;
+ /* Check if is already collapsed */
+ dev = PCI_DEV(bus, 0, 0);
+ id = pci_read_config32(dev, PCI_VENDOR_ID);
+ if ( ! ( (id == 0xffffffff) || (id == 0x00000000) ||
+ (id == 0x0000ffff) || (id == 0xffff0000) ) ) {
+ return;
+ }
+
/* Spin through the devices and collapse any previous
* hypertransport enumeration.
*/
- for(dev = PCI_DEV(bus, 0, 0); dev <= PCI_DEV(bus, 0x1f, 0x7); dev += PCI_DEV(0, 1, 0)) {
+ for(dev = PCI_DEV(bus, 1, 0); dev <= PCI_DEV(bus, 0x1f, 0x7); dev += PCI_DEV(0, 1, 0)) {
uint32_t id;
unsigned pos, flags;
id = pci_read_config32(dev, PCI_VENDOR_ID);
if ((id == 0xffffffff) || (id == 0x00000000) ||
- (id == 0x0000ffff) || (id == 0xffff0000))
- {
+ (id == 0x0000ffff) || (id == 0xffff0000)) {
continue;
}
@@ -92,7 +99,7 @@ static unsigned ht_read_freq_cap(device_t dev, unsigned pos)
return freq_cap;
}
-#define LINK_OFFS(WIDTH,FREQ,FREQ_CAP) \
+#define LINK_OFFS(WIDTH,FREQ,FREQ_CAP) \
(((WIDTH & 0xff) << 16) | ((FREQ & 0xff) << 8) | (FREQ_CAP & 0xFF))
#define LINK_WIDTH(OFFS) ((OFFS >> 16) & 0xFF)
@@ -196,8 +203,6 @@ static int ht_setup_chain(device_t udev, unsigned upos)
int reset_needed;
unsigned uoffs;
-#warning "FIXME handle multiple chains!"
-
/* Make certain the HT bus is not enumerated */
ht_collapse_previous_enumeration(0);
@@ -214,8 +219,8 @@ static int ht_setup_chain(device_t udev, unsigned upos)
id = pci_read_config32(dev, PCI_VENDOR_ID);
/* If the chain is enumerated quit */
if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0x0000)) {
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
break;
}
@@ -247,9 +252,6 @@ static int ht_setup_chain(device_t udev, unsigned upos)
return reset_needed;
}
-struct ht_chain {
- unsigned devreg;
-};
static int ht_setup_chainx(device_t udev, unsigned upos, unsigned bus)
{
unsigned next_unitid, last_unitid;
@@ -274,15 +276,7 @@ static int ht_setup_chainx(device_t udev, unsigned upos, unsigned bus)
(((id >> 16) & 0xffff) == 0x0000)) {
break;
}
-#if 0
- print_debug("bus=");
- print_debug_hex8(bus);
- print_debug(" id =");
- print_debug_hex32(id);
- print_debug("\r\n");
-#endif
-
pos = ht_lookup_slave_capability(dev);
if (!pos) {
print_err("HT link capability not found\r\n");
@@ -311,7 +305,7 @@ static int ht_setup_chainx(device_t udev, unsigned upos, unsigned bus)
return reset_needed;
}
-static int ht_setup_chains(const struct ht_chain *ht_c, int ht_c_num)
+static int ht_setup_chains(int ht_c_num)
{
/* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
* On most boards this just happens. If a cpu has multiple
@@ -332,7 +326,7 @@ static int ht_setup_chains(const struct ht_chain *ht_c, int ht_c_num)
uint32_t dword;
unsigned busn;
- reg = pci_read_config32(PCI_DEV(0,0x18,1), ht_c[i].devreg);
+ reg = pci_read_config32(PCI_DEV(0,0x18,1), 0xe0 + i * 4);
//We need setup 0x94, 0xb4, and 0xd4 according to the reg
devpos = ((reg & 0xf0)>>4)+0x18; // nodeid; it will decide 0x18 or 0x19
@@ -343,13 +337,9 @@ static int ht_setup_chains(const struct ht_chain *ht_c, int ht_c_num)
dword &= ~(0xffff<<8);
dword |= (reg & 0xffff0000)>>8;
pci_write_config32( PCI_DEV(0, devpos,0), regpos , dword);
+
#if 0
- print_debug("udev=(0,0x");
- print_debug_hex8(devpos);
- print_debug(",0) 0x");
- print_debug_hex8(regpos);
- print_debug("=");
- print_debug_hex32(dword);
+ dump_pci_devices_on_bus(busn);
#endif
/* Make certain the HT bus is not enumerated */
@@ -357,11 +347,10 @@ static int ht_setup_chains(const struct ht_chain *ht_c, int ht_c_num)
upos = ((reg & 0xf00)>>8) * 0x20 + 0x80;
udev = PCI_DEV(0, devpos, 0);
+
#if 0
- print_debug("\tupos=0x");
- print_debug_hex32(upos);
- print_debug("\r\n");
-#endif
+ dump_pci_devices_on_bus(busn);
+#endif
reset_needed |= ht_setup_chainx(udev,upos,busn );
@@ -369,3 +358,89 @@ static int ht_setup_chains(const struct ht_chain *ht_c, int ht_c_num)
return reset_needed;
}
+
+static int ht_setup_chains_x(void)
+{
+ int nodeid;
+ uint32_t reg;
+ uint32_t tempreg;
+ unsigned next_busn;
+ int ht_c_num;
+
+ // read PCI_DEV(0,0x18,0) 0x64 bit [8:9] to find out SbLink m
+ reg = pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64);
+ //update PCI_DEV(0, 0x18, 1) 0xe0 to 0x05000m03, and next_busn=5+1;
+ tempreg = 3 | ( 0<<4) | (((reg>>8) & 3)<<8) | (0<<16)| (5<<24);
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0, tempreg);
+ next_busn=5+1; // 0 will be used ht chain with SB we need to keep SB in bus0 in auto stage
+ // clean others
+ for(ht_c_num=1;ht_c_num<4; ht_c_num++) {
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4, 0);
+ }
+
+ for(nodeid=0; nodeid<8; nodeid++) {
+ device_t dev;
+ unsigned linkn;
+ dev = PCI_DEV(0, 0x18+nodeid,0);
+ //read id, check id to see if dev exists ;
+ reg = pci_read_config32(dev, PCI_VENDOR_ID);
+ if (((reg & 0xffff) == 0x0000) || ((reg & 0xffff) == 0xffff) ||
+ (((reg >> 16) & 0xffff) == 0xffff) ||
+ (((reg >> 16) & 0xffff) == 0x0000)) {
+ break;
+ }
+ for(linkn = 0; linkn<3; linkn++) {
+ unsigned regpos;
+ regpos = 0x98 + 0x20 * linkn;
+ reg = pci_read_config32(dev, regpos);
+ if ((reg & 7) != 7) continue; // it is not non conherent or not connected
+ tempreg = 3 | (nodeid <<4) | (linkn<<8);
+ //compare (temp & 0xffff), with (PCI(0, 0x18, 1) 0xe0 to 0xec & 0xfffff)
+ for(ht_c_num=0;ht_c_num<4; ht_c_num++) {
+ reg = pci_read_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4);
+ if(((reg & 0xffff) == (tempreg & 0xffff)) || ((reg & 0xffff) == 0x0000)) { // we got it
+ break;
+ }
+ }
+ if(ht_c_num == 4) break; //used up onle 4 non conherent allowed
+ //update to 0xe0...
+ if((reg & 0xf) == 3) continue; //SBLink so don't touch it
+ tempreg |= (next_busn<<16)|((next_busn+5)<<24);
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4, tempreg);
+ next_busn+=5+1;
+ }
+ }
+ //update 0xe0, 0xe4, 0xe8, 0xec from PCI_DEV(0, 0x18,1) to PCI_DEV(0, 0x19,1) to PCI_DEV(0, 0x1f,1);
+
+ for(nodeid = 1; nodeid<8; nodeid++) {
+ int i;
+ device_t dev;
+ dev = PCI_DEV(0, 0x18+nodeid,1);
+ //read id, check id to see if dev exists ;
+ reg = pci_read_config32(dev, PCI_VENDOR_ID);
+ if (((reg & 0xffff) == 0x0000) || ((reg & 0xffff) == 0xffff) ||
+ (((reg >> 16) & 0xffff) == 0xffff) ||
+ (((reg >> 16) & 0xffff) == 0x0000)) {
+ break;
+ }
+ for(i = 0; i< 4; i++) {
+ unsigned regpos;
+ regpos = 0xe0 + i * 4;
+ reg = pci_read_config32(PCI_DEV(0, 0x18, 1), regpos);
+ pci_write_config32(dev, regpos, reg);
+
+ }
+ }
+
+ // recount ht_c_num
+ int i=0;
+ for(ht_c_num=0;ht_c_num<4; ht_c_num++) {
+ reg = pci_read_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4);
+ if(((reg & 0xf) != 0x0)) {
+ i++;
+ }
+ }
+
+ return ht_setup_chains(i);
+
+}