blob: c4fd3fdcee1913ac9b34942a2f0eb14f0c5c0118 [file] [log] [blame]
arch import user (historical)ef03afa2005-07-06 17:15:30 +00001/* This should be done by Eric
2 2004.12 yhlu add dual core support
Uwe Hermann607614d2010-11-18 20:12:13 +00003 2005.01 yhlu add support move apic before pci_domain in MB devicetree.cb
arch import user (historical)ef03afa2005-07-06 17:15:30 +00004 2005.02 yhlu add e0 memory hole support
Stefan Reinauer7ce8c542005-12-02 21:52:30 +00005 2005.11 yhlu add put sb ht chain on bus 0
arch import user (historical)ef03afa2005-07-06 17:15:30 +00006*/
7
Eric Biederman0ac6b412003-09-02 17:16:48 +00008#include <console/console.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +00009#include <arch/io.h>
10#include <stdint.h>
Eric Biederman2c018fb2003-07-21 20:13:45 +000011#include <device/device.h>
12#include <device/pci.h>
Eric Biederman17729a22003-12-08 21:48:01 +000013#include <device/pci_ids.h>
Eric Biederman0ac6b412003-09-02 17:16:48 +000014#include <device/hypertransport.h>
Eric Biederman0ac6b412003-09-02 17:16:48 +000015#include <stdlib.h>
16#include <string.h>
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -080017#include <lib.h>
Eric Biederman7003ba42004-10-16 06:20:29 +000018#include <cpu/cpu.h>
Vladimir Serbinenkof21271e2014-10-16 18:00:27 +020019#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
Vladimir Serbinenko6985d4e2014-09-21 14:31:19 +020020#include <arch/acpi.h>
21#include "acpi.h"
22#endif
arch import user (historical)ef03afa2005-07-06 17:15:30 +000023
24#include <cpu/x86/lapic.h>
Kyösti Mälkkiba589e32012-07-11 08:03:13 +030025#include <cpu/amd/mtrr.h>
arch import user (historical)ef03afa2005-07-06 17:15:30 +000026
Stefan Reinauer9a16e3e2010-03-29 14:45:36 +000027#include <cpu/amd/multicore.h>
Patrick Georgie1667822012-05-05 15:29:32 +020028#if CONFIG_LOGICAL_CPUS
arch import user (historical)ef03afa2005-07-06 17:15:30 +000029#include <pc80/mc146818rtc.h>
30#endif
31
Eric Biederman0ac6b412003-09-02 17:16:48 +000032#include "northbridge.h"
Stefan Reinauerf5183cf2005-12-01 11:01:01 +000033
Eric Biederman4ab9f172003-12-06 00:11:56 +000034#include "amdk8.h"
Stefan Reinauerf5183cf2005-12-01 11:01:01 +000035
Stefan Reinauerf5183cf2005-12-01 11:01:01 +000036#include <cpu/amd/model_fxx_rev.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +000037
Yinghai Lud4b278c2006-10-04 20:46:15 +000038#include <cpu/amd/amdk8_sysconf.h>
39
40struct amdk8_sysconf_t sysconf;
41
Myles Watsonc7233e02009-07-02 19:02:33 +000042#define MAX_FX_DEVS 8
43static device_t __f0_dev[MAX_FX_DEVS];
44static device_t __f1_dev[MAX_FX_DEVS];
45static unsigned fx_devs=0;
Eric Biederman0ac6b412003-09-02 17:16:48 +000046
Eric Biedermanb78c1972004-10-14 20:54:17 +000047static void get_fx_devs(void)
Eric Biederman0ac6b412003-09-02 17:16:48 +000048{
49 int i;
Myles Watsonc7233e02009-07-02 19:02:33 +000050 for(i = 0; i < MAX_FX_DEVS; i++) {
Eric Biedermanb78c1972004-10-14 20:54:17 +000051 __f0_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 0));
Eric Biederman0ac6b412003-09-02 17:16:48 +000052 __f1_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 1));
Myles Watsonc7233e02009-07-02 19:02:33 +000053 if (__f0_dev[i] != NULL && __f1_dev[i] != NULL)
54 fx_devs = i+1;
Eric Biederman0ac6b412003-09-02 17:16:48 +000055 }
Myles Watsonc7233e02009-07-02 19:02:33 +000056 if (__f1_dev[0] == NULL || __f0_dev[0] == NULL || fx_devs == 0) {
57 die("Cannot find 0:0x18.[0|1]\n");
Eric Biederman0ac6b412003-09-02 17:16:48 +000058 }
59}
60
Myles Watson6507b392010-06-09 22:39:00 +000061static u32 f1_read_config32(unsigned reg)
Eric Biederman0ac6b412003-09-02 17:16:48 +000062{
Myles Watson6507b392010-06-09 22:39:00 +000063 if (fx_devs == 0)
Myles Watsonc7233e02009-07-02 19:02:33 +000064 get_fx_devs();
Eric Biederman0ac6b412003-09-02 17:16:48 +000065 return pci_read_config32(__f1_dev[0], reg);
66}
67
Myles Watson6507b392010-06-09 22:39:00 +000068static void f1_write_config32(unsigned reg, u32 value)
Eric Biederman0ac6b412003-09-02 17:16:48 +000069{
70 int i;
Myles Watson6507b392010-06-09 22:39:00 +000071 if (fx_devs == 0)
Myles Watsonc7233e02009-07-02 19:02:33 +000072 get_fx_devs();
73 for(i = 0; i < fx_devs; i++) {
Eric Biederman0ac6b412003-09-02 17:16:48 +000074 device_t dev;
75 dev = __f1_dev[i];
Eric Biedermanb78c1972004-10-14 20:54:17 +000076 if (dev && dev->enabled) {
Eric Biederman0ac6b412003-09-02 17:16:48 +000077 pci_write_config32(dev, reg, value);
78 }
79 }
80}
81
Kyösti Mälkki20968c92015-02-23 12:05:33 +020082typedef enum {
83 HT_ROUTE_CLOSE,
84 HT_ROUTE_SCAN,
85 HT_ROUTE_FINAL,
86} scan_state;
87
88static void ht_route_link(struct bus *link, scan_state mode)
89{
90 struct device *dev = link->dev;
91 struct bus *parent = dev->bus;
92 u32 busses;
93
Kyösti Mälkki09705ab2015-03-21 11:11:58 +020094 if (mode == HT_ROUTE_SCAN) {
95 if (link->dev->bus->subordinate == 0)
96 link->secondary = 0;
97 else
98 link->secondary = parent->subordinate + 1;
99
100 link->subordinate = link->secondary;
101 }
102
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200103 /* Configure the bus numbers for this bridge: the configuration
104 * transactions will not be propagated by the bridge if it is
105 * not correctly configured
106 */
107 busses = pci_read_config32(link->dev, link->cap + 0x14);
108 busses &= 0xff000000;
109 busses |= parent->secondary & 0xff;
110 if (mode == HT_ROUTE_CLOSE) {
111 busses |= 0xfeff << 8;
112 } else if (mode == HT_ROUTE_SCAN) {
113 busses |= ((u32) link->secondary & 0xff) << 8;
114 busses |= 0xff << 16;
115 } else if (mode == HT_ROUTE_FINAL) {
116 busses |= ((u32) link->secondary & 0xff) << 8;
117 busses |= ((u32) link->subordinate & 0xff) << 16;
118 }
119 pci_write_config32(link->dev, link->cap + 0x14, busses);
120
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200121 if (mode == HT_ROUTE_FINAL) {
122 /* Second chain will be on 0x40, third 0x80, forth 0xc0. */
123 if (CONFIG_HT_CHAIN_DISTRIBUTE)
124 parent->subordinate = ALIGN_UP(link->subordinate, 0x40) - 1;
125 else
126 parent->subordinate = link->subordinate;
127 }
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200128}
129
Myles Watson6507b392010-06-09 22:39:00 +0000130static u32 amdk8_nodeid(device_t dev)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000131{
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000132 return (dev->path.pci.devfn >> 3) - 0x18;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000133}
134
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200135static void amdk8_scan_chain(struct bus *link)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000136{
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200137 unsigned int next_unitid;
Kyösti Mälkkied7bc2c2015-02-22 08:27:13 +0200138 int index;
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200139 u32 config_busses;
Myles Watson6507b392010-06-09 22:39:00 +0000140 u32 free_reg, config_reg;
Kyösti Mälkki328531f2015-02-28 12:03:20 +0200141 u32 nodeid = amdk8_nodeid(link->dev);
Kyösti Mälkki328531f2015-02-28 12:03:20 +0200142
Li-Ta Lo3a812852004-12-03 22:39:34 +0000143 /* See if there is an available configuration space mapping
Myles Watsond61ada62008-10-02 19:20:22 +0000144 * register in function 1.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000145 */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000146 free_reg = 0;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000147 for(config_reg = 0xe0; config_reg <= 0xec; config_reg += 4) {
Myles Watson6507b392010-06-09 22:39:00 +0000148 u32 config;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000149 config = f1_read_config32(config_reg);
150 if (!free_reg && ((config & 3) == 0)) {
151 free_reg = config_reg;
152 continue;
153 }
Myles Watsond61ada62008-10-02 19:20:22 +0000154 if (((config & 3) == 3) &&
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000155 (((config >> 4) & 7) == nodeid) &&
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200156 (((config >> 8) & 3) == link->link_num)) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000157 break;
158 }
159 }
160 if (free_reg && (config_reg > 0xec)) {
161 config_reg = free_reg;
162 }
Li-Ta Lo3a812852004-12-03 22:39:34 +0000163 /* If we can't find an available configuration space mapping
Myles Watsond61ada62008-10-02 19:20:22 +0000164 * register skip this bus
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000165 */
Eric Biederman0ac6b412003-09-02 17:16:48 +0000166 if (config_reg > 0xec) {
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200167 return;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000168 }
169
Li-Ta Lo3a812852004-12-03 22:39:34 +0000170 /* Set up the primary, secondary and subordinate bus numbers.
171 * We have no idea how many busses are behind this bridge yet,
172 * so we set the subordinate bus number to 0xff for the moment.
Eric Biederman0ac6b412003-09-02 17:16:48 +0000173 */
Kyösti Mälkki57978a32015-02-05 08:12:20 +0200174
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200175 ht_route_link(link, HT_ROUTE_SCAN);
176
Eric Biederman0ac6b412003-09-02 17:16:48 +0000177 config_busses = f1_read_config32(config_reg);
Eric Biederman17729a22003-12-08 21:48:01 +0000178 config_busses &= 0x000fc88;
Myles Watsond61ada62008-10-02 19:20:22 +0000179 config_busses |=
Eric Biederman17729a22003-12-08 21:48:01 +0000180 (3 << 0) | /* rw enable, no device compare */
Myles Watsond61ada62008-10-02 19:20:22 +0000181 (( nodeid & 7) << 4) |
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200182 ((link->link_num & 3) << 8) |
Myles Watson894a3472010-06-09 22:41:35 +0000183 ((link->secondary) << 16) |
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200184 (0xff << 24);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000185 f1_write_config32(config_reg, config_busses);
186
Li-Ta Lo3a812852004-12-03 22:39:34 +0000187 /* Now we can scan all of the subordinate busses i.e. the
Myles Watsond61ada62008-10-02 19:20:22 +0000188 * chain on the hypertranport link
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000189 */
Yinghai Lu18c70d72007-09-14 14:58:33 +0000190
Kyösti Mälkkied7bc2c2015-02-22 08:27:13 +0200191 next_unitid = hypertransport_scan_chain(link);
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200192
193 /* Now that nothing is overlapping it is safe to scan the children. */
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200194 pci_scan_bus(link, 0x00, ((next_unitid - 1) << 3) | 7);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000195
Li-Ta Lo3a812852004-12-03 22:39:34 +0000196 /* We know the number of busses behind this bridge. Set the
197 * subordinate bus number to it's real value
Eric Biederman0ac6b412003-09-02 17:16:48 +0000198 */
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200199
200 ht_route_link(link, HT_ROUTE_FINAL);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000201
Li-Ta Lo3a812852004-12-03 22:39:34 +0000202 config_busses = (config_busses & 0x00ffffff) |
Myles Watson894a3472010-06-09 22:41:35 +0000203 (link->subordinate << 24);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000204 f1_write_config32(config_reg, config_busses);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000205
Kyösti Mälkkied7bc2c2015-02-22 08:27:13 +0200206 index = (config_reg-0xe0) >> 2;
Kyösti Mälkki37d5afb2015-02-21 11:19:01 +0200207 sysconf.hcdn_reg[index] = link->hcdn_reg;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000208}
209
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200210/* Do sb ht chain at first, in case s2885 put sb chain
211 * (8131/8111) on link2, but put 8151 on link0.
212 */
213static void relocate_sb_ht_chain(void)
214{
215 struct device *dev;
216 struct bus *link, *prev = NULL;
217 u8 sblink;
218
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200219 dev = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
220 sblink = (pci_read_config32(dev, 0x64)>>8) & 3;
221 link = dev->link_list;
222
223 while (link) {
224 if (link->link_num == sblink) {
225 if (!prev)
226 return;
227 prev->next = link->next;
228 link->next = dev->link_list;
229 dev->link_list = link;
230 return;
231 }
232 prev = link;
233 link = link->next;
234 }
235}
236
Kyösti Mälkki0a3d4e42015-02-23 00:34:26 +0200237static void trim_ht_chain(struct device *dev)
238{
239 struct bus *link;
240
241 /* Check for connected links. */
242 for (link = dev->link_list; link; link = link->next) {
243 link->cap = 0x80 + (link->link_num * 0x20);
244 link->ht_link_up = ht_is_non_coherent_link(link);
245 }
246}
247
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200248static void amdk8_scan_chains(device_t dev)
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000249{
Myles Watson894a3472010-06-09 22:41:35 +0000250 struct bus *link;
Myles Watson6507b392010-06-09 22:39:00 +0000251
Kyösti Mälkki0a3d4e42015-02-23 00:34:26 +0200252 trim_ht_chain(dev);
253
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200254 for (link = dev->link_list; link; link = link->next) {
Kyösti Mälkki0a3d4e42015-02-23 00:34:26 +0200255 if (link->ht_link_up)
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200256 amdk8_scan_chain(link);
Myles Watsond61ada62008-10-02 19:20:22 +0000257 }
Stefan Reinauer7ce8c542005-12-02 21:52:30 +0000258}
259
260
Myles Watson6507b392010-06-09 22:39:00 +0000261static int reg_useable(unsigned reg, device_t goal_dev, unsigned goal_nodeid,
262 unsigned goal_link)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000263{
Eric Biedermanb78c1972004-10-14 20:54:17 +0000264 struct resource *res;
Myles Watson6507b392010-06-09 22:39:00 +0000265 unsigned nodeid, link = 0;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000266 int result;
267 res = 0;
Myles Watsonc7233e02009-07-02 19:02:33 +0000268 for(nodeid = 0; !res && (nodeid < fx_devs); nodeid++) {
Eric Biedermanb78c1972004-10-14 20:54:17 +0000269 device_t dev;
270 dev = __f0_dev[nodeid];
Rudolf Marek3a8565a2009-03-26 21:45:26 +0000271 if (!dev)
272 continue;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000273 for(link = 0; !res && (link < 3); link++) {
Myles Watson29cc9ed2009-07-02 18:56:24 +0000274 res = probe_resource(dev, IOINDEX(0x100 + reg, link));
Eric Biederman0ac6b412003-09-02 17:16:48 +0000275 }
276 }
Eric Biedermanb78c1972004-10-14 20:54:17 +0000277 result = 2;
278 if (res) {
279 result = 0;
Myles Watsond61ada62008-10-02 19:20:22 +0000280 if ( (goal_link == (link - 1)) &&
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000281 (goal_nodeid == (nodeid - 1)) &&
282 (res->flags <= 1)) {
Eric Biedermanb78c1972004-10-14 20:54:17 +0000283 result = 1;
284 }
285 }
Eric Biedermanb78c1972004-10-14 20:54:17 +0000286 return result;
287}
288
Myles Watsonc7233e02009-07-02 19:02:33 +0000289static unsigned amdk8_find_reg(device_t dev, unsigned nodeid, unsigned link,
290 unsigned min, unsigned max)
Eric Biedermanb78c1972004-10-14 20:54:17 +0000291{
Myles Watsonc7233e02009-07-02 19:02:33 +0000292 unsigned resource;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000293 unsigned free_reg, reg;
294 resource = 0;
295 free_reg = 0;
Myles Watsonc7233e02009-07-02 19:02:33 +0000296 for(reg = min; reg <= max; reg += 0x8) {
Eric Biedermanb78c1972004-10-14 20:54:17 +0000297 int result;
298 result = reg_useable(reg, dev, nodeid, link);
299 if (result == 1) {
300 /* I have been allocated this one */
301 break;
302 }
303 else if (result > 1) {
304 /* I have a free register pair */
305 free_reg = reg;
306 }
307 }
Myles Watsonc7233e02009-07-02 19:02:33 +0000308 if (reg > max) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000309 reg = free_reg;
310 }
Eric Biedermanb78c1972004-10-14 20:54:17 +0000311 if (reg > 0) {
Myles Watsonc7233e02009-07-02 19:02:33 +0000312 resource = IOINDEX(0x100 + reg, link);
Eric Biedermanb78c1972004-10-14 20:54:17 +0000313 }
314 return resource;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000315}
316
Myles Watsonc7233e02009-07-02 19:02:33 +0000317static unsigned amdk8_find_iopair(device_t dev, unsigned nodeid, unsigned link)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000318{
Myles Watsonc7233e02009-07-02 19:02:33 +0000319 return amdk8_find_reg(dev, nodeid, link, 0xc0, 0xd8);
320}
321
322static unsigned amdk8_find_mempair(device_t dev, unsigned nodeid, unsigned link)
323{
324 return amdk8_find_reg(dev, nodeid, link, 0x80, 0xb8);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000325}
Li-Ta Lo3a812852004-12-03 22:39:34 +0000326
Eric Biederman0ac6b412003-09-02 17:16:48 +0000327static void amdk8_link_read_bases(device_t dev, unsigned nodeid, unsigned link)
328{
Eric Biedermanb78c1972004-10-14 20:54:17 +0000329 struct resource *resource;
Myles Watsond61ada62008-10-02 19:20:22 +0000330
Eric Biederman0ac6b412003-09-02 17:16:48 +0000331 /* Initialize the io space constraints on the current bus */
Myles Watsonc7233e02009-07-02 19:02:33 +0000332 resource = new_resource(dev, IOINDEX(0, link));
Eric Biedermanb78c1972004-10-14 20:54:17 +0000333 if (resource) {
334 resource->base = 0;
335 resource->size = 0;
336 resource->align = log2(HT_IO_HOST_ALIGN);
337 resource->gran = log2(HT_IO_HOST_ALIGN);
338 resource->limit = 0xffffUL;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000339 resource->flags = IORESOURCE_IO | IORESOURCE_BRIDGE;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000340 }
341
342 /* Initialize the prefetchable memory constraints on the current bus */
Myles Watsonc7233e02009-07-02 19:02:33 +0000343 resource = new_resource(dev, IOINDEX(2, link));
Eric Biedermanb78c1972004-10-14 20:54:17 +0000344 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000345 resource->base = 0;
346 resource->size = 0;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000347 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000348 resource->gran = log2(HT_MEM_HOST_ALIGN);
Eric Biedermanb78c1972004-10-14 20:54:17 +0000349 resource->limit = 0xffffffffffULL;
350 resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000351 resource->flags |= IORESOURCE_BRIDGE;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000352 }
353
354 /* Initialize the memory constraints on the current bus */
Myles Watsonc7233e02009-07-02 19:02:33 +0000355 resource = new_resource(dev, IOINDEX(1, link));
Eric Biedermanb78c1972004-10-14 20:54:17 +0000356 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000357 resource->base = 0;
358 resource->size = 0;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000359 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000360 resource->gran = log2(HT_MEM_HOST_ALIGN);
Myles Watson29cc9ed2009-07-02 18:56:24 +0000361 resource->limit = 0xffffffffULL;
362 resource->flags = IORESOURCE_MEM | IORESOURCE_BRIDGE;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000363 }
Eric Biederman0ac6b412003-09-02 17:16:48 +0000364}
365
Myles Watsonc7233e02009-07-02 19:02:33 +0000366static void amdk8_create_vga_resource(device_t dev, unsigned nodeid);
367
Eric Biederman0ac6b412003-09-02 17:16:48 +0000368static void amdk8_read_resources(device_t dev)
369{
Myles Watson894a3472010-06-09 22:41:35 +0000370 unsigned nodeid;
371 struct bus *link;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000372 nodeid = amdk8_nodeid(dev);
Myles Watson894a3472010-06-09 22:41:35 +0000373 for(link = dev->link_list; link; link = link->next) {
374 if (link->children) {
375 amdk8_link_read_bases(dev, nodeid, link->link_num);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000376 }
377 }
Myles Watsonc7233e02009-07-02 19:02:33 +0000378 amdk8_create_vga_resource(dev, nodeid);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000379}
380
Eric Biedermanb78c1972004-10-14 20:54:17 +0000381static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned nodeid)
Eric Biederman0ac6b412003-09-02 17:16:48 +0000382{
Myles Watson894a3472010-06-09 22:41:35 +0000383 struct bus *link;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000384 resource_t rbase, rend;
Myles Watson894a3472010-06-09 22:41:35 +0000385 unsigned reg, link_num;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000386 char buf[50];
Eric Biederman5cd81732004-03-11 15:01:31 +0000387
Eric Biederman0ac6b412003-09-02 17:16:48 +0000388 /* Make certain the resource has actually been set */
Eric Biederman5cd81732004-03-11 15:01:31 +0000389 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000390 printk(BIOS_ERR, "%s: can't set unassigned resource @%lx %lx\n",
Myles Watson29cc9ed2009-07-02 18:56:24 +0000391 __func__, resource->index, resource->flags);
Eric Biederman5cd81732004-03-11 15:01:31 +0000392 return;
393 }
394
395 /* If I have already stored this resource don't worry about it */
396 if (resource->flags & IORESOURCE_STORED) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000397 printk(BIOS_ERR, "%s: can't set stored resource @%lx %lx\n", __func__,
Myles Watson29cc9ed2009-07-02 18:56:24 +0000398 resource->index, resource->flags);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000399 return;
400 }
Myles Watsond61ada62008-10-02 19:20:22 +0000401
Eric Biederman0ac6b412003-09-02 17:16:48 +0000402 /* Only handle PCI memory and IO resources */
403 if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
404 return;
405
Eric Biedermanb78c1972004-10-14 20:54:17 +0000406 /* Ensure I am actually looking at a resource of function 1 */
407 if (resource->index < 0x100) {
408 return;
409 }
Myles Watson29cc9ed2009-07-02 18:56:24 +0000410
411 if (resource->size == 0)
412 return;
413
Eric Biederman0ac6b412003-09-02 17:16:48 +0000414 /* Get the base address */
415 rbase = resource->base;
Myles Watsond61ada62008-10-02 19:20:22 +0000416
Eric Biederman0ac6b412003-09-02 17:16:48 +0000417 /* Get the limit (rounded up) */
Eric Biedermanb78c1972004-10-14 20:54:17 +0000418 rend = resource_end(resource);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000419
420 /* Get the register and link */
Eric Biedermanb78c1972004-10-14 20:54:17 +0000421 reg = resource->index & 0xfc;
Myles Watson894a3472010-06-09 22:41:35 +0000422 link_num = IOINDEX_LINK(resource->index);
423
424 for (link = dev->link_list; link; link = link->next)
425 if (link->link_num == link_num)
426 break;
427
428 if (link == NULL) {
429 printk(BIOS_ERR, "%s: can't find link %x for %lx\n", __func__,
430 link_num, resource->index);
431 return;
432 }
Eric Biederman5cd81732004-03-11 15:01:31 +0000433
Eric Biederman0ac6b412003-09-02 17:16:48 +0000434 if (resource->flags & IORESOURCE_IO) {
Myles Watson6507b392010-06-09 22:39:00 +0000435 u32 base, limit;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000436 base = f1_read_config32(reg);
437 limit = f1_read_config32(reg + 0x4);
438 base &= 0xfe000fcc;
439 base |= rbase & 0x01fff000;
440 base |= 3;
441 limit &= 0xfe000fc8;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000442 limit |= rend & 0x01fff000;
Myles Watson894a3472010-06-09 22:41:35 +0000443 limit |= (link_num & 3) << 4;
Li-Ta Lo32597842004-02-23 22:33:10 +0000444 limit |= (nodeid & 7);
Eric Biederman5cd81732004-03-11 15:01:31 +0000445
Myles Watson894a3472010-06-09 22:41:35 +0000446 if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000447 printk(BIOS_SPEW, "%s, enabling legacy VGA IO forwarding for %s link 0x%x\n",
Myles Watson894a3472010-06-09 22:41:35 +0000448 __func__, dev_path(dev), link_num);
Eric Biederman5cd81732004-03-11 15:01:31 +0000449 base |= PCI_IO_BASE_VGA_EN;
David W. Hendricks854e4522004-02-09 22:47:38 +0000450 }
Myles Watson894a3472010-06-09 22:41:35 +0000451 if (link->bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000452 base |= PCI_IO_BASE_NO_ISA;
453 }
Myles Watsond61ada62008-10-02 19:20:22 +0000454
Eric Biederman0ac6b412003-09-02 17:16:48 +0000455 f1_write_config32(reg + 0x4, limit);
456 f1_write_config32(reg, base);
Eric Biedermanb78c1972004-10-14 20:54:17 +0000457 }
458 else if (resource->flags & IORESOURCE_MEM) {
Myles Watson6507b392010-06-09 22:39:00 +0000459 u32 base, limit;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000460 base = f1_read_config32(reg);
461 limit = f1_read_config32(reg + 0x4);
462 base &= 0x000000f0;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000463 base |= (rbase >> 8) & 0xffffff00;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000464 base |= 3;
465 limit &= 0x00000048;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000466 limit |= (rend >> 8) & 0xffffff00;
Myles Watson894a3472010-06-09 22:41:35 +0000467 limit |= (link_num & 3) << 4;
Li-Ta Lo32597842004-02-23 22:33:10 +0000468 limit |= (nodeid & 7);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000469 f1_write_config32(reg + 0x4, limit);
470 f1_write_config32(reg, base);
471 }
Eric Biederman5cd81732004-03-11 15:01:31 +0000472 resource->flags |= IORESOURCE_STORED;
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100473 snprintf(buf, sizeof (buf), " <node %x link %x>",
474 nodeid, link_num);
Eric Biedermanb78c1972004-10-14 20:54:17 +0000475 report_resource_stored(dev, resource, buf);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000476}
477
Li-Ta Lo3a812852004-12-03 22:39:34 +0000478static void amdk8_create_vga_resource(device_t dev, unsigned nodeid)
479{
480 struct resource *resource;
Myles Watson894a3472010-06-09 22:41:35 +0000481 struct bus *link;
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000482
483 /* find out which link the VGA card is connected,
484 * we only deal with the 'first' vga card */
Myles Watson894a3472010-06-09 22:41:35 +0000485 for (link = dev->link_list; link; link = link->next) {
486 if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Patrick Georgie1667822012-05-05 15:29:32 +0200487#if CONFIG_MULTIPLE_VGA_ADAPTERS
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000488 extern device_t vga_pri; // the primary vga device, defined in device.c
Myles Watson894a3472010-06-09 22:41:35 +0000489 printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d link bus range [%d,%d]\n", vga_pri->bus->secondary,
490 link->secondary,link->subordinate);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000491 /* We need to make sure the vga_pri is under the link */
Myles Watson894a3472010-06-09 22:41:35 +0000492 if((vga_pri->bus->secondary >= link->secondary ) &&
493 (vga_pri->bus->secondary <= link->subordinate )
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000494 )
495#endif
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000496 break;
Li-Ta Lo3a812852004-12-03 22:39:34 +0000497 }
498 }
Myles Watsond61ada62008-10-02 19:20:22 +0000499
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000500 /* no VGA card installed */
Myles Watson894a3472010-06-09 22:41:35 +0000501 if (link == NULL)
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000502 return;
503
Myles Watson894a3472010-06-09 22:41:35 +0000504 printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link->link_num);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000505
Myles Watsonc7233e02009-07-02 19:02:33 +0000506 /* allocate a temp resource for the legacy VGA buffer */
Myles Watson894a3472010-06-09 22:41:35 +0000507 resource = new_resource(dev, IOINDEX(4, link->link_num));
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000508 if(!resource){
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000509 printk(BIOS_DEBUG, "VGA: %s out of resources.\n", dev_path(dev));
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000510 return;
511 }
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000512 resource->base = 0xa0000;
513 resource->size = 0x20000;
Myles Watsonc7233e02009-07-02 19:02:33 +0000514 resource->limit = 0xffffffff;
515 resource->flags = IORESOURCE_FIXED | IORESOURCE_MEM |
516 IORESOURCE_ASSIGNED;
Li-Ta Lo3a812852004-12-03 22:39:34 +0000517}
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000518
Eric Biederman0ac6b412003-09-02 17:16:48 +0000519static void amdk8_set_resources(device_t dev)
520{
Myles Watson894a3472010-06-09 22:41:35 +0000521 unsigned nodeid;
522 struct bus *bus;
Myles Watsonc25cc112010-05-21 14:33:48 +0000523 struct resource *res;
Eric Biederman0ac6b412003-09-02 17:16:48 +0000524
525 /* Find the nodeid */
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000526 nodeid = amdk8_nodeid(dev);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000527
528 /* Set each resource we have found */
Myles Watsonc25cc112010-05-21 14:33:48 +0000529 for(res = dev->resource_list; res; res = res->next) {
Myles Watsonc7233e02009-07-02 19:02:33 +0000530 struct resource *old = NULL;
531 unsigned index;
532
533 if (res->size == 0) /* No need to allocate registers. */
534 continue;
535
536 if (res->flags & IORESOURCE_IO)
537 index = amdk8_find_iopair(dev, nodeid,
538 IOINDEX_LINK(res->index));
539 else
540 index = amdk8_find_mempair(dev, nodeid,
541 IOINDEX_LINK(res->index));
542
543 old = probe_resource(dev, index);
544 if (old) {
545 res->index = old->index;
546 old->index = 0;
547 old->flags = 0;
548 }
549 else
550 res->index = index;
551
552 amdk8_set_resource(dev, res, nodeid);
Eric Biederman0ac6b412003-09-02 17:16:48 +0000553 }
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000554
Myles Watsonc7233e02009-07-02 19:02:33 +0000555 compact_resources(dev);
556
Myles Watson894a3472010-06-09 22:41:35 +0000557 for(bus = dev->link_list; bus; bus = bus->next) {
Eric Biederman0ac6b412003-09-02 17:16:48 +0000558 if (bus->children) {
559 assign_resources(bus);
560 }
561 }
562}
563
Eric Biederman5cd81732004-03-11 15:01:31 +0000564static void mcf0_control_init(struct device *dev)
David W. Hendricks854e4522004-02-09 22:47:38 +0000565{
Myles Watsond61ada62008-10-02 19:20:22 +0000566#if 0
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000567 printk(BIOS_DEBUG, "NB: Function 0 Misc Control.. ");
Eric Biedermanb78c1972004-10-14 20:54:17 +0000568#endif
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000569#if 0
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000570 printk(BIOS_DEBUG, "done.\n");
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000571#endif
Li-Ta Loe5266692004-03-23 21:28:05 +0000572}
573
Eric Biederman0ac6b412003-09-02 17:16:48 +0000574static struct device_operations northbridge_operations = {
Myles Watson6507b392010-06-09 22:39:00 +0000575 .read_resources = amdk8_read_resources,
576 .set_resources = amdk8_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000577 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenkof21271e2014-10-16 18:00:27 +0200578#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
Vladimir Serbinenko6985d4e2014-09-21 14:31:19 +0200579 .acpi_fill_ssdt_generator = k8acpi_write_vars,
580 .write_acpi_tables = northbridge_write_acpi_tables,
581#endif
Myles Watson6507b392010-06-09 22:39:00 +0000582 .init = mcf0_control_init,
583 .scan_bus = amdk8_scan_chains,
584 .enable = 0,
585 .ops_pci = 0,
Eric Biederman0ac6b412003-09-02 17:16:48 +0000586};
587
Eric Biedermanb78c1972004-10-14 20:54:17 +0000588
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000589static const struct pci_driver mcf0_driver __pci_driver = {
Myles Watson6507b392010-06-09 22:39:00 +0000590 .ops = &northbridge_operations,
Eric Biederman5cd81732004-03-11 15:01:31 +0000591 .vendor = PCI_VENDOR_ID_AMD,
592 .device = 0x1100,
593};
594
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200595static void amdk8_nb_init(void *chip_info)
596{
597 relocate_sb_ht_chain();
598}
599
Eric Biederman8bd55522004-11-05 07:04:54 +0000600struct chip_operations northbridge_amd_amdk8_ops = {
601 CHIP_NAME("AMD K8 Northbridge")
602 .enable_dev = 0,
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200603 .init = amdk8_nb_init,
Eric Biederman8bd55522004-11-05 07:04:54 +0000604};
605
Myles Watson29cc9ed2009-07-02 18:56:24 +0000606static void amdk8_domain_read_resources(device_t dev)
Eric Biedermanb78c1972004-10-14 20:54:17 +0000607{
Eric Biedermanb78c1972004-10-14 20:54:17 +0000608 unsigned reg;
609
610 /* Find the already assigned resource pairs */
611 get_fx_devs();
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000612 for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
Myles Watson6507b392010-06-09 22:39:00 +0000613 u32 base, limit;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000614 base = f1_read_config32(reg);
615 limit = f1_read_config32(reg + 0x04);
616 /* Is this register allocated? */
617 if ((base & 3) != 0) {
Myles Watson6507b392010-06-09 22:39:00 +0000618 unsigned nodeid, reg_link;
Myles Watsonfa12b672009-04-30 22:45:41 +0000619 device_t reg_dev;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000620 nodeid = limit & 7;
Myles Watson6507b392010-06-09 22:39:00 +0000621 reg_link = (limit >> 4) & 3;
Myles Watsonfa12b672009-04-30 22:45:41 +0000622 reg_dev = __f0_dev[nodeid];
623 if (reg_dev) {
Eric Biedermanb78c1972004-10-14 20:54:17 +0000624 /* Reserve the resource */
Myles Watsonc7233e02009-07-02 19:02:33 +0000625 struct resource *res;
Myles Watson6507b392010-06-09 22:39:00 +0000626 res = new_resource(reg_dev, IOINDEX(0x100 + reg, reg_link));
Myles Watsonc7233e02009-07-02 19:02:33 +0000627 if (res) {
628 res->base = base;
629 res->limit = limit;
630 res->flags = 1;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000631 }
632 }
633 }
634 }
Li-Ta Loe8b1c9d2004-12-27 04:25:41 +0000635
Myles Watson29cc9ed2009-07-02 18:56:24 +0000636 pci_domain_read_resources(dev);
Eric Biedermanb78c1972004-10-14 20:54:17 +0000637}
638
Uwe Hermann4b42a622010-10-11 19:36:13 +0000639static void my_tolm_test(void *gp, struct device *dev, struct resource *new)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000640{
641 struct resource **best_p = gp;
642 struct resource *best;
643 best = *best_p;
Myles Watsonc7233e02009-07-02 19:02:33 +0000644 /* Skip VGA. */
645 if (!best || (best->base > new->base && new->base > 0xa0000)) {
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000646 best = new;
647 }
648 *best_p = best;
649}
650
Uwe Hermann4b42a622010-10-11 19:36:13 +0000651static u32 my_find_pci_tolm(struct bus *bus)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000652{
653 struct resource *min;
Myles Watson6507b392010-06-09 22:39:00 +0000654 u32 tolm;
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000655 min = 0;
Uwe Hermann4b42a622010-10-11 19:36:13 +0000656 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, my_tolm_test, &min);
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000657 tolm = 0xffffffffUL;
658 if (min && tolm > min->base) {
659 tolm = min->base;
660 }
661 return tolm;
662}
663
Stefan Reinauer08670622009-06-30 15:17:49 +0000664#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000665
666struct hw_mem_hole_info {
667 unsigned hole_startk;
668 int node_id;
669};
670
671static struct hw_mem_hole_info get_hw_mem_hole_info(void)
Jason Schildt8b26cab2005-10-25 21:24:23 +0000672{
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000673 struct hw_mem_hole_info mem_hole;
674 int i;
Jason Schildt8b26cab2005-10-25 21:24:23 +0000675
Stefan Reinauer08670622009-06-30 15:17:49 +0000676 mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000677 mem_hole.node_id = -1;
Jason Schildt8b26cab2005-10-25 21:24:23 +0000678
Myles Watsonc7233e02009-07-02 19:02:33 +0000679 for (i = 0; i < fx_devs; i++) {
Myles Watson6507b392010-06-09 22:39:00 +0000680 u32 base;
681 u32 hole;
Myles Watsond61ada62008-10-02 19:20:22 +0000682 base = f1_read_config32(0x40 + (i << 3));
683 if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
684 continue;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000685 }
Myles Watsonc7233e02009-07-02 19:02:33 +0000686
Myles Watsond61ada62008-10-02 19:20:22 +0000687 hole = pci_read_config32(__f1_dev[i], 0xf0);
688 if(hole & 1) { // we find the hole
689 mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
690 mem_hole.node_id = i; // record the node No with hole
691 break; // only one hole
692 }
693 }
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000694
Kyösti Mälkki2f9b3af2014-06-26 05:30:54 +0300695 /* We need to double check if there is special set on base reg and limit reg
696 * are not continuous instead of hole, it will find out its hole_startk.
697 */
Myles Watsond61ada62008-10-02 19:20:22 +0000698 if(mem_hole.node_id==-1) {
Myles Watson6507b392010-06-09 22:39:00 +0000699 u32 limitk_pri = 0;
Myles Watsond61ada62008-10-02 19:20:22 +0000700 for(i=0; i<8; i++) {
Myles Watson6507b392010-06-09 22:39:00 +0000701 u32 base, limit;
Myles Watsond61ada62008-10-02 19:20:22 +0000702 unsigned base_k, limit_k;
703 base = f1_read_config32(0x40 + (i << 3));
704 if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
705 continue;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000706 }
707
Myles Watsond61ada62008-10-02 19:20:22 +0000708 base_k = (base & 0xffff0000) >> 2;
709 if(limitk_pri != base_k) { // we find the hole
710 mem_hole.hole_startk = limitk_pri;
711 mem_hole.node_id = i;
712 break; //only one hole
713 }
714
715 limit = f1_read_config32(0x44 + (i << 3));
716 limit_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
717 limitk_pri = limit_k;
718 }
719 }
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000720 return mem_hole;
Jason Schildt8b26cab2005-10-25 21:24:23 +0000721}
Myles Watsonc7233e02009-07-02 19:02:33 +0000722
723static void disable_hoist_memory(unsigned long hole_startk, int node_id)
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000724{
Myles Watsonc7233e02009-07-02 19:02:33 +0000725 int i;
Myles Watsond61ada62008-10-02 19:20:22 +0000726 device_t dev;
Myles Watson6507b392010-06-09 22:39:00 +0000727 u32 base, limit;
728 u32 hoist;
729 u32 hole_sizek;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000730
731
Myles Watsond61ada62008-10-02 19:20:22 +0000732 //1. find which node has hole
733 //2. change limit in that node.
734 //3. change base and limit in later node
735 //4. clear that node f0
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000736
737 //if there is not mem hole enabled, we need to change it's base instead
738
739 hole_sizek = (4*1024*1024) - hole_startk;
740
Myles Watsonc7233e02009-07-02 19:02:33 +0000741 for(i=7;i>node_id;i--) {
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000742
Myles Watsonc7233e02009-07-02 19:02:33 +0000743 base = f1_read_config32(0x40 + (i << 3));
Myles Watsond61ada62008-10-02 19:20:22 +0000744 if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
745 continue;
746 }
Myles Watsonc7233e02009-07-02 19:02:33 +0000747 limit = f1_read_config32(0x44 + (i << 3));
748 f1_write_config32(0x44 + (i << 3),limit - (hole_sizek << 2));
749 f1_write_config32(0x40 + (i << 3),base - (hole_sizek << 2));
Myles Watsond61ada62008-10-02 19:20:22 +0000750 }
Myles Watsonc7233e02009-07-02 19:02:33 +0000751 limit = f1_read_config32(0x44 + (node_id << 3));
752 f1_write_config32(0x44 + (node_id << 3),limit - (hole_sizek << 2));
753 dev = __f1_dev[node_id];
754 if (dev == NULL) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000755 printk(BIOS_ERR, "%s: node %x is NULL!\n", __func__, node_id);
Myles Watsonc7233e02009-07-02 19:02:33 +0000756 return;
757 }
758 hoist = pci_read_config32(dev, 0xf0);
Myles Watson6507b392010-06-09 22:39:00 +0000759 if(hoist & 1) {
Myles Watsonc7233e02009-07-02 19:02:33 +0000760 pci_write_config32(dev, 0xf0, 0);
Myles Watson6507b392010-06-09 22:39:00 +0000761 } else {
Myles Watsonc7233e02009-07-02 19:02:33 +0000762 base = pci_read_config32(dev, 0x40 + (node_id << 3));
763 f1_write_config32(0x40 + (node_id << 3),base - (hole_sizek << 2));
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000764 }
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000765}
766
Myles Watson6507b392010-06-09 22:39:00 +0000767static u32 hoist_memory(unsigned long hole_startk, int node_id)
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000768{
Myles Watsonc7233e02009-07-02 19:02:33 +0000769 int i;
Myles Watson6507b392010-06-09 22:39:00 +0000770 u32 carry_over;
Myles Watsond61ada62008-10-02 19:20:22 +0000771 device_t dev;
Myles Watson6507b392010-06-09 22:39:00 +0000772 u32 base, limit;
773 u32 basek;
774 u32 hoist;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000775
Myles Watsond61ada62008-10-02 19:20:22 +0000776 carry_over = (4*1024*1024) - hole_startk;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000777
Myles Watsonc7233e02009-07-02 19:02:33 +0000778 for(i=7;i>node_id;i--) {
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000779
Myles Watsonc7233e02009-07-02 19:02:33 +0000780 base = f1_read_config32(0x40 + (i << 3));
Myles Watsond61ada62008-10-02 19:20:22 +0000781 if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
782 continue;
783 }
Myles Watsonc7233e02009-07-02 19:02:33 +0000784 limit = f1_read_config32(0x44 + (i << 3));
785 f1_write_config32(0x44 + (i << 3),limit + (carry_over << 2));
786 f1_write_config32(0x40 + (i << 3),base + (carry_over << 2));
Myles Watsond61ada62008-10-02 19:20:22 +0000787 }
Myles Watsonc7233e02009-07-02 19:02:33 +0000788 limit = f1_read_config32(0x44 + (node_id << 3));
789 f1_write_config32(0x44 + (node_id << 3),limit + (carry_over << 2));
790 dev = __f1_dev[node_id];
791 base = pci_read_config32(dev, 0x40 + (node_id << 3));
Myles Watsond61ada62008-10-02 19:20:22 +0000792 basek = (base & 0xffff0000) >> 2;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000793 if(basek == hole_startk) {
794 //don't need set memhole here, because hole off set will be 0, overflow
795 //so need to change base reg instead, new basek will be 4*1024*1024
796 base &= 0x0000ffff;
797 base |= (4*1024*1024)<<2;
Myles Watsonc7233e02009-07-02 19:02:33 +0000798 f1_write_config32(0x40 + (node_id<<3), base);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000799 }
Rudolf Marek3a8565a2009-03-26 21:45:26 +0000800 else if (dev)
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000801 {
Myles Watsond61ada62008-10-02 19:20:22 +0000802 hoist = /* hole start address */
803 ((hole_startk << 10) & 0xff000000) +
804 /* hole address to memory controller address */
805 (((basek + carry_over) >> 6) & 0x0000ff00) +
806 /* enable */
807 1;
808
809 pci_write_config32(dev, 0xf0, hoist);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000810 }
811
Myles Watsond61ada62008-10-02 19:20:22 +0000812 return carry_over;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000813}
814#endif
Jason Schildt8b26cab2005-10-25 21:24:23 +0000815
Rudolf Marekbcaea142010-11-22 22:00:52 +0000816#include <cbmem.h>
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000817
Kyösti Mälkki6b5eb1c2012-07-19 19:26:43 +0300818static void setup_uma_memory(void)
Kyösti Mälkkiba589e32012-07-11 08:03:13 +0300819{
820#if CONFIG_GFXUMA
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300821 uint32_t topmem = (uint32_t) bsp_topmem();
Kyösti Mälkkiba589e32012-07-11 08:03:13 +0300822
823#if !CONFIG_BOARD_ASROCK_939A785GMH && !CONFIG_BOARD_AMD_MAHOGANY
824
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300825 switch (topmem) {
Kyösti Mälkkiba589e32012-07-11 08:03:13 +0300826 case 0x10000000: /* 256M system memory */
827 uma_memory_size = 0x2000000; /* 32M recommended UMA */
828 break;
829
830 case 0x18000000: /* 384M system memory */
831 uma_memory_size = 0x4000000; /* 64M recommended UMA */
832 break;
833
834 case 0x20000000: /* 512M system memory */
835 uma_memory_size = 0x4000000; /* 64M recommended UMA */
836 break;
837
838 default: /* 1GB and above system memory */
839 uma_memory_size = 0x8000000; /* 128M recommended UMA */
840 break;
841 }
842#else
843 /* refer to UMA Size Consideration in 780 BDG. */
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300844 switch (topmem) {
Kyösti Mälkkiba589e32012-07-11 08:03:13 +0300845 case 0x10000000: /* 256M system memory */
846 uma_memory_size = 0x4000000; /* 64M recommended UMA */
847 break;
848
849 case 0x20000000: /* 512M system memory */
850 uma_memory_size = 0x8000000; /* 128M recommended UMA */
851 break;
852
853 default: /* 1GB and above system memory */
854 uma_memory_size = 0x10000000; /* 256M recommended UMA */
855 break;
856 }
857#endif
858
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300859 uma_memory_base = topmem - uma_memory_size; /* TOP_MEM1 */
Kyösti Mälkkiba589e32012-07-11 08:03:13 +0300860 printk(BIOS_INFO, "%s: uma size 0x%08llx, memory start 0x%08llx\n",
861 __func__, uma_memory_size, uma_memory_base);
Kyösti Mälkkiba589e32012-07-11 08:03:13 +0300862#endif
863}
864
Myles Watson29cc9ed2009-07-02 18:56:24 +0000865static void amdk8_domain_set_resources(device_t dev)
Eric Biedermanb78c1972004-10-14 20:54:17 +0000866{
Eric Biedermanb78c1972004-10-14 20:54:17 +0000867 unsigned long mmio_basek;
Myles Watson6507b392010-06-09 22:39:00 +0000868 u32 pci_tolm;
Kyösti Mälkki2b790f62013-09-03 05:25:57 +0300869 u64 ramtop = 0;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000870 int i, idx;
Stefan Reinauer08670622009-06-30 15:17:49 +0000871#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000872 struct hw_mem_hole_info mem_hole;
Myles Watson6507b392010-06-09 22:39:00 +0000873 u32 reset_memhole = 1;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000874#endif
875
Uwe Hermann4b42a622010-10-11 19:36:13 +0000876 pci_tolm = my_find_pci_tolm(dev->link_list);
Eric Biedermanb78c1972004-10-14 20:54:17 +0000877
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000878 // FIXME handle interleaved nodes. If you fix this here, please fix
879 // amdfam10, too.
Eric Biedermanb78c1972004-10-14 20:54:17 +0000880 mmio_basek = pci_tolm >> 10;
881 /* Round mmio_basek to something the processor can support */
882 mmio_basek &= ~((1 << 6) -1);
883
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000884 // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M
885 // MMIO hole. If you fix this here, please fix amdfam10, too.
Stefan Reinauerd4f53732010-04-09 14:46:51 +0000886 /* Round the mmio hole to 64M */
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000887 mmio_basek &= ~((64*1024) - 1);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000888
Stefan Reinauer08670622009-06-30 15:17:49 +0000889#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Myles Watsond61ada62008-10-02 19:20:22 +0000890 /* if the hw mem hole is already set in raminit stage, here we will compare mmio_basek and hole_basek
891 * if mmio_basek is bigger that hole_basek and will use hole_basek as mmio_basek and we don't need to reset hole.
892 * otherwise We reset the hole to the mmio_basek
893 */
Patrick Georgie1667822012-05-05 15:29:32 +0200894 #if !CONFIG_K8_REV_F_SUPPORT
Myles Watsond61ada62008-10-02 19:20:22 +0000895 if (!is_cpu_pre_e0()) {
896 #endif
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000897
898 mem_hole = get_hw_mem_hole_info();
899
Myles Watsond61ada62008-10-02 19:20:22 +0000900 if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) { //We will use hole_basek as mmio_basek, and we don't need to reset hole anymore
901 mmio_basek = mem_hole.hole_startk;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000902 reset_memhole = 0;
Myles Watsond61ada62008-10-02 19:20:22 +0000903 }
904
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000905 //mmio_basek = 3*1024*1024; // for debug to meet boundary
906
907 if(reset_memhole) {
Stefan Reinauer08670622009-06-30 15:17:49 +0000908 if(mem_hole.node_id!=-1) { // We need to select CONFIG_HW_MEM_HOLE_SIZEK for raminit, it can not make hole_startk to some basek too....!
Myles Watsond61ada62008-10-02 19:20:22 +0000909 // We need to reset our Mem Hole, because We want more big HOLE than we already set
910 //Before that We need to disable mem hole at first, becase memhole could already be set on i+1 instead
911 disable_hoist_memory(mem_hole.hole_startk, mem_hole.node_id);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000912 }
913
Patrick Georgie1667822012-05-05 15:29:32 +0200914 #if CONFIG_HW_MEM_HOLE_SIZE_AUTO_INC
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000915 //We need to double check if the mmio_basek is valid for hole setting, if it is equal to basek, we need to decrease it some
Myles Watson6507b392010-06-09 22:39:00 +0000916 u32 basek_pri;
Myles Watsonc7233e02009-07-02 19:02:33 +0000917 for (i = 0; i < fx_devs; i++) {
Myles Watson6507b392010-06-09 22:39:00 +0000918 u32 base;
919 u32 basek;
Myles Watsond61ada62008-10-02 19:20:22 +0000920 base = f1_read_config32(0x40 + (i << 3));
921 if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
922 continue;
923 }
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000924
925 basek = (base & 0xffff0000) >> 2;
926 if(mmio_basek == basek) {
Myles Watsond61ada62008-10-02 19:20:22 +0000927 mmio_basek -= (basek - basek_pri)>>1; // increase mem hole size to make sure it is on middle of pri node
928 break;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000929 }
930 basek_pri = basek;
Myles Watsond61ada62008-10-02 19:20:22 +0000931 }
932 #endif
933 }
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000934
Patrick Georgie1667822012-05-05 15:29:32 +0200935#if !CONFIG_K8_REV_F_SUPPORT
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000936 } // is_cpu_pre_e0
Yinghai Lud4b278c2006-10-04 20:46:15 +0000937#endif
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000938
939#endif
940
Stefan Reinauerf622d592005-11-26 16:56:05 +0000941 idx = 0x10;
Myles Watsonc7233e02009-07-02 19:02:33 +0000942 for(i = 0; i < fx_devs; i++) {
Myles Watson6507b392010-06-09 22:39:00 +0000943 u32 base, limit;
944 u32 basek, limitk, sizek;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000945 base = f1_read_config32(0x40 + (i << 3));
946 limit = f1_read_config32(0x44 + (i << 3));
947 if ((base & ((1<<1)|(1<<0))) != ((1<<1)|(1<<0))) {
948 continue;
949 }
950 basek = (base & 0xffff0000) >> 2;
951 limitk = ((limit + 0x00010000) & 0xffff0000) >> 2;
952 sizek = limitk - basek;
953
954 /* see if we need a hole from 0xa0000 to 0xbffff */
955 if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) {
Stefan Reinauerf622d592005-11-26 16:56:05 +0000956 ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek);
957 idx += 0x10;
Eric Biedermanb78c1972004-10-14 20:54:17 +0000958 basek = (8*64)+(16*16);
959 sizek = limitk - ((8*64)+(16*16));
Myles Watsond61ada62008-10-02 19:20:22 +0000960
Eric Biedermanb78c1972004-10-14 20:54:17 +0000961 }
arch import user (historical)ef03afa2005-07-06 17:15:30 +0000962
Myles Watsond61ada62008-10-02 19:20:22 +0000963
Patrick Georgie1667822012-05-05 15:29:32 +0200964#if CONFIG_GFXUMA
Myles Watson08e0fb82010-03-22 16:33:25 +0000965 printk(BIOS_DEBUG, "node %d : uma_memory_base/1024=0x%08llx, mmio_basek=0x%08lx, basek=0x%08x, limitk=0x%08x\n", i, uma_memory_base >> 10, mmio_basek, basek, limitk);
Stefan Reinauer8f3b8582009-10-24 12:40:52 +0000966 if ((uma_memory_base >> 10) < mmio_basek)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000967 printk(BIOS_ALERT, "node %d: UMA memory starts below mmio_basek\n", i);
Stefan Reinauer8f3b8582009-10-24 12:40:52 +0000968#else
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000969// printk(BIOS_DEBUG, "node %d : mmio_basek=%08x, basek=%08x, limitk=%08x\n", i, mmio_basek, basek, limitk); //yhlu
Stefan Reinauer8f3b8582009-10-24 12:40:52 +0000970#endif
Myles Watsond61ada62008-10-02 19:20:22 +0000971
Kyösti Mälkki26c65432014-06-26 05:30:54 +0300972 /* See if I need to split the region to accommodate pci memory space */
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000973 if ( (basek < 4*1024*1024 ) && (limitk > mmio_basek) ) {
974 if (basek <= mmio_basek) {
Eric Biedermanb78c1972004-10-14 20:54:17 +0000975 unsigned pre_sizek;
976 pre_sizek = mmio_basek - basek;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000977 if(pre_sizek>0) {
978 ram_resource(dev, (idx | i), basek, pre_sizek);
979 idx += 0x10;
980 sizek -= pre_sizek;
Kyösti Mälkki2b790f62013-09-03 05:25:57 +0300981 if (!ramtop)
982 ramtop = mmio_basek * 1024;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000983 }
Stefan Reinauer08670622009-06-30 15:17:49 +0000984 #if CONFIG_HW_MEM_HOLE_SIZEK != 0
Myles Watsond61ada62008-10-02 19:20:22 +0000985 if(reset_memhole)
Patrick Georgie1667822012-05-05 15:29:32 +0200986 #if !CONFIG_K8_REV_F_SUPPORT
Myles Watsond61ada62008-10-02 19:20:22 +0000987 if(!is_cpu_pre_e0() )
Yinghai Lud4b278c2006-10-04 20:46:15 +0000988 #endif
Myles Watsond61ada62008-10-02 19:20:22 +0000989 sizek += hoist_memory(mmio_basek,i);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +0000990 #endif
Myles Watsond61ada62008-10-02 19:20:22 +0000991
Eric Biedermanb78c1972004-10-14 20:54:17 +0000992 basek = mmio_basek;
993 }
994 if ((basek + sizek) <= 4*1024*1024) {
995 sizek = 0;
996 }
997 else {
998 basek = 4*1024*1024;
999 sizek -= (4*1024*1024 - mmio_basek);
1000 }
1001 }
Kyösti Mälkkide3dde42012-07-10 13:10:24 +03001002
1003 ram_resource(dev, (idx | i), basek, sizek);
Stefan Reinauerf622d592005-11-26 16:56:05 +00001004 idx += 0x10;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001005 printk(BIOS_DEBUG, "%d: mmio_basek=%08lx, basek=%08x, limitk=%08x\n",
Myles Watson283a4942009-03-10 20:39:27 +00001006 i, mmio_basek, basek, limitk);
Kyösti Mälkki2b790f62013-09-03 05:25:57 +03001007 if (!ramtop)
1008 ramtop = limitk * 1024;
Eric Biedermanb78c1972004-10-14 20:54:17 +00001009 }
Scott Duplichanf3cce2f2010-11-13 19:07:59 +00001010
Patrick Georgie1667822012-05-05 15:29:32 +02001011#if CONFIG_GFXUMA
Kyösti Mälkki2b790f62013-09-03 05:25:57 +03001012 set_top_of_ram(uma_memory_base);
Kyösti Mälkki63f8c082012-07-10 13:27:26 +03001013 uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10);
Kyösti Mälkki2b790f62013-09-03 05:25:57 +03001014#else
1015 set_top_of_ram(ramtop);
Scott Duplichanf3cce2f2010-11-13 19:07:59 +00001016#endif
Myles Watson894a3472010-06-09 22:41:35 +00001017 assign_resources(dev->link_list);
Myles Watson283a4942009-03-10 20:39:27 +00001018
Eric Biedermanb78c1972004-10-14 20:54:17 +00001019}
1020
Kyösti Mälkki580e7222015-03-19 21:04:23 +02001021static void amdk8_domain_scan_bus(device_t dev)
Eric Biedermanb78c1972004-10-14 20:54:17 +00001022{
Myles Watson6507b392010-06-09 22:39:00 +00001023 u32 reg;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001024 int i;
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +02001025 struct bus *link = dev->link_list;
1026
Eric Biedermanb78c1972004-10-14 20:54:17 +00001027 /* Unmap all of the HT chains */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001028 for(reg = 0xe0; reg <= 0xec; reg += 4) {
Eric Biedermanb78c1972004-10-14 20:54:17 +00001029 f1_write_config32(reg, 0);
1030 }
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +02001031
1032 link->secondary = dev->bus->subordinate;
Kyösti Mälkkide271a82015-03-18 13:09:47 +02001033 pci_scan_bus(link, PCI_DEVFN(0x18, 0), 0xff);
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +02001034 dev->bus->subordinate = link->subordinate;
Myles Watsond61ada62008-10-02 19:20:22 +00001035
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001036 /* Tune the hypertransport transaction for best performance.
1037 * Including enabling relaxed ordering if it is safe.
1038 */
1039 get_fx_devs();
Myles Watsonc7233e02009-07-02 19:02:33 +00001040 for(i = 0; i < fx_devs; i++) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001041 device_t f0_dev;
1042 f0_dev = __f0_dev[i];
1043 if (f0_dev && f0_dev->enabled) {
Myles Watson6507b392010-06-09 22:39:00 +00001044 u32 httc;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001045 httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
1046 httc &= ~HTTC_RSP_PASS_PW;
Myles Watson894a3472010-06-09 22:41:35 +00001047 if (!dev->link_list->disable_relaxed_ordering) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001048 httc |= HTTC_RSP_PASS_PW;
1049 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001050 printk(BIOS_SPEW, "%s passpw: %s\n",
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001051 dev_path(dev),
Myles Watson894a3472010-06-09 22:41:35 +00001052 (!dev->link_list->disable_relaxed_ordering)?
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001053 "enabled":"disabled");
1054 pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
1055 }
1056 }
Eric Biederman7003ba42004-10-16 06:20:29 +00001057}
1058
1059static struct device_operations pci_domain_ops = {
Myles Watson6507b392010-06-09 22:39:00 +00001060 .read_resources = amdk8_domain_read_resources,
1061 .set_resources = amdk8_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +00001062 .enable_resources = NULL,
1063 .init = NULL,
Myles Watson6507b392010-06-09 22:39:00 +00001064 .scan_bus = amdk8_domain_scan_bus,
Kyösti Mälkki33e5df32013-07-03 10:51:34 +03001065 .ops_pci_bus = pci_bus_default_ops,
Eric Biederman7003ba42004-10-16 06:20:29 +00001066};
1067
Myles Watson894a3472010-06-09 22:41:35 +00001068static void add_more_links(device_t dev, unsigned total_links)
1069{
1070 struct bus *link, *last = NULL;
Kyösti Mälkkic0ee9372015-02-21 23:56:07 +02001071 int link_num = -1;
Myles Watson894a3472010-06-09 22:41:35 +00001072
Kyösti Mälkkic0ee9372015-02-21 23:56:07 +02001073 for (link = dev->link_list; link; link = link->next) {
1074 if (link_num < link->link_num)
1075 link_num = link->link_num;
Myles Watson894a3472010-06-09 22:41:35 +00001076 last = link;
Kyösti Mälkkic0ee9372015-02-21 23:56:07 +02001077 }
Myles Watson894a3472010-06-09 22:41:35 +00001078
1079 if (last) {
Kyösti Mälkkic0ee9372015-02-21 23:56:07 +02001080 int links = total_links - (link_num + 1);
Myles Watson894a3472010-06-09 22:41:35 +00001081 if (links > 0) {
1082 link = malloc(links*sizeof(*link));
1083 if (!link)
1084 die("Couldn't allocate more links!\n");
1085 memset(link, 0, links*sizeof(*link));
1086 last->next = link;
1087 }
1088 }
1089 else {
Myles Watson894a3472010-06-09 22:41:35 +00001090 link = malloc(total_links*sizeof(*link));
1091 memset(link, 0, total_links*sizeof(*link));
1092 dev->link_list = link;
1093 }
1094
1095 for (link_num = link_num + 1; link_num < total_links; link_num++) {
1096 link->link_num = link_num;
1097 link->dev = dev;
1098 link->next = link + 1;
1099 last = link;
1100 link = link->next;
1101 }
1102 last->next = NULL;
1103}
1104
Stefan Reinauer4d6db952015-06-13 11:01:54 +02001105static void remap_bsp_lapic(struct bus *cpu_bus)
1106{
1107 struct device_path cpu_path;
1108 device_t cpu;
1109 u32 bsp_lapic_id = lapicid();
1110
1111 if (bsp_lapic_id) {
1112 cpu_path.type = DEVICE_PATH_APIC;
1113 cpu_path.apic.apic_id = 0;
1114 cpu = find_dev_path(cpu_bus, &cpu_path);
1115 if (cpu)
1116 cpu->path.apic.apic_id = bsp_lapic_id;
1117 }
1118}
1119
Kyösti Mälkki580e7222015-03-19 21:04:23 +02001120static void cpu_bus_scan(device_t dev)
Eric Biederman7003ba42004-10-16 06:20:29 +00001121{
1122 struct bus *cpu_bus;
Yinghai Lu90a04ee2005-01-07 21:12:05 +00001123 device_t dev_mc;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001124 int bsp_apicid;
arch import user (historical)ef03afa2005-07-06 17:15:30 +00001125 int i,j;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001126 unsigned nb_cfg_54;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001127 unsigned siblings;
Myles Watsond61ada62008-10-02 19:20:22 +00001128 int e0_later_single_core;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +00001129 int disable_siblings;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001130
1131 nb_cfg_54 = 0;
Yinghai Lud4b278c2006-10-04 20:46:15 +00001132 sysconf.enabled_apic_ext_id = 0;
1133 sysconf.lift_bsp_apicid = 0;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001134 siblings = 0;
1135
1136 /* Find the bootstrap processors apicid */
1137 bsp_apicid = lapicid();
Yinghai Lud4b278c2006-10-04 20:46:15 +00001138 sysconf.apicid_offset = bsp_apicid;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001139
1140 disable_siblings = !CONFIG_LOGICAL_CPUS;
Patrick Georgie1667822012-05-05 15:29:32 +02001141#if CONFIG_LOGICAL_CPUS
Myles Watson4839e2c2010-04-08 15:06:44 +00001142 get_option(&disable_siblings, "multi_core");
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001143#endif
1144
Myles Watson6507b392010-06-09 22:39:00 +00001145 // for pre_e0, nb_cfg_54 can not be set, (when you read it still is 0)
1146 // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp???
1147 // and differ d0 and e0 single core
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001148 nb_cfg_54 = read_nb_cfg_54();
Yinghai Lu90a04ee2005-01-07 21:12:05 +00001149
arch import user (historical)ef03afa2005-07-06 17:15:30 +00001150 dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0));
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001151 if (!dev_mc) {
1152 die("0:18.0 not found?");
1153 }
arch import user (historical)ef03afa2005-07-06 17:15:30 +00001154
Yinghai Lud4b278c2006-10-04 20:46:15 +00001155 sysconf.nodes = ((pci_read_config32(dev_mc, 0x60)>>4) & 7) + 1;
Myles Watsond61ada62008-10-02 19:20:22 +00001156
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001157
1158 if (pci_read_config32(dev_mc, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
1159 {
Yinghai Lud4b278c2006-10-04 20:46:15 +00001160 sysconf.enabled_apic_ext_id = 1;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001161 if(bsp_apicid == 0) {
1162 /* bsp apic id is not changed */
Stefan Reinauer08670622009-06-30 15:17:49 +00001163 sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET;
Myles Watsond61ada62008-10-02 19:20:22 +00001164 } else
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001165 {
Yinghai Lud4b278c2006-10-04 20:46:15 +00001166 sysconf.lift_bsp_apicid = 1;
Myles Watsond61ada62008-10-02 19:20:22 +00001167 }
1168
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001169 }
1170
Eric Biedermanb78c1972004-10-14 20:54:17 +00001171 /* Find which cpus are present */
Myles Watson894a3472010-06-09 22:41:35 +00001172 cpu_bus = dev->link_list;
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001173
1174 /* Always use the devicetree node with lapic_id 0 for BSP. */
1175 remap_bsp_lapic(cpu_bus);
1176
Yinghai Lud4b278c2006-10-04 20:46:15 +00001177 for(i = 0; i < sysconf.nodes; i++) {
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001178 device_t cpu_dev;
Eric Biedermanb78c1972004-10-14 20:54:17 +00001179
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001180 /* Find the cpu's pci device */
Myles Watsonfa12b672009-04-30 22:45:41 +00001181 cpu_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3));
1182 if (!cpu_dev) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001183 /* If I am probing things in a weird order
1184 * ensure all of the cpu's pci devices are found.
1185 */
Myles Watsonfa12b672009-04-30 22:45:41 +00001186 int local_j;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001187 device_t dev_f0;
Myles Watsonfa12b672009-04-30 22:45:41 +00001188 for(local_j = 0; local_j <= 3; local_j++) {
1189 cpu_dev = pci_probe_dev(NULL, dev_mc->bus,
1190 PCI_DEVFN(0x18 + i, local_j));
Eric Biedermanb78c1972004-10-14 20:54:17 +00001191 }
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001192 /* Ok, We need to set the links for that device.
1193 * otherwise the device under it will not be scanned
1194 */
1195 dev_f0 = dev_find_slot(0, PCI_DEVFN(0x18+i,0));
1196 if(dev_f0) {
Myles Watson894a3472010-06-09 22:41:35 +00001197 add_more_links(dev_f0, 3);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001198 }
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001199 }
1200
1201 e0_later_single_core = 0;
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001202 int enable_node = cpu_dev && cpu_dev->enabled;
1203 if (enable_node) {
Myles Watsonfa12b672009-04-30 22:45:41 +00001204 j = pci_read_config32(cpu_dev, 0xe8);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001205 j = (j >> 12) & 3; // dev is func 3
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001206 printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cpu_dev), j);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001207
1208 if(nb_cfg_54) {
Myles Watsond61ada62008-10-02 19:20:22 +00001209 // For e0 single core if nb_cfg_54 is set, apicid will be 0, 2, 4....
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001210 // ----> you can mixed single core e0 and dual core e0 at any sequence
1211 // That is the typical case
1212
Myles Watsond61ada62008-10-02 19:20:22 +00001213 if(j == 0 ){
Patrick Georgie1667822012-05-05 15:29:32 +02001214 #if !CONFIG_K8_REV_F_SUPPORT
Myles Watsond61ada62008-10-02 19:20:22 +00001215 e0_later_single_core = is_e0_later_in_bsp(i); // single core
Yinghai Lud4b278c2006-10-04 20:46:15 +00001216 #else
1217 e0_later_single_core = is_cpu_f0_in_bsp(i); // We can read cpuid(1) from Func3
1218 #endif
Myles Watsond61ada62008-10-02 19:20:22 +00001219 } else {
1220 e0_later_single_core = 0;
1221 }
1222 if(e0_later_single_core) {
Stefan Reinauer64ed2b72010-03-31 14:47:43 +00001223 printk(BIOS_DEBUG, "\tFound Rev E or Rev F later single core\n");
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001224
Myles Watsond61ada62008-10-02 19:20:22 +00001225 j=1;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001226 }
Myles Watsond61ada62008-10-02 19:20:22 +00001227
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001228 if(siblings > j ) {
1229 }
1230 else {
1231 siblings = j;
1232 }
1233 } else {
1234 siblings = j;
1235 }
Eric Biedermanb78c1972004-10-14 20:54:17 +00001236 }
Myles Watsond61ada62008-10-02 19:20:22 +00001237
Myles Watson6507b392010-06-09 22:39:00 +00001238 u32 jj;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001239 if(e0_later_single_core || disable_siblings) {
1240 jj = 0;
Myles Watsond61ada62008-10-02 19:20:22 +00001241 } else
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001242 {
1243 jj = siblings;
1244 }
Myles Watsond61ada62008-10-02 19:20:22 +00001245
1246 for (j = 0; j <=jj; j++ ) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001247 u32 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:8);
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001248 if(sysconf.enabled_apic_ext_id) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001249 if (apic_id != 0 || sysconf.lift_bsp_apicid) {
1250 apic_id += sysconf.apicid_offset;
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001251 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001252 }
Myles Watsond61ada62008-10-02 19:20:22 +00001253
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001254 device_t cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
1255 if (cpu)
1256 amd_cpu_topology(cpu, i, j);
Stefan Reinauerf5183cf2005-12-01 11:01:01 +00001257 } //j
1258 }
Eric Biedermanb78c1972004-10-14 20:54:17 +00001259}
1260
Eric Biederman7003ba42004-10-16 06:20:29 +00001261static void cpu_bus_init(device_t dev)
1262{
Kyösti Mälkki7bdf85b2012-07-07 13:42:03 +03001263#if CONFIG_WAIT_BEFORE_CPUS_INIT
1264 cpus_ready_for_init();
1265#endif
Myles Watson894a3472010-06-09 22:41:35 +00001266 initialize_cpus(dev->link_list);
Eric Biedermanf3ed1cf2004-10-16 08:38:58 +00001267}
1268
Eric Biederman7003ba42004-10-16 06:20:29 +00001269static struct device_operations cpu_bus_ops = {
Edward O'Callaghan812d2a42014-10-31 08:17:23 +11001270 .read_resources = DEVICE_NOOP,
1271 .set_resources = DEVICE_NOOP,
1272 .enable_resources = DEVICE_NOOP,
Myles Watson6507b392010-06-09 22:39:00 +00001273 .init = cpu_bus_init,
1274 .scan_bus = cpu_bus_scan,
Eric Biedermanb78c1972004-10-14 20:54:17 +00001275};
1276
Eric Biederman8bd55522004-11-05 07:04:54 +00001277static void root_complex_enable_dev(struct device *dev)
Eric Biederman0ac6b412003-09-02 17:16:48 +00001278{
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001279 static int done = 0;
1280
1281 /* Do not delay UMA setup, as a device on the PCI bus may evaluate
1282 the global uma_memory variables already in its enable function. */
1283 if (!done) {
1284 setup_bsp_ramtop();
1285 setup_uma_memory();
1286 done = 1;
1287 }
1288
Eric Biederman7003ba42004-10-16 06:20:29 +00001289 /* Set the operations if it is a special bus type */
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001290 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Eric Biederman7003ba42004-10-16 06:20:29 +00001291 dev->ops = &pci_domain_ops;
1292 }
Stefan Reinauer0aa37c42013-02-12 15:20:54 -08001293 else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
Eric Biederman7003ba42004-10-16 06:20:29 +00001294 dev->ops = &cpu_bus_ops;
Eric Biedermanb78c1972004-10-14 20:54:17 +00001295 }
Eric Biederman0ac6b412003-09-02 17:16:48 +00001296}
1297
Eric Biederman8bd55522004-11-05 07:04:54 +00001298struct chip_operations northbridge_amd_amdk8_root_complex_ops = {
1299 CHIP_NAME("AMD K8 Root Complex")
1300 .enable_dev = root_complex_enable_dev,
Eric Biederman0ac6b412003-09-02 17:16:48 +00001301};