blob: 3f2b138533f4823971da815672ee319d9ffebf80 [file] [log] [blame]
Marc Jones8ae8c882007-12-19 01:32:08 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Marc Jones8ae8c882007-12-19 01:32:08 +00003 *
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 Jones8ae8c882007-12-19 01:32:08 +000014 */
15
Damien Zammit75a3d1f2016-11-28 00:29:10 +110016#include "early_ht.h"
Jacob Garber5cf9ccc2019-08-08 13:35:31 -060017#include <stdint.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020018#include <device/pci_ops.h>
Damien Zammit75a3d1f2016-11-28 00:29:10 +110019#include <device/pci_def.h>
20
Marc Jones8ae8c882007-12-19 01:32:08 +000021// For SB HT chain only
22// mmconf is not ready yet
Damien Zammit75a3d1f2016-11-28 00:29:10 +110023void set_bsp_node_CHtExtNodeCfgEn(void)
Marc Jones8ae8c882007-12-19 01:32:08 +000024{
Julius Wernercd49cce2019-03-05 16:53:33 -080025#if CONFIG(EXT_RT_TBL_SUPPORT)
Marc Jones8ae8c882007-12-19 01:32:08 +000026 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 Reinauer08670622009-06-30 15:17:49 +000038 // CPU on bus 0xff and 0xfe now. For now on we can use CONFIG_CBB and CONFIG_CDB.
Marc Jones8ae8c882007-12-19 01:32:08 +000039#endif
40}
41
Damien Zammit75a3d1f2016-11-28 00:29:10 +110042void enumerate_ht_chain(void)
Marc Jones8ae8c882007-12-19 01:32:08 +000043{
Stefan Reinauer08670622009-06-30 15:17:49 +000044#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 Jones8ae8c882007-12-19 01:32:08 +000046 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 HAOUAS15279a92016-07-28 21:05:26 +020049 * On most boards this just happens. If a CPU has multiple
Marc Jones8ae8c882007-12-19 01:32:08 +000050 * 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 Reinauer08670622009-06-30 15:17:49 +000054#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Marc Jones8ae8c882007-12-19 01:32:08 +000055 // let't record the device of last ht device, So we can set the
Stefan Reinauer08670622009-06-30 15:17:49 +000056 // Unitid to CONFIG_HT_CHAIN_END_UNITID_BASE
Marc Jones8ae8c882007-12-19 01:32:08 +000057 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 Reinauer08670622009-06-30 15:17:49 +000063 next_unitid = CONFIG_HT_CHAIN_UNITID_BASE;
Marc Jones8ae8c882007-12-19 01:32:08 +000064 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 HAOUAS5a7e72f2016-08-23 21:36:02 +020087 while (pos != 0) {
Marc Jones8ae8c882007-12-19 01:32:08 +000088 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 Dettorif65ccb22016-09-03 10:45:33 +0200101 pci_devfn_t devx;
Marc Jones8ae8c882007-12-19 01:32:08 +0000102
Stefan Reinauer08670622009-06-30 15:17:49 +0000103#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600104 if (next_unitid >= 0x18) {
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200105 if (!end_used) {
Stefan Reinauer08670622009-06-30 15:17:49 +0000106 next_unitid = CONFIG_HT_CHAIN_END_UNITID_BASE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000107 end_used = 1;
108 } else {
109 goto out;
110 }
111 }
112 real_last_unitid = next_unitid;
113 real_last_pos = pos;
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200114 ht_dev_num++;
Marc Jones8ae8c882007-12-19 01:32:08 +0000115#endif
Patrick Georgie1667822012-05-05 15:29:32 +0200116 #if !CONFIG_HT_CHAIN_END_UNITID_BASE
Marc Jones8ae8c882007-12-19 01:32:08 +0000117 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 Gleditschd6689ed2010-09-09 14:54:07 +0000133 ctrl = pci_io_read_config16(devx, pos + ctrl_off);
Marc Jones8ae8c882007-12-19 01:32:08 +0000134 /* 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 Gleditschd6689ed2010-09-09 14:54:07 +0000148 pci_io_write_config16(devx, pos + ctrl_off, ctrl);
149 ctrl = pci_io_read_config16(devx, pos + ctrl_off);
Marc Jones8ae8c882007-12-19 01:32:08 +0000150 if (ctrl & ((1 << 4) | (1 << 8))) {
151 // can not clear the error
152 break;
153 }
154 }
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200155 } while ((ctrl & (1 << 5)) == 0);
Marc Jones8ae8c882007-12-19 01:32:08 +0000156
157 break;
158 }
159 }
160 pos = pci_io_read_config8(PCI_DEV(0, 0, 0), pos + PCI_CAP_LIST_NEXT);
161 }
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200162 } while (last_unitid != next_unitid);
Marc Jones8ae8c882007-12-19 01:32:08 +0000163
164out: ;
Stefan Reinauer08670622009-06-30 15:17:49 +0000165#if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600166 if ((ht_dev_num > 1) && (real_last_unitid != CONFIG_HT_CHAIN_END_UNITID_BASE) && !end_used) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000167 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 Reinauer08670622009-06-30 15:17:49 +0000170 flags |= CONFIG_HT_CHAIN_END_UNITID_BASE & 0x1f;
Marc Jones8ae8c882007-12-19 01:32:08 +0000171 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}