Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 1 | /* |
Stefan Reinauer | 7e61e45 | 2008-01-18 10:35:56 +0000 | [diff] [blame] | 2 | * This file is part of the coreboot project. |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2007 Advanced Micro Devices, Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 14 | */ |
| 15 | |
Damien Zammit | 75a3d1f | 2016-11-28 00:29:10 +1100 | [diff] [blame] | 16 | #include "early_ht.h" |
| 17 | #include <inttypes.h> |
Kyösti Mälkki | f1b58b7 | 2019-03-01 13:43:02 +0200 | [diff] [blame] | 18 | #include <device/pci_ops.h> |
Damien Zammit | 75a3d1f | 2016-11-28 00:29:10 +1100 | [diff] [blame] | 19 | #include <device/pci_def.h> |
| 20 | |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 21 | // For SB HT chain only |
| 22 | // mmconf is not ready yet |
Damien Zammit | 75a3d1f | 2016-11-28 00:29:10 +1100 | [diff] [blame] | 23 | void set_bsp_node_CHtExtNodeCfgEn(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 24 | { |
Martin Roth | 77a58b9 | 2017-06-24 14:45:48 -0600 | [diff] [blame] | 25 | #if IS_ENABLED(CONFIG_EXT_RT_TBL_SUPPORT) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 26 | u32 dword; |
| 27 | dword = pci_io_read_config32(PCI_DEV(0, 0x18, 0), 0x68); |
| 28 | dword |= (1<<27) | (1<<25); |
| 29 | /* CHtExtNodeCfgEn: coherent link extended node configuration enable, |
| 30 | Nodes[31:0] will be 0xff:[31:0], Nodes[63:32] will be 0xfe:[31:0] |
| 31 | ---- 32 nodes now only |
| 32 | It can be used even nodes less than 8 nodes. |
| 33 | We can have 8 more device on bus 0 in that case |
| 34 | */ |
| 35 | |
| 36 | /* CHtExtAddrEn */ |
| 37 | pci_io_write_config32(PCI_DEV(0, 0x18, 0), 0x68, dword); |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 38 | // CPU on bus 0xff and 0xfe now. For now on we can use CONFIG_CBB and CONFIG_CDB. |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 39 | #endif |
| 40 | } |
| 41 | |
Damien Zammit | 75a3d1f | 2016-11-28 00:29:10 +1100 | [diff] [blame] | 42 | void enumerate_ht_chain(void) |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 43 | { |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 44 | #if CONFIG_HT_CHAIN_UNITID_BASE != 0 |
| 45 | /* CONFIG_HT_CHAIN_UNITID_BASE could be 0 (only one ht device in the ht chain), |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 46 | if so, don't need to go through the chain */ |
| 47 | |
| 48 | /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it. |
Elyes HAOUAS | 15279a9 | 2016-07-28 21:05:26 +0200 | [diff] [blame] | 49 | * On most boards this just happens. If a CPU has multiple |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 50 | * non Coherent links the appropriate bus registers for the |
| 51 | * links needs to be programed to point at bus 0. |
| 52 | */ |
| 53 | unsigned next_unitid, last_unitid = 0; |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 54 | #if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 55 | // let't record the device of last ht device, So we can set the |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 56 | // Unitid to CONFIG_HT_CHAIN_END_UNITID_BASE |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 57 | unsigned real_last_unitid = 0; |
| 58 | u8 real_last_pos = 0; |
| 59 | int ht_dev_num = 0; // except host_bridge |
| 60 | u8 end_used = 0; |
| 61 | #endif |
| 62 | |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 63 | next_unitid = CONFIG_HT_CHAIN_UNITID_BASE; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 64 | do { |
| 65 | u32 id; |
| 66 | u8 hdr_type, pos; |
| 67 | last_unitid = next_unitid; |
| 68 | |
| 69 | id = pci_io_read_config32(PCI_DEV(0,0,0), PCI_VENDOR_ID); |
| 70 | /* If the chain is enumerated quit */ |
| 71 | if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || |
| 72 | (((id >> 16) & 0xffff) == 0xffff) || |
| 73 | (((id >> 16) & 0xffff) == 0x0000)) |
| 74 | { |
| 75 | break; |
| 76 | } |
| 77 | |
| 78 | hdr_type = pci_io_read_config8(PCI_DEV(0,0,0), PCI_HEADER_TYPE); |
| 79 | pos = 0; |
| 80 | hdr_type &= 0x7f; |
| 81 | |
| 82 | if ((hdr_type == PCI_HEADER_TYPE_NORMAL) || |
| 83 | (hdr_type == PCI_HEADER_TYPE_BRIDGE)) |
| 84 | { |
| 85 | pos = pci_io_read_config8(PCI_DEV(0,0,0), PCI_CAPABILITY_LIST); |
| 86 | } |
Elyes HAOUAS | 5a7e72f | 2016-08-23 21:36:02 +0200 | [diff] [blame] | 87 | while (pos != 0) { |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 88 | u8 cap; |
| 89 | cap = pci_io_read_config8(PCI_DEV(0,0,0), pos + PCI_CAP_LIST_ID); |
| 90 | if (cap == PCI_CAP_ID_HT) { |
| 91 | u16 flags; |
| 92 | /* Read and write and reread flags so the link |
| 93 | * direction bit is valid. |
| 94 | */ |
| 95 | flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS); |
| 96 | pci_io_write_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS, flags); |
| 97 | flags = pci_io_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS); |
| 98 | if ((flags >> 13) == 0) { |
| 99 | unsigned count; |
| 100 | unsigned ctrl, ctrl_off; |
Antonello Dettori | f65ccb2 | 2016-09-03 10:45:33 +0200 | [diff] [blame] | 101 | pci_devfn_t devx; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 102 | |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 103 | #if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 |
Elyes HAOUAS | 04f8fd9 | 2016-09-19 10:24:34 -0600 | [diff] [blame] | 104 | if (next_unitid >= 0x18) { |
Elyes HAOUAS | 5a7e72f | 2016-08-23 21:36:02 +0200 | [diff] [blame] | 105 | if (!end_used) { |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 106 | next_unitid = CONFIG_HT_CHAIN_END_UNITID_BASE; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 107 | end_used = 1; |
| 108 | } else { |
| 109 | goto out; |
| 110 | } |
| 111 | } |
| 112 | real_last_unitid = next_unitid; |
| 113 | real_last_pos = pos; |
Elyes HAOUAS | 7db506c | 2016-10-02 11:56:39 +0200 | [diff] [blame] | 114 | ht_dev_num++; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 115 | #endif |
Patrick Georgi | e166782 | 2012-05-05 15:29:32 +0200 | [diff] [blame] | 116 | #if !CONFIG_HT_CHAIN_END_UNITID_BASE |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 117 | if (!next_unitid) |
| 118 | goto out; |
| 119 | #endif |
| 120 | flags &= ~0x1f; |
| 121 | flags |= next_unitid & 0x1f; |
| 122 | count = (flags >> 5) & 0x1f; |
| 123 | devx = PCI_DEV(0, next_unitid, 0); |
| 124 | next_unitid += count; |
| 125 | |
| 126 | pci_io_write_config16(PCI_DEV(0, 0, 0), pos + PCI_CAP_FLAGS, flags); |
| 127 | |
| 128 | /* Test for end of chain */ |
| 129 | ctrl_off = ((flags >> 10) & 1)? |
| 130 | PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1; |
| 131 | |
| 132 | do { |
Arne Georg Gleditsch | d6689ed | 2010-09-09 14:54:07 +0000 | [diff] [blame] | 133 | ctrl = pci_io_read_config16(devx, pos + ctrl_off); |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 134 | /* Is this the end of the hypertransport chain? */ |
| 135 | if (ctrl & (1 << 6)) { |
| 136 | goto out; |
| 137 | } |
| 138 | |
| 139 | if (ctrl & ((1 << 4) | (1 << 8))) { |
| 140 | /* |
| 141 | * Either the link has failed, or we have |
| 142 | * a CRC error. |
| 143 | * Sometimes this can happen due to link |
| 144 | * retrain, so lets knock it down and see |
| 145 | * if its transient |
| 146 | */ |
| 147 | ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc |
Arne Georg Gleditsch | d6689ed | 2010-09-09 14:54:07 +0000 | [diff] [blame] | 148 | pci_io_write_config16(devx, pos + ctrl_off, ctrl); |
| 149 | ctrl = pci_io_read_config16(devx, pos + ctrl_off); |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 150 | if (ctrl & ((1 << 4) | (1 << 8))) { |
| 151 | // can not clear the error |
| 152 | break; |
| 153 | } |
| 154 | } |
Elyes HAOUAS | 5a7e72f | 2016-08-23 21:36:02 +0200 | [diff] [blame] | 155 | } while ((ctrl & (1 << 5)) == 0); |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 156 | |
| 157 | break; |
| 158 | } |
| 159 | } |
| 160 | pos = pci_io_read_config8(PCI_DEV(0, 0, 0), pos + PCI_CAP_LIST_NEXT); |
| 161 | } |
Elyes HAOUAS | 5a7e72f | 2016-08-23 21:36:02 +0200 | [diff] [blame] | 162 | } while (last_unitid != next_unitid); |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 163 | |
| 164 | out: ; |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 165 | #if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20 |
Elyes HAOUAS | 04f8fd9 | 2016-09-19 10:24:34 -0600 | [diff] [blame] | 166 | if ((ht_dev_num > 1) && (real_last_unitid != CONFIG_HT_CHAIN_END_UNITID_BASE) && !end_used) { |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 167 | u16 flags; |
| 168 | flags = pci_io_read_config16(PCI_DEV(0,real_last_unitid,0), real_last_pos + PCI_CAP_FLAGS); |
| 169 | flags &= ~0x1f; |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 170 | flags |= CONFIG_HT_CHAIN_END_UNITID_BASE & 0x1f; |
Marc Jones | 8ae8c88 | 2007-12-19 01:32:08 +0000 | [diff] [blame] | 171 | pci_io_write_config16(PCI_DEV(0, real_last_unitid, 0), real_last_pos + PCI_CAP_FLAGS, flags); |
| 172 | } |
| 173 | #endif |
| 174 | |
| 175 | #endif |
| 176 | } |