blob: ff5dc31a03666b66f49d760e65aa1460bccddafa [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älkki20968c92015-02-23 12:05:33 +0200161typedef enum {
162 HT_ROUTE_CLOSE,
163 HT_ROUTE_SCAN,
164 HT_ROUTE_FINAL,
165} scan_state;
166
167static void ht_route_link(struct bus *link, scan_state mode)
168{
169 struct bus *parent = link->dev->bus;
170 u32 busses;
171
172 /* Configure the bus numbers for this bridge: the configuration
173 * transactions will not be propagated by the bridge if it is
174 * not correctly configured
175 */
176 busses = pci_read_config32(link->dev, link->cap + 0x14);
177 busses &= 0xff000000;
178 busses |= parent->secondary & 0xff;
179 if (mode == HT_ROUTE_CLOSE) {
180 busses |= 0xfeff << 8;
181 } else if (mode == HT_ROUTE_SCAN) {
182 busses |= ((u32) link->secondary & 0xff) << 8;
183 busses |= 0xfc << 16;
184 } else if (mode == HT_ROUTE_FINAL) {
185 busses |= ((u32) link->secondary & 0xff) << 8;
186 busses |= ((u32) link->subordinate & 0xff) << 16;
187 }
188 pci_write_config32(link->dev, link->cap + 0x14, busses);
189
190}
191
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200192static u32 amdfam10_scan_chain(device_t dev, u32 nodeid, struct bus *link, bool is_sblink,
193 u32 max)
Marc Jones8ae8c882007-12-19 01:32:08 +0000194{
195// I want to put sb chain in bus 0 can I?
196
197
Marc Jones8ae8c882007-12-19 01:32:08 +0000198 int i;
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200199 unsigned int next_unitid;
Marc Jones8ae8c882007-12-19 01:32:08 +0000200 u32 ht_c_index;
201 u32 ht_unitid_base[4]; // here assume only 4 HT device on chain
202 u32 max_bus;
203 u32 min_bus;
Myles Watson362db612010-04-08 15:12:18 +0000204#if CONFIG_SB_HT_CHAIN_ON_BUS0 > 1
Marc Jones8ae8c882007-12-19 01:32:08 +0000205 u32 busn = max&0xff;
Myles Watson362db612010-04-08 15:12:18 +0000206#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000207 u32 max_devfn;
208
Kyösti Mälkkie40beb12015-02-04 15:23:03 +0200209 /* Check for connected link. */
Kyösti Mälkki59d60922015-02-21 23:56:07 +0200210 link->cap = 0x80 + (link->link_num * 0x20);
Kyösti Mälkki72550622015-02-04 15:37:45 +0200211 if (!is_non_coherent_link(dev, link))
Marc Jones8ae8c882007-12-19 01:32:08 +0000212 return max;
Kyösti Mälkkie40beb12015-02-04 15:23:03 +0200213
Marc Jones8ae8c882007-12-19 01:32:08 +0000214 /* See if there is an available configuration space mapping
215 * register in function 1.
216 */
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200217 ht_c_index = get_ht_c_index(nodeid, link->link_num, &sysconf);
Marc Jones8ae8c882007-12-19 01:32:08 +0000218
Marc Jones8ae8c882007-12-19 01:32:08 +0000219 if(ht_c_index>=4) return max;
Marc Jones8ae8c882007-12-19 01:32:08 +0000220
221 /* Set up the primary, secondary and subordinate bus numbers.
222 * We have no idea how many busses are behind this bridge yet,
223 * so we set the subordinate bus number to 0xff for the moment.
224 */
Stefan Reinauer08670622009-06-30 15:17:49 +0000225#if CONFIG_SB_HT_CHAIN_ON_BUS0 > 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000226 // first chain will on bus 0
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200227 if (is_sblink) { // actually max is 0 here
Myles Watson6507b392010-06-09 22:39:00 +0000228 min_bus = max;
Marc Jones8ae8c882007-12-19 01:32:08 +0000229 }
Stefan Reinauer08670622009-06-30 15:17:49 +0000230 #if CONFIG_SB_HT_CHAIN_ON_BUS0 > 1
Marc Jones8ae8c882007-12-19 01:32:08 +0000231 // second chain will be on 0x40, third 0x80, forth 0xc0
232 // i would refined that to 2, 3, 4 ==> 0, 0x, 40, 0x80, 0xc0
233 // >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.
234 else {
235 min_bus = ((busn>>3) + 1) << 3; // one node can have 8 link and segn is the same
236 }
Kyösti Mälkkibf62b2d2015-02-21 12:42:51 +0200237 max = min_bus;
Myles Watson6507b392010-06-09 22:39:00 +0000238 #else
Marc Jones8ae8c882007-12-19 01:32:08 +0000239 //other ...
240 else {
241 min_bus = ++max;
242 }
Myles Watson6507b392010-06-09 22:39:00 +0000243 #endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000244#else
245 min_bus = ++max;
246#endif
Kyösti Mälkkibf62b2d2015-02-21 12:42:51 +0200247 max_bus = 0xfc;
Marc Jones8ae8c882007-12-19 01:32:08 +0000248
Myles Watson894a3472010-06-09 22:41:35 +0000249 link->secondary = min_bus;
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200250 link->subordinate = link->secondary;
Myles Watson6507b392010-06-09 22:39:00 +0000251
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200252 ht_route_link(link, HT_ROUTE_SCAN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000253
254 /* set the config map space */
255
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200256 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 +0000257
258 /* Now we can scan all of the subordinate busses i.e. the
259 * chain on the hypertranport link
260 */
261 for(i=0;i<4;i++) {
262 ht_unitid_base[i] = 0x20;
263 }
264
265 //if ext conf is enabled, only need use 0x1f
266 if (min_bus == 0)
267 max_devfn = (0x17<<3) | 7;
268 else
269 max_devfn = (0x1f<<3) | 7;
270
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200271 next_unitid = hypertransport_scan_chain(link, 0, max_devfn, ht_unitid_base, offset_unit_id(is_sblink));
272
273 /* Now that nothing is overlapping it is safe to scan the children. */
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200274 pci_scan_bus(link, 0x00, ((next_unitid - 1) << 3) | 7);
Marc Jones8ae8c882007-12-19 01:32:08 +0000275
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200276 ht_route_link(link, HT_ROUTE_FINAL);
277
Marc Jones8ae8c882007-12-19 01:32:08 +0000278 /* We know the number of busses behind this bridge. Set the
279 * subordinate bus number to it's real value
280 */
Kyösti Mälkki260a6db2015-02-04 11:09:52 +0200281 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 +0000282 sysconf.ht_c_num++;
283
284 {
Myles Watson6507b392010-06-09 22:39:00 +0000285 // use ht_unitid_base to update hcdn_reg
Marc Jones8ae8c882007-12-19 01:32:08 +0000286 u32 temp = 0;
287 for(i=0;i<4;i++) {
288 temp |= (ht_unitid_base[i] & 0xff) << (i*8);
289 }
290
291 sysconf.hcdn_reg[ht_c_index] = temp;
292
293 }
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200294 store_ht_c_conf_bus(nodeid, link->link_num, ht_c_index, link->secondary, link->subordinate, &sysconf);
295 return link->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +0000296}
297
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200298static void amdfam10_scan_chains(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000299{
Myles Watson6507b392010-06-09 22:39:00 +0000300 unsigned nodeid;
Myles Watson894a3472010-06-09 22:41:35 +0000301 struct bus *link;
Myles Watson6507b392010-06-09 22:39:00 +0000302 unsigned sblink = sysconf.sblk;
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200303 unsigned int max = dev->bus->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +0000304
305 nodeid = amdfam10_nodeid(dev);
306
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200307 /* Do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0 */
308 for (link = dev->link_list; link; link = link->next) {
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200309 bool is_sblink = (nodeid == 0) && (link->link_num == sblink);
310 if ((CONFIG_SB_HT_CHAIN_ON_BUS0 > 0) && is_sblink)
311 max = amdfam10_scan_chain(dev, nodeid, link, is_sblink, max);
Marc Jones8ae8c882007-12-19 01:32:08 +0000312 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000313
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200314 for (link = dev->link_list; link; link = link->next) {
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200315 bool is_sblink = (nodeid == 0) && (link->link_num == sblink);
316 if ((CONFIG_SB_HT_CHAIN_ON_BUS0 > 0) && is_sblink)
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200317 continue;
318
Kyösti Mälkki26c66472015-02-04 13:09:06 +0200319 max = amdfam10_scan_chain(dev, nodeid, link, is_sblink, max);
Marc Jones8ae8c882007-12-19 01:32:08 +0000320 }
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200321
322 dev->bus->subordinate = max;
Marc Jones8ae8c882007-12-19 01:32:08 +0000323}
324
325
Myles Watson6507b392010-06-09 22:39:00 +0000326static int reg_useable(unsigned reg, device_t goal_dev, unsigned goal_nodeid,
327 unsigned goal_link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000328{
329 struct resource *res;
Myles Watson6507b392010-06-09 22:39:00 +0000330 unsigned nodeid, link = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000331 int result;
332 res = 0;
Myles Watson6507b392010-06-09 22:39:00 +0000333 for(nodeid = 0; !res && (nodeid < fx_devs); nodeid++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000334 device_t dev;
335 dev = __f0_dev[nodeid];
Rudolf Marek3a8565a2009-03-26 21:45:26 +0000336 if (!dev)
337 continue;
Marc Jones8ae8c882007-12-19 01:32:08 +0000338 for(link = 0; !res && (link < 8); link++) {
Myles Watson29cc9ed2009-07-02 18:56:24 +0000339 res = probe_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000340 }
341 }
342 result = 2;
343 if (res) {
344 result = 0;
345 if ( (goal_link == (link - 1)) &&
346 (goal_nodeid == (nodeid - 1)) &&
347 (res->flags <= 1)) {
348 result = 1;
349 }
350 }
351 return result;
352}
353
Myles Watson6507b392010-06-09 22:39:00 +0000354static struct resource *amdfam10_find_iopair(device_t dev, unsigned nodeid, unsigned link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000355{
356 struct resource *resource;
357 u32 free_reg, reg;
358 resource = 0;
359 free_reg = 0;
360 for(reg = 0xc0; reg <= 0xd8; reg += 0x8) {
361 int result;
362 result = reg_useable(reg, dev, nodeid, link);
363 if (result == 1) {
364 /* I have been allocated this one */
365 break;
366 }
367 else if (result > 1) {
368 /* I have a free register pair */
369 free_reg = reg;
370 }
371 }
372 if (reg > 0xd8) {
373 reg = free_reg; // if no free, the free_reg still be 0
374 }
375
376 //Ext conf space
377 if(!reg) {
378 //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
379 u32 index = get_io_addr_index(nodeid, link);
380 reg = 0x110+ (index<<24) + (4<<20); // index could be 0, 255
381 }
382
Myles Watson29cc9ed2009-07-02 18:56:24 +0000383 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000384
385 return resource;
386}
387
388static struct resource *amdfam10_find_mempair(device_t dev, u32 nodeid, u32 link)
389{
390 struct resource *resource;
391 u32 free_reg, reg;
392 resource = 0;
393 free_reg = 0;
394 for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
395 int result;
396 result = reg_useable(reg, dev, nodeid, link);
397 if (result == 1) {
398 /* I have been allocated this one */
399 break;
400 }
401 else if (result > 1) {
402 /* I have a free register pair */
403 free_reg = reg;
404 }
405 }
406 if (reg > 0xb8) {
407 reg = free_reg;
408 }
409
410 //Ext conf space
411 if(!reg) {
412 //because of Extend conf space, we will never run out of reg,
413 // but we need one index to differ them. so same node and
414 // same link can have multi range
415 u32 index = get_mmio_addr_index(nodeid, link);
416 reg = 0x110+ (index<<24) + (6<<20); // index could be 0, 63
417
418 }
Myles Watson29cc9ed2009-07-02 18:56:24 +0000419 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000420 return resource;
421}
422
423
424static void amdfam10_link_read_bases(device_t dev, u32 nodeid, u32 link)
425{
426 struct resource *resource;
427
428 /* Initialize the io space constraints on the current bus */
Myles Watson6507b392010-06-09 22:39:00 +0000429 resource = amdfam10_find_iopair(dev, nodeid, link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000430 if (resource) {
431 u32 align;
Kyösti Mälkki45033592014-12-14 08:35:29 +0200432 align = log2(HT_IO_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000433 resource->base = 0;
434 resource->size = 0;
435 resource->align = align;
436 resource->gran = align;
437 resource->limit = 0xffffUL;
Myles Watson280df102009-07-07 13:26:35 +0000438 resource->flags = IORESOURCE_IO | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000439 }
440
441 /* Initialize the prefetchable memory constraints on the current bus */
442 resource = amdfam10_find_mempair(dev, nodeid, link);
443 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000444 resource->base = 0;
445 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000446 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000447 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000448 resource->limit = 0xffffffffffULL;
Myles Watson6507b392010-06-09 22:39:00 +0000449 resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
450 resource->flags |= IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000451 }
452
453 /* Initialize the memory constraints on the current bus */
454 resource = amdfam10_find_mempair(dev, nodeid, link);
455 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000456 resource->base = 0;
457 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000458 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000459 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000460 resource->limit = 0xffffffffffULL;
Myles Watson280df102009-07-07 13:26:35 +0000461 resource->flags = IORESOURCE_MEM | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000462 }
463}
464
Marc Jones8ae8c882007-12-19 01:32:08 +0000465static void amdfam10_read_resources(device_t dev)
466{
Myles Watson894a3472010-06-09 22:41:35 +0000467 u32 nodeid;
468 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000469 nodeid = amdfam10_nodeid(dev);
Myles Watson894a3472010-06-09 22:41:35 +0000470 for(link = dev->link_list; link; link = link->next) {
471 if (link->children) {
472 amdfam10_link_read_bases(dev, nodeid, link->link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000473 }
474 }
475}
476
Marc Jones8ae8c882007-12-19 01:32:08 +0000477static void amdfam10_set_resource(device_t dev, struct resource *resource,
478 u32 nodeid)
479{
480 resource_t rbase, rend;
Myles Watson894a3472010-06-09 22:41:35 +0000481 unsigned reg, link_num;
Marc Jones8ae8c882007-12-19 01:32:08 +0000482 char buf[50];
483
484 /* Make certain the resource has actually been set */
485 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
486 return;
487 }
488
489 /* If I have already stored this resource don't worry about it */
490 if (resource->flags & IORESOURCE_STORED) {
491 return;
492 }
493
494 /* Only handle PCI memory and IO resources */
495 if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
496 return;
497
498 /* Ensure I am actually looking at a resource of function 1 */
499 if ((resource->index & 0xffff) < 0x1000) {
500 return;
501 }
502 /* Get the base address */
503 rbase = resource->base;
504
505 /* Get the limit (rounded up) */
506 rend = resource_end(resource);
507
508 /* Get the register and link */
509 reg = resource->index & 0xfff; // 4k
Myles Watson894a3472010-06-09 22:41:35 +0000510 link_num = IOINDEX_LINK(resource->index);
Marc Jones8ae8c882007-12-19 01:32:08 +0000511
512 if (resource->flags & IORESOURCE_IO) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000513
Myles Watson894a3472010-06-09 22:41:35 +0000514 set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8);
515 store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 24), rbase>>8, rend>>8);
Marc Jones8ae8c882007-12-19 01:32:08 +0000516 }
517 else if (resource->flags & IORESOURCE_MEM) {
Myles Watson894a3472010-06-09 22:41:35 +0000518 set_mmio_addr_reg(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
519 store_conf_mmio_addr(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8);
Marc Jones8ae8c882007-12-19 01:32:08 +0000520 }
521 resource->flags |= IORESOURCE_STORED;
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100522 snprintf(buf, sizeof (buf), " <node %x link %x>",
523 nodeid, link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000524 report_resource_stored(dev, resource, buf);
525}
526
527/**
Marc Jones8ae8c882007-12-19 01:32:08 +0000528 * I tried to reuse the resource allocation code in amdfam10_set_resource()
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000529 * but it is too difficult to deal with the resource allocation magic.
Marc Jones8ae8c882007-12-19 01:32:08 +0000530 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000531
532static void amdfam10_create_vga_resource(device_t dev, unsigned nodeid)
533{
Myles Watson894a3472010-06-09 22:41:35 +0000534 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000535
536 /* find out which link the VGA card is connected,
537 * we only deal with the 'first' vga card */
Myles Watson894a3472010-06-09 22:41:35 +0000538 for (link = dev->link_list; link; link = link->next) {
539 if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Patrick Georgie1667822012-05-05 15:29:32 +0200540#if CONFIG_MULTIPLE_VGA_ADAPTERS
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000541 extern device_t vga_pri; // the primary vga device, defined in device.c
Myles Watson894a3472010-06-09 22:41:35 +0000542 printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d bus range [%d,%d]\n", vga_pri->bus->secondary,
543 link->secondary,link->subordinate);
Marc Jones8ae8c882007-12-19 01:32:08 +0000544 /* We need to make sure the vga_pri is under the link */
Myles Watson894a3472010-06-09 22:41:35 +0000545 if((vga_pri->bus->secondary >= link->secondary ) &&
546 (vga_pri->bus->secondary <= link->subordinate )
Marc Jones8ae8c882007-12-19 01:32:08 +0000547 )
548#endif
549 break;
550 }
551 }
552
553 /* no VGA card installed */
Myles Watson894a3472010-06-09 22:41:35 +0000554 if (link == NULL)
Marc Jones8ae8c882007-12-19 01:32:08 +0000555 return;
556
Myles Watson894a3472010-06-09 22:41:35 +0000557 printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link->link_num);
558 set_vga_enable_reg(nodeid, link->link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000559}
560
561static void amdfam10_set_resources(device_t dev)
562{
Myles Watson894a3472010-06-09 22:41:35 +0000563 unsigned nodeid;
564 struct bus *bus;
Myles Watsonc25cc112010-05-21 14:33:48 +0000565 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000566
567 /* Find the nodeid */
568 nodeid = amdfam10_nodeid(dev);
569
570 amdfam10_create_vga_resource(dev, nodeid);
571
572 /* Set each resource we have found */
Myles Watsonc25cc112010-05-21 14:33:48 +0000573 for(res = dev->resource_list; res; res = res->next) {
574 amdfam10_set_resource(dev, res, nodeid);
Marc Jones8ae8c882007-12-19 01:32:08 +0000575 }
576
Myles Watson894a3472010-06-09 22:41:35 +0000577 for(bus = dev->link_list; bus; bus = bus->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000578 if (bus->children) {
579 assign_resources(bus);
580 }
581 }
582}
583
Marc Jones8ae8c882007-12-19 01:32:08 +0000584static void mcf0_control_init(struct device *dev)
585{
586}
587
588static struct device_operations northbridge_operations = {
589 .read_resources = amdfam10_read_resources,
590 .set_resources = amdfam10_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000591 .enable_resources = pci_dev_enable_resources,
Marc Jones8ae8c882007-12-19 01:32:08 +0000592 .init = mcf0_control_init,
593 .scan_bus = amdfam10_scan_chains,
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200594#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
595 .write_acpi_tables = northbridge_write_acpi_tables,
596 .acpi_fill_ssdt_generator = northbridge_acpi_write_vars,
597#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000598 .enable = 0,
599 .ops_pci = 0,
600};
601
602
Stefan Reinauer8e96ba22010-03-16 23:33:29 +0000603static const struct pci_driver mcf0_driver __pci_driver = {
Marc Jones8ae8c882007-12-19 01:32:08 +0000604 .ops = &northbridge_operations,
605 .vendor = PCI_VENDOR_ID_AMD,
606 .device = 0x1200,
607};
608
Marc Jones8ae8c882007-12-19 01:32:08 +0000609struct chip_operations northbridge_amd_amdfam10_ops = {
610 CHIP_NAME("AMD FAM10 Northbridge")
611 .enable_dev = 0,
612};
613
Myles Watson29cc9ed2009-07-02 18:56:24 +0000614static void amdfam10_domain_read_resources(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000615{
Marc Jones8ae8c882007-12-19 01:32:08 +0000616 unsigned reg;
Marc Jones8ae8c882007-12-19 01:32:08 +0000617
618 /* Find the already assigned resource pairs */
619 get_fx_devs();
620 for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
621 u32 base, limit;
622 base = f1_read_config32(reg);
623 limit = f1_read_config32(reg + 0x04);
624 /* Is this register allocated? */
625 if ((base & 3) != 0) {
Myles Watson362db612010-04-08 15:12:18 +0000626 unsigned nodeid, reg_link;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000627 device_t reg_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +0000628 if(reg<0xc0) { // mmio
629 nodeid = (limit & 0xf) + (base&0x30);
630 } else { // io
631 nodeid = (limit & 0xf) + ((base>>4)&0x30);
632 }
Myles Watson6507b392010-06-09 22:39:00 +0000633 reg_link = (limit >> 4) & 7;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000634 reg_dev = __f0_dev[nodeid];
635 if (reg_dev) {
636 /* Reserve the resource */
Myles Watson6507b392010-06-09 22:39:00 +0000637 struct resource *res;
638 res = new_resource(reg_dev, IOINDEX(0x1000 + reg, reg_link));
639 if (res) {
640 res->flags = 1;
Marc Jones8ae8c882007-12-19 01:32:08 +0000641 }
642 }
643 }
644 }
645 /* FIXME: do we need to check extend conf space?
646 I don't believe that much preset value */
647
Patrick Georgie1667822012-05-05 15:29:32 +0200648#if !CONFIG_PCI_64BIT_PREF_MEM
Myles Watson280df102009-07-07 13:26:35 +0000649 pci_domain_read_resources(dev);
Marc Jones8ae8c882007-12-19 01:32:08 +0000650#else
Myles Watson894a3472010-06-09 22:41:35 +0000651 struct bus *link;
Myles Watson362db612010-04-08 15:12:18 +0000652 struct resource *resource;
Myles Watson894a3472010-06-09 22:41:35 +0000653 for(link=dev->link_list; link; link = link->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000654 /* Initialize the system wide io space constraints */
Myles Watson894a3472010-06-09 22:41:35 +0000655 resource = new_resource(dev, 0|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000656 resource->base = 0x400;
657 resource->limit = 0xffffUL;
658 resource->flags = IORESOURCE_IO;
Marc Jones8ae8c882007-12-19 01:32:08 +0000659
660 /* Initialize the system wide prefetchable memory resources constraints */
Myles Watson894a3472010-06-09 22:41:35 +0000661 resource = new_resource(dev, 1|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000662 resource->limit = 0xfcffffffffULL;
663 resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
Marc Jones8ae8c882007-12-19 01:32:08 +0000664
665 /* Initialize the system wide memory resources constraints */
Myles Watson894a3472010-06-09 22:41:35 +0000666 resource = new_resource(dev, 2|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000667 resource->limit = 0xfcffffffffULL;
668 resource->flags = IORESOURCE_MEM;
Marc Jones8ae8c882007-12-19 01:32:08 +0000669 }
670#endif
Myles Watson1bc5cca2010-12-07 19:34:01 +0000671#if CONFIG_MMCONF_SUPPORT
672 struct resource *res = new_resource(dev, 0xc0010058);
673 res->base = CONFIG_MMCONF_BASE_ADDRESS;
674 res->size = CONFIG_MMCONF_BUS_NUMBER * 4096*256;
675 res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
676 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
Timothy Pearsona6f669e2015-01-23 20:20:56 -0600677
678 /* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
679 ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
Myles Watson1bc5cca2010-12-07 19:34:01 +0000680#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000681}
682
Uwe Hermann4b42a622010-10-11 19:36:13 +0000683static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
Marc Jones8ae8c882007-12-19 01:32:08 +0000684{
685 struct resource *min;
686 min = 0;
687 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
688 if (min && tolm > min->base) {
689 tolm = min->base;
690 }
691 return tolm;
692}
693
Stefan Reinauer08670622009-06-30 15:17:49 +0000694#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000695
696struct hw_mem_hole_info {
697 unsigned hole_startk;
698 int node_id;
699};
700
701static struct hw_mem_hole_info get_hw_mem_hole_info(void)
702{
703 struct hw_mem_hole_info mem_hole;
704 int i;
705
Stefan Reinauer08670622009-06-30 15:17:49 +0000706 mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
Marc Jones8ae8c882007-12-19 01:32:08 +0000707 mem_hole.node_id = -1;
708
709 for (i = 0; i < sysconf.nodes; i++) {
710 struct dram_base_mask_t d;
711 u32 hole;
712 d = get_dram_base_mask(i);
713 if(!(d.mask & 1)) continue; // no memory on this node
714
715 hole = pci_read_config32(__f1_dev[i], 0xf0);
716 if(hole & 1) { // we find the hole
717 mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
718 mem_hole.node_id = i; // record the node No with hole
719 break; // only one hole
720 }
721 }
722
Kyösti Mälkki2f9b3af2014-06-26 05:30:54 +0300723 /* We need to double check if there is special set on base reg and limit reg
724 * are not continuous instead of hole, it will find out its hole_startk.
725 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000726 if(mem_hole.node_id==-1) {
727 resource_t limitk_pri = 0;
728 for(i=0; i<sysconf.nodes; i++) {
729 struct dram_base_mask_t d;
730 resource_t base_k, limit_k;
731 d = get_dram_base_mask(i);
732 if(!(d.base & 1)) continue;
733
734 base_k = ((resource_t)(d.base & 0x1fffff00)) <<9;
735 if(base_k > 4 *1024 * 1024) break; // don't need to go to check
736 if(limitk_pri != base_k) { // we find the hole
737 mem_hole.hole_startk = (unsigned)limitk_pri; // must beblow 4G
738 mem_hole.node_id = i;
739 break; //only one hole
740 }
741
742 limit_k = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9;
743 limitk_pri = limit_k;
744 }
745 }
746 return mem_hole;
747}
748
Marc Jones8ae8c882007-12-19 01:32:08 +0000749#endif
750
Rudolf Marek97be27e2010-12-13 19:50:25 +0000751#include <cbmem.h>
Myles Watson6c029e62010-09-13 14:50:20 +0000752
Kyösti Mälkki6b5eb1c2012-07-19 19:26:43 +0300753static void setup_uma_memory(void)
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300754{
755#if CONFIG_GFXUMA
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300756 uint32_t topmem = (uint32_t) bsp_topmem();
Timothy Pearson49168802015-03-13 12:48:31 -0500757 uma_memory_size = get_uma_memory_size(topmem);
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300758 uma_memory_base = topmem - uma_memory_size; /* TOP_MEM1 */
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300759 printk(BIOS_INFO, "%s: uma size 0x%08llx, memory start 0x%08llx\n",
760 __func__, uma_memory_size, uma_memory_base);
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300761#endif
762}
763
Myles Watson6507b392010-06-09 22:39:00 +0000764static void amdfam10_domain_set_resources(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000765{
Patrick Georgie1667822012-05-05 15:29:32 +0200766#if CONFIG_PCI_64BIT_PREF_MEM
Timothy Pearsone538dae2015-01-23 20:26:03 -0600767 struct resource *mem1, *mem2;
Myles Watsonc25cc112010-05-21 14:33:48 +0000768 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000769#endif
770 unsigned long mmio_basek;
771 u32 pci_tolm;
772 int i, idx;
Myles Watson894a3472010-06-09 22:41:35 +0000773 struct bus *link;
Stefan Reinauer08670622009-06-30 15:17:49 +0000774#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000775 struct hw_mem_hole_info mem_hole;
776 u32 reset_memhole = 1;
777#endif
778
Patrick Georgie1667822012-05-05 15:29:32 +0200779#if CONFIG_PCI_64BIT_PREF_MEM
Marc Jones8ae8c882007-12-19 01:32:08 +0000780
Myles Watson894a3472010-06-09 22:41:35 +0000781 for(link = dev->link_list; link; link = link->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000782 /* Now reallocate the pci resources memory with the
783 * highest addresses I can manage.
784 */
Myles Watson894a3472010-06-09 22:41:35 +0000785 mem1 = find_resource(dev, 1|(link->link_num<<2));
786 mem2 = find_resource(dev, 2|(link->link_num<<2));
Marc Jones8ae8c882007-12-19 01:32:08 +0000787
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000788 printk(BIOS_DEBUG, "base1: 0x%08Lx limit1: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000789 mem1->base, mem1->limit, mem1->size, mem1->align);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000790 printk(BIOS_DEBUG, "base2: 0x%08Lx limit2: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000791 mem2->base, mem2->limit, mem2->size, mem2->align);
792
793 /* See if both resources have roughly the same limits */
794 if (((mem1->limit <= 0xffffffff) && (mem2->limit <= 0xffffffff)) ||
795 ((mem1->limit > 0xffffffff) && (mem2->limit > 0xffffffff)))
796 {
797 /* If so place the one with the most stringent alignment first
798 */
799 if (mem2->align > mem1->align) {
800 struct resource *tmp;
801 tmp = mem1;
802 mem1 = mem2;
803 mem2 = tmp;
804 }
805 /* Now place the memory as high up as it will go */
806 mem2->base = resource_max(mem2);
807 mem1->limit = mem2->base - 1;
808 mem1->base = resource_max(mem1);
809 }
810 else {
811 /* Place the resources as high up as they will go */
812 mem2->base = resource_max(mem2);
813 mem1->base = resource_max(mem1);
814 }
815
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000816 printk(BIOS_DEBUG, "base1: 0x%08Lx limit1: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000817 mem1->base, mem1->limit, mem1->size, mem1->align);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000818 printk(BIOS_DEBUG, "base2: 0x%08Lx limit2: 0x%08Lx size: 0x%08Lx align: %d\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000819 mem2->base, mem2->limit, mem2->size, mem2->align);
820 }
821
Timothy Pearsone538dae2015-01-23 20:26:03 -0600822 for(res = dev->resource_list; res; res = res->next)
Marc Jones8ae8c882007-12-19 01:32:08 +0000823 {
Myles Watsonc25cc112010-05-21 14:33:48 +0000824 res->flags |= IORESOURCE_ASSIGNED;
Myles Watsonc25cc112010-05-21 14:33:48 +0000825 res->flags |= IORESOURCE_STORED;
826 report_resource_stored(dev, res, "");
Marc Jones8ae8c882007-12-19 01:32:08 +0000827 }
828#endif
829
830 pci_tolm = 0xffffffffUL;
Myles Watson894a3472010-06-09 22:41:35 +0000831 for(link = dev->link_list; link; link = link->next) {
Uwe Hermann4b42a622010-10-11 19:36:13 +0000832 pci_tolm = my_find_pci_tolm(link, pci_tolm);
Marc Jones8ae8c882007-12-19 01:32:08 +0000833 }
834
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000835 // FIXME handle interleaved nodes. If you fix this here, please fix
836 // amdk8, too.
Marc Jones8ae8c882007-12-19 01:32:08 +0000837 mmio_basek = pci_tolm >> 10;
838 /* Round mmio_basek to something the processor can support */
839 mmio_basek &= ~((1 << 6) -1);
840
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000841 // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M
842 // MMIO hole. If you fix this here, please fix amdk8, too.
Myles Watson6507b392010-06-09 22:39:00 +0000843 /* Round the mmio hole to 64M */
Marc Jones8ae8c882007-12-19 01:32:08 +0000844 mmio_basek &= ~((64*1024) - 1);
845
Stefan Reinauer08670622009-06-30 15:17:49 +0000846#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000847/* if the hw mem hole is already set in raminit stage, here we will compare
848 * mmio_basek and hole_basek. if mmio_basek is bigger that hole_basek and will
849 * use hole_basek as mmio_basek and we don't need to reset hole.
850 * otherwise We reset the hole to the mmio_basek
851 */
852
853 mem_hole = get_hw_mem_hole_info();
854
855 // Use hole_basek as mmio_basek, and we don't need to reset hole anymore
856 if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) {
857 mmio_basek = mem_hole.hole_startk;
858 reset_memhole = 0;
859 }
860
Marc Jones8ae8c882007-12-19 01:32:08 +0000861#endif
862
863 idx = 0x10;
864 for(i = 0; i < sysconf.nodes; i++) {
865 struct dram_base_mask_t d;
866 resource_t basek, limitk, sizek; // 4 1T
867 d = get_dram_base_mask(i);
868
869 if(!(d.mask & 1)) continue;
870 basek = ((resource_t)(d.base & 0x1fffff00)) << 9; // could overflow, we may lost 6 bit here
871 limitk = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9 ;
872 sizek = limitk - basek;
873
874 /* see if we need a hole from 0xa0000 to 0xbffff */
875 if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) {
876 ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek);
877 idx += 0x10;
878 basek = (8*64)+(16*16);
879 sizek = limitk - ((8*64)+(16*16));
880
881 }
882
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000883// 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 +0000884
Kyösti Mälkki26c65432014-06-26 05:30:54 +0300885 /* split the region to accommodate pci memory space */
Marc Jones8ae8c882007-12-19 01:32:08 +0000886 if ( (basek < 4*1024*1024 ) && (limitk > mmio_basek) ) {
887 if (basek <= mmio_basek) {
888 unsigned pre_sizek;
889 pre_sizek = mmio_basek - basek;
890 if(pre_sizek>0) {
891 ram_resource(dev, (idx | i), basek, pre_sizek);
892 idx += 0x10;
893 sizek -= pre_sizek;
894 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000895 basek = mmio_basek;
896 }
897 if ((basek + sizek) <= 4*1024*1024) {
898 sizek = 0;
899 }
900 else {
901 basek = 4*1024*1024;
902 sizek -= (4*1024*1024 - mmio_basek);
903 }
904 }
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000905
Marc Jones8ae8c882007-12-19 01:32:08 +0000906 ram_resource(dev, (idx | i), basek, sizek);
907 idx += 0x10;
Myles Watson08e0fb82010-03-22 16:33:25 +0000908 printk(BIOS_DEBUG, "%d: mmio_basek=%08lx, basek=%08llx, limitk=%08llx\n",
Stefan Reinauerb5fb0c52009-04-30 13:58:42 +0000909 i, mmio_basek, basek, limitk);
Marc Jones8ae8c882007-12-19 01:32:08 +0000910 }
911
Patrick Georgie1667822012-05-05 15:29:32 +0200912#if CONFIG_GFXUMA
Kyösti Mälkki63f8c082012-07-10 13:27:26 +0300913 uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10);
Myles Watson6c029e62010-09-13 14:50:20 +0000914#endif
915
Myles Watson894a3472010-06-09 22:41:35 +0000916 for(link = dev->link_list; link; link = link->next) {
917 if (link->children) {
918 assign_resources(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000919 }
920 }
921}
922
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200923static void amdfam10_domain_scan_bus(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000924{
925 u32 reg;
926 int i;
Myles Watson894a3472010-06-09 22:41:35 +0000927 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000928 /* Unmap all of the HT chains */
929 for(reg = 0xe0; reg <= 0xec; reg += 4) {
930 f1_write_config32(reg, 0);
931 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000932
Myles Watson894a3472010-06-09 22:41:35 +0000933 for(link = dev->link_list; link; link = link->next) {
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200934 link->secondary = dev->bus->subordinate;
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200935 pci_scan_bus(link, PCI_DEVFN(CONFIG_CDB, 0), 0xff);
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200936 dev->bus->subordinate = link->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +0000937 }
938
939 /* Tune the hypertransport transaction for best performance.
940 * Including enabling relaxed ordering if it is safe.
941 */
942 get_fx_devs();
Myles Watson6507b392010-06-09 22:39:00 +0000943 for(i = 0; i < fx_devs; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000944 device_t f0_dev;
945 f0_dev = __f0_dev[i];
946 if (f0_dev && f0_dev->enabled) {
947 u32 httc;
948 httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
949 httc &= ~HTTC_RSP_PASS_PW;
Myles Watson894a3472010-06-09 22:41:35 +0000950 if (!dev->link_list->disable_relaxed_ordering) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000951 httc |= HTTC_RSP_PASS_PW;
952 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000953 printk(BIOS_SPEW, "%s passpw: %s\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000954 dev_path(dev),
Myles Watson894a3472010-06-09 22:41:35 +0000955 (!dev->link_list->disable_relaxed_ordering)?
Marc Jones8ae8c882007-12-19 01:32:08 +0000956 "enabled":"disabled");
957 pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
958 }
959 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000960}
961
Timothy Pearson6e523a62015-03-27 22:58:45 -0500962#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
963static int amdfam10_get_smbios_data16(int* count, int handle, unsigned long *current)
964{
965 struct amdmct_memory_info *mem_info;
966 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
967 if (mem_info == NULL)
968 return 0; /* can't find amdmct information in cbmem */
969
970 struct device *dev = get_node_pci(0, 0);
971 struct northbridge_amd_amdfam10_config *config = dev->chip_info;
972
973 int node;
974 int slot;
975
976 struct smbios_type16 *t = (struct smbios_type16 *)*current;
977 int len = sizeof(struct smbios_type16);
978
979 memset(t, 0, sizeof(struct smbios_type16));
980 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
981 t->handle = handle;
982 t->length = len - 2;
983 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
984 t->use = MEMORY_ARRAY_USE_SYSTEM;
985 t->memory_error_correction = MEMORY_ARRAY_ECC_NONE;
986 if ((mem_info->ecc_enabled)
987 && (mem_info->mct_stat.GStatus & (1 << GSB_ECCDIMMs))
988 && !(mem_info->mct_stat.GStatus & (1 << GSB_DramECCDis)))
989 /* Single-bit ECC enabled */
990 t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT;
991 t->maximum_capacity = config->maximum_memory_capacity / 1024; /* Convert to kilobytes */
992 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
993
994 t->number_of_memory_devices = 0;
995 /* Check all nodes for installed DIMMs */
996 for (node = 0; node < MAX_NODES_SUPPORTED; node++)
997 /* Check all slots for installed DIMMs */
998 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++)
999 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot))
1000 /* Found an installed DIMM; increment count */
1001 t->number_of_memory_devices++;
1002
1003 *current += len;
1004 *count += 1;
1005 return len;
1006}
1007
1008static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
1009{
1010 switch (speed) {
1011 case 1:
1012 return 200;
1013 case 2:
1014 return 266;
1015 case 3:
1016 return 333;
1017 case 4:
1018 return 400;
1019 case 5:
1020 return 533;
1021 default:
1022 return 0;
1023 }
1024}
1025
1026static int amdfam10_get_smbios_data17(int* count, int handle, int parent_handle, unsigned long *current)
1027{
1028 struct amdmct_memory_info *mem_info;
1029 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
1030 if (mem_info == NULL)
1031 return 0; /* can't find amdmct information in cbmem */
1032
1033 int single_len;
1034 int len = 0;
1035 int node;
1036 int slot;
1037
1038 /* Check all nodes for installed DIMMs */
1039 for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
1040 /* Get configured RAM bus speed */
1041 uint16_t speed;
1042 speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].Speed);
1043
1044 /* Get maximum RAM bus speed */
1045 uint16_t max_speed;
1046 max_speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].DIMMAutoSpeed);
1047
1048 /* Check all slots for installed DIMMs */
1049 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++) {
1050 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot)) {
1051 /* Found an installed DIMM; populate tables */
1052 struct smbios_type17 *t = (struct smbios_type17 *)*current;
1053 char string_buffer[256];
1054
1055 /* Initialize structure */
1056 memset(t, 0, sizeof(struct smbios_type17));
1057
1058 /* Calculate the total module size in bytes:
1059 * Primary data width * 2^(#rows) * 2^(#cols) * #banks * #ranks
1060 */
1061 uint8_t width, rows, cols, banks, ranks;
1062 width = 8;
1063 rows = mem_info->dct_stat[node].DimmRows[slot];
1064 cols = mem_info->dct_stat[node].DimmCols[slot];
1065 ranks = mem_info->dct_stat[node].DimmRanks[slot];
1066 banks = mem_info->dct_stat[node].DimmBanks[slot];
1067 uint64_t dimm_size_bytes = width * (1ULL << rows) * (1ULL << cols) * banks * ranks;
1068
1069 memset(t, 0, sizeof(struct smbios_type17));
1070 t->type = SMBIOS_MEMORY_DEVICE;
1071 t->handle = handle;
1072 t->phys_memory_array_handle = parent_handle;
1073 t->length = sizeof(struct smbios_type17) - 2;
1074 if (dimm_size_bytes > 0x800000000) {
1075 t->size = 0x7FFF;
1076 t->extended_size = dimm_size_bytes;
1077 }
1078 else {
1079 t->size = dimm_size_bytes / (1024*1024);
1080 t->size &= (~0x8000); /* size specified in megabytes */
1081 }
1082 t->total_width = t->data_width = 64;
1083 if (mem_info->dct_stat[node].DimmECCPresent & (1 << slot))
1084 t->total_width += 8;
1085 t->attributes = 0;
1086 t->attributes |= ranks & 0xf; /* rank number is stored in the lowest 4 bits of the attributes field */
1087 t->form_factor = MEMORY_FORMFACTOR_DIMM;
1088 snprintf(string_buffer, sizeof (string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1);
1089 t->device_locator = smbios_add_string(t->eos, string_buffer);
1090 if (IS_ENABLED(CONFIG_DIMM_DDR2))
1091 t->memory_type = MEMORY_TYPE_DDR2;
1092 else if (IS_ENABLED(CONFIG_DIMM_DDR3))
1093 t->memory_type = MEMORY_TYPE_DDR3;
1094 t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS;
1095 if (mem_info->dct_stat[node].DimmRegistered[slot])
1096 t->type_detail |= MEMORY_TYPE_DETAIL_REGISTERED;
1097 else
1098 t->type_detail |= MEMORY_TYPE_DETAIL_UNBUFFERED;
1099 t->speed = max_speed;
1100 t->clock_speed = speed;
1101 smbios_fill_dimm_manufacturer_from_id(mem_info->dct_stat[node].DimmManufacturerID[slot], t);
1102 t->part_number = smbios_add_string(t->eos, mem_info->dct_stat[node].DimmPartNumber[slot]);
1103 if (mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) {
1104 t->serial_number = smbios_add_string(t->eos, "None");
1105 }
1106 else {
1107 snprintf(string_buffer, sizeof (string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
1108 t->serial_number = smbios_add_string(t->eos, string_buffer);
1109 }
1110 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1111 single_len = t->length + smbios_string_table_len(t->eos);
1112 len += single_len;
1113 *current += single_len;
1114 handle++;
1115 *count += 1;
1116 }
1117 }
1118 }
1119
1120 return len;
1121}
1122
1123static int amdfam10_get_smbios_data(device_t dev, int *handle, unsigned long *current)
1124{
1125 int len;
1126 int count = 0;
1127 len = amdfam10_get_smbios_data16(&count, *handle, current);
1128 len += amdfam10_get_smbios_data17(&count, *handle + 1, *handle, current);
1129 *handle += count;
1130 return len;
1131}
1132#endif
1133
Marc Jones8ae8c882007-12-19 01:32:08 +00001134static struct device_operations pci_domain_ops = {
Myles Watson29cc9ed2009-07-02 18:56:24 +00001135 .read_resources = amdfam10_domain_read_resources,
Myles Watson6507b392010-06-09 22:39:00 +00001136 .set_resources = amdfam10_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +00001137 .enable_resources = NULL,
1138 .init = NULL,
Myles Watson29cc9ed2009-07-02 18:56:24 +00001139 .scan_bus = amdfam10_domain_scan_bus,
Kyösti Mälkki872c9222013-07-03 09:44:28 +03001140 .ops_pci_bus = pci_bus_default_ops,
Timothy Pearson6e523a62015-03-27 22:58:45 -05001141#if CONFIG_GENERATE_SMBIOS_TABLES
1142 .get_smbios_data = amdfam10_get_smbios_data,
1143#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001144};
1145
1146static void sysconf_init(device_t dev) // first node
1147{
1148 sysconf.sblk = (pci_read_config32(dev, 0x64)>>8) & 7; // don't forget sublink1
1149 sysconf.segbit = 0;
1150 sysconf.ht_c_num = 0;
1151
1152 unsigned ht_c_index;
1153
1154 for(ht_c_index=0; ht_c_index<32; ht_c_index++) {
1155 sysconf.ht_c_conf_bus[ht_c_index] = 0;
1156 }
1157
1158 sysconf.nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) + 1;
1159#if CONFIG_MAX_PHYSICAL_CPUS > 8
1160 sysconf.nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
1161#endif
1162
1163 sysconf.enabled_apic_ext_id = 0;
1164 sysconf.lift_bsp_apicid = 0;
1165
1166 /* Find the bootstrap processors apicid */
1167 sysconf.bsp_apicid = lapicid();
1168 sysconf.apicid_offset = sysconf.bsp_apicid;
1169
Patrick Georgie1667822012-05-05 15:29:32 +02001170#if CONFIG_ENABLE_APIC_EXT_ID
Marc Jones8ae8c882007-12-19 01:32:08 +00001171 if (pci_read_config32(dev, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
1172 {
1173 sysconf.enabled_apic_ext_id = 1;
1174 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001175 #if (CONFIG_APIC_ID_OFFSET>0)
Marc Jones8ae8c882007-12-19 01:32:08 +00001176 if(sysconf.enabled_apic_ext_id) {
1177 if(sysconf.bsp_apicid == 0) {
1178 /* bsp apic id is not changed */
Stefan Reinauer08670622009-06-30 15:17:49 +00001179 sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET;
Marc Jones8ae8c882007-12-19 01:32:08 +00001180 } else {
1181 sysconf.lift_bsp_apicid = 1;
1182 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001183 }
1184 #endif
1185#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001186}
1187
Myles Watson894a3472010-06-09 22:41:35 +00001188static void add_more_links(device_t dev, unsigned total_links)
1189{
1190 struct bus *link, *last = NULL;
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001191 int link_num = -1;
Myles Watson894a3472010-06-09 22:41:35 +00001192
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001193 for (link = dev->link_list; link; link = link->next) {
1194 if (link_num < link->link_num)
1195 link_num = link->link_num;
Myles Watson894a3472010-06-09 22:41:35 +00001196 last = link;
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001197 }
Myles Watson894a3472010-06-09 22:41:35 +00001198
1199 if (last) {
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001200 int links = total_links - (link_num + 1);
Myles Watson894a3472010-06-09 22:41:35 +00001201 if (links > 0) {
1202 link = malloc(links*sizeof(*link));
1203 if (!link)
1204 die("Couldn't allocate more links!\n");
1205 memset(link, 0, links*sizeof(*link));
1206 last->next = link;
1207 }
1208 }
1209 else {
Myles Watson894a3472010-06-09 22:41:35 +00001210 link = malloc(total_links*sizeof(*link));
1211 memset(link, 0, total_links*sizeof(*link));
1212 dev->link_list = link;
1213 }
1214
1215 for (link_num = link_num + 1; link_num < total_links; link_num++) {
1216 link->link_num = link_num;
1217 link->dev = dev;
1218 link->next = link + 1;
1219 last = link;
1220 link = link->next;
1221 }
1222 last->next = NULL;
1223}
1224
Kyösti Mälkki580e7222015-03-19 21:04:23 +02001225static void cpu_bus_scan(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +00001226{
1227 struct bus *cpu_bus;
1228 device_t dev_mc;
Myles Watson362db612010-04-08 15:12:18 +00001229#if CONFIG_CBB
Marc Jones8ae8c882007-12-19 01:32:08 +00001230 device_t pci_domain;
Myles Watson362db612010-04-08 15:12:18 +00001231#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001232 int i,j;
1233 int nodes;
1234 unsigned nb_cfg_54;
1235 unsigned siblings;
1236 int cores_found;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +00001237 int disable_siblings;
Marc Jones8ae8c882007-12-19 01:32:08 +00001238 unsigned ApicIdCoreIdSize;
1239
1240 nb_cfg_54 = 0;
1241 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
1242 if(ApicIdCoreIdSize) {
1243 siblings = (1<<ApicIdCoreIdSize)-1;
1244 } else {
1245 siblings = 3; //quad core
1246 }
1247
1248 disable_siblings = !CONFIG_LOGICAL_CPUS;
Patrick Georgie1667822012-05-05 15:29:32 +02001249#if CONFIG_LOGICAL_CPUS
Myles Watson4839e2c2010-04-08 15:06:44 +00001250 get_option(&disable_siblings, "multi_core");
Marc Jones8ae8c882007-12-19 01:32:08 +00001251#endif
1252
Myles Watson6507b392010-06-09 22:39:00 +00001253 // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp???
Marc Jones8ae8c882007-12-19 01:32:08 +00001254 nb_cfg_54 = read_nb_cfg_54();
1255
Stefan Reinauer08670622009-06-30 15:17:49 +00001256#if CONFIG_CBB
1257 dev_mc = dev_find_slot(0, PCI_DEVFN(CONFIG_CDB, 0)); //0x00
Marc Jones8ae8c882007-12-19 01:32:08 +00001258 if(dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001259 printk(BIOS_DEBUG, "%s found", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001260 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001261 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001262 printk(BIOS_DEBUG, "\n%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001263 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001264 printk(BIOS_DEBUG, "%s",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001265
1266 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001267 printk(BIOS_DEBUG, " but it is not under pci_domain directly ");
Marc Jones8ae8c882007-12-19 01:32:08 +00001268 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001269 printk(BIOS_DEBUG, "\n");
Marc Jones8ae8c882007-12-19 01:32:08 +00001270 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001271 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001272 if(!dev_mc) {
1273 dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0));
1274 if (dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001275 printk(BIOS_DEBUG, "%s found\n", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001276 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001277 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Myles Watson894a3472010-06-09 22:41:35 +00001278 if((pci_domain->link_list) && (pci_domain->link_list->children == dev_mc)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001279 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001280 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001281 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001282 while(dev_mc){
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001283 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer2b34db82009-02-28 20:10:20 +00001284 dev_mc->path.pci.devfn -= PCI_DEVFN(0x18,0);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001285 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001286 dev_mc = dev_mc->sibling;
1287 }
1288 }
1289 }
1290 }
1291 }
1292
1293#endif
1294
Stefan Reinauer08670622009-06-30 15:17:49 +00001295 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001296 if (!dev_mc) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001297 printk(BIOS_ERR, "%02x:%02x.0 not found", CONFIG_CBB, CONFIG_CDB);
Marc Jones8ae8c882007-12-19 01:32:08 +00001298 die("");
1299 }
1300
1301 sysconf_init(dev_mc);
1302
1303 nodes = sysconf.nodes;
1304
Stefan Reinauer08670622009-06-30 15:17:49 +00001305#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001306 if(nodes>32) { // need to put node 32 to node 63 to bus 0xfe
Myles Watson894a3472010-06-09 22:41:35 +00001307 if(pci_domain->link_list && !pci_domain->link_list->next) {
1308 struct bus *new_link = new_link(pci_domain);
1309 pci_domain->link_list->next = new_link;
1310 new_link->link_num = 1;
1311 new_link->dev = pci_domain;
1312 new_link->children = 0;
1313 printk(BIOS_DEBUG, "%s links now 2\n", dev_path(pci_domain));
Marc Jones8ae8c882007-12-19 01:32:08 +00001314 }
Myles Watson894a3472010-06-09 22:41:35 +00001315 pci_domain->link_list->next->secondary = CONFIG_CBB - 1;
Marc Jones8ae8c882007-12-19 01:32:08 +00001316 }
1317#endif
1318 /* Find which cpus are present */
Myles Watson894a3472010-06-09 22:41:35 +00001319 cpu_bus = dev->link_list;
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001320
1321 /* Always use the devicetree node with lapic_id 0 for BSP. */
1322 remap_bsp_lapic(cpu_bus);
1323
Marc Jones8ae8c882007-12-19 01:32:08 +00001324 for(i = 0; i < nodes; i++) {
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001325 device_t cdb_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +00001326 unsigned busn, devn;
1327 struct bus *pbus;
1328
Stefan Reinauer08670622009-06-30 15:17:49 +00001329 busn = CONFIG_CBB;
1330 devn = CONFIG_CDB+i;
Marc Jones8ae8c882007-12-19 01:32:08 +00001331 pbus = dev_mc->bus;
Stefan Reinauer08670622009-06-30 15:17:49 +00001332#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001333 if(i>=32) {
1334 busn--;
1335 devn-=32;
Myles Watson894a3472010-06-09 22:41:35 +00001336 pbus = pci_domain->link_list->next);
Marc Jones8ae8c882007-12-19 01:32:08 +00001337 }
1338#endif
1339
1340 /* Find the cpu's pci device */
Myles Watson362db612010-04-08 15:12:18 +00001341 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1342 if (!cdb_dev) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001343 /* If I am probing things in a weird order
1344 * ensure all of the cpu's pci devices are found.
1345 */
Myles Watson362db612010-04-08 15:12:18 +00001346 int fn;
1347 for(fn = 0; fn <= 5; fn++) { //FBDIMM?
1348 cdb_dev = pci_probe_dev(NULL, pbus,
1349 PCI_DEVFN(devn, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +00001350 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001351 }
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001352
1353 /* Ok, We need to set the links for that device.
1354 * otherwise the device under it will not be scanned
1355 */
1356 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1357 if (cdb_dev)
1358 add_more_links(cdb_dev, 4);
1359
1360 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 4));
1361 if (cdb_dev)
1362 add_more_links(cdb_dev, 4);
Marc Jones8ae8c882007-12-19 01:32:08 +00001363
1364 cores_found = 0; // one core
Myles Watson362db612010-04-08 15:12:18 +00001365 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001366 int enable_node = cdb_dev && cdb_dev->enabled;
1367 if (enable_node) {
Myles Watson362db612010-04-08 15:12:18 +00001368 j = pci_read_config32(cdb_dev, 0xe8);
Marc Jones8ae8c882007-12-19 01:32:08 +00001369 cores_found = (j >> 12) & 3; // dev is func 3
Arne Georg Gleditschbc259d02010-03-10 03:43:05 +00001370 if (siblings > 3)
1371 cores_found |= (j >> 13) & 4;
Myles Watson362db612010-04-08 15:12:18 +00001372 printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cdb_dev), cores_found);
Marc Jones8ae8c882007-12-19 01:32:08 +00001373 }
1374
1375 u32 jj;
1376 if(disable_siblings) {
1377 jj = 0;
1378 } else
1379 {
1380 jj = cores_found;
1381 }
1382
1383 for (j = 0; j <=jj; j++ ) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001384 u32 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
Marc Jones8ae8c882007-12-19 01:32:08 +00001385
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001386#if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
1387 if(sysconf.enabled_apic_ext_id) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001388 if (apic_id != 0 || sysconf.lift_bsp_apicid) {
1389 apic_id += sysconf.apicid_offset;
Marc Jones8ae8c882007-12-19 01:32:08 +00001390 }
1391 }
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001392#endif
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001393 device_t cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
1394 if (cpu)
1395 amd_cpu_topology(cpu, i, j);
Marc Jones8ae8c882007-12-19 01:32:08 +00001396 } //j
1397 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001398}
1399
Marc Jones8ae8c882007-12-19 01:32:08 +00001400static void cpu_bus_init(device_t dev)
1401{
Myles Watson894a3472010-06-09 22:41:35 +00001402 initialize_cpus(dev->link_list);
Kerry Shefeed3292011-08-18 18:03:44 +08001403#if CONFIG_AMD_SB_CIMX
1404 sb_After_Pci_Init();
1405 sb_Mid_Post_Init();
1406#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001407}
1408
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001409static void cpu_bus_set_resources(struct device *dev)
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001410{
1411 struct resource *resource = find_resource(dev, 0xc0010058);
1412 if (resource) {
1413 report_resource_stored(dev, resource, " <mmconfig>");
1414 }
1415 pci_dev_set_resources(dev);
1416}
1417
Marc Jones8ae8c882007-12-19 01:32:08 +00001418static struct device_operations cpu_bus_ops = {
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001419 .read_resources = DEVICE_NOOP,
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001420 .set_resources = cpu_bus_set_resources,
Edward O'Callaghan812d2a42014-10-31 08:17:23 +11001421 .enable_resources = DEVICE_NOOP,
Marc Jones8ae8c882007-12-19 01:32:08 +00001422 .init = cpu_bus_init,
1423 .scan_bus = cpu_bus_scan,
1424};
1425
Marc Jones8ae8c882007-12-19 01:32:08 +00001426static void root_complex_enable_dev(struct device *dev)
1427{
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001428 static int done = 0;
1429
1430 /* Do not delay UMA setup, as a device on the PCI bus may evaluate
1431 the global uma_memory variables already in its enable function. */
1432 if (!done) {
1433 setup_bsp_ramtop();
1434 setup_uma_memory();
1435 done = 1;
1436 }
1437
Marc Jones8ae8c882007-12-19 01:32:08 +00001438 /* Set the operations if it is a special bus type */
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001439 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001440 dev->ops = &pci_domain_ops;
1441 }
Stefan Reinauer0aa37c42013-02-12 15:20:54 -08001442 else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001443 dev->ops = &cpu_bus_ops;
1444 }
1445}
1446
1447struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
1448 CHIP_NAME("AMD FAM10 Root Complex")
1449 .enable_dev = root_complex_enable_dev,
1450};