blob: 121cdf201c67f6b829a14a088af933b2d3d2baf6 [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 *
Timothy Pearsone538dae2015-01-23 20:26:03 -06004 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
Marc Jones8ae8c882007-12-19 01:32:08 +00005 * Copyright (C) 2007 Advanced Micro Devices, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
Patrick Georgib890a122015-03-26 15:17:45 +010018 * Foundation, Inc.
Marc Jones8ae8c882007-12-19 01:32:08 +000019 */
20
21#include <console/console.h>
22#include <arch/io.h>
23#include <stdint.h>
24#include <device/device.h>
25#include <device/pci.h>
26#include <device/pci_ids.h>
27#include <device/hypertransport.h>
28#include <stdlib.h>
29#include <string.h>
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -080030#include <lib.h>
Timothy Pearson6e523a62015-03-27 22:58:45 -050031#include <smbios.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000032#include <cpu/cpu.h>
33
34#include <cpu/x86/lapic.h>
Kyösti Mälkki231f2612012-07-11 08:02:57 +030035#include <cpu/amd/mtrr.h>
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020036#include <cpu/amd/amdfam10_sysconf.h>
Timothy Pearson49168802015-03-13 12:48:31 -050037#include <cpu/amd/model_10xxx/ram_calc.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000038
Patrick Georgie1667822012-05-05 15:29:32 +020039#if CONFIG_LOGICAL_CPUS
Stefan Reinauer9a16e3e2010-03-29 14:45:36 +000040#include <cpu/amd/multicore.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000041#include <pc80/mc146818rtc.h>
42#endif
43
Marc Jones8ae8c882007-12-19 01:32:08 +000044#include "northbridge.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000045#include "amdfam10.h"
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020046#include "ht_config.h"
Timothy Pearson6e523a62015-03-27 22:58:45 -050047#include "chip.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000048
Stefan Reinauer08670622009-06-30 15:17:49 +000049#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +000050#include <cpu/amd/model_10xxx_rev.h>
51#endif
52
Kerry Shefeed3292011-08-18 18:03:44 +080053#if CONFIG_AMD_SB_CIMX
54#include <sb_cimx.h>
55#endif
Marc Jones8ae8c882007-12-19 01:32:08 +000056
57struct amdfam10_sysconf_t sysconf;
58
59#define FX_DEVS NODE_NUMS
60static device_t __f0_dev[FX_DEVS];
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020061device_t __f1_dev[FX_DEVS];
Marc Jones8ae8c882007-12-19 01:32:08 +000062static device_t __f2_dev[FX_DEVS];
63static device_t __f4_dev[FX_DEVS];
Myles Watson6507b392010-06-09 22:39:00 +000064static unsigned fx_devs=0;
Marc Jones8ae8c882007-12-19 01:32:08 +000065
66device_t get_node_pci(u32 nodeid, u32 fn)
67{
zbao49bb26a42012-08-03 15:44:42 +080068#if NODE_NUMS + CONFIG_CDB >= 32
69 if((CONFIG_CDB + nodeid) < 32) {
Stefan Reinauer08670622009-06-30 15:17:49 +000070 return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000071 } else {
Stefan Reinauer08670622009-06-30 15:17:49 +000072 return dev_find_slot(CONFIG_CBB-1, PCI_DEVFN(CONFIG_CDB + nodeid - 32, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000073 }
74
75#else
Stefan Reinauer08670622009-06-30 15:17:49 +000076 return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000077#endif
Marc Jones8ae8c882007-12-19 01:32:08 +000078}
Myles Watson6507b392010-06-09 22:39:00 +000079
Marc Jones8ae8c882007-12-19 01:32:08 +000080static void get_fx_devs(void)
81{
82 int i;
Marc Jones8ae8c882007-12-19 01:32:08 +000083 for(i = 0; i < FX_DEVS; i++) {
84 __f0_dev[i] = get_node_pci(i, 0);
85 __f1_dev[i] = get_node_pci(i, 1);
86 __f2_dev[i] = get_node_pci(i, 2);
87 __f4_dev[i] = get_node_pci(i, 4);
Myles Watson6507b392010-06-09 22:39:00 +000088 if (__f0_dev[i] != NULL && __f1_dev[i] != NULL)
89 fx_devs = i+1;
Marc Jones8ae8c882007-12-19 01:32:08 +000090 }
Myles Watson6507b392010-06-09 22:39:00 +000091 if (__f1_dev[0] == NULL || __f0_dev[0] == NULL || fx_devs == 0) {
92 die("Cannot find 0:0x18.[0|1]\n");
Marc Jones8ae8c882007-12-19 01:32:08 +000093 }
94}
95
Myles Watson6507b392010-06-09 22:39:00 +000096static u32 f1_read_config32(unsigned reg)
Marc Jones8ae8c882007-12-19 01:32:08 +000097{
Myles Watson6507b392010-06-09 22:39:00 +000098 if (fx_devs == 0)
99 get_fx_devs();
Marc Jones8ae8c882007-12-19 01:32:08 +0000100 return pci_read_config32(__f1_dev[0], reg);
101}
102
Myles Watson6507b392010-06-09 22:39:00 +0000103static void f1_write_config32(unsigned reg, u32 value)
Marc Jones8ae8c882007-12-19 01:32:08 +0000104{
105 int i;
Myles Watson6507b392010-06-09 22:39:00 +0000106 if (fx_devs == 0)
107 get_fx_devs();
108 for(i = 0; i < fx_devs; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000109 device_t dev;
110 dev = __f1_dev[i];
111 if (dev && dev->enabled) {
112 pci_write_config32(dev, reg, value);
113 }
114 }
115}
116
Marc Jones8ae8c882007-12-19 01:32:08 +0000117static u32 amdfam10_nodeid(device_t dev)
118{
119#if NODE_NUMS == 64
120 unsigned busn;
121 busn = dev->bus->secondary;
Stefan Reinauer08670622009-06-30 15:17:49 +0000122 if(busn != CONFIG_CBB) {
123 return (dev->path.pci.devfn >> 3) - CONFIG_CDB + 32;
Marc Jones8ae8c882007-12-19 01:32:08 +0000124 } else {
Stefan Reinauer08670622009-06-30 15:17:49 +0000125 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000126 }
127
128#else
Stefan Reinauer08670622009-06-30 15:17:49 +0000129 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000130#endif
131}
132
Marc Jones8ae8c882007-12-19 01:32:08 +0000133static void set_vga_enable_reg(u32 nodeid, u32 linkn)
134{
135 u32 val;
136
137 val = 1 | (nodeid<<4) | (linkn<<12);
138 /* it will routing (1)mmio 0xa0000:0xbffff (2) io 0x3b0:0x3bb,
139 0x3c0:0x3df */
140 f1_write_config32(0xf4, val);
141
142}
143
Kyösti Mälkkie40beb12015-02-04 15:23:03 +0200144static bool is_non_coherent_link(struct device *dev, struct bus *link)
145{
146 u32 link_type;
147 do {
148 link_type = pci_read_config32(dev, link->cap + 0x18);
149 } while (link_type & ConnectionPending);
150
151 if (!(link_type & LinkConnected))
152 return false;
153
154 do {
155 link_type = pci_read_config32(dev, link->cap + 0x18);
156 } while (!(link_type & InitComplete));
157
158 return !!(link_type & NonCoherent);
159}
160
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200161static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, struct bus *link, bool is_sblink,
162 u32 max)
Marc Jones8ae8c882007-12-19 01:32:08 +0000163{
164// I want to put sb chain in bus 0 can I?
165
166
Marc Jones8ae8c882007-12-19 01:32:08 +0000167 int i;
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200168 unsigned int next_unitid;
Marc Jones8ae8c882007-12-19 01:32:08 +0000169 u32 ht_c_index;
170 u32 ht_unitid_base[4]; // here assume only 4 HT device on chain
171 u32 max_bus;
172 u32 min_bus;
Marc Jones8ae8c882007-12-19 01:32:08 +0000173 u32 busses;
Myles Watson362db612010-04-08 15:12:18 +0000174#if CONFIG_SB_HT_CHAIN_ON_BUS0 > 1
Marc Jones8ae8c882007-12-19 01:32:08 +0000175 u32 busn = max&0xff;
Myles Watson362db612010-04-08 15:12:18 +0000176#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000177 u32 max_devfn;
178
Kyösti Mälkkif5e7fa22015-02-04 13:49:07 +0200179 if (link->link_num > 3) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000180 u32 regpos;
181 u32 reg;
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200182 regpos = 0x170 + 4 * (link->link_num & 3); // it is only on sublink0
Marc Jones8ae8c882007-12-19 01:32:08 +0000183 reg = pci_read_config32(dev, regpos);
184 if(reg & 1) return max; // already ganged no sblink1
Kyösti Mälkki72550622015-02-04 15:37:45 +0200185
186 dev = get_node_pci(nodeid, 4);
Kyösti Mälkkif5e7fa22015-02-04 13:49:07 +0200187 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000188
Kyösti Mälkkie40beb12015-02-04 15:23:03 +0200189 /* Check for connected link. */
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200190 link->cap = 0x80 + ((link->link_num & 3) * 0x20);
Kyösti Mälkki72550622015-02-04 15:37:45 +0200191 if (!is_non_coherent_link(dev, link))
Marc Jones8ae8c882007-12-19 01:32:08 +0000192 return max;
Kyösti Mälkkie40beb12015-02-04 15:23:03 +0200193
Marc Jones8ae8c882007-12-19 01:32:08 +0000194 /* See if there is an available configuration space mapping
195 * register in function 1.
196 */
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200197 ht_c_index = get_ht_c_index(nodeid, link->link_num, &sysconf);
Marc Jones8ae8c882007-12-19 01:32:08 +0000198
Marc Jones8ae8c882007-12-19 01:32:08 +0000199 if(ht_c_index>=4) return max;
Marc Jones8ae8c882007-12-19 01:32:08 +0000200
201 /* Set up the primary, secondary and subordinate bus numbers.
202 * We have no idea how many busses are behind this bridge yet,
203 * so we set the subordinate bus number to 0xff for the moment.
204 */
Stefan Reinauer08670622009-06-30 15:17:49 +0000205#if CONFIG_SB_HT_CHAIN_ON_BUS0 > 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000206 // first chain will on bus 0
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200207 if (is_sblink) { // actually max is 0 here
Myles Watson6507b392010-06-09 22:39:00 +0000208 min_bus = max;
Marc Jones8ae8c882007-12-19 01:32:08 +0000209 }
Stefan Reinauer08670622009-06-30 15:17:49 +0000210 #if CONFIG_SB_HT_CHAIN_ON_BUS0 > 1
Marc Jones8ae8c882007-12-19 01:32:08 +0000211 // second chain will be on 0x40, third 0x80, forth 0xc0
212 // i would refined that to 2, 3, 4 ==> 0, 0x, 40, 0x80, 0xc0
213 // >4 will use more segments, We can have 16 segmment and every segment have 256 bus, For that case need the kernel support mmio pci config.
214 else {
215 min_bus = ((busn>>3) + 1) << 3; // one node can have 8 link and segn is the same
216 }
Kyösti Mälkkibf62b2d2015-02-21 12:42:51 +0200217 max = min_bus;
Myles Watson6507b392010-06-09 22:39:00 +0000218 #else
Marc Jones8ae8c882007-12-19 01:32:08 +0000219 //other ...
220 else {
221 min_bus = ++max;
222 }
Myles Watson6507b392010-06-09 22:39:00 +0000223 #endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000224#else
225 min_bus = ++max;
226#endif
Kyösti Mälkkibf62b2d2015-02-21 12:42:51 +0200227 max_bus = 0xfc;
Marc Jones8ae8c882007-12-19 01:32:08 +0000228
Myles Watson894a3472010-06-09 22:41:35 +0000229 link->secondary = min_bus;
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200230 link->subordinate = link->secondary;
Myles Watson6507b392010-06-09 22:39:00 +0000231
Marc Jones8ae8c882007-12-19 01:32:08 +0000232 /* Read the existing primary/secondary/subordinate bus
233 * number configuration.
234 */
Kyösti Mälkki72550622015-02-04 15:37:45 +0200235 busses = pci_read_config32(dev, link->cap + 0x14);
Marc Jones8ae8c882007-12-19 01:32:08 +0000236
237 /* Configure the bus numbers for this bridge: the configuration
238 * transactions will not be propagates by the bridge if it is
239 * not correctly configured
240 */
241 busses &= 0xffff00ff;
Myles Watson894a3472010-06-09 22:41:35 +0000242 busses |= ((u32)(link->secondary) << 8);
Kyösti Mälkki72550622015-02-04 15:37:45 +0200243 pci_write_config32(dev, link->cap + 0x14, busses);
Marc Jones8ae8c882007-12-19 01:32:08 +0000244
245
246 /* set the config map space */
247
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200248 set_config_map_reg(nodeid, link->link_num, ht_c_index, link->secondary, max_bus, sysconf.segbit, sysconf.nodes);
Marc Jones8ae8c882007-12-19 01:32:08 +0000249
250 /* Now we can scan all of the subordinate busses i.e. the
251 * chain on the hypertranport link
252 */
253 for(i=0;i<4;i++) {
254 ht_unitid_base[i] = 0x20;
255 }
256
257 //if ext conf is enabled, only need use 0x1f
258 if (min_bus == 0)
259 max_devfn = (0x17<<3) | 7;
260 else
261 max_devfn = (0x1f<<3) | 7;
262
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200263 next_unitid = hypertransport_scan_chain(link, 0, max_devfn, ht_unitid_base, offset_unit_id(is_sblink));
264
265 /* Now that nothing is overlapping it is safe to scan the children. */
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200266 link->subordinate = pci_scan_bus(link, 0x00, ((next_unitid - 1) << 3) | 7, link->secondary);
Marc Jones8ae8c882007-12-19 01:32:08 +0000267
Marc Jones8ae8c882007-12-19 01:32:08 +0000268 /* We know the number of busses behind this bridge. Set the
269 * subordinate bus number to it's real value
270 */
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200271 set_config_map_reg(nodeid, link->link_num, ht_c_index, link->secondary, link->subordinate, sysconf.segbit, sysconf.nodes);
Marc Jones8ae8c882007-12-19 01:32:08 +0000272 sysconf.ht_c_num++;
273
274 {
Myles Watson6507b392010-06-09 22:39:00 +0000275 // use ht_unitid_base to update hcdn_reg
Marc Jones8ae8c882007-12-19 01:32:08 +0000276 u32 temp = 0;
277 for(i=0;i<4;i++) {
278 temp |= (ht_unitid_base[i] & 0xff) << (i*8);
279 }
280
281 sysconf.hcdn_reg[ht_c_index] = temp;
282
283 }
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200284 store_ht_c_conf_bus(nodeid, link->link_num, ht_c_index, link->secondary, link->subordinate, &sysconf);
285 return link->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +0000286}
287
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200288static unsigned amdfam10_scan_chains(device_t dev, unsigned unused)
Marc Jones8ae8c882007-12-19 01:32:08 +0000289{
Myles Watson6507b392010-06-09 22:39:00 +0000290 unsigned nodeid;
Myles Watson894a3472010-06-09 22:41:35 +0000291 struct bus *link;
Myles Watson6507b392010-06-09 22:39:00 +0000292 unsigned sblink = sysconf.sblk;
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200293 unsigned int max = dev->bus->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +0000294
295 nodeid = amdfam10_nodeid(dev);
296
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200297 /* Do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0 */
298 for (link = dev->link_list; link; link = link->next) {
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200299 bool is_sblink = (nodeid == 0) && (link->link_num == sblink);
300 if ((CONFIG_SB_HT_CHAIN_ON_BUS0 > 0) && is_sblink)
301 max = amdfam10_scan_chain(dev, nodeid, link, is_sblink, max);
Marc Jones8ae8c882007-12-19 01:32:08 +0000302 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000303
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200304 for (link = dev->link_list; link; link = link->next) {
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200305 bool is_sblink = (nodeid == 0) && (link->link_num == sblink);
306 if ((CONFIG_SB_HT_CHAIN_ON_BUS0 > 0) && is_sblink)
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200307 continue;
308
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200309 max = amdfam10_scan_chain(dev, nodeid, link, is_sblink, max);
Marc Jones8ae8c882007-12-19 01:32:08 +0000310 }
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200311
312 dev->bus->subordinate = max;
313
314 return unused;
Marc Jones8ae8c882007-12-19 01:32:08 +0000315}
316
317
Myles Watson6507b392010-06-09 22:39:00 +0000318static int reg_useable(unsigned reg, device_t goal_dev, unsigned goal_nodeid,
319 unsigned goal_link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000320{
321 struct resource *res;
Myles Watson6507b392010-06-09 22:39:00 +0000322 unsigned nodeid, link = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000323 int result;
324 res = 0;
Myles Watson6507b392010-06-09 22:39:00 +0000325 for(nodeid = 0; !res && (nodeid < fx_devs); nodeid++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000326 device_t dev;
327 dev = __f0_dev[nodeid];
Rudolf Marek3a8565a2009-03-26 21:45:26 +0000328 if (!dev)
329 continue;
Marc Jones8ae8c882007-12-19 01:32:08 +0000330 for(link = 0; !res && (link < 8); link++) {
Myles Watson29cc9ed2009-07-02 18:56:24 +0000331 res = probe_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000332 }
333 }
334 result = 2;
335 if (res) {
336 result = 0;
337 if ( (goal_link == (link - 1)) &&
338 (goal_nodeid == (nodeid - 1)) &&
339 (res->flags <= 1)) {
340 result = 1;
341 }
342 }
343 return result;
344}
345
Myles Watson6507b392010-06-09 22:39:00 +0000346static struct resource *amdfam10_find_iopair(device_t dev, unsigned nodeid, unsigned link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000347{
348 struct resource *resource;
349 u32 free_reg, reg;
350 resource = 0;
351 free_reg = 0;
352 for(reg = 0xc0; reg <= 0xd8; reg += 0x8) {
353 int result;
354 result = reg_useable(reg, dev, nodeid, link);
355 if (result == 1) {
356 /* I have been allocated this one */
357 break;
358 }
359 else if (result > 1) {
360 /* I have a free register pair */
361 free_reg = reg;
362 }
363 }
364 if (reg > 0xd8) {
365 reg = free_reg; // if no free, the free_reg still be 0
366 }
367
368 //Ext conf space
369 if(!reg) {
370 //because of Extend conf space, we will never run out of reg, but we need one index to differ them. so same node and same link can have multi range
371 u32 index = get_io_addr_index(nodeid, link);
372 reg = 0x110+ (index<<24) + (4<<20); // index could be 0, 255
373 }
374
Myles Watson29cc9ed2009-07-02 18:56:24 +0000375 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000376
377 return resource;
378}
379
380static struct resource *amdfam10_find_mempair(device_t dev, u32 nodeid, u32 link)
381{
382 struct resource *resource;
383 u32 free_reg, reg;
384 resource = 0;
385 free_reg = 0;
386 for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
387 int result;
388 result = reg_useable(reg, dev, nodeid, link);
389 if (result == 1) {
390 /* I have been allocated this one */
391 break;
392 }
393 else if (result > 1) {
394 /* I have a free register pair */
395 free_reg = reg;
396 }
397 }
398 if (reg > 0xb8) {
399 reg = free_reg;
400 }
401
402 //Ext conf space
403 if(!reg) {
404 //because of Extend conf space, we will never run out of reg,
405 // but we need one index to differ them. so same node and
406 // same link can have multi range
407 u32 index = get_mmio_addr_index(nodeid, link);
408 reg = 0x110+ (index<<24) + (6<<20); // index could be 0, 63
409
410 }
Myles Watson29cc9ed2009-07-02 18:56:24 +0000411 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000412 return resource;
413}
414
415
416static void amdfam10_link_read_bases(device_t dev, u32 nodeid, u32 link)
417{
418 struct resource *resource;
419
420 /* Initialize the io space constraints on the current bus */
Myles Watson6507b392010-06-09 22:39:00 +0000421 resource = amdfam10_find_iopair(dev, nodeid, link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000422 if (resource) {
423 u32 align;
Kyösti Mälkki45033592014-12-14 08:35:29 +0200424 align = log2(HT_IO_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000425 resource->base = 0;
426 resource->size = 0;
427 resource->align = align;
428 resource->gran = align;
429 resource->limit = 0xffffUL;
Myles Watson280df102009-07-07 13:26:35 +0000430 resource->flags = IORESOURCE_IO | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000431 }
432
433 /* Initialize the prefetchable memory constraints on the current bus */
434 resource = amdfam10_find_mempair(dev, nodeid, link);
435 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000436 resource->base = 0;
437 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000438 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000439 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000440 resource->limit = 0xffffffffffULL;
Myles Watson6507b392010-06-09 22:39:00 +0000441 resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
442 resource->flags |= IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000443 }
444
445 /* Initialize the memory constraints on the current bus */
446 resource = amdfam10_find_mempair(dev, nodeid, link);
447 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000448 resource->base = 0;
449 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000450 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000451 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000452 resource->limit = 0xffffffffffULL;
Myles Watson280df102009-07-07 13:26:35 +0000453 resource->flags = IORESOURCE_MEM | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000454 }
455}
456
Marc Jones8ae8c882007-12-19 01:32:08 +0000457static void amdfam10_read_resources(device_t dev)
458{
Myles Watson894a3472010-06-09 22:41:35 +0000459 u32 nodeid;
460 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000461 nodeid = amdfam10_nodeid(dev);
Myles Watson894a3472010-06-09 22:41:35 +0000462 for(link = dev->link_list; link; link = link->next) {
463 if (link->children) {
464 amdfam10_link_read_bases(dev, nodeid, link->link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000465 }
466 }
467}
468
Marc Jones8ae8c882007-12-19 01:32:08 +0000469static void amdfam10_set_resource(device_t dev, struct resource *resource,
470 u32 nodeid)
471{
472 resource_t rbase, rend;
Myles Watson894a3472010-06-09 22:41:35 +0000473 unsigned reg, link_num;
Marc Jones8ae8c882007-12-19 01:32:08 +0000474 char buf[50];
475
476 /* Make certain the resource has actually been set */
477 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
478 return;
479 }
480
481 /* If I have already stored this resource don't worry about it */
482 if (resource->flags & IORESOURCE_STORED) {
483 return;
484 }
485
486 /* Only handle PCI memory and IO resources */
487 if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
488 return;
489
490 /* Ensure I am actually looking at a resource of function 1 */
491 if ((resource->index & 0xffff) < 0x1000) {
492 return;
493 }
494 /* Get the base address */
495 rbase = resource->base;
496
497 /* Get the limit (rounded up) */
498 rend = resource_end(resource);
499
500 /* Get the register and link */
501 reg = resource->index & 0xfff; // 4k
Myles Watson894a3472010-06-09 22:41:35 +0000502 link_num = IOINDEX_LINK(resource->index);
Marc Jones8ae8c882007-12-19 01:32:08 +0000503
504 if (resource->flags & IORESOURCE_IO) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000505
Myles Watson894a3472010-06-09 22:41:35 +0000506 set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8);
507 store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 24), rbase>>8, rend>>8);
Marc Jones8ae8c882007-12-19 01:32:08 +0000508 }
509 else if (resource->flags & IORESOURCE_MEM) {
Myles Watson894a3472010-06-09 22:41:35 +0000510 set_mmio_addr_reg(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
511 store_conf_mmio_addr(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8);
Marc Jones8ae8c882007-12-19 01:32:08 +0000512 }
513 resource->flags |= IORESOURCE_STORED;
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100514 snprintf(buf, sizeof (buf), " <node %x link %x>",
515 nodeid, link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000516 report_resource_stored(dev, resource, buf);
517}
518
519/**
Marc Jones8ae8c882007-12-19 01:32:08 +0000520 * I tried to reuse the resource allocation code in amdfam10_set_resource()
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000521 * but it is too difficult to deal with the resource allocation magic.
Marc Jones8ae8c882007-12-19 01:32:08 +0000522 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000523
524static void amdfam10_create_vga_resource(device_t dev, unsigned nodeid)
525{
Myles Watson894a3472010-06-09 22:41:35 +0000526 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000527
528 /* find out which link the VGA card is connected,
529 * we only deal with the 'first' vga card */
Myles Watson894a3472010-06-09 22:41:35 +0000530 for (link = dev->link_list; link; link = link->next) {
531 if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Patrick Georgie1667822012-05-05 15:29:32 +0200532#if CONFIG_MULTIPLE_VGA_ADAPTERS
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000533 extern device_t vga_pri; // the primary vga device, defined in device.c
Myles Watson894a3472010-06-09 22:41:35 +0000534 printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d bus range [%d,%d]\n", vga_pri->bus->secondary,
535 link->secondary,link->subordinate);
Marc Jones8ae8c882007-12-19 01:32:08 +0000536 /* We need to make sure the vga_pri is under the link */
Myles Watson894a3472010-06-09 22:41:35 +0000537 if((vga_pri->bus->secondary >= link->secondary ) &&
538 (vga_pri->bus->secondary <= link->subordinate )
Marc Jones8ae8c882007-12-19 01:32:08 +0000539 )
540#endif
541 break;
542 }
543 }
544
545 /* no VGA card installed */
Myles Watson894a3472010-06-09 22:41:35 +0000546 if (link == NULL)
Marc Jones8ae8c882007-12-19 01:32:08 +0000547 return;
548
Myles Watson894a3472010-06-09 22:41:35 +0000549 printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link->link_num);
550 set_vga_enable_reg(nodeid, link->link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000551}
552
553static void amdfam10_set_resources(device_t dev)
554{
Myles Watson894a3472010-06-09 22:41:35 +0000555 unsigned nodeid;
556 struct bus *bus;
Myles Watsonc25cc112010-05-21 14:33:48 +0000557 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000558
559 /* Find the nodeid */
560 nodeid = amdfam10_nodeid(dev);
561
562 amdfam10_create_vga_resource(dev, nodeid);
563
564 /* Set each resource we have found */
Myles Watsonc25cc112010-05-21 14:33:48 +0000565 for(res = dev->resource_list; res; res = res->next) {
566 amdfam10_set_resource(dev, res, nodeid);
Marc Jones8ae8c882007-12-19 01:32:08 +0000567 }
568
Myles Watson894a3472010-06-09 22:41:35 +0000569 for(bus = dev->link_list; bus; bus = bus->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000570 if (bus->children) {
571 assign_resources(bus);
572 }
573 }
574}
575
Marc Jones8ae8c882007-12-19 01:32:08 +0000576static void mcf0_control_init(struct device *dev)
577{
578}
579
580static struct device_operations northbridge_operations = {
581 .read_resources = amdfam10_read_resources,
582 .set_resources = amdfam10_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000583 .enable_resources = pci_dev_enable_resources,
Marc Jones8ae8c882007-12-19 01:32:08 +0000584 .init = mcf0_control_init,
585 .scan_bus = amdfam10_scan_chains,
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200586#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
587 .write_acpi_tables = northbridge_write_acpi_tables,
588 .acpi_fill_ssdt_generator = northbridge_acpi_write_vars,
589#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000590 .enable = 0,
591 .ops_pci = 0,
592};
593
594
Stefan Reinauer8e96ba22010-03-16 23:33:29 +0000595static const struct pci_driver mcf0_driver __pci_driver = {
Marc Jones8ae8c882007-12-19 01:32:08 +0000596 .ops = &northbridge_operations,
597 .vendor = PCI_VENDOR_ID_AMD,
598 .device = 0x1200,
599};
600
Marc Jones8ae8c882007-12-19 01:32:08 +0000601struct chip_operations northbridge_amd_amdfam10_ops = {
602 CHIP_NAME("AMD FAM10 Northbridge")
603 .enable_dev = 0,
604};
605
Myles Watson29cc9ed2009-07-02 18:56:24 +0000606static void amdfam10_domain_read_resources(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000607{
Marc Jones8ae8c882007-12-19 01:32:08 +0000608 unsigned reg;
Marc Jones8ae8c882007-12-19 01:32:08 +0000609
610 /* Find the already assigned resource pairs */
611 get_fx_devs();
612 for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
613 u32 base, limit;
614 base = f1_read_config32(reg);
615 limit = f1_read_config32(reg + 0x04);
616 /* Is this register allocated? */
617 if ((base & 3) != 0) {
Myles Watson362db612010-04-08 15:12:18 +0000618 unsigned nodeid, reg_link;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000619 device_t reg_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +0000620 if(reg<0xc0) { // mmio
621 nodeid = (limit & 0xf) + (base&0x30);
622 } else { // io
623 nodeid = (limit & 0xf) + ((base>>4)&0x30);
624 }
Myles Watson6507b392010-06-09 22:39:00 +0000625 reg_link = (limit >> 4) & 7;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000626 reg_dev = __f0_dev[nodeid];
627 if (reg_dev) {
628 /* Reserve the resource */
Myles Watson6507b392010-06-09 22:39:00 +0000629 struct resource *res;
630 res = new_resource(reg_dev, IOINDEX(0x1000 + reg, reg_link));
631 if (res) {
632 res->flags = 1;
Marc Jones8ae8c882007-12-19 01:32:08 +0000633 }
634 }
635 }
636 }
637 /* FIXME: do we need to check extend conf space?
638 I don't believe that much preset value */
639
Patrick Georgie1667822012-05-05 15:29:32 +0200640#if !CONFIG_PCI_64BIT_PREF_MEM
Myles Watson280df102009-07-07 13:26:35 +0000641 pci_domain_read_resources(dev);
Marc Jones8ae8c882007-12-19 01:32:08 +0000642#else
Myles Watson894a3472010-06-09 22:41:35 +0000643 struct bus *link;
Myles Watson362db612010-04-08 15:12:18 +0000644 struct resource *resource;
Myles Watson894a3472010-06-09 22:41:35 +0000645 for(link=dev->link_list; link; link = link->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000646 /* Initialize the system wide io space constraints */
Myles Watson894a3472010-06-09 22:41:35 +0000647 resource = new_resource(dev, 0|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000648 resource->base = 0x400;
649 resource->limit = 0xffffUL;
650 resource->flags = IORESOURCE_IO;
Marc Jones8ae8c882007-12-19 01:32:08 +0000651
652 /* Initialize the system wide prefetchable memory resources constraints */
Myles Watson894a3472010-06-09 22:41:35 +0000653 resource = new_resource(dev, 1|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000654 resource->limit = 0xfcffffffffULL;
655 resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
Marc Jones8ae8c882007-12-19 01:32:08 +0000656
657 /* Initialize the system wide memory resources constraints */
Myles Watson894a3472010-06-09 22:41:35 +0000658 resource = new_resource(dev, 2|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000659 resource->limit = 0xfcffffffffULL;
660 resource->flags = IORESOURCE_MEM;
Marc Jones8ae8c882007-12-19 01:32:08 +0000661 }
662#endif
Myles Watson1bc5cca2010-12-07 19:34:01 +0000663#if CONFIG_MMCONF_SUPPORT
664 struct resource *res = new_resource(dev, 0xc0010058);
665 res->base = CONFIG_MMCONF_BASE_ADDRESS;
666 res->size = CONFIG_MMCONF_BUS_NUMBER * 4096*256;
667 res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
668 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
Timothy Pearsona6f669e2015-01-23 20:20:56 -0600669
670 /* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
671 ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
Myles Watson1bc5cca2010-12-07 19:34:01 +0000672#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000673}
674
Uwe Hermann4b42a622010-10-11 19:36:13 +0000675static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
Marc Jones8ae8c882007-12-19 01:32:08 +0000676{
677 struct resource *min;
678 min = 0;
679 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
680 if (min && tolm > min->base) {
681 tolm = min->base;
682 }
683 return tolm;
684}
685
Stefan Reinauer08670622009-06-30 15:17:49 +0000686#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000687
688struct hw_mem_hole_info {
689 unsigned hole_startk;
690 int node_id;
691};
692
693static struct hw_mem_hole_info get_hw_mem_hole_info(void)
694{
695 struct hw_mem_hole_info mem_hole;
696 int i;
697
Stefan Reinauer08670622009-06-30 15:17:49 +0000698 mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
Marc Jones8ae8c882007-12-19 01:32:08 +0000699 mem_hole.node_id = -1;
700
701 for (i = 0; i < sysconf.nodes; i++) {
702 struct dram_base_mask_t d;
703 u32 hole;
704 d = get_dram_base_mask(i);
705 if(!(d.mask & 1)) continue; // no memory on this node
706
707 hole = pci_read_config32(__f1_dev[i], 0xf0);
708 if(hole & 1) { // we find the hole
709 mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
710 mem_hole.node_id = i; // record the node No with hole
711 break; // only one hole
712 }
713 }
714
Kyösti Mälkki2f9b3af2014-06-26 05:30:54 +0300715 /* We need to double check if there is special set on base reg and limit reg
716 * are not continuous instead of hole, it will find out its hole_startk.
717 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000718 if(mem_hole.node_id==-1) {
719 resource_t limitk_pri = 0;
720 for(i=0; i<sysconf.nodes; i++) {
721 struct dram_base_mask_t d;
722 resource_t base_k, limit_k;
723 d = get_dram_base_mask(i);
724 if(!(d.base & 1)) continue;
725
726 base_k = ((resource_t)(d.base & 0x1fffff00)) <<9;
727 if(base_k > 4 *1024 * 1024) break; // don't need to go to check
728 if(limitk_pri != base_k) { // we find the hole
729 mem_hole.hole_startk = (unsigned)limitk_pri; // must beblow 4G
730 mem_hole.node_id = i;
731 break; //only one hole
732 }
733
734 limit_k = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9;
735 limitk_pri = limit_k;
736 }
737 }
738 return mem_hole;
739}
740
Marc Jones8ae8c882007-12-19 01:32:08 +0000741#endif
742
Rudolf Marek97be27e2010-12-13 19:50:25 +0000743#include <cbmem.h>
Myles Watson6c029e62010-09-13 14:50:20 +0000744
Kyösti Mälkki6b5eb1c2012-07-19 19:26:43 +0300745static void setup_uma_memory(void)
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300746{
747#if CONFIG_GFXUMA
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300748 uint32_t topmem = (uint32_t) bsp_topmem();
Timothy Pearson49168802015-03-13 12:48:31 -0500749 uma_memory_size = get_uma_memory_size(topmem);
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300750 uma_memory_base = topmem - uma_memory_size; /* TOP_MEM1 */
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300751 printk(BIOS_INFO, "%s: uma size 0x%08llx, memory start 0x%08llx\n",
752 __func__, uma_memory_size, uma_memory_base);
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300753#endif
754}
755
Myles Watson6507b392010-06-09 22:39:00 +0000756static void amdfam10_domain_set_resources(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000757{
Patrick Georgie1667822012-05-05 15:29:32 +0200758#if CONFIG_PCI_64BIT_PREF_MEM
Timothy Pearsone538dae2015-01-23 20:26:03 -0600759 struct resource *mem1, *mem2;
Myles Watsonc25cc112010-05-21 14:33:48 +0000760 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000761#endif
762 unsigned long mmio_basek;
763 u32 pci_tolm;
764 int i, idx;
Myles Watson894a3472010-06-09 22:41:35 +0000765 struct bus *link;
Stefan Reinauer08670622009-06-30 15:17:49 +0000766#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000767 struct hw_mem_hole_info mem_hole;
768 u32 reset_memhole = 1;
769#endif
770
Patrick Georgie1667822012-05-05 15:29:32 +0200771#if CONFIG_PCI_64BIT_PREF_MEM
Marc Jones8ae8c882007-12-19 01:32:08 +0000772
Myles Watson894a3472010-06-09 22:41:35 +0000773 for(link = dev->link_list; link; link = link->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000774 /* Now reallocate the pci resources memory with the
775 * highest addresses I can manage.
776 */
Myles Watson894a3472010-06-09 22:41:35 +0000777 mem1 = find_resource(dev, 1|(link->link_num<<2));
778 mem2 = find_resource(dev, 2|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000779
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000780 printk(BIOS_DEBUG, "base1: 0x%08Lx limit1: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000781 mem1->base, mem1->limit, mem1->size, mem1->align);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000782 printk(BIOS_DEBUG, "base2: 0x%08Lx limit2: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000783 mem2->base, mem2->limit, mem2->size, mem2->align);
784
785 /* See if both resources have roughly the same limits */
786 if (((mem1->limit <= 0xffffffff) && (mem2->limit <= 0xffffffff)) ||
787 ((mem1->limit > 0xffffffff) && (mem2->limit > 0xffffffff)))
788 {
789 /* If so place the one with the most stringent alignment first
790 */
791 if (mem2->align > mem1->align) {
792 struct resource *tmp;
793 tmp = mem1;
794 mem1 = mem2;
795 mem2 = tmp;
796 }
797 /* Now place the memory as high up as it will go */
798 mem2->base = resource_max(mem2);
799 mem1->limit = mem2->base - 1;
800 mem1->base = resource_max(mem1);
801 }
802 else {
803 /* Place the resources as high up as they will go */
804 mem2->base = resource_max(mem2);
805 mem1->base = resource_max(mem1);
806 }
807
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000808 printk(BIOS_DEBUG, "base1: 0x%08Lx limit1: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000809 mem1->base, mem1->limit, mem1->size, mem1->align);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000810 printk(BIOS_DEBUG, "base2: 0x%08Lx limit2: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000811 mem2->base, mem2->limit, mem2->size, mem2->align);
812 }
813
Timothy Pearsone538dae2015-01-23 20:26:03 -0600814 for(res = dev->resource_list; res; res = res->next)
Marc Jones8ae8c882007-12-19 01:32:08 +0000815 {
Myles Watsonc25cc112010-05-21 14:33:48 +0000816 res->flags |= IORESOURCE_ASSIGNED;
Myles Watsonc25cc112010-05-21 14:33:48 +0000817 res->flags |= IORESOURCE_STORED;
818 report_resource_stored(dev, res, "");
Marc Jones8ae8c882007-12-19 01:32:08 +0000819 }
820#endif
821
822 pci_tolm = 0xffffffffUL;
Myles Watson894a3472010-06-09 22:41:35 +0000823 for(link = dev->link_list; link; link = link->next) {
Uwe Hermann4b42a622010-10-11 19:36:13 +0000824 pci_tolm = my_find_pci_tolm(link, pci_tolm);
Marc Jones8ae8c882007-12-19 01:32:08 +0000825 }
826
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000827 // FIXME handle interleaved nodes. If you fix this here, please fix
828 // amdk8, too.
Marc Jones8ae8c882007-12-19 01:32:08 +0000829 mmio_basek = pci_tolm >> 10;
830 /* Round mmio_basek to something the processor can support */
831 mmio_basek &= ~((1 << 6) -1);
832
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000833 // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M
834 // MMIO hole. If you fix this here, please fix amdk8, too.
Myles Watson6507b392010-06-09 22:39:00 +0000835 /* Round the mmio hole to 64M */
Marc Jones8ae8c882007-12-19 01:32:08 +0000836 mmio_basek &= ~((64*1024) - 1);
837
Stefan Reinauer08670622009-06-30 15:17:49 +0000838#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000839/* if the hw mem hole is already set in raminit stage, here we will compare
840 * mmio_basek and hole_basek. if mmio_basek is bigger that hole_basek and will
841 * use hole_basek as mmio_basek and we don't need to reset hole.
842 * otherwise We reset the hole to the mmio_basek
843 */
844
845 mem_hole = get_hw_mem_hole_info();
846
847 // Use hole_basek as mmio_basek, and we don't need to reset hole anymore
848 if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) {
849 mmio_basek = mem_hole.hole_startk;
850 reset_memhole = 0;
851 }
852
Marc Jones8ae8c882007-12-19 01:32:08 +0000853#endif
854
855 idx = 0x10;
856 for(i = 0; i < sysconf.nodes; i++) {
857 struct dram_base_mask_t d;
858 resource_t basek, limitk, sizek; // 4 1T
859 d = get_dram_base_mask(i);
860
861 if(!(d.mask & 1)) continue;
862 basek = ((resource_t)(d.base & 0x1fffff00)) << 9; // could overflow, we may lost 6 bit here
863 limitk = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9 ;
864 sizek = limitk - basek;
865
866 /* see if we need a hole from 0xa0000 to 0xbffff */
867 if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) {
868 ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek);
869 idx += 0x10;
870 basek = (8*64)+(16*16);
871 sizek = limitk - ((8*64)+(16*16));
872
873 }
874
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000875// printk(BIOS_DEBUG, "node %d : mmio_basek=%08x, basek=%08x, limitk=%08x\n", i, mmio_basek, basek, limitk);
Marc Jones8ae8c882007-12-19 01:32:08 +0000876
Kyösti Mälkki26c65432014-06-26 05:30:54 +0300877 /* split the region to accommodate pci memory space */
Marc Jones8ae8c882007-12-19 01:32:08 +0000878 if ( (basek < 4*1024*1024 ) && (limitk > mmio_basek) ) {
879 if (basek <= mmio_basek) {
880 unsigned pre_sizek;
881 pre_sizek = mmio_basek - basek;
882 if(pre_sizek>0) {
883 ram_resource(dev, (idx | i), basek, pre_sizek);
884 idx += 0x10;
885 sizek -= pre_sizek;
886 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000887 basek = mmio_basek;
888 }
889 if ((basek + sizek) <= 4*1024*1024) {
890 sizek = 0;
891 }
892 else {
893 basek = 4*1024*1024;
894 sizek -= (4*1024*1024 - mmio_basek);
895 }
896 }
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000897
Marc Jones8ae8c882007-12-19 01:32:08 +0000898 ram_resource(dev, (idx | i), basek, sizek);
899 idx += 0x10;
Myles Watson08e0fb82010-03-22 16:33:25 +0000900 printk(BIOS_DEBUG, "%d: mmio_basek=%08lx, basek=%08llx, limitk=%08llx\n",
Stefan Reinauerb5fb0c52009-04-30 13:58:42 +0000901 i, mmio_basek, basek, limitk);
Marc Jones8ae8c882007-12-19 01:32:08 +0000902 }
903
Patrick Georgie1667822012-05-05 15:29:32 +0200904#if CONFIG_GFXUMA
Kyösti Mälkki63f8c082012-07-10 13:27:26 +0300905 uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10);
Myles Watson6c029e62010-09-13 14:50:20 +0000906#endif
907
Myles Watson894a3472010-06-09 22:41:35 +0000908 for(link = dev->link_list; link; link = link->next) {
909 if (link->children) {
910 assign_resources(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000911 }
912 }
913}
914
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200915static u32 amdfam10_domain_scan_bus(device_t dev, u32 unused)
Marc Jones8ae8c882007-12-19 01:32:08 +0000916{
917 u32 reg;
918 int i;
Myles Watson894a3472010-06-09 22:41:35 +0000919 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000920 /* Unmap all of the HT chains */
921 for(reg = 0xe0; reg <= 0xec; reg += 4) {
922 f1_write_config32(reg, 0);
923 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000924
Myles Watson894a3472010-06-09 22:41:35 +0000925 for(link = dev->link_list; link; link = link->next) {
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200926 link->secondary = dev->bus->subordinate;
927 link->subordinate = pci_scan_bus(link, PCI_DEVFN(CONFIG_CDB, 0), 0xff, link->secondary);
928 dev->bus->subordinate = link->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +0000929 }
930
931 /* Tune the hypertransport transaction for best performance.
932 * Including enabling relaxed ordering if it is safe.
933 */
934 get_fx_devs();
Myles Watson6507b392010-06-09 22:39:00 +0000935 for(i = 0; i < fx_devs; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000936 device_t f0_dev;
937 f0_dev = __f0_dev[i];
938 if (f0_dev && f0_dev->enabled) {
939 u32 httc;
940 httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
941 httc &= ~HTTC_RSP_PASS_PW;
Myles Watson894a3472010-06-09 22:41:35 +0000942 if (!dev->link_list->disable_relaxed_ordering) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000943 httc |= HTTC_RSP_PASS_PW;
944 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000945 printk(BIOS_SPEW, "%s passpw: %s\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000946 dev_path(dev),
Myles Watson894a3472010-06-09 22:41:35 +0000947 (!dev->link_list->disable_relaxed_ordering)?
Marc Jones8ae8c882007-12-19 01:32:08 +0000948 "enabled":"disabled");
949 pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
950 }
951 }
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200952 return unused;
Marc Jones8ae8c882007-12-19 01:32:08 +0000953}
954
Timothy Pearson6e523a62015-03-27 22:58:45 -0500955#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
956static int amdfam10_get_smbios_data16(int* count, int handle, unsigned long *current)
957{
958 struct amdmct_memory_info *mem_info;
959 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
960 if (mem_info == NULL)
961 return 0; /* can't find amdmct information in cbmem */
962
963 struct device *dev = get_node_pci(0, 0);
964 struct northbridge_amd_amdfam10_config *config = dev->chip_info;
965
966 int node;
967 int slot;
968
969 struct smbios_type16 *t = (struct smbios_type16 *)*current;
970 int len = sizeof(struct smbios_type16);
971
972 memset(t, 0, sizeof(struct smbios_type16));
973 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
974 t->handle = handle;
975 t->length = len - 2;
976 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
977 t->use = MEMORY_ARRAY_USE_SYSTEM;
978 t->memory_error_correction = MEMORY_ARRAY_ECC_NONE;
979 if ((mem_info->ecc_enabled)
980 && (mem_info->mct_stat.GStatus & (1 << GSB_ECCDIMMs))
981 && !(mem_info->mct_stat.GStatus & (1 << GSB_DramECCDis)))
982 /* Single-bit ECC enabled */
983 t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT;
984 t->maximum_capacity = config->maximum_memory_capacity / 1024; /* Convert to kilobytes */
985 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
986
987 t->number_of_memory_devices = 0;
988 /* Check all nodes for installed DIMMs */
989 for (node = 0; node < MAX_NODES_SUPPORTED; node++)
990 /* Check all slots for installed DIMMs */
991 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++)
992 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot))
993 /* Found an installed DIMM; increment count */
994 t->number_of_memory_devices++;
995
996 *current += len;
997 *count += 1;
998 return len;
999}
1000
1001static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
1002{
1003 switch (speed) {
1004 case 1:
1005 return 200;
1006 case 2:
1007 return 266;
1008 case 3:
1009 return 333;
1010 case 4:
1011 return 400;
1012 case 5:
1013 return 533;
1014 default:
1015 return 0;
1016 }
1017}
1018
1019static int amdfam10_get_smbios_data17(int* count, int handle, int parent_handle, unsigned long *current)
1020{
1021 struct amdmct_memory_info *mem_info;
1022 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
1023 if (mem_info == NULL)
1024 return 0; /* can't find amdmct information in cbmem */
1025
1026 int single_len;
1027 int len = 0;
1028 int node;
1029 int slot;
1030
1031 /* Check all nodes for installed DIMMs */
1032 for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
1033 /* Get configured RAM bus speed */
1034 uint16_t speed;
1035 speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].Speed);
1036
1037 /* Get maximum RAM bus speed */
1038 uint16_t max_speed;
1039 max_speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].DIMMAutoSpeed);
1040
1041 /* Check all slots for installed DIMMs */
1042 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++) {
1043 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot)) {
1044 /* Found an installed DIMM; populate tables */
1045 struct smbios_type17 *t = (struct smbios_type17 *)*current;
1046 char string_buffer[256];
1047
1048 /* Initialize structure */
1049 memset(t, 0, sizeof(struct smbios_type17));
1050
1051 /* Calculate the total module size in bytes:
1052 * Primary data width * 2^(#rows) * 2^(#cols) * #banks * #ranks
1053 */
1054 uint8_t width, rows, cols, banks, ranks;
1055 width = 8;
1056 rows = mem_info->dct_stat[node].DimmRows[slot];
1057 cols = mem_info->dct_stat[node].DimmCols[slot];
1058 ranks = mem_info->dct_stat[node].DimmRanks[slot];
1059 banks = mem_info->dct_stat[node].DimmBanks[slot];
1060 uint64_t dimm_size_bytes = width * (1ULL << rows) * (1ULL << cols) * banks * ranks;
1061
1062 memset(t, 0, sizeof(struct smbios_type17));
1063 t->type = SMBIOS_MEMORY_DEVICE;
1064 t->handle = handle;
1065 t->phys_memory_array_handle = parent_handle;
1066 t->length = sizeof(struct smbios_type17) - 2;
1067 if (dimm_size_bytes > 0x800000000) {
1068 t->size = 0x7FFF;
1069 t->extended_size = dimm_size_bytes;
1070 }
1071 else {
1072 t->size = dimm_size_bytes / (1024*1024);
1073 t->size &= (~0x8000); /* size specified in megabytes */
1074 }
1075 t->total_width = t->data_width = 64;
1076 if (mem_info->dct_stat[node].DimmECCPresent & (1 << slot))
1077 t->total_width += 8;
1078 t->attributes = 0;
1079 t->attributes |= ranks & 0xf; /* rank number is stored in the lowest 4 bits of the attributes field */
1080 t->form_factor = MEMORY_FORMFACTOR_DIMM;
1081 snprintf(string_buffer, sizeof (string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1);
1082 t->device_locator = smbios_add_string(t->eos, string_buffer);
1083 if (IS_ENABLED(CONFIG_DIMM_DDR2))
1084 t->memory_type = MEMORY_TYPE_DDR2;
1085 else if (IS_ENABLED(CONFIG_DIMM_DDR3))
1086 t->memory_type = MEMORY_TYPE_DDR3;
1087 t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS;
1088 if (mem_info->dct_stat[node].DimmRegistered[slot])
1089 t->type_detail |= MEMORY_TYPE_DETAIL_REGISTERED;
1090 else
1091 t->type_detail |= MEMORY_TYPE_DETAIL_UNBUFFERED;
1092 t->speed = max_speed;
1093 t->clock_speed = speed;
1094 smbios_fill_dimm_manufacturer_from_id(mem_info->dct_stat[node].DimmManufacturerID[slot], t);
1095 t->part_number = smbios_add_string(t->eos, mem_info->dct_stat[node].DimmPartNumber[slot]);
1096 if (mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) {
1097 t->serial_number = smbios_add_string(t->eos, "None");
1098 }
1099 else {
1100 snprintf(string_buffer, sizeof (string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
1101 t->serial_number = smbios_add_string(t->eos, string_buffer);
1102 }
1103 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1104 single_len = t->length + smbios_string_table_len(t->eos);
1105 len += single_len;
1106 *current += single_len;
1107 handle++;
1108 *count += 1;
1109 }
1110 }
1111 }
1112
1113 return len;
1114}
1115
1116static int amdfam10_get_smbios_data(device_t dev, int *handle, unsigned long *current)
1117{
1118 int len;
1119 int count = 0;
1120 len = amdfam10_get_smbios_data16(&count, *handle, current);
1121 len += amdfam10_get_smbios_data17(&count, *handle + 1, *handle, current);
1122 *handle += count;
1123 return len;
1124}
1125#endif
1126
Marc Jones8ae8c882007-12-19 01:32:08 +00001127static struct device_operations pci_domain_ops = {
Myles Watson29cc9ed2009-07-02 18:56:24 +00001128 .read_resources = amdfam10_domain_read_resources,
Myles Watson6507b392010-06-09 22:39:00 +00001129 .set_resources = amdfam10_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +00001130 .enable_resources = NULL,
1131 .init = NULL,
Myles Watson29cc9ed2009-07-02 18:56:24 +00001132 .scan_bus = amdfam10_domain_scan_bus,
Kyösti Mälkki872c9222013-07-03 09:44:28 +03001133 .ops_pci_bus = pci_bus_default_ops,
Timothy Pearson6e523a62015-03-27 22:58:45 -05001134#if CONFIG_GENERATE_SMBIOS_TABLES
1135 .get_smbios_data = amdfam10_get_smbios_data,
1136#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001137};
1138
1139static void sysconf_init(device_t dev) // first node
1140{
1141 sysconf.sblk = (pci_read_config32(dev, 0x64)>>8) & 7; // don't forget sublink1
1142 sysconf.segbit = 0;
1143 sysconf.ht_c_num = 0;
1144
1145 unsigned ht_c_index;
1146
1147 for(ht_c_index=0; ht_c_index<32; ht_c_index++) {
1148 sysconf.ht_c_conf_bus[ht_c_index] = 0;
1149 }
1150
1151 sysconf.nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) + 1;
1152#if CONFIG_MAX_PHYSICAL_CPUS > 8
1153 sysconf.nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
1154#endif
1155
1156 sysconf.enabled_apic_ext_id = 0;
1157 sysconf.lift_bsp_apicid = 0;
1158
1159 /* Find the bootstrap processors apicid */
1160 sysconf.bsp_apicid = lapicid();
1161 sysconf.apicid_offset = sysconf.bsp_apicid;
1162
Patrick Georgie1667822012-05-05 15:29:32 +02001163#if CONFIG_ENABLE_APIC_EXT_ID
Marc Jones8ae8c882007-12-19 01:32:08 +00001164 if (pci_read_config32(dev, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
1165 {
1166 sysconf.enabled_apic_ext_id = 1;
1167 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001168 #if (CONFIG_APIC_ID_OFFSET>0)
Marc Jones8ae8c882007-12-19 01:32:08 +00001169 if(sysconf.enabled_apic_ext_id) {
1170 if(sysconf.bsp_apicid == 0) {
1171 /* bsp apic id is not changed */
Stefan Reinauer08670622009-06-30 15:17:49 +00001172 sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET;
Marc Jones8ae8c882007-12-19 01:32:08 +00001173 } else {
1174 sysconf.lift_bsp_apicid = 1;
1175 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001176 }
1177 #endif
1178#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001179}
1180
Myles Watson894a3472010-06-09 22:41:35 +00001181static void add_more_links(device_t dev, unsigned total_links)
1182{
1183 struct bus *link, *last = NULL;
1184 int link_num;
1185
1186 for (link = dev->link_list; link; link = link->next)
1187 last = link;
1188
1189 if (last) {
1190 int links = total_links - last->link_num;
1191 link_num = last->link_num;
1192 if (links > 0) {
1193 link = malloc(links*sizeof(*link));
1194 if (!link)
1195 die("Couldn't allocate more links!\n");
1196 memset(link, 0, links*sizeof(*link));
1197 last->next = link;
1198 }
1199 }
1200 else {
1201 link_num = -1;
1202 link = malloc(total_links*sizeof(*link));
1203 memset(link, 0, total_links*sizeof(*link));
1204 dev->link_list = link;
1205 }
1206
1207 for (link_num = link_num + 1; link_num < total_links; link_num++) {
1208 link->link_num = link_num;
1209 link->dev = dev;
1210 link->next = link + 1;
1211 last = link;
1212 link = link->next;
1213 }
1214 last->next = NULL;
1215}
1216
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +02001217static u32 cpu_bus_scan(device_t dev, u32 passthru)
Marc Jones8ae8c882007-12-19 01:32:08 +00001218{
1219 struct bus *cpu_bus;
1220 device_t dev_mc;
Myles Watson362db612010-04-08 15:12:18 +00001221#if CONFIG_CBB
Marc Jones8ae8c882007-12-19 01:32:08 +00001222 device_t pci_domain;
Myles Watson362db612010-04-08 15:12:18 +00001223#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001224 int i,j;
1225 int nodes;
1226 unsigned nb_cfg_54;
1227 unsigned siblings;
1228 int cores_found;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +00001229 int disable_siblings;
Marc Jones8ae8c882007-12-19 01:32:08 +00001230 unsigned ApicIdCoreIdSize;
1231
1232 nb_cfg_54 = 0;
1233 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
1234 if(ApicIdCoreIdSize) {
1235 siblings = (1<<ApicIdCoreIdSize)-1;
1236 } else {
1237 siblings = 3; //quad core
1238 }
1239
1240 disable_siblings = !CONFIG_LOGICAL_CPUS;
Patrick Georgie1667822012-05-05 15:29:32 +02001241#if CONFIG_LOGICAL_CPUS
Myles Watson4839e2c2010-04-08 15:06:44 +00001242 get_option(&disable_siblings, "multi_core");
Marc Jones8ae8c882007-12-19 01:32:08 +00001243#endif
1244
Myles Watson6507b392010-06-09 22:39:00 +00001245 // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp???
Marc Jones8ae8c882007-12-19 01:32:08 +00001246 nb_cfg_54 = read_nb_cfg_54();
1247
Stefan Reinauer08670622009-06-30 15:17:49 +00001248#if CONFIG_CBB
1249 dev_mc = dev_find_slot(0, PCI_DEVFN(CONFIG_CDB, 0)); //0x00
Marc Jones8ae8c882007-12-19 01:32:08 +00001250 if(dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001251 printk(BIOS_DEBUG, "%s found", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001252 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001253 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001254 printk(BIOS_DEBUG, "\n%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001255 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001256 printk(BIOS_DEBUG, "%s",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001257
1258 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001259 printk(BIOS_DEBUG, " but it is not under pci_domain directly ");
Marc Jones8ae8c882007-12-19 01:32:08 +00001260 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001261 printk(BIOS_DEBUG, "\n");
Marc Jones8ae8c882007-12-19 01:32:08 +00001262 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001263 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001264 if(!dev_mc) {
1265 dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0));
1266 if (dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001267 printk(BIOS_DEBUG, "%s found\n", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001268 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001269 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Myles Watson894a3472010-06-09 22:41:35 +00001270 if((pci_domain->link_list) && (pci_domain->link_list->children == dev_mc)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001271 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001272 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001273 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001274 while(dev_mc){
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001275 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer2b34db82009-02-28 20:10:20 +00001276 dev_mc->path.pci.devfn -= PCI_DEVFN(0x18,0);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001277 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001278 dev_mc = dev_mc->sibling;
1279 }
1280 }
1281 }
1282 }
1283 }
1284
1285#endif
1286
Stefan Reinauer08670622009-06-30 15:17:49 +00001287 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001288 if (!dev_mc) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001289 printk(BIOS_ERR, "%02x:%02x.0 not found", CONFIG_CBB, CONFIG_CDB);
Marc Jones8ae8c882007-12-19 01:32:08 +00001290 die("");
1291 }
1292
1293 sysconf_init(dev_mc);
1294
1295 nodes = sysconf.nodes;
1296
Stefan Reinauer08670622009-06-30 15:17:49 +00001297#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001298 if(nodes>32) { // need to put node 32 to node 63 to bus 0xfe
Myles Watson894a3472010-06-09 22:41:35 +00001299 if(pci_domain->link_list && !pci_domain->link_list->next) {
1300 struct bus *new_link = new_link(pci_domain);
1301 pci_domain->link_list->next = new_link;
1302 new_link->link_num = 1;
1303 new_link->dev = pci_domain;
1304 new_link->children = 0;
1305 printk(BIOS_DEBUG, "%s links now 2\n", dev_path(pci_domain));
Marc Jones8ae8c882007-12-19 01:32:08 +00001306 }
Myles Watson894a3472010-06-09 22:41:35 +00001307 pci_domain->link_list->next->secondary = CONFIG_CBB - 1;
Marc Jones8ae8c882007-12-19 01:32:08 +00001308 }
1309#endif
1310 /* Find which cpus are present */
Myles Watson894a3472010-06-09 22:41:35 +00001311 cpu_bus = dev->link_list;
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001312
1313 /* Always use the devicetree node with lapic_id 0 for BSP. */
1314 remap_bsp_lapic(cpu_bus);
1315
Marc Jones8ae8c882007-12-19 01:32:08 +00001316 for(i = 0; i < nodes; i++) {
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001317 device_t cdb_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +00001318 unsigned busn, devn;
1319 struct bus *pbus;
1320
Stefan Reinauer08670622009-06-30 15:17:49 +00001321 busn = CONFIG_CBB;
1322 devn = CONFIG_CDB+i;
Marc Jones8ae8c882007-12-19 01:32:08 +00001323 pbus = dev_mc->bus;
Stefan Reinauer08670622009-06-30 15:17:49 +00001324#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001325 if(i>=32) {
1326 busn--;
1327 devn-=32;
Myles Watson894a3472010-06-09 22:41:35 +00001328 pbus = pci_domain->link_list->next);
Marc Jones8ae8c882007-12-19 01:32:08 +00001329 }
1330#endif
1331
1332 /* Find the cpu's pci device */
Myles Watson362db612010-04-08 15:12:18 +00001333 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1334 if (!cdb_dev) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001335 /* If I am probing things in a weird order
1336 * ensure all of the cpu's pci devices are found.
1337 */
Myles Watson362db612010-04-08 15:12:18 +00001338 int fn;
1339 for(fn = 0; fn <= 5; fn++) { //FBDIMM?
1340 cdb_dev = pci_probe_dev(NULL, pbus,
1341 PCI_DEVFN(devn, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +00001342 }
Myles Watson6507b392010-06-09 22:39:00 +00001343 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001344 }
Myles Watson6507b392010-06-09 22:39:00 +00001345 if (cdb_dev) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001346 /* Ok, We need to set the links for that device.
1347 * otherwise the device under it will not be scanned
1348 */
Kyösti Mälkkif5e7fa22015-02-04 13:49:07 +02001349 add_more_links(cdb_dev, 8);
Marc Jones8ae8c882007-12-19 01:32:08 +00001350 }
1351
1352 cores_found = 0; // one core
Myles Watson362db612010-04-08 15:12:18 +00001353 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001354 int enable_node = cdb_dev && cdb_dev->enabled;
1355 if (enable_node) {
Myles Watson362db612010-04-08 15:12:18 +00001356 j = pci_read_config32(cdb_dev, 0xe8);
Marc Jones8ae8c882007-12-19 01:32:08 +00001357 cores_found = (j >> 12) & 3; // dev is func 3
Arne Georg Gleditschbc259d02010-03-10 03:43:05 +00001358 if (siblings > 3)
1359 cores_found |= (j >> 13) & 4;
Myles Watson362db612010-04-08 15:12:18 +00001360 printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cdb_dev), cores_found);
Marc Jones8ae8c882007-12-19 01:32:08 +00001361 }
1362
1363 u32 jj;
1364 if(disable_siblings) {
1365 jj = 0;
1366 } else
1367 {
1368 jj = cores_found;
1369 }
1370
1371 for (j = 0; j <=jj; j++ ) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001372 u32 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
Marc Jones8ae8c882007-12-19 01:32:08 +00001373
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001374#if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
1375 if(sysconf.enabled_apic_ext_id) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001376 if (apic_id != 0 || sysconf.lift_bsp_apicid) {
1377 apic_id += sysconf.apicid_offset;
Marc Jones8ae8c882007-12-19 01:32:08 +00001378 }
1379 }
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001380#endif
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001381 device_t cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
1382 if (cpu)
1383 amd_cpu_topology(cpu, i, j);
Marc Jones8ae8c882007-12-19 01:32:08 +00001384 } //j
1385 }
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +02001386 return passthru;
Marc Jones8ae8c882007-12-19 01:32:08 +00001387}
1388
Marc Jones8ae8c882007-12-19 01:32:08 +00001389static void cpu_bus_init(device_t dev)
1390{
Myles Watson894a3472010-06-09 22:41:35 +00001391 initialize_cpus(dev->link_list);
Kerry Shefeed3292011-08-18 18:03:44 +08001392#if CONFIG_AMD_SB_CIMX
1393 sb_After_Pci_Init();
1394 sb_Mid_Post_Init();
1395#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001396}
1397
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001398static void cpu_bus_set_resources(struct device *dev)
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001399{
1400 struct resource *resource = find_resource(dev, 0xc0010058);
1401 if (resource) {
1402 report_resource_stored(dev, resource, " <mmconfig>");
1403 }
1404 pci_dev_set_resources(dev);
1405}
1406
Marc Jones8ae8c882007-12-19 01:32:08 +00001407static struct device_operations cpu_bus_ops = {
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001408 .read_resources = DEVICE_NOOP,
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001409 .set_resources = cpu_bus_set_resources,
Edward O'Callaghan812d2a42014-10-31 08:17:23 +11001410 .enable_resources = DEVICE_NOOP,
Marc Jones8ae8c882007-12-19 01:32:08 +00001411 .init = cpu_bus_init,
1412 .scan_bus = cpu_bus_scan,
1413};
1414
Marc Jones8ae8c882007-12-19 01:32:08 +00001415static void root_complex_enable_dev(struct device *dev)
1416{
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001417 static int done = 0;
1418
1419 /* Do not delay UMA setup, as a device on the PCI bus may evaluate
1420 the global uma_memory variables already in its enable function. */
1421 if (!done) {
1422 setup_bsp_ramtop();
1423 setup_uma_memory();
1424 done = 1;
1425 }
1426
Marc Jones8ae8c882007-12-19 01:32:08 +00001427 /* Set the operations if it is a special bus type */
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001428 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001429 dev->ops = &pci_domain_ops;
1430 }
Stefan Reinauer0aa37c42013-02-12 15:20:54 -08001431 else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001432 dev->ops = &cpu_bus_ops;
1433 }
1434}
1435
1436struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
1437 CHIP_NAME("AMD FAM10 Root Complex")
1438 .enable_dev = root_complex_enable_dev,
1439};