diff options
author | Marc Jones <marc.jones@amd.com> | 2007-12-19 01:32:08 +0000 |
---|---|---|
committer | Marc Jones <marc.jones@amd.com> | 2007-12-19 01:32:08 +0000 |
commit | 8ae8c8822068ef1722c08073ffa4ecc25633cbee (patch) | |
tree | 8c7bbf2f7b791081e486439a9b7ffb2fd6e649ac /src/northbridge/amd/amdfam10/early_ht.c | |
parent | 2006b38fed2f5f3680de1736f7fc878823f2f93b (diff) | |
download | coreboot-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/amdfam10/early_ht.c')
-rw-r--r-- | src/northbridge/amd/amdfam10/early_ht.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdfam10/early_ht.c b/src/northbridge/amd/amdfam10/early_ht.c new file mode 100644 index 0000000000..0ddbf9993a --- /dev/null +++ b/src/northbridge/amd/amdfam10/early_ht.c @@ -0,0 +1,175 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// For SB HT chain only +// mmconf is not ready yet +static void set_bsp_node_CHtExtNodeCfgEn(void) +{ +#if EXT_RT_TBL_SUPPORT == 1 + u32 dword; + dword = pci_io_read_config32(PCI_DEV(0, 0x18, 0), 0x68); + dword |= (1<<27) | (1<<25); + /* CHtExtNodeCfgEn: coherent link extended node configuration enable, + Nodes[31:0] will be 0xff:[31:0], Nodes[63:32] will be 0xfe:[31:0] + ---- 32 nodes now only + It can be used even nodes less than 8 nodes. + We can have 8 more device on bus 0 in that case + */ + + /* CHtExtAddrEn */ + pci_io_write_config32(PCI_DEV(0, 0x18, 0), 0x68, dword); + // CPU on bus 0xff and 0xfe now. For now on we can use CBB and CDB. +#endif +} + +static void enumerate_ht_chain(void) +{ +#if HT_CHAIN_UNITID_BASE != 0 +/* HT_CHAIN_UNITID_BASE could be 0 (only one ht device in the ht chain), + if so, don't need to go through the chain */ + + /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it. + * On most boards this just happens. If a cpu has multiple + * non Coherent links the appropriate bus registers for the + * links needs to be programed to point at bus 0. + */ + unsigned next_unitid, last_unitid = 0; +#if HT_CHAIN_END_UNITID_BASE != 0x20 + // let't record the device of last ht device, So we can set the + // Unitid to HT_CHAIN_END_UNITID_BASE + unsigned real_last_unitid = 0; + u8 real_last_pos = 0; + int ht_dev_num = 0; // except host_bridge + u8 end_used = 0; +#endif + + next_unitid = HT_CHAIN_UNITID_BASE; + do { + u32 id; + u8 hdr_type, pos; + last_unitid = next_unitid; + + id = pci_io_read_config32(PCI_DEV(0,0,0), PCI_VENDOR_ID); + /* If the chain is enumerated quit */ + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) + { + break; + } + + hdr_type = pci_io_read_config8(PCI_DEV(0,0,0), PCI_HEADER_TYPE); + pos = 0; + hdr_type &= 0x7f; + + if ((hdr_type == PCI_HEADER_TYPE_NORMAL) || + (hdr_type == PCI_HEADER_TYPE_BRIDGE)) + { + pos = pci_io_read_config8(PCI_DEV(0,0,0), PCI_CAPABILITY_LIST); + } + while(pos != 0) { + u8 cap; + cap = pci_io_read_config8(PCI_DEV(0,0,0), pos + PCI_CAP_LIST_ID); + if (cap == PCI_CAP_ID_HT) { + u16 flags; + /* Read and write and reread flags so the link + * direction bit is valid. + */ + flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS); + pci_io_write_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS, flags); + flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS); + if ((flags >> 13) == 0) { + unsigned count; + unsigned ctrl, ctrl_off; + device_t devx; + +#if HT_CHAIN_END_UNITID_BASE != 0x20 + if(next_unitid>=0x18) { + if(!end_used) { + next_unitid = HT_CHAIN_END_UNITID_BASE; + end_used = 1; + } else { + goto out; + } + } + real_last_unitid = next_unitid; + real_last_pos = pos; + ht_dev_num++ ; +#endif + #if HT_CHAIN_END_UNITID_BASE == 0 + if (!next_unitid) + goto out; + #endif + flags &= ~0x1f; + flags |= next_unitid & 0x1f; + count = (flags >> 5) & 0x1f; + devx = PCI_DEV(0, next_unitid, 0); + next_unitid += count; + + pci_io_write_config16(PCI_DEV(0, 0, 0), pos + PCI_CAP_FLAGS, flags); + + /* Test for end of chain */ + ctrl_off = ((flags >> 10) & 1)? + PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1; + + do { + ctrl = pci_read_config16(devx, pos + ctrl_off); + /* Is this the end of the hypertransport chain? */ + if (ctrl & (1 << 6)) { + goto out; + } + + if (ctrl & ((1 << 4) | (1 << 8))) { + /* + * Either the link has failed, or we have + * a CRC error. + * Sometimes this can happen due to link + * retrain, so lets knock it down and see + * if its transient + */ + ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc + pci_write_config16(devx, pos + ctrl_off, ctrl); + ctrl = pci_read_config16(devx, pos + ctrl_off); + if (ctrl & ((1 << 4) | (1 << 8))) { + // can not clear the error + break; + } + } + } while((ctrl & (1 << 5)) == 0); + + break; + } + } + pos = pci_io_read_config8(PCI_DEV(0, 0, 0), pos + PCI_CAP_LIST_NEXT); + } + } while(last_unitid != next_unitid); + +out: ; +#if HT_CHAIN_END_UNITID_BASE != 0x20 + if((ht_dev_num>1) && (real_last_unitid != HT_CHAIN_END_UNITID_BASE) && !end_used) { + u16 flags; + flags = pci_io_read_config16(PCI_DEV(0,real_last_unitid,0), real_last_pos + PCI_CAP_FLAGS); + flags &= ~0x1f; + flags |= HT_CHAIN_END_UNITID_BASE & 0x1f; + pci_io_write_config16(PCI_DEV(0, real_last_unitid, 0), real_last_pos + PCI_CAP_FLAGS, flags); + } +#endif + +#endif +} |