blob: d1803ae667c7bf976107f53f59a5db9e48b7d228 [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.
Marc Jones8ae8c882007-12-19 01:32:08 +000015 */
16
17#include <console/console.h>
18#include <arch/io.h>
19#include <stdint.h>
20#include <device/device.h>
21#include <device/pci.h>
22#include <device/pci_ids.h>
23#include <device/hypertransport.h>
24#include <stdlib.h>
25#include <string.h>
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -080026#include <lib.h>
Timothy Pearson6e523a62015-03-27 22:58:45 -050027#include <smbios.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000028#include <cpu/cpu.h>
29
30#include <cpu/x86/lapic.h>
Kyösti Mälkki231f2612012-07-11 08:02:57 +030031#include <cpu/amd/mtrr.h>
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020032#include <cpu/amd/amdfam10_sysconf.h>
Timothy Pearsonb30d7ed2015-10-16 14:24:06 -050033#include <cpu/amd/family_10h-family_15h/ram_calc.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000034
Patrick Georgie1667822012-05-05 15:29:32 +020035#if CONFIG_LOGICAL_CPUS
Stefan Reinauer9a16e3e2010-03-29 14:45:36 +000036#include <cpu/amd/multicore.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000037#include <pc80/mc146818rtc.h>
38#endif
39
Marc Jones8ae8c882007-12-19 01:32:08 +000040#include "northbridge.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000041#include "amdfam10.h"
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020042#include "ht_config.h"
Timothy Pearson6e523a62015-03-27 22:58:45 -050043#include "chip.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000044
Stefan Reinauer08670622009-06-30 15:17:49 +000045#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +000046#include <cpu/amd/model_10xxx_rev.h>
47#endif
48
Kerry Shefeed3292011-08-18 18:03:44 +080049#if CONFIG_AMD_SB_CIMX
50#include <sb_cimx.h>
51#endif
Marc Jones8ae8c882007-12-19 01:32:08 +000052
Timothy Pearson59d0e042015-09-05 18:40:31 -050053#if IS_ENABLED(CONFIG_DIMM_DDR3)
54#include "../amdmct/mct_ddr3/s3utils.h"
55#endif
56
Marc Jones8ae8c882007-12-19 01:32:08 +000057struct 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
Timothy Pearson730a0432015-10-16 13:51:51 -050080static inline uint8_t is_fam15h(void)
81{
82 uint8_t fam15h = 0;
83 uint32_t family;
84
85 family = cpuid_eax(0x80000001);
86 family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
87
88 if (family >= 0x6f)
89 /* Family 15h or later */
90 fam15h = 1;
91
92 return fam15h;
93}
94
Marc Jones8ae8c882007-12-19 01:32:08 +000095static void get_fx_devs(void)
96{
97 int i;
Marc Jones8ae8c882007-12-19 01:32:08 +000098 for(i = 0; i < FX_DEVS; i++) {
99 __f0_dev[i] = get_node_pci(i, 0);
100 __f1_dev[i] = get_node_pci(i, 1);
101 __f2_dev[i] = get_node_pci(i, 2);
102 __f4_dev[i] = get_node_pci(i, 4);
Myles Watson6507b392010-06-09 22:39:00 +0000103 if (__f0_dev[i] != NULL && __f1_dev[i] != NULL)
104 fx_devs = i+1;
Marc Jones8ae8c882007-12-19 01:32:08 +0000105 }
Myles Watson6507b392010-06-09 22:39:00 +0000106 if (__f1_dev[0] == NULL || __f0_dev[0] == NULL || fx_devs == 0) {
107 die("Cannot find 0:0x18.[0|1]\n");
Marc Jones8ae8c882007-12-19 01:32:08 +0000108 }
109}
110
Myles Watson6507b392010-06-09 22:39:00 +0000111static u32 f1_read_config32(unsigned reg)
Marc Jones8ae8c882007-12-19 01:32:08 +0000112{
Myles Watson6507b392010-06-09 22:39:00 +0000113 if (fx_devs == 0)
114 get_fx_devs();
Marc Jones8ae8c882007-12-19 01:32:08 +0000115 return pci_read_config32(__f1_dev[0], reg);
116}
117
Myles Watson6507b392010-06-09 22:39:00 +0000118static void f1_write_config32(unsigned reg, u32 value)
Marc Jones8ae8c882007-12-19 01:32:08 +0000119{
120 int i;
Myles Watson6507b392010-06-09 22:39:00 +0000121 if (fx_devs == 0)
122 get_fx_devs();
123 for(i = 0; i < fx_devs; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000124 device_t dev;
125 dev = __f1_dev[i];
126 if (dev && dev->enabled) {
127 pci_write_config32(dev, reg, value);
128 }
129 }
130}
131
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200132u32 amdfam10_nodeid(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000133{
134#if NODE_NUMS == 64
135 unsigned busn;
136 busn = dev->bus->secondary;
Stefan Reinauer08670622009-06-30 15:17:49 +0000137 if(busn != CONFIG_CBB) {
138 return (dev->path.pci.devfn >> 3) - CONFIG_CDB + 32;
Marc Jones8ae8c882007-12-19 01:32:08 +0000139 } else {
Stefan Reinauer08670622009-06-30 15:17:49 +0000140 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000141 }
142
143#else
Stefan Reinauer08670622009-06-30 15:17:49 +0000144 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000145#endif
146}
147
Marc Jones8ae8c882007-12-19 01:32:08 +0000148static void set_vga_enable_reg(u32 nodeid, u32 linkn)
149{
150 u32 val;
151
152 val = 1 | (nodeid<<4) | (linkn<<12);
153 /* it will routing (1)mmio 0xa0000:0xbffff (2) io 0x3b0:0x3bb,
154 0x3c0:0x3df */
155 f1_write_config32(0xf4, val);
156
157}
158
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200159typedef enum {
160 HT_ROUTE_CLOSE,
161 HT_ROUTE_SCAN,
162 HT_ROUTE_FINAL,
163} scan_state;
164
165static void ht_route_link(struct bus *link, scan_state mode)
166{
167 struct bus *parent = link->dev->bus;
168 u32 busses;
169
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200170 if (mode == HT_ROUTE_SCAN) {
171 if (parent->subordinate == 0)
172 link->secondary = 0;
173 else
174 link->secondary = parent->subordinate + 1;
175
176 link->subordinate = link->secondary;
177 }
178
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200179 /* Configure the bus numbers for this bridge: the configuration
180 * transactions will not be propagated by the bridge if it is
181 * not correctly configured
182 */
183 busses = pci_read_config32(link->dev, link->cap + 0x14);
184 busses &= 0xff000000;
185 busses |= parent->secondary & 0xff;
186 if (mode == HT_ROUTE_CLOSE) {
187 busses |= 0xfeff << 8;
188 } else if (mode == HT_ROUTE_SCAN) {
189 busses |= ((u32) link->secondary & 0xff) << 8;
190 busses |= 0xfc << 16;
191 } else if (mode == HT_ROUTE_FINAL) {
192 busses |= ((u32) link->secondary & 0xff) << 8;
193 busses |= ((u32) link->subordinate & 0xff) << 16;
194 }
195 pci_write_config32(link->dev, link->cap + 0x14, busses);
196
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200197 if (mode == HT_ROUTE_FINAL) {
198 if (CONFIG_HT_CHAIN_DISTRIBUTE)
199 parent->subordinate = ALIGN_UP(link->subordinate, 8) - 1;
200 else
201 parent->subordinate = link->subordinate;
202 }
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200203}
204
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500205static void amd_g34_fixup(struct bus *link, device_t dev)
206{
207 uint32_t nodeid = amdfam10_nodeid(dev);
208 uint8_t rev_gte_d = 0;
209 uint8_t dual_node = 0;
210 uint32_t f3xe8;
211
212 if (cpuid_eax(0x80000001) >= 0x8)
213 /* Revision D or later */
214 rev_gte_d = 1;
215
Timothy Pearson730a0432015-10-16 13:51:51 -0500216 if (rev_gte_d || is_fam15h()) {
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500217 f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
218
219 /* Check for dual node capability */
220 if (f3xe8 & 0x20000000)
221 dual_node = 1;
222
223 if (dual_node) {
224 /* Each G34 processor contains a defective HT link.
225 * See the BKDG Rev 3.62 section 2.7.1.5 for details.
226 */
227 f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 0xe8);
228 uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 30);
Timothy Pearson730a0432015-10-16 13:51:51 -0500229 uint8_t defective_link_number_1;
230 uint8_t defective_link_number_2;
231 if (is_fam15h()) {
232 defective_link_number_1 = 4; /* Link 0 Sublink 1 */
233 defective_link_number_2 = 7; /* Link 3 Sublink 1 */
234 } else {
235 defective_link_number_1 = 6; /* Link 2 Sublink 1 */
236 defective_link_number_2 = 5; /* Link 1 Sublink 1 */
237 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500238 if (internal_node_number == 0) {
239 /* Node 0 */
240 if (link->link_num == 6) /* Link 2 Sublink 1 */
241 printk(BIOS_DEBUG, "amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT link\n", nodeid, internal_node_number);
242 } else {
243 /* Node 1 */
244 if (link->link_num == 5) /* Link 1 Sublink 1 */
245 printk(BIOS_DEBUG, "amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT link\n", nodeid, internal_node_number);
246 }
247 }
248 }
249}
250
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200251static void amdfam10_scan_chain(struct bus *link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000252{
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200253 unsigned int next_unitid;
Marc Jones8ae8c882007-12-19 01:32:08 +0000254
Marc Jones8ae8c882007-12-19 01:32:08 +0000255 /* See if there is an available configuration space mapping
256 * register in function 1.
257 */
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200258 if (get_ht_c_index(link) >= 4)
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200259 return;
Marc Jones8ae8c882007-12-19 01:32:08 +0000260
261 /* Set up the primary, secondary and subordinate bus numbers.
262 * We have no idea how many busses are behind this bridge yet,
263 * so we set the subordinate bus number to 0xff for the moment.
264 */
Kyösti Mälkkia9f43272015-02-22 09:24:59 +0200265
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200266 ht_route_link(link, HT_ROUTE_SCAN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000267
268 /* set the config map space */
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200269 set_config_map_reg(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000270
271 /* Now we can scan all of the subordinate busses i.e. the
272 * chain on the hypertranport link
273 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000274
Kyösti Mälkkied7bc2c2015-02-22 08:27:13 +0200275 next_unitid = hypertransport_scan_chain(link);
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200276
277 /* Now that nothing is overlapping it is safe to scan the children. */
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200278 pci_scan_bus(link, 0x00, ((next_unitid - 1) << 3) | 7);
Marc Jones8ae8c882007-12-19 01:32:08 +0000279
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200280 ht_route_link(link, HT_ROUTE_FINAL);
281
Marc Jones8ae8c882007-12-19 01:32:08 +0000282 /* We know the number of busses behind this bridge. Set the
283 * subordinate bus number to it's real value
284 */
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200285 if (0) {
286 /* Clear the extend reg. */
287 clear_config_map_reg(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000288 }
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200289
290 set_config_map_reg(link);
291
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200292 store_ht_c_conf_bus(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000293}
294
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200295/* Do sb ht chain at first, in case s2885 put sb chain
296 * (8131/8111) on link2, but put 8151 on link0.
297 */
298static void relocate_sb_ht_chain(void)
299{
300 struct device *dev;
301 struct bus *link, *prev = NULL;
302 u8 sblink;
303
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200304 dev = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
305 sblink = (pci_read_config32(dev, 0x64)>>8) & 7;
306 link = dev->link_list;
307
308 while (link) {
309 if (link->link_num == sblink) {
310 if (!prev)
311 return;
312 prev->next = link->next;
313 link->next = dev->link_list;
314 dev->link_list = link;
315 return;
316 }
317 prev = link;
318 link = link->next;
319 }
320}
321
Kyösti Mälkki0a3d4e42015-02-23 00:34:26 +0200322static void trim_ht_chain(struct device *dev)
323{
324 struct bus *link;
325
326 /* Check for connected link. */
327 for (link = dev->link_list; link; link = link->next) {
328 link->cap = 0x80 + (link->link_num * 0x20);
329 link->ht_link_up = ht_is_non_coherent_link(link);
330 }
331}
332
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200333static void amdfam10_scan_chains(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000334{
Myles Watson894a3472010-06-09 22:41:35 +0000335 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000336
Timothy Pearson730a0432015-10-16 13:51:51 -0500337#if CONFIG_CPU_AMD_SOCKET_G34_NON_AGESA
338 if (is_fam15h()) {
339 uint8_t current_link_number = 0;
340
341 for (link = dev->link_list; link; link = link->next) {
342 /* The following links have changed position in Fam15h G34 processors:
343 * Fam10 Fam15
344 * Node 0
345 * L3 --> L1
346 * L0 --> L3
347 * L1 --> L2
348 * L2 --> L0
349 * Node 1
350 * L0 --> L0
351 * L1 --> L3
352 * L2 --> L1
353 * L3 --> L2
354 */
355 if (link->link_num == 0)
356 link->link_num = 3;
357 else if (link->link_num == 1)
358 link->link_num = 2;
359 else if (link->link_num == 2)
360 link->link_num = 0;
361 else if (link->link_num == 3)
362 link->link_num = 1;
363 else if (link->link_num == 5)
364 link->link_num = 7;
365 else if (link->link_num == 6)
366 link->link_num = 5;
367 else if (link->link_num == 7)
368 link->link_num = 6;
369
370 current_link_number++;
371 if (current_link_number > 3)
372 current_link_number = 0;
373 }
374 }
375#endif
376
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200377 /* Do sb ht chain at first, in case s2885 put sb chain (8131/8111) on link2, but put 8151 on link0 */
Kyösti Mälkki0a3d4e42015-02-23 00:34:26 +0200378 trim_ht_chain(dev);
379
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200380 for (link = dev->link_list; link; link = link->next) {
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500381 if (link->ht_link_up) {
382 if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
383 amd_g34_fixup(link, dev);
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200384 amdfam10_scan_chain(link);
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500385 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000386 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000387}
388
389
Myles Watson6507b392010-06-09 22:39:00 +0000390static int reg_useable(unsigned reg, device_t goal_dev, unsigned goal_nodeid,
391 unsigned goal_link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000392{
393 struct resource *res;
Myles Watson6507b392010-06-09 22:39:00 +0000394 unsigned nodeid, link = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000395 int result;
396 res = 0;
Myles Watson6507b392010-06-09 22:39:00 +0000397 for(nodeid = 0; !res && (nodeid < fx_devs); nodeid++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000398 device_t dev;
399 dev = __f0_dev[nodeid];
Rudolf Marek3a8565a2009-03-26 21:45:26 +0000400 if (!dev)
401 continue;
Marc Jones8ae8c882007-12-19 01:32:08 +0000402 for(link = 0; !res && (link < 8); link++) {
Myles Watson29cc9ed2009-07-02 18:56:24 +0000403 res = probe_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000404 }
405 }
406 result = 2;
407 if (res) {
408 result = 0;
409 if ( (goal_link == (link - 1)) &&
410 (goal_nodeid == (nodeid - 1)) &&
411 (res->flags <= 1)) {
412 result = 1;
413 }
414 }
415 return result;
416}
417
Myles Watson6507b392010-06-09 22:39:00 +0000418static struct resource *amdfam10_find_iopair(device_t dev, unsigned nodeid, unsigned link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000419{
420 struct resource *resource;
421 u32 free_reg, reg;
422 resource = 0;
423 free_reg = 0;
424 for(reg = 0xc0; reg <= 0xd8; reg += 0x8) {
425 int result;
426 result = reg_useable(reg, dev, nodeid, link);
427 if (result == 1) {
428 /* I have been allocated this one */
429 break;
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500430 } else if (result > 1) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000431 /* I have a free register pair */
432 free_reg = reg;
433 }
434 }
435 if (reg > 0xd8) {
436 reg = free_reg; // if no free, the free_reg still be 0
437 }
438
439 //Ext conf space
440 if(!reg) {
441 //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
442 u32 index = get_io_addr_index(nodeid, link);
443 reg = 0x110+ (index<<24) + (4<<20); // index could be 0, 255
444 }
445
Myles Watson29cc9ed2009-07-02 18:56:24 +0000446 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000447
448 return resource;
449}
450
451static struct resource *amdfam10_find_mempair(device_t dev, u32 nodeid, u32 link)
452{
453 struct resource *resource;
454 u32 free_reg, reg;
455 resource = 0;
456 free_reg = 0;
457 for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
458 int result;
459 result = reg_useable(reg, dev, nodeid, link);
460 if (result == 1) {
461 /* I have been allocated this one */
462 break;
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500463 } else if (result > 1) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000464 /* I have a free register pair */
465 free_reg = reg;
466 }
467 }
468 if (reg > 0xb8) {
469 reg = free_reg;
470 }
471
472 //Ext conf space
473 if(!reg) {
474 //because of Extend conf space, we will never run out of reg,
475 // but we need one index to differ them. so same node and
476 // same link can have multi range
477 u32 index = get_mmio_addr_index(nodeid, link);
478 reg = 0x110+ (index<<24) + (6<<20); // index could be 0, 63
479
480 }
Myles Watson29cc9ed2009-07-02 18:56:24 +0000481 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000482 return resource;
483}
484
485
486static void amdfam10_link_read_bases(device_t dev, u32 nodeid, u32 link)
487{
488 struct resource *resource;
489
490 /* Initialize the io space constraints on the current bus */
Myles Watson6507b392010-06-09 22:39:00 +0000491 resource = amdfam10_find_iopair(dev, nodeid, link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000492 if (resource) {
493 u32 align;
Kyösti Mälkki45033592014-12-14 08:35:29 +0200494 align = log2(HT_IO_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000495 resource->base = 0;
496 resource->size = 0;
497 resource->align = align;
498 resource->gran = align;
499 resource->limit = 0xffffUL;
Myles Watson280df102009-07-07 13:26:35 +0000500 resource->flags = IORESOURCE_IO | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000501 }
502
503 /* Initialize the prefetchable memory constraints on the current bus */
504 resource = amdfam10_find_mempair(dev, nodeid, link);
505 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000506 resource->base = 0;
507 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000508 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000509 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000510 resource->limit = 0xffffffffffULL;
Myles Watson6507b392010-06-09 22:39:00 +0000511 resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
512 resource->flags |= IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000513 }
514
515 /* Initialize the memory constraints on the current bus */
516 resource = amdfam10_find_mempair(dev, nodeid, link);
517 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000518 resource->base = 0;
519 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000520 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000521 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000522 resource->limit = 0xffffffffffULL;
Myles Watson280df102009-07-07 13:26:35 +0000523 resource->flags = IORESOURCE_MEM | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000524 }
525}
526
Marc Jones8ae8c882007-12-19 01:32:08 +0000527static void amdfam10_read_resources(device_t dev)
528{
Myles Watson894a3472010-06-09 22:41:35 +0000529 u32 nodeid;
530 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000531 nodeid = amdfam10_nodeid(dev);
Myles Watson894a3472010-06-09 22:41:35 +0000532 for(link = dev->link_list; link; link = link->next) {
533 if (link->children) {
534 amdfam10_link_read_bases(dev, nodeid, link->link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000535 }
536 }
537}
538
Marc Jones8ae8c882007-12-19 01:32:08 +0000539static void amdfam10_set_resource(device_t dev, struct resource *resource,
540 u32 nodeid)
541{
542 resource_t rbase, rend;
Myles Watson894a3472010-06-09 22:41:35 +0000543 unsigned reg, link_num;
Marc Jones8ae8c882007-12-19 01:32:08 +0000544 char buf[50];
545
546 /* Make certain the resource has actually been set */
547 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
548 return;
549 }
550
551 /* If I have already stored this resource don't worry about it */
552 if (resource->flags & IORESOURCE_STORED) {
553 return;
554 }
555
556 /* Only handle PCI memory and IO resources */
557 if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
558 return;
559
560 /* Ensure I am actually looking at a resource of function 1 */
561 if ((resource->index & 0xffff) < 0x1000) {
562 return;
563 }
564 /* Get the base address */
565 rbase = resource->base;
566
567 /* Get the limit (rounded up) */
568 rend = resource_end(resource);
569
570 /* Get the register and link */
571 reg = resource->index & 0xfff; // 4k
Myles Watson894a3472010-06-09 22:41:35 +0000572 link_num = IOINDEX_LINK(resource->index);
Marc Jones8ae8c882007-12-19 01:32:08 +0000573
574 if (resource->flags & IORESOURCE_IO) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000575
Myles Watson894a3472010-06-09 22:41:35 +0000576 set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8);
577 store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 24), rbase>>8, rend>>8);
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500578 } else if (resource->flags & IORESOURCE_MEM) {
Myles Watson894a3472010-06-09 22:41:35 +0000579 set_mmio_addr_reg(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
580 store_conf_mmio_addr(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8);
Marc Jones8ae8c882007-12-19 01:32:08 +0000581 }
582 resource->flags |= IORESOURCE_STORED;
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100583 snprintf(buf, sizeof (buf), " <node %x link %x>",
584 nodeid, link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000585 report_resource_stored(dev, resource, buf);
586}
587
588/**
Marc Jones8ae8c882007-12-19 01:32:08 +0000589 * I tried to reuse the resource allocation code in amdfam10_set_resource()
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000590 * but it is too difficult to deal with the resource allocation magic.
Marc Jones8ae8c882007-12-19 01:32:08 +0000591 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000592
593static void amdfam10_create_vga_resource(device_t dev, unsigned nodeid)
594{
Myles Watson894a3472010-06-09 22:41:35 +0000595 struct bus *link;
Timothy Pearson5cac25e2015-08-14 16:31:14 -0500596 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000597
598 /* find out which link the VGA card is connected,
599 * we only deal with the 'first' vga card */
Myles Watson894a3472010-06-09 22:41:35 +0000600 for (link = dev->link_list; link; link = link->next) {
601 if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Patrick Georgie1667822012-05-05 15:29:32 +0200602#if CONFIG_MULTIPLE_VGA_ADAPTERS
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000603 extern device_t vga_pri; // the primary vga device, defined in device.c
Myles Watson894a3472010-06-09 22:41:35 +0000604 printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d bus range [%d,%d]\n", vga_pri->bus->secondary,
605 link->secondary,link->subordinate);
Marc Jones8ae8c882007-12-19 01:32:08 +0000606 /* We need to make sure the vga_pri is under the link */
Myles Watson894a3472010-06-09 22:41:35 +0000607 if((vga_pri->bus->secondary >= link->secondary ) &&
608 (vga_pri->bus->secondary <= link->subordinate )
Marc Jones8ae8c882007-12-19 01:32:08 +0000609 )
610#endif
611 break;
612 }
613 }
614
615 /* no VGA card installed */
Myles Watson894a3472010-06-09 22:41:35 +0000616 if (link == NULL)
Marc Jones8ae8c882007-12-19 01:32:08 +0000617 return;
618
Myles Watson894a3472010-06-09 22:41:35 +0000619 printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link->link_num);
620 set_vga_enable_reg(nodeid, link->link_num);
Timothy Pearson5cac25e2015-08-14 16:31:14 -0500621
622 /* Redirect VGA memory access to MMIO
623 * This signals the Family 10h resource parser
624 * to add a new MMIO mapping to the Range 11
625 * MMIO control registers (starting at F1x1B8),
626 * and also reserves the resource in the E820 map.
627 */
628 res = new_resource(dev, IOINDEX(0x1000 + 0x1b8, link->link_num));
629 res->base = 0xa0000;
630 res->size = 0x20000;
631 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
632 amdfam10_set_resource(dev, res, nodeid);
Marc Jones8ae8c882007-12-19 01:32:08 +0000633}
634
635static void amdfam10_set_resources(device_t dev)
636{
Myles Watson894a3472010-06-09 22:41:35 +0000637 unsigned nodeid;
638 struct bus *bus;
Myles Watsonc25cc112010-05-21 14:33:48 +0000639 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000640
641 /* Find the nodeid */
642 nodeid = amdfam10_nodeid(dev);
643
644 amdfam10_create_vga_resource(dev, nodeid);
645
646 /* Set each resource we have found */
Myles Watsonc25cc112010-05-21 14:33:48 +0000647 for(res = dev->resource_list; res; res = res->next) {
648 amdfam10_set_resource(dev, res, nodeid);
Marc Jones8ae8c882007-12-19 01:32:08 +0000649 }
650
Myles Watson894a3472010-06-09 22:41:35 +0000651 for(bus = dev->link_list; bus; bus = bus->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000652 if (bus->children) {
653 assign_resources(bus);
654 }
655 }
656}
657
Marc Jones8ae8c882007-12-19 01:32:08 +0000658static void mcf0_control_init(struct device *dev)
659{
660}
661
662static struct device_operations northbridge_operations = {
663 .read_resources = amdfam10_read_resources,
664 .set_resources = amdfam10_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000665 .enable_resources = pci_dev_enable_resources,
Marc Jones8ae8c882007-12-19 01:32:08 +0000666 .init = mcf0_control_init,
667 .scan_bus = amdfam10_scan_chains,
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200668#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
669 .write_acpi_tables = northbridge_write_acpi_tables,
670 .acpi_fill_ssdt_generator = northbridge_acpi_write_vars,
671#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000672 .enable = 0,
673 .ops_pci = 0,
674};
675
676
Stefan Reinauer8e96ba22010-03-16 23:33:29 +0000677static const struct pci_driver mcf0_driver __pci_driver = {
Marc Jones8ae8c882007-12-19 01:32:08 +0000678 .ops = &northbridge_operations,
679 .vendor = PCI_VENDOR_ID_AMD,
680 .device = 0x1200,
681};
682
Timothy Pearson730a0432015-10-16 13:51:51 -0500683
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200684static void amdfam10_nb_init(void *chip_info)
685{
686 relocate_sb_ht_chain();
687}
688
Timothy Pearson730a0432015-10-16 13:51:51 -0500689static const struct pci_driver mcf0_driver_fam15 __pci_driver = {
690 .ops = &northbridge_operations,
691 .vendor = PCI_VENDOR_ID_AMD,
692 .device = 0x1600,
693};
694
695
Marc Jones8ae8c882007-12-19 01:32:08 +0000696struct chip_operations northbridge_amd_amdfam10_ops = {
Timothy Pearson730a0432015-10-16 13:51:51 -0500697 CHIP_NAME("AMD Family 10h/15h Northbridge")
Marc Jones8ae8c882007-12-19 01:32:08 +0000698 .enable_dev = 0,
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200699 .init = amdfam10_nb_init,
Marc Jones8ae8c882007-12-19 01:32:08 +0000700};
701
Myles Watson29cc9ed2009-07-02 18:56:24 +0000702static void amdfam10_domain_read_resources(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000703{
Marc Jones8ae8c882007-12-19 01:32:08 +0000704 unsigned reg;
Marc Jones8ae8c882007-12-19 01:32:08 +0000705
706 /* Find the already assigned resource pairs */
707 get_fx_devs();
708 for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
709 u32 base, limit;
710 base = f1_read_config32(reg);
711 limit = f1_read_config32(reg + 0x04);
712 /* Is this register allocated? */
713 if ((base & 3) != 0) {
Myles Watson362db612010-04-08 15:12:18 +0000714 unsigned nodeid, reg_link;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000715 device_t reg_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +0000716 if(reg<0xc0) { // mmio
717 nodeid = (limit & 0xf) + (base&0x30);
718 } else { // io
719 nodeid = (limit & 0xf) + ((base>>4)&0x30);
720 }
Myles Watson6507b392010-06-09 22:39:00 +0000721 reg_link = (limit >> 4) & 7;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000722 reg_dev = __f0_dev[nodeid];
723 if (reg_dev) {
724 /* Reserve the resource */
Myles Watson6507b392010-06-09 22:39:00 +0000725 struct resource *res;
726 res = new_resource(reg_dev, IOINDEX(0x1000 + reg, reg_link));
727 if (res) {
728 res->flags = 1;
Marc Jones8ae8c882007-12-19 01:32:08 +0000729 }
730 }
731 }
732 }
733 /* FIXME: do we need to check extend conf space?
734 I don't believe that much preset value */
735
Myles Watson280df102009-07-07 13:26:35 +0000736 pci_domain_read_resources(dev);
Marc Jones8ae8c882007-12-19 01:32:08 +0000737
Myles Watson1bc5cca2010-12-07 19:34:01 +0000738#if CONFIG_MMCONF_SUPPORT
739 struct resource *res = new_resource(dev, 0xc0010058);
740 res->base = CONFIG_MMCONF_BASE_ADDRESS;
741 res->size = CONFIG_MMCONF_BUS_NUMBER * 4096*256;
742 res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
743 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
Timothy Pearsona6f669e2015-01-23 20:20:56 -0600744
745 /* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
746 ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
Myles Watson1bc5cca2010-12-07 19:34:01 +0000747#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000748}
749
Uwe Hermann4b42a622010-10-11 19:36:13 +0000750static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
Marc Jones8ae8c882007-12-19 01:32:08 +0000751{
752 struct resource *min;
753 min = 0;
754 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
755 if (min && tolm > min->base) {
756 tolm = min->base;
757 }
758 return tolm;
759}
760
Stefan Reinauer08670622009-06-30 15:17:49 +0000761#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000762
763struct hw_mem_hole_info {
764 unsigned hole_startk;
765 int node_id;
766};
767
768static struct hw_mem_hole_info get_hw_mem_hole_info(void)
769{
770 struct hw_mem_hole_info mem_hole;
771 int i;
772
Stefan Reinauer08670622009-06-30 15:17:49 +0000773 mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
Marc Jones8ae8c882007-12-19 01:32:08 +0000774 mem_hole.node_id = -1;
775
776 for (i = 0; i < sysconf.nodes; i++) {
777 struct dram_base_mask_t d;
778 u32 hole;
779 d = get_dram_base_mask(i);
780 if(!(d.mask & 1)) continue; // no memory on this node
781
782 hole = pci_read_config32(__f1_dev[i], 0xf0);
783 if(hole & 1) { // we find the hole
784 mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
785 mem_hole.node_id = i; // record the node No with hole
786 break; // only one hole
787 }
788 }
789
Kyösti Mälkki2f9b3af2014-06-26 05:30:54 +0300790 /* We need to double check if there is special set on base reg and limit reg
791 * are not continuous instead of hole, it will find out its hole_startk.
792 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000793 if(mem_hole.node_id==-1) {
794 resource_t limitk_pri = 0;
795 for(i=0; i<sysconf.nodes; i++) {
796 struct dram_base_mask_t d;
797 resource_t base_k, limit_k;
798 d = get_dram_base_mask(i);
799 if(!(d.base & 1)) continue;
800
801 base_k = ((resource_t)(d.base & 0x1fffff00)) <<9;
802 if(base_k > 4 *1024 * 1024) break; // don't need to go to check
803 if(limitk_pri != base_k) { // we find the hole
804 mem_hole.hole_startk = (unsigned)limitk_pri; // must beblow 4G
805 mem_hole.node_id = i;
806 break; //only one hole
807 }
808
809 limit_k = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9;
810 limitk_pri = limit_k;
811 }
812 }
813 return mem_hole;
814}
815
Marc Jones8ae8c882007-12-19 01:32:08 +0000816#endif
817
Rudolf Marek97be27e2010-12-13 19:50:25 +0000818#include <cbmem.h>
Myles Watson6c029e62010-09-13 14:50:20 +0000819
Kyösti Mälkki6b5eb1c2012-07-19 19:26:43 +0300820static void setup_uma_memory(void)
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300821{
822#if CONFIG_GFXUMA
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300823 uint32_t topmem = (uint32_t) bsp_topmem();
Timothy Pearson49168802015-03-13 12:48:31 -0500824 uma_memory_size = get_uma_memory_size(topmem);
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300825 uma_memory_base = topmem - uma_memory_size; /* TOP_MEM1 */
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300826 printk(BIOS_INFO, "%s: uma size 0x%08llx, memory start 0x%08llx\n",
827 __func__, uma_memory_size, uma_memory_base);
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300828#endif
829}
830
Myles Watson6507b392010-06-09 22:39:00 +0000831static void amdfam10_domain_set_resources(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000832{
Marc Jones8ae8c882007-12-19 01:32:08 +0000833 unsigned long mmio_basek;
834 u32 pci_tolm;
835 int i, idx;
Myles Watson894a3472010-06-09 22:41:35 +0000836 struct bus *link;
Stefan Reinauer08670622009-06-30 15:17:49 +0000837#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000838 struct hw_mem_hole_info mem_hole;
839 u32 reset_memhole = 1;
840#endif
841
Marc Jones8ae8c882007-12-19 01:32:08 +0000842 pci_tolm = 0xffffffffUL;
Myles Watson894a3472010-06-09 22:41:35 +0000843 for(link = dev->link_list; link; link = link->next) {
Uwe Hermann4b42a622010-10-11 19:36:13 +0000844 pci_tolm = my_find_pci_tolm(link, pci_tolm);
Marc Jones8ae8c882007-12-19 01:32:08 +0000845 }
846
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000847 // FIXME handle interleaved nodes. If you fix this here, please fix
848 // amdk8, too.
Marc Jones8ae8c882007-12-19 01:32:08 +0000849 mmio_basek = pci_tolm >> 10;
850 /* Round mmio_basek to something the processor can support */
851 mmio_basek &= ~((1 << 6) -1);
852
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000853 // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M
854 // MMIO hole. If you fix this here, please fix amdk8, too.
Myles Watson6507b392010-06-09 22:39:00 +0000855 /* Round the mmio hole to 64M */
Marc Jones8ae8c882007-12-19 01:32:08 +0000856 mmio_basek &= ~((64*1024) - 1);
857
Stefan Reinauer08670622009-06-30 15:17:49 +0000858#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000859/* if the hw mem hole is already set in raminit stage, here we will compare
860 * mmio_basek and hole_basek. if mmio_basek is bigger that hole_basek and will
861 * use hole_basek as mmio_basek and we don't need to reset hole.
862 * otherwise We reset the hole to the mmio_basek
863 */
864
865 mem_hole = get_hw_mem_hole_info();
866
867 // Use hole_basek as mmio_basek, and we don't need to reset hole anymore
868 if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) {
869 mmio_basek = mem_hole.hole_startk;
870 reset_memhole = 0;
871 }
872
Marc Jones8ae8c882007-12-19 01:32:08 +0000873#endif
874
875 idx = 0x10;
876 for(i = 0; i < sysconf.nodes; i++) {
877 struct dram_base_mask_t d;
878 resource_t basek, limitk, sizek; // 4 1T
879 d = get_dram_base_mask(i);
880
881 if(!(d.mask & 1)) continue;
882 basek = ((resource_t)(d.base & 0x1fffff00)) << 9; // could overflow, we may lost 6 bit here
883 limitk = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9 ;
884 sizek = limitk - basek;
885
886 /* see if we need a hole from 0xa0000 to 0xbffff */
887 if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) {
888 ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek);
889 idx += 0x10;
890 basek = (8*64)+(16*16);
891 sizek = limitk - ((8*64)+(16*16));
892
893 }
894
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000895// 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 +0000896
Kyösti Mälkki26c65432014-06-26 05:30:54 +0300897 /* split the region to accommodate pci memory space */
Marc Jones8ae8c882007-12-19 01:32:08 +0000898 if ( (basek < 4*1024*1024 ) && (limitk > mmio_basek) ) {
899 if (basek <= mmio_basek) {
900 unsigned pre_sizek;
901 pre_sizek = mmio_basek - basek;
902 if(pre_sizek>0) {
903 ram_resource(dev, (idx | i), basek, pre_sizek);
904 idx += 0x10;
905 sizek -= pre_sizek;
906 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000907 basek = mmio_basek;
908 }
909 if ((basek + sizek) <= 4*1024*1024) {
910 sizek = 0;
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500911 } else {
Marc Jones8ae8c882007-12-19 01:32:08 +0000912 basek = 4*1024*1024;
913 sizek -= (4*1024*1024 - mmio_basek);
914 }
915 }
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000916
Marc Jones8ae8c882007-12-19 01:32:08 +0000917 ram_resource(dev, (idx | i), basek, sizek);
918 idx += 0x10;
Myles Watson08e0fb82010-03-22 16:33:25 +0000919 printk(BIOS_DEBUG, "%d: mmio_basek=%08lx, basek=%08llx, limitk=%08llx\n",
Stefan Reinauerb5fb0c52009-04-30 13:58:42 +0000920 i, mmio_basek, basek, limitk);
Marc Jones8ae8c882007-12-19 01:32:08 +0000921 }
922
Patrick Georgie1667822012-05-05 15:29:32 +0200923#if CONFIG_GFXUMA
Kyösti Mälkki63f8c082012-07-10 13:27:26 +0300924 uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10);
Myles Watson6c029e62010-09-13 14:50:20 +0000925#endif
926
Myles Watson894a3472010-06-09 22:41:35 +0000927 for(link = dev->link_list; link; link = link->next) {
928 if (link->children) {
929 assign_resources(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000930 }
931 }
932}
933
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200934static void amdfam10_domain_scan_bus(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000935{
936 u32 reg;
937 int i;
Myles Watson894a3472010-06-09 22:41:35 +0000938 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000939 /* Unmap all of the HT chains */
940 for(reg = 0xe0; reg <= 0xec; reg += 4) {
941 f1_write_config32(reg, 0);
942 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000943
Myles Watson894a3472010-06-09 22:41:35 +0000944 for(link = dev->link_list; link; link = link->next) {
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200945 link->secondary = dev->bus->subordinate;
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200946 pci_scan_bus(link, PCI_DEVFN(CONFIG_CDB, 0), 0xff);
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200947 dev->bus->subordinate = link->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +0000948 }
949
950 /* Tune the hypertransport transaction for best performance.
951 * Including enabling relaxed ordering if it is safe.
952 */
953 get_fx_devs();
Myles Watson6507b392010-06-09 22:39:00 +0000954 for(i = 0; i < fx_devs; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000955 device_t f0_dev;
956 f0_dev = __f0_dev[i];
957 if (f0_dev && f0_dev->enabled) {
958 u32 httc;
959 httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
960 httc &= ~HTTC_RSP_PASS_PW;
Myles Watson894a3472010-06-09 22:41:35 +0000961 if (!dev->link_list->disable_relaxed_ordering) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000962 httc |= HTTC_RSP_PASS_PW;
963 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000964 printk(BIOS_SPEW, "%s passpw: %s\n",
Marc Jones8ae8c882007-12-19 01:32:08 +0000965 dev_path(dev),
Myles Watson894a3472010-06-09 22:41:35 +0000966 (!dev->link_list->disable_relaxed_ordering)?
Marc Jones8ae8c882007-12-19 01:32:08 +0000967 "enabled":"disabled");
968 pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
969 }
970 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000971}
972
Timothy Pearson6e523a62015-03-27 22:58:45 -0500973#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
974static int amdfam10_get_smbios_data16(int* count, int handle, unsigned long *current)
975{
976 struct amdmct_memory_info *mem_info;
977 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
978 if (mem_info == NULL)
979 return 0; /* can't find amdmct information in cbmem */
980
981 struct device *dev = get_node_pci(0, 0);
982 struct northbridge_amd_amdfam10_config *config = dev->chip_info;
983
984 int node;
985 int slot;
986
987 struct smbios_type16 *t = (struct smbios_type16 *)*current;
988 int len = sizeof(struct smbios_type16);
989
990 memset(t, 0, sizeof(struct smbios_type16));
991 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
992 t->handle = handle;
993 t->length = len - 2;
994 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
995 t->use = MEMORY_ARRAY_USE_SYSTEM;
996 t->memory_error_correction = MEMORY_ARRAY_ECC_NONE;
997 if ((mem_info->ecc_enabled)
998 && (mem_info->mct_stat.GStatus & (1 << GSB_ECCDIMMs))
999 && !(mem_info->mct_stat.GStatus & (1 << GSB_DramECCDis)))
1000 /* Single-bit ECC enabled */
1001 t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT;
1002 t->maximum_capacity = config->maximum_memory_capacity / 1024; /* Convert to kilobytes */
1003 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1004
1005 t->number_of_memory_devices = 0;
1006 /* Check all nodes for installed DIMMs */
1007 for (node = 0; node < MAX_NODES_SUPPORTED; node++)
1008 /* Check all slots for installed DIMMs */
1009 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++)
1010 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot))
1011 /* Found an installed DIMM; increment count */
1012 t->number_of_memory_devices++;
1013
1014 *current += len;
1015 *count += 1;
1016 return len;
1017}
1018
1019static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
1020{
Timothy Pearson730a0432015-10-16 13:51:51 -05001021 if (is_fam15h()) {
1022 if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
1023 switch (speed) {
1024 case 0x4:
1025 return 333;
1026 case 0x6:
1027 return 400;
1028 case 0xa:
1029 return 533;
1030 case 0xe:
1031 return 667;
1032 case 0x12:
1033 return 800;
1034 case 0x16:
1035 return 933;
1036 default:
1037 return 0;
1038 }
1039 } else {
1040 return 0;
Timothy Pearson160ad6a2015-10-30 18:53:48 -05001041 }
1042 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001043 if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
1044 switch (speed) {
1045 case 1:
1046 return 200;
1047 case 2:
1048 return 266;
1049 case 3:
1050 return 333;
1051 case 4:
1052 return 400;
1053 case 5:
1054 return 533;
1055 default:
1056 return 0;
1057 }
1058 } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
1059 switch (speed) {
1060 case 3:
1061 return 333;
1062 case 4:
1063 return 400;
1064 case 5:
1065 return 533;
1066 case 6:
1067 return 667;
1068 case 7:
1069 return 800;
1070 default:
1071 return 0;
1072 }
1073 } else {
1074 return 0;
1075 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001076 }
1077}
1078
1079static int amdfam10_get_smbios_data17(int* count, int handle, int parent_handle, unsigned long *current)
1080{
1081 struct amdmct_memory_info *mem_info;
1082 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
1083 if (mem_info == NULL)
1084 return 0; /* can't find amdmct information in cbmem */
1085
1086 int single_len;
1087 int len = 0;
1088 int node;
1089 int slot;
1090
1091 /* Check all nodes for installed DIMMs */
1092 for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
1093 /* Get configured RAM bus speed */
1094 uint16_t speed;
1095 speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].Speed);
1096
1097 /* Get maximum RAM bus speed */
1098 uint16_t max_speed;
1099 max_speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].DIMMAutoSpeed);
1100
1101 /* Check all slots for installed DIMMs */
1102 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++) {
1103 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot)) {
1104 /* Found an installed DIMM; populate tables */
1105 struct smbios_type17 *t = (struct smbios_type17 *)*current;
1106 char string_buffer[256];
1107
1108 /* Initialize structure */
1109 memset(t, 0, sizeof(struct smbios_type17));
1110
1111 /* Calculate the total module size in bytes:
1112 * Primary data width * 2^(#rows) * 2^(#cols) * #banks * #ranks
1113 */
1114 uint8_t width, rows, cols, banks, ranks;
1115 width = 8;
1116 rows = mem_info->dct_stat[node].DimmRows[slot];
1117 cols = mem_info->dct_stat[node].DimmCols[slot];
1118 ranks = mem_info->dct_stat[node].DimmRanks[slot];
1119 banks = mem_info->dct_stat[node].DimmBanks[slot];
1120 uint64_t dimm_size_bytes = width * (1ULL << rows) * (1ULL << cols) * banks * ranks;
1121
1122 memset(t, 0, sizeof(struct smbios_type17));
1123 t->type = SMBIOS_MEMORY_DEVICE;
1124 t->handle = handle;
1125 t->phys_memory_array_handle = parent_handle;
1126 t->length = sizeof(struct smbios_type17) - 2;
1127 if (dimm_size_bytes > 0x800000000) {
1128 t->size = 0x7FFF;
1129 t->extended_size = dimm_size_bytes;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001130 } else {
Timothy Pearson6e523a62015-03-27 22:58:45 -05001131 t->size = dimm_size_bytes / (1024*1024);
1132 t->size &= (~0x8000); /* size specified in megabytes */
1133 }
1134 t->total_width = t->data_width = 64;
1135 if (mem_info->dct_stat[node].DimmECCPresent & (1 << slot))
1136 t->total_width += 8;
1137 t->attributes = 0;
1138 t->attributes |= ranks & 0xf; /* rank number is stored in the lowest 4 bits of the attributes field */
1139 t->form_factor = MEMORY_FORMFACTOR_DIMM;
1140 snprintf(string_buffer, sizeof (string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1);
1141 t->device_locator = smbios_add_string(t->eos, string_buffer);
1142 if (IS_ENABLED(CONFIG_DIMM_DDR2))
1143 t->memory_type = MEMORY_TYPE_DDR2;
1144 else if (IS_ENABLED(CONFIG_DIMM_DDR3))
1145 t->memory_type = MEMORY_TYPE_DDR3;
1146 t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS;
1147 if (mem_info->dct_stat[node].DimmRegistered[slot])
1148 t->type_detail |= MEMORY_TYPE_DETAIL_REGISTERED;
1149 else
1150 t->type_detail |= MEMORY_TYPE_DETAIL_UNBUFFERED;
1151 t->speed = max_speed;
1152 t->clock_speed = speed;
1153 smbios_fill_dimm_manufacturer_from_id(mem_info->dct_stat[node].DimmManufacturerID[slot], t);
1154 t->part_number = smbios_add_string(t->eos, mem_info->dct_stat[node].DimmPartNumber[slot]);
1155 if (mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) {
1156 t->serial_number = smbios_add_string(t->eos, "None");
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001157 } else {
Timothy Pearson6e523a62015-03-27 22:58:45 -05001158 snprintf(string_buffer, sizeof (string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
1159 t->serial_number = smbios_add_string(t->eos, string_buffer);
1160 }
Timothy Pearson2a839352015-09-05 18:56:05 -05001161 if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
1162 /* JEDEC specifies 1.8V only, so assume that the memory is configured for 1.8V */
1163 t->minimum_voltage = 1800;
1164 t->maximum_voltage = 1800;
1165 t->configured_voltage = 1800;
1166 } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
1167#if IS_ENABLED(CONFIG_DIMM_DDR3)
1168 /* Find the maximum and minimum supported voltages */
1169 uint8_t supported_voltages = mem_info->dct_stat[node].DimmSupportedVoltages[slot];
Timothy Pearson730a0432015-10-16 13:51:51 -05001170 uint8_t configured_voltage = mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
1171
Timothy Pearson2a839352015-09-05 18:56:05 -05001172 if (supported_voltages & 0x8)
1173 t->minimum_voltage = 1150;
1174 else if (supported_voltages & 0x4)
1175 t->minimum_voltage = 1250;
1176 else if (supported_voltages & 0x2)
1177 t->minimum_voltage = 1350;
1178 else if (supported_voltages & 0x1)
1179 t->minimum_voltage = 1500;
1180
1181 if (supported_voltages & 0x1)
1182 t->maximum_voltage = 1500;
1183 else if (supported_voltages & 0x2)
1184 t->maximum_voltage = 1350;
1185 else if (supported_voltages & 0x4)
1186 t->maximum_voltage = 1250;
1187 else if (supported_voltages & 0x8)
1188 t->maximum_voltage = 1150;
1189
Timothy Pearson730a0432015-10-16 13:51:51 -05001190 if (configured_voltage & 0x8)
1191 t->configured_voltage = 1150;
1192 else if (configured_voltage & 0x4)
1193 t->configured_voltage = 1250;
1194 else if (configured_voltage & 0x2)
1195 t->configured_voltage = 1350;
1196 else if (configured_voltage & 0x1)
1197 t->configured_voltage = 1500;
Timothy Pearson2a839352015-09-05 18:56:05 -05001198#endif
1199 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001200 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1201 single_len = t->length + smbios_string_table_len(t->eos);
1202 len += single_len;
1203 *current += single_len;
1204 handle++;
1205 *count += 1;
1206 }
1207 }
1208 }
1209
1210 return len;
1211}
1212
1213static int amdfam10_get_smbios_data(device_t dev, int *handle, unsigned long *current)
1214{
1215 int len;
1216 int count = 0;
1217 len = amdfam10_get_smbios_data16(&count, *handle, current);
1218 len += amdfam10_get_smbios_data17(&count, *handle + 1, *handle, current);
1219 *handle += count;
1220 return len;
1221}
1222#endif
1223
Marc Jones8ae8c882007-12-19 01:32:08 +00001224static struct device_operations pci_domain_ops = {
Myles Watson29cc9ed2009-07-02 18:56:24 +00001225 .read_resources = amdfam10_domain_read_resources,
Myles Watson6507b392010-06-09 22:39:00 +00001226 .set_resources = amdfam10_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +00001227 .enable_resources = NULL,
1228 .init = NULL,
Myles Watson29cc9ed2009-07-02 18:56:24 +00001229 .scan_bus = amdfam10_domain_scan_bus,
Kyösti Mälkki872c9222013-07-03 09:44:28 +03001230 .ops_pci_bus = pci_bus_default_ops,
Timothy Pearson6e523a62015-03-27 22:58:45 -05001231#if CONFIG_GENERATE_SMBIOS_TABLES
1232 .get_smbios_data = amdfam10_get_smbios_data,
1233#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001234};
1235
1236static void sysconf_init(device_t dev) // first node
1237{
1238 sysconf.sblk = (pci_read_config32(dev, 0x64)>>8) & 7; // don't forget sublink1
1239 sysconf.segbit = 0;
1240 sysconf.ht_c_num = 0;
1241
1242 unsigned ht_c_index;
1243
1244 for(ht_c_index=0; ht_c_index<32; ht_c_index++) {
1245 sysconf.ht_c_conf_bus[ht_c_index] = 0;
1246 }
1247
1248 sysconf.nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) + 1;
1249#if CONFIG_MAX_PHYSICAL_CPUS > 8
1250 sysconf.nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
1251#endif
1252
1253 sysconf.enabled_apic_ext_id = 0;
1254 sysconf.lift_bsp_apicid = 0;
1255
1256 /* Find the bootstrap processors apicid */
1257 sysconf.bsp_apicid = lapicid();
1258 sysconf.apicid_offset = sysconf.bsp_apicid;
1259
Patrick Georgie1667822012-05-05 15:29:32 +02001260#if CONFIG_ENABLE_APIC_EXT_ID
Marc Jones8ae8c882007-12-19 01:32:08 +00001261 if (pci_read_config32(dev, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
1262 {
1263 sysconf.enabled_apic_ext_id = 1;
1264 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001265 #if (CONFIG_APIC_ID_OFFSET>0)
Marc Jones8ae8c882007-12-19 01:32:08 +00001266 if(sysconf.enabled_apic_ext_id) {
1267 if(sysconf.bsp_apicid == 0) {
1268 /* bsp apic id is not changed */
Stefan Reinauer08670622009-06-30 15:17:49 +00001269 sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET;
Marc Jones8ae8c882007-12-19 01:32:08 +00001270 } else {
1271 sysconf.lift_bsp_apicid = 1;
1272 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001273 }
1274 #endif
1275#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001276}
1277
Myles Watson894a3472010-06-09 22:41:35 +00001278static void add_more_links(device_t dev, unsigned total_links)
1279{
1280 struct bus *link, *last = NULL;
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001281 int link_num = -1;
Myles Watson894a3472010-06-09 22:41:35 +00001282
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001283 for (link = dev->link_list; link; link = link->next) {
1284 if (link_num < link->link_num)
1285 link_num = link->link_num;
Myles Watson894a3472010-06-09 22:41:35 +00001286 last = link;
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001287 }
Myles Watson894a3472010-06-09 22:41:35 +00001288
1289 if (last) {
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001290 int links = total_links - (link_num + 1);
Myles Watson894a3472010-06-09 22:41:35 +00001291 if (links > 0) {
1292 link = malloc(links*sizeof(*link));
1293 if (!link)
1294 die("Couldn't allocate more links!\n");
1295 memset(link, 0, links*sizeof(*link));
1296 last->next = link;
1297 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001298 } else {
Myles Watson894a3472010-06-09 22:41:35 +00001299 link = malloc(total_links*sizeof(*link));
1300 memset(link, 0, total_links*sizeof(*link));
1301 dev->link_list = link;
1302 }
1303
1304 for (link_num = link_num + 1; link_num < total_links; link_num++) {
1305 link->link_num = link_num;
1306 link->dev = dev;
1307 link->next = link + 1;
1308 last = link;
1309 link = link->next;
1310 }
1311 last->next = NULL;
1312}
1313
Stefan Reinauer4d6db952015-06-13 11:01:54 +02001314static void remap_bsp_lapic(struct bus *cpu_bus)
1315{
1316 struct device_path cpu_path;
1317 device_t cpu;
1318 u32 bsp_lapic_id = lapicid();
1319
1320 if (bsp_lapic_id) {
1321 cpu_path.type = DEVICE_PATH_APIC;
1322 cpu_path.apic.apic_id = 0;
1323 cpu = find_dev_path(cpu_bus, &cpu_path);
1324 if (cpu)
1325 cpu->path.apic.apic_id = bsp_lapic_id;
1326 }
1327}
1328
Kyösti Mälkki580e7222015-03-19 21:04:23 +02001329static void cpu_bus_scan(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +00001330{
1331 struct bus *cpu_bus;
1332 device_t dev_mc;
Myles Watson362db612010-04-08 15:12:18 +00001333#if CONFIG_CBB
Marc Jones8ae8c882007-12-19 01:32:08 +00001334 device_t pci_domain;
Myles Watson362db612010-04-08 15:12:18 +00001335#endif
Timothy Pearson730a0432015-10-16 13:51:51 -05001336 int nvram = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +00001337 int i,j;
1338 int nodes;
1339 unsigned nb_cfg_54;
1340 unsigned siblings;
1341 int cores_found;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +00001342 int disable_siblings;
Timothy Pearson730a0432015-10-16 13:51:51 -05001343 uint8_t disable_cu_siblings = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +00001344 unsigned ApicIdCoreIdSize;
1345
1346 nb_cfg_54 = 0;
1347 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
1348 if(ApicIdCoreIdSize) {
1349 siblings = (1<<ApicIdCoreIdSize)-1;
1350 } else {
1351 siblings = 3; //quad core
1352 }
1353
1354 disable_siblings = !CONFIG_LOGICAL_CPUS;
Patrick Georgie1667822012-05-05 15:29:32 +02001355#if CONFIG_LOGICAL_CPUS
Myles Watson4839e2c2010-04-08 15:06:44 +00001356 get_option(&disable_siblings, "multi_core");
Marc Jones8ae8c882007-12-19 01:32:08 +00001357#endif
1358
Myles Watson6507b392010-06-09 22:39:00 +00001359 // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp???
Marc Jones8ae8c882007-12-19 01:32:08 +00001360 nb_cfg_54 = read_nb_cfg_54();
1361
Stefan Reinauer08670622009-06-30 15:17:49 +00001362#if CONFIG_CBB
1363 dev_mc = dev_find_slot(0, PCI_DEVFN(CONFIG_CDB, 0)); //0x00
Marc Jones8ae8c882007-12-19 01:32:08 +00001364 if(dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001365 printk(BIOS_DEBUG, "%s found", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001366 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001367 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001368 printk(BIOS_DEBUG, "\n%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001369 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001370 printk(BIOS_DEBUG, "%s",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001371
1372 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001373 printk(BIOS_DEBUG, " but it is not under pci_domain directly ");
Marc Jones8ae8c882007-12-19 01:32:08 +00001374 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001375 printk(BIOS_DEBUG, "\n");
Marc Jones8ae8c882007-12-19 01:32:08 +00001376 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001377 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001378 if(!dev_mc) {
1379 dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0));
1380 if (dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001381 printk(BIOS_DEBUG, "%s found\n", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001382 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001383 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Myles Watson894a3472010-06-09 22:41:35 +00001384 if((pci_domain->link_list) && (pci_domain->link_list->children == dev_mc)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001385 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001386 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001387 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001388 while(dev_mc){
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001389 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer2b34db82009-02-28 20:10:20 +00001390 dev_mc->path.pci.devfn -= PCI_DEVFN(0x18,0);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001391 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001392 dev_mc = dev_mc->sibling;
1393 }
1394 }
1395 }
1396 }
1397 }
1398
1399#endif
1400
Stefan Reinauer08670622009-06-30 15:17:49 +00001401 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001402 if (!dev_mc) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001403 printk(BIOS_ERR, "%02x:%02x.0 not found", CONFIG_CBB, CONFIG_CDB);
Marc Jones8ae8c882007-12-19 01:32:08 +00001404 die("");
1405 }
1406
1407 sysconf_init(dev_mc);
1408
1409 nodes = sysconf.nodes;
1410
Stefan Reinauer08670622009-06-30 15:17:49 +00001411#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001412 if(nodes>32) { // need to put node 32 to node 63 to bus 0xfe
Myles Watson894a3472010-06-09 22:41:35 +00001413 if(pci_domain->link_list && !pci_domain->link_list->next) {
1414 struct bus *new_link = new_link(pci_domain);
1415 pci_domain->link_list->next = new_link;
1416 new_link->link_num = 1;
1417 new_link->dev = pci_domain;
1418 new_link->children = 0;
1419 printk(BIOS_DEBUG, "%s links now 2\n", dev_path(pci_domain));
Marc Jones8ae8c882007-12-19 01:32:08 +00001420 }
Myles Watson894a3472010-06-09 22:41:35 +00001421 pci_domain->link_list->next->secondary = CONFIG_CBB - 1;
Marc Jones8ae8c882007-12-19 01:32:08 +00001422 }
1423#endif
1424 /* Find which cpus are present */
Myles Watson894a3472010-06-09 22:41:35 +00001425 cpu_bus = dev->link_list;
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001426
1427 /* Always use the devicetree node with lapic_id 0 for BSP. */
1428 remap_bsp_lapic(cpu_bus);
1429
Timothy Pearson730a0432015-10-16 13:51:51 -05001430 if (get_option(&nvram, "compute_unit_siblings") == CB_SUCCESS)
1431 disable_cu_siblings = !!nvram;
1432
1433 if (disable_cu_siblings)
1434 printk(BIOS_DEBUG, "Disabling siblings on each compute unit as requested\n");
1435
Marc Jones8ae8c882007-12-19 01:32:08 +00001436 for(i = 0; i < nodes; i++) {
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001437 device_t cdb_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +00001438 unsigned busn, devn;
1439 struct bus *pbus;
1440
Timothy Pearson730a0432015-10-16 13:51:51 -05001441 uint8_t fam15h = 0;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001442 uint8_t rev_gte_d = 0;
1443 uint8_t dual_node = 0;
1444 uint32_t f3xe8;
Timothy Pearson730a0432015-10-16 13:51:51 -05001445 uint32_t family;
1446 uint32_t model;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001447
Stefan Reinauer08670622009-06-30 15:17:49 +00001448 busn = CONFIG_CBB;
1449 devn = CONFIG_CDB+i;
Marc Jones8ae8c882007-12-19 01:32:08 +00001450 pbus = dev_mc->bus;
Stefan Reinauer08670622009-06-30 15:17:49 +00001451#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001452 if(i>=32) {
1453 busn--;
1454 devn-=32;
Myles Watson894a3472010-06-09 22:41:35 +00001455 pbus = pci_domain->link_list->next);
Marc Jones8ae8c882007-12-19 01:32:08 +00001456 }
1457#endif
1458
1459 /* Find the cpu's pci device */
Myles Watson362db612010-04-08 15:12:18 +00001460 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1461 if (!cdb_dev) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001462 /* If I am probing things in a weird order
1463 * ensure all of the cpu's pci devices are found.
1464 */
Myles Watson362db612010-04-08 15:12:18 +00001465 int fn;
1466 for(fn = 0; fn <= 5; fn++) { //FBDIMM?
1467 cdb_dev = pci_probe_dev(NULL, pbus,
1468 PCI_DEVFN(devn, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +00001469 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001470 }
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001471
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001472
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001473 /* Ok, We need to set the links for that device.
1474 * otherwise the device under it will not be scanned
1475 */
1476 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1477 if (cdb_dev)
1478 add_more_links(cdb_dev, 4);
1479
1480 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 4));
1481 if (cdb_dev)
1482 add_more_links(cdb_dev, 4);
Marc Jones8ae8c882007-12-19 01:32:08 +00001483
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001484 f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
1485
Timothy Pearson730a0432015-10-16 13:51:51 -05001486 family = model = cpuid_eax(0x80000001);
1487 model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
1488
1489 if (is_fam15h()) {
1490 /* Family 15h or later */
1491 fam15h = 1;
1492 nb_cfg_54 = 1;
1493 }
1494
1495 if ((model >= 0x8) || fam15h)
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001496 /* Revision D or later */
1497 rev_gte_d = 1;
1498
1499 if (rev_gte_d)
1500 /* Check for dual node capability */
1501 if (f3xe8 & 0x20000000)
1502 dual_node = 1;
1503
Marc Jones8ae8c882007-12-19 01:32:08 +00001504 cores_found = 0; // one core
Timothy Pearson730a0432015-10-16 13:51:51 -05001505 if (fam15h)
1506 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 5));
1507 else
1508 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001509 int enable_node = cdb_dev && cdb_dev->enabled;
1510 if (enable_node) {
Timothy Pearson730a0432015-10-16 13:51:51 -05001511 if (fam15h) {
1512 cores_found = pci_read_config32(cdb_dev, 0x84) & 0xff;
1513 } else {
1514 j = pci_read_config32(cdb_dev, 0xe8);
1515 cores_found = (j >> 12) & 3; // dev is func 3
1516 if (siblings > 3)
1517 cores_found |= (j >> 13) & 4;
1518 }
Myles Watson362db612010-04-08 15:12:18 +00001519 printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cdb_dev), cores_found);
Marc Jones8ae8c882007-12-19 01:32:08 +00001520 }
1521
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001522 if (siblings > cores_found)
1523 siblings = cores_found;
1524
Marc Jones8ae8c882007-12-19 01:32:08 +00001525 u32 jj;
1526 if(disable_siblings) {
1527 jj = 0;
1528 } else
1529 {
1530 jj = cores_found;
1531 }
1532
1533 for (j = 0; j <=jj; j++ ) {
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001534 u32 apic_id;
1535
1536 if (dual_node) {
1537 apic_id = 0;
Timothy Pearson730a0432015-10-16 13:51:51 -05001538 if (fam15h) {
1539 apic_id |= ((i >> 1) & 0x3) << 5; /* Node ID */
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001540 apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
1541 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001542 if (nb_cfg_54) {
1543 apic_id |= ((i >> 1) & 0x3) << 4; /* Node ID */
1544 apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
1545 } else {
1546 apic_id |= i & 0x3; /* Node ID */
1547 apic_id |= (((i & 0x1) * (siblings + 1)) + j) << 4; /* Core ID */
1548 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001549 }
1550 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001551 if (fam15h) {
1552 apic_id = (i * (siblings + 1)) + j;
1553 } else {
1554 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
1555 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001556 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001557
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001558#if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
1559 if(sysconf.enabled_apic_ext_id) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001560 if (apic_id != 0 || sysconf.lift_bsp_apicid) {
1561 apic_id += sysconf.apicid_offset;
Marc Jones8ae8c882007-12-19 01:32:08 +00001562 }
1563 }
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001564#endif
Timothy Pearson730a0432015-10-16 13:51:51 -05001565 if (disable_cu_siblings && (j & 0x1))
1566 continue;
1567
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001568 device_t cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
1569 if (cpu)
1570 amd_cpu_topology(cpu, i, j);
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001571 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001572 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001573}
1574
Marc Jones8ae8c882007-12-19 01:32:08 +00001575static void cpu_bus_init(device_t dev)
1576{
Myles Watson894a3472010-06-09 22:41:35 +00001577 initialize_cpus(dev->link_list);
Kerry Shefeed3292011-08-18 18:03:44 +08001578#if CONFIG_AMD_SB_CIMX
1579 sb_After_Pci_Init();
1580 sb_Mid_Post_Init();
1581#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001582}
1583
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001584static void cpu_bus_set_resources(struct device *dev)
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001585{
1586 struct resource *resource = find_resource(dev, 0xc0010058);
1587 if (resource) {
1588 report_resource_stored(dev, resource, " <mmconfig>");
1589 }
1590 pci_dev_set_resources(dev);
1591}
1592
Marc Jones8ae8c882007-12-19 01:32:08 +00001593static struct device_operations cpu_bus_ops = {
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001594 .read_resources = DEVICE_NOOP,
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001595 .set_resources = cpu_bus_set_resources,
Edward O'Callaghan812d2a42014-10-31 08:17:23 +11001596 .enable_resources = DEVICE_NOOP,
Marc Jones8ae8c882007-12-19 01:32:08 +00001597 .init = cpu_bus_init,
1598 .scan_bus = cpu_bus_scan,
1599};
1600
Marc Jones8ae8c882007-12-19 01:32:08 +00001601static void root_complex_enable_dev(struct device *dev)
1602{
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001603 static int done = 0;
1604
1605 /* Do not delay UMA setup, as a device on the PCI bus may evaluate
1606 the global uma_memory variables already in its enable function. */
1607 if (!done) {
Timothy Pearson59d0e042015-09-05 18:40:31 -05001608#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && IS_ENABLED(CONFIG_DIMM_DDR3)
1609 save_mct_information_to_nvram();
1610#endif
1611
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001612 setup_bsp_ramtop();
1613 setup_uma_memory();
1614 done = 1;
1615 }
1616
Marc Jones8ae8c882007-12-19 01:32:08 +00001617 /* Set the operations if it is a special bus type */
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001618 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001619 dev->ops = &pci_domain_ops;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001620 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001621 dev->ops = &cpu_bus_ops;
1622 }
1623}
1624
1625struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
Timothy Pearson730a0432015-10-16 13:51:51 -05001626 CHIP_NAME("AMD Family 10h/15h Root Complex")
Marc Jones8ae8c882007-12-19 01:32:08 +00001627 .enable_dev = root_complex_enable_dev,
1628};