blob: 563f21b1079030b790db13b0a56515239ef026e0 [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>
Timothy Pearson0f1553b2015-08-02 21:06:39 -050029#include <delay.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000030
31#include <cpu/x86/lapic.h>
Timothy Pearson0f1553b2015-08-02 21:06:39 -050032#include <cpu/x86/cache.h>
Kyösti Mälkki231f2612012-07-11 08:02:57 +030033#include <cpu/amd/mtrr.h>
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020034#include <cpu/amd/amdfam10_sysconf.h>
Stefan Reinauer991f1842015-11-22 23:40:29 +010035#include <cpu/amd/msr.h>
Timothy Pearsonb30d7ed2015-10-16 14:24:06 -050036#include <cpu/amd/family_10h-family_15h/ram_calc.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000037
Patrick Georgie1667822012-05-05 15:29:32 +020038#if CONFIG_LOGICAL_CPUS
Stefan Reinauer9a16e3e2010-03-29 14:45:36 +000039#include <cpu/amd/multicore.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000040#include <pc80/mc146818rtc.h>
41#endif
42
Marc Jones8ae8c882007-12-19 01:32:08 +000043#include "northbridge.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000044#include "amdfam10.h"
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020045#include "ht_config.h"
Timothy Pearson6e523a62015-03-27 22:58:45 -050046#include "chip.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000047
Stefan Reinauer08670622009-06-30 15:17:49 +000048#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +000049#include <cpu/amd/model_10xxx_rev.h>
50#endif
51
Kerry Shefeed3292011-08-18 18:03:44 +080052#if CONFIG_AMD_SB_CIMX
53#include <sb_cimx.h>
54#endif
Marc Jones8ae8c882007-12-19 01:32:08 +000055
Timothy Pearson59d0e042015-09-05 18:40:31 -050056#if IS_ENABLED(CONFIG_DIMM_DDR3)
57#include "../amdmct/mct_ddr3/s3utils.h"
58#endif
59
Marc Jones8ae8c882007-12-19 01:32:08 +000060struct amdfam10_sysconf_t sysconf;
61
62#define FX_DEVS NODE_NUMS
63static device_t __f0_dev[FX_DEVS];
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020064device_t __f1_dev[FX_DEVS];
Marc Jones8ae8c882007-12-19 01:32:08 +000065static device_t __f2_dev[FX_DEVS];
66static device_t __f4_dev[FX_DEVS];
Myles Watson6507b392010-06-09 22:39:00 +000067static unsigned fx_devs=0;
Marc Jones8ae8c882007-12-19 01:32:08 +000068
69device_t get_node_pci(u32 nodeid, u32 fn)
70{
zbao49bb26a42012-08-03 15:44:42 +080071#if NODE_NUMS + CONFIG_CDB >= 32
72 if((CONFIG_CDB + nodeid) < 32) {
Stefan Reinauer08670622009-06-30 15:17:49 +000073 return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000074 } else {
Stefan Reinauer08670622009-06-30 15:17:49 +000075 return dev_find_slot(CONFIG_CBB-1, PCI_DEVFN(CONFIG_CDB + nodeid - 32, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000076 }
77
78#else
Stefan Reinauer08670622009-06-30 15:17:49 +000079 return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000080#endif
Marc Jones8ae8c882007-12-19 01:32:08 +000081}
Myles Watson6507b392010-06-09 22:39:00 +000082
Timothy Pearson730a0432015-10-16 13:51:51 -050083static inline uint8_t is_fam15h(void)
84{
85 uint8_t fam15h = 0;
86 uint32_t family;
87
88 family = cpuid_eax(0x80000001);
89 family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
90
91 if (family >= 0x6f)
92 /* Family 15h or later */
93 fam15h = 1;
94
95 return fam15h;
96}
97
Marc Jones8ae8c882007-12-19 01:32:08 +000098static void get_fx_devs(void)
99{
100 int i;
Marc Jones8ae8c882007-12-19 01:32:08 +0000101 for(i = 0; i < FX_DEVS; i++) {
102 __f0_dev[i] = get_node_pci(i, 0);
103 __f1_dev[i] = get_node_pci(i, 1);
104 __f2_dev[i] = get_node_pci(i, 2);
105 __f4_dev[i] = get_node_pci(i, 4);
Myles Watson6507b392010-06-09 22:39:00 +0000106 if (__f0_dev[i] != NULL && __f1_dev[i] != NULL)
107 fx_devs = i+1;
Marc Jones8ae8c882007-12-19 01:32:08 +0000108 }
Myles Watson6507b392010-06-09 22:39:00 +0000109 if (__f1_dev[0] == NULL || __f0_dev[0] == NULL || fx_devs == 0) {
110 die("Cannot find 0:0x18.[0|1]\n");
Marc Jones8ae8c882007-12-19 01:32:08 +0000111 }
112}
113
Myles Watson6507b392010-06-09 22:39:00 +0000114static u32 f1_read_config32(unsigned reg)
Marc Jones8ae8c882007-12-19 01:32:08 +0000115{
Myles Watson6507b392010-06-09 22:39:00 +0000116 if (fx_devs == 0)
117 get_fx_devs();
Marc Jones8ae8c882007-12-19 01:32:08 +0000118 return pci_read_config32(__f1_dev[0], reg);
119}
120
Myles Watson6507b392010-06-09 22:39:00 +0000121static void f1_write_config32(unsigned reg, u32 value)
Marc Jones8ae8c882007-12-19 01:32:08 +0000122{
123 int i;
Myles Watson6507b392010-06-09 22:39:00 +0000124 if (fx_devs == 0)
125 get_fx_devs();
126 for(i = 0; i < fx_devs; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000127 device_t dev;
128 dev = __f1_dev[i];
129 if (dev && dev->enabled) {
130 pci_write_config32(dev, reg, value);
131 }
132 }
133}
134
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200135u32 amdfam10_nodeid(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000136{
137#if NODE_NUMS == 64
138 unsigned busn;
139 busn = dev->bus->secondary;
Stefan Reinauer08670622009-06-30 15:17:49 +0000140 if(busn != CONFIG_CBB) {
141 return (dev->path.pci.devfn >> 3) - CONFIG_CDB + 32;
Marc Jones8ae8c882007-12-19 01:32:08 +0000142 } else {
Stefan Reinauer08670622009-06-30 15:17:49 +0000143 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000144 }
145
146#else
Stefan Reinauer08670622009-06-30 15:17:49 +0000147 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000148#endif
149}
150
Marc Jones8ae8c882007-12-19 01:32:08 +0000151static void set_vga_enable_reg(u32 nodeid, u32 linkn)
152{
153 u32 val;
154
155 val = 1 | (nodeid<<4) | (linkn<<12);
156 /* it will routing (1)mmio 0xa0000:0xbffff (2) io 0x3b0:0x3bb,
157 0x3c0:0x3df */
158 f1_write_config32(0xf4, val);
159
160}
161
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200162typedef enum {
163 HT_ROUTE_CLOSE,
164 HT_ROUTE_SCAN,
165 HT_ROUTE_FINAL,
166} scan_state;
167
168static void ht_route_link(struct bus *link, scan_state mode)
169{
170 struct bus *parent = link->dev->bus;
171 u32 busses;
172
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200173 if (mode == HT_ROUTE_SCAN) {
174 if (parent->subordinate == 0)
175 link->secondary = 0;
176 else
177 link->secondary = parent->subordinate + 1;
178
179 link->subordinate = link->secondary;
180 }
181
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200182 /* Configure the bus numbers for this bridge: the configuration
183 * transactions will not be propagated by the bridge if it is
184 * not correctly configured
185 */
186 busses = pci_read_config32(link->dev, link->cap + 0x14);
Timothy Pearson93107be2015-09-07 03:39:15 -0500187 busses &= ~(0xff << 8);
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200188 busses |= parent->secondary & 0xff;
Timothy Pearson93107be2015-09-07 03:39:15 -0500189 if (mode == HT_ROUTE_CLOSE)
190 busses |= 0xff << 8;
191 else if (mode == HT_ROUTE_SCAN)
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200192 busses |= ((u32) link->secondary & 0xff) << 8;
Timothy Pearson93107be2015-09-07 03:39:15 -0500193 else if (mode == HT_ROUTE_FINAL)
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200194 busses |= ((u32) link->secondary & 0xff) << 8;
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200195 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;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500705 uint8_t nvram;
706 uint8_t enable_cc6;
Marc Jones8ae8c882007-12-19 01:32:08 +0000707
708 /* Find the already assigned resource pairs */
709 get_fx_devs();
710 for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
711 u32 base, limit;
712 base = f1_read_config32(reg);
713 limit = f1_read_config32(reg + 0x04);
714 /* Is this register allocated? */
715 if ((base & 3) != 0) {
Myles Watson362db612010-04-08 15:12:18 +0000716 unsigned nodeid, reg_link;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000717 device_t reg_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +0000718 if(reg<0xc0) { // mmio
719 nodeid = (limit & 0xf) + (base&0x30);
720 } else { // io
721 nodeid = (limit & 0xf) + ((base>>4)&0x30);
722 }
Myles Watson6507b392010-06-09 22:39:00 +0000723 reg_link = (limit >> 4) & 7;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000724 reg_dev = __f0_dev[nodeid];
725 if (reg_dev) {
726 /* Reserve the resource */
Myles Watson6507b392010-06-09 22:39:00 +0000727 struct resource *res;
728 res = new_resource(reg_dev, IOINDEX(0x1000 + reg, reg_link));
729 if (res) {
730 res->flags = 1;
Marc Jones8ae8c882007-12-19 01:32:08 +0000731 }
732 }
733 }
734 }
735 /* FIXME: do we need to check extend conf space?
736 I don't believe that much preset value */
737
Myles Watson280df102009-07-07 13:26:35 +0000738 pci_domain_read_resources(dev);
Marc Jones8ae8c882007-12-19 01:32:08 +0000739
Timothy Pearson16ff8072015-12-11 12:58:07 -0600740 if (IS_ENABLED(CONFIG_MMCONF_SUPPORT)) {
741 struct resource *res = new_resource(dev, 0xc0010058);
742 res->base = CONFIG_MMCONF_BASE_ADDRESS;
Timothy Pearson1eaaa0e2015-08-14 15:20:42 -0500743 res->size = CONFIG_MMCONF_BUS_NUMBER * 1024 * 1024; /* Each bus needs 1M */
744 res->align = log2(res->size);
745 res->gran = log2(res->size);
746 res->limit = 0xffffffffffffffffULL; /* 64-bit location allowed */
Timothy Pearson16ff8072015-12-11 12:58:07 -0600747 res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
748 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
Timothy Pearsona6f669e2015-01-23 20:20:56 -0600749
Timothy Pearson16ff8072015-12-11 12:58:07 -0600750 /* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
751 ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
752 }
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500753
754 if (is_fam15h()) {
755 enable_cc6 = 0;
756 if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
757 enable_cc6 = !!nvram;
758
759 if (enable_cc6) {
760 uint8_t node;
761 uint8_t interleaved;
762 int8_t range;
763 int8_t max_range;
764 uint8_t max_node;
765 uint64_t max_range_limit;
766 uint32_t dword;
767 uint32_t dword2;
768 uint64_t qword;
769 uint8_t num_nodes;
770
771 /* Find highest DRAM range (DramLimitAddr) */
Timothy Pearson83abd812015-06-08 19:35:06 -0500772 num_nodes = 0;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500773 max_node = 0;
774 max_range = -1;
775 interleaved = 0;
776 max_range_limit = 0;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500777 device_t node_dev;
778 for (node = 0; node < FX_DEVS; node++) {
779 node_dev = get_node_pci(node, 0);
780 /* Test for node presence */
Timothy Pearson83abd812015-06-08 19:35:06 -0500781 if ((!node_dev) || (pci_read_config32(node_dev, PCI_VENDOR_ID) == 0xffffffff))
782 continue;
783
784 num_nodes++;
785 for (range = 0; range < 8; range++) {
786 dword = pci_read_config32(get_node_pci(node, 1), 0x40 + (range * 0x8));
787 if (!(dword & 0x3))
788 continue;
789
790 if ((dword >> 8) & 0x7)
791 interleaved = 1;
792
793 dword = pci_read_config32(get_node_pci(node, 1), 0x44 + (range * 0x8));
794 dword2 = pci_read_config32(get_node_pci(node, 1), 0x144 + (range * 0x8));
795 qword = 0xffffff;
796 qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24;
797 qword |= (((uint64_t)dword2) & 0xff) << 40;
798
799 if (qword > max_range_limit) {
800 max_range = range;
801 max_range_limit = qword;
802 max_node = dword & 0x7;
803 }
804 }
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500805 }
806
Timothy Pearson83abd812015-06-08 19:35:06 -0500807 /* Calculate CC6 storage area size */
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500808 if (interleaved)
809 qword = (0x1000000 * num_nodes);
810 else
811 qword = 0x1000000;
812
Timothy Pearson8528e392015-08-20 15:53:25 -0500813 /* FIXME
814 * The BKDG appears to be incorrect as to the location of the CC6 save region
815 * lower boundary on non-interleaved systems, causing lockups on attempted write
816 * to the CC6 save region.
817 *
818 * For now, work around by allocating the maximum possible CC6 save region size.
819 *
820 * Determine if this is a BKDG error or a setup problem and remove this warning!
821 */
822 qword = (0x1 << 27);
823 max_range_limit = (((uint64_t)(pci_read_config32(get_node_pci(max_node, 1), 0x124) & 0x1fffff)) << 27) - 1;
824
825 printk(BIOS_INFO, "Reserving CC6 save segment base: %08llx size: %08llx\n", (max_range_limit + 1), qword);
826
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500827 /* Reserve the CC6 save segment */
Timothy Pearson83abd812015-06-08 19:35:06 -0500828 reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 10, qword >> 10);
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500829 }
830 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000831}
832
Uwe Hermann4b42a622010-10-11 19:36:13 +0000833static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
Marc Jones8ae8c882007-12-19 01:32:08 +0000834{
835 struct resource *min;
836 min = 0;
837 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
838 if (min && tolm > min->base) {
839 tolm = min->base;
840 }
841 return tolm;
842}
843
Stefan Reinauer08670622009-06-30 15:17:49 +0000844#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000845
846struct hw_mem_hole_info {
847 unsigned hole_startk;
848 int node_id;
849};
850
851static struct hw_mem_hole_info get_hw_mem_hole_info(void)
852{
853 struct hw_mem_hole_info mem_hole;
854 int i;
855
Stefan Reinauer08670622009-06-30 15:17:49 +0000856 mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
Marc Jones8ae8c882007-12-19 01:32:08 +0000857 mem_hole.node_id = -1;
858
859 for (i = 0; i < sysconf.nodes; i++) {
860 struct dram_base_mask_t d;
861 u32 hole;
862 d = get_dram_base_mask(i);
863 if(!(d.mask & 1)) continue; // no memory on this node
864
865 hole = pci_read_config32(__f1_dev[i], 0xf0);
866 if(hole & 1) { // we find the hole
867 mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
868 mem_hole.node_id = i; // record the node No with hole
869 break; // only one hole
870 }
871 }
872
Kyösti Mälkki2f9b3af2014-06-26 05:30:54 +0300873 /* We need to double check if there is special set on base reg and limit reg
874 * are not continuous instead of hole, it will find out its hole_startk.
875 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000876 if(mem_hole.node_id==-1) {
877 resource_t limitk_pri = 0;
878 for(i=0; i<sysconf.nodes; i++) {
879 struct dram_base_mask_t d;
880 resource_t base_k, limit_k;
881 d = get_dram_base_mask(i);
882 if(!(d.base & 1)) continue;
883
884 base_k = ((resource_t)(d.base & 0x1fffff00)) <<9;
885 if(base_k > 4 *1024 * 1024) break; // don't need to go to check
886 if(limitk_pri != base_k) { // we find the hole
887 mem_hole.hole_startk = (unsigned)limitk_pri; // must beblow 4G
888 mem_hole.node_id = i;
889 break; //only one hole
890 }
891
892 limit_k = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9;
893 limitk_pri = limit_k;
894 }
895 }
896 return mem_hole;
897}
898
Marc Jones8ae8c882007-12-19 01:32:08 +0000899#endif
900
Rudolf Marek97be27e2010-12-13 19:50:25 +0000901#include <cbmem.h>
Myles Watson6c029e62010-09-13 14:50:20 +0000902
Kyösti Mälkki6b5eb1c2012-07-19 19:26:43 +0300903static void setup_uma_memory(void)
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300904{
905#if CONFIG_GFXUMA
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300906 uint32_t topmem = (uint32_t) bsp_topmem();
Timothy Pearson49168802015-03-13 12:48:31 -0500907 uma_memory_size = get_uma_memory_size(topmem);
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300908 uma_memory_base = topmem - uma_memory_size; /* TOP_MEM1 */
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300909 printk(BIOS_INFO, "%s: uma size 0x%08llx, memory start 0x%08llx\n",
910 __func__, uma_memory_size, uma_memory_base);
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300911#endif
912}
913
Myles Watson6507b392010-06-09 22:39:00 +0000914static void amdfam10_domain_set_resources(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000915{
Marc Jones8ae8c882007-12-19 01:32:08 +0000916 unsigned long mmio_basek;
917 u32 pci_tolm;
918 int i, idx;
Myles Watson894a3472010-06-09 22:41:35 +0000919 struct bus *link;
Stefan Reinauer08670622009-06-30 15:17:49 +0000920#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000921 struct hw_mem_hole_info mem_hole;
922 u32 reset_memhole = 1;
923#endif
924
Marc Jones8ae8c882007-12-19 01:32:08 +0000925 pci_tolm = 0xffffffffUL;
Myles Watson894a3472010-06-09 22:41:35 +0000926 for(link = dev->link_list; link; link = link->next) {
Uwe Hermann4b42a622010-10-11 19:36:13 +0000927 pci_tolm = my_find_pci_tolm(link, pci_tolm);
Marc Jones8ae8c882007-12-19 01:32:08 +0000928 }
929
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000930 // FIXME handle interleaved nodes. If you fix this here, please fix
931 // amdk8, too.
Marc Jones8ae8c882007-12-19 01:32:08 +0000932 mmio_basek = pci_tolm >> 10;
933 /* Round mmio_basek to something the processor can support */
934 mmio_basek &= ~((1 << 6) -1);
935
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000936 // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M
937 // MMIO hole. If you fix this here, please fix amdk8, too.
Myles Watson6507b392010-06-09 22:39:00 +0000938 /* Round the mmio hole to 64M */
Marc Jones8ae8c882007-12-19 01:32:08 +0000939 mmio_basek &= ~((64*1024) - 1);
940
Stefan Reinauer08670622009-06-30 15:17:49 +0000941#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000942/* if the hw mem hole is already set in raminit stage, here we will compare
943 * mmio_basek and hole_basek. if mmio_basek is bigger that hole_basek and will
944 * use hole_basek as mmio_basek and we don't need to reset hole.
945 * otherwise We reset the hole to the mmio_basek
946 */
947
948 mem_hole = get_hw_mem_hole_info();
949
950 // Use hole_basek as mmio_basek, and we don't need to reset hole anymore
951 if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) {
952 mmio_basek = mem_hole.hole_startk;
953 reset_memhole = 0;
954 }
955
Marc Jones8ae8c882007-12-19 01:32:08 +0000956#endif
957
958 idx = 0x10;
959 for(i = 0; i < sysconf.nodes; i++) {
960 struct dram_base_mask_t d;
961 resource_t basek, limitk, sizek; // 4 1T
962 d = get_dram_base_mask(i);
963
964 if(!(d.mask & 1)) continue;
965 basek = ((resource_t)(d.base & 0x1fffff00)) << 9; // could overflow, we may lost 6 bit here
966 limitk = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9 ;
967 sizek = limitk - basek;
968
969 /* see if we need a hole from 0xa0000 to 0xbffff */
970 if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) {
971 ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek);
972 idx += 0x10;
973 basek = (8*64)+(16*16);
974 sizek = limitk - ((8*64)+(16*16));
975
976 }
977
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000978// 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 +0000979
Kyösti Mälkki26c65432014-06-26 05:30:54 +0300980 /* split the region to accommodate pci memory space */
Marc Jones8ae8c882007-12-19 01:32:08 +0000981 if ( (basek < 4*1024*1024 ) && (limitk > mmio_basek) ) {
982 if (basek <= mmio_basek) {
983 unsigned pre_sizek;
984 pre_sizek = mmio_basek - basek;
985 if(pre_sizek>0) {
986 ram_resource(dev, (idx | i), basek, pre_sizek);
987 idx += 0x10;
988 sizek -= pre_sizek;
989 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000990 basek = mmio_basek;
991 }
992 if ((basek + sizek) <= 4*1024*1024) {
993 sizek = 0;
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500994 } else {
Marc Jones8ae8c882007-12-19 01:32:08 +0000995 basek = 4*1024*1024;
996 sizek -= (4*1024*1024 - mmio_basek);
997 }
998 }
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000999
Marc Jones8ae8c882007-12-19 01:32:08 +00001000 ram_resource(dev, (idx | i), basek, sizek);
1001 idx += 0x10;
Myles Watson08e0fb82010-03-22 16:33:25 +00001002 printk(BIOS_DEBUG, "%d: mmio_basek=%08lx, basek=%08llx, limitk=%08llx\n",
Stefan Reinauerb5fb0c52009-04-30 13:58:42 +00001003 i, mmio_basek, basek, limitk);
Marc Jones8ae8c882007-12-19 01:32:08 +00001004 }
1005
Patrick Georgie1667822012-05-05 15:29:32 +02001006#if CONFIG_GFXUMA
Kyösti Mälkki63f8c082012-07-10 13:27:26 +03001007 uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10);
Myles Watson6c029e62010-09-13 14:50:20 +00001008#endif
1009
Myles Watson894a3472010-06-09 22:41:35 +00001010 for(link = dev->link_list; link; link = link->next) {
1011 if (link->children) {
1012 assign_resources(link);
Marc Jones8ae8c882007-12-19 01:32:08 +00001013 }
1014 }
1015}
1016
Kyösti Mälkki580e7222015-03-19 21:04:23 +02001017static void amdfam10_domain_scan_bus(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +00001018{
1019 u32 reg;
1020 int i;
Myles Watson894a3472010-06-09 22:41:35 +00001021 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +00001022 /* Unmap all of the HT chains */
1023 for(reg = 0xe0; reg <= 0xec; reg += 4) {
1024 f1_write_config32(reg, 0);
1025 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001026
Myles Watson894a3472010-06-09 22:41:35 +00001027 for(link = dev->link_list; link; link = link->next) {
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +02001028 link->secondary = dev->bus->subordinate;
Kyösti Mälkkide271a82015-03-18 13:09:47 +02001029 pci_scan_bus(link, PCI_DEVFN(CONFIG_CDB, 0), 0xff);
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +02001030 dev->bus->subordinate = link->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +00001031 }
1032
1033 /* Tune the hypertransport transaction for best performance.
1034 * Including enabling relaxed ordering if it is safe.
1035 */
1036 get_fx_devs();
Myles Watson6507b392010-06-09 22:39:00 +00001037 for(i = 0; i < fx_devs; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001038 device_t f0_dev;
1039 f0_dev = __f0_dev[i];
1040 if (f0_dev && f0_dev->enabled) {
1041 u32 httc;
1042 httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
1043 httc &= ~HTTC_RSP_PASS_PW;
Myles Watson894a3472010-06-09 22:41:35 +00001044 if (!dev->link_list->disable_relaxed_ordering) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001045 httc |= HTTC_RSP_PASS_PW;
1046 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001047 printk(BIOS_SPEW, "%s passpw: %s\n",
Marc Jones8ae8c882007-12-19 01:32:08 +00001048 dev_path(dev),
Myles Watson894a3472010-06-09 22:41:35 +00001049 (!dev->link_list->disable_relaxed_ordering)?
Marc Jones8ae8c882007-12-19 01:32:08 +00001050 "enabled":"disabled");
1051 pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
1052 }
1053 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001054}
1055
Timothy Pearson6e523a62015-03-27 22:58:45 -05001056#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
1057static int amdfam10_get_smbios_data16(int* count, int handle, unsigned long *current)
1058{
1059 struct amdmct_memory_info *mem_info;
1060 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
1061 if (mem_info == NULL)
1062 return 0; /* can't find amdmct information in cbmem */
1063
1064 struct device *dev = get_node_pci(0, 0);
1065 struct northbridge_amd_amdfam10_config *config = dev->chip_info;
1066
1067 int node;
1068 int slot;
1069
1070 struct smbios_type16 *t = (struct smbios_type16 *)*current;
1071 int len = sizeof(struct smbios_type16);
1072
1073 memset(t, 0, sizeof(struct smbios_type16));
1074 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
1075 t->handle = handle;
1076 t->length = len - 2;
1077 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
1078 t->use = MEMORY_ARRAY_USE_SYSTEM;
1079 t->memory_error_correction = MEMORY_ARRAY_ECC_NONE;
1080 if ((mem_info->ecc_enabled)
1081 && (mem_info->mct_stat.GStatus & (1 << GSB_ECCDIMMs))
1082 && !(mem_info->mct_stat.GStatus & (1 << GSB_DramECCDis)))
1083 /* Single-bit ECC enabled */
1084 t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT;
1085 t->maximum_capacity = config->maximum_memory_capacity / 1024; /* Convert to kilobytes */
1086 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1087
1088 t->number_of_memory_devices = 0;
1089 /* Check all nodes for installed DIMMs */
1090 for (node = 0; node < MAX_NODES_SUPPORTED; node++)
1091 /* Check all slots for installed DIMMs */
1092 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++)
1093 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot))
1094 /* Found an installed DIMM; increment count */
1095 t->number_of_memory_devices++;
1096
1097 *current += len;
1098 *count += 1;
1099 return len;
1100}
1101
1102static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
1103{
Timothy Pearson730a0432015-10-16 13:51:51 -05001104 if (is_fam15h()) {
1105 if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
1106 switch (speed) {
1107 case 0x4:
1108 return 333;
1109 case 0x6:
1110 return 400;
1111 case 0xa:
1112 return 533;
1113 case 0xe:
1114 return 667;
1115 case 0x12:
1116 return 800;
1117 case 0x16:
1118 return 933;
1119 default:
1120 return 0;
1121 }
1122 } else {
1123 return 0;
Timothy Pearson160ad6a2015-10-30 18:53:48 -05001124 }
1125 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001126 if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
1127 switch (speed) {
1128 case 1:
1129 return 200;
1130 case 2:
1131 return 266;
1132 case 3:
1133 return 333;
1134 case 4:
1135 return 400;
1136 case 5:
1137 return 533;
1138 default:
1139 return 0;
1140 }
1141 } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
1142 switch (speed) {
1143 case 3:
1144 return 333;
1145 case 4:
1146 return 400;
1147 case 5:
1148 return 533;
1149 case 6:
1150 return 667;
1151 case 7:
1152 return 800;
1153 default:
1154 return 0;
1155 }
1156 } else {
1157 return 0;
1158 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001159 }
1160}
1161
1162static int amdfam10_get_smbios_data17(int* count, int handle, int parent_handle, unsigned long *current)
1163{
1164 struct amdmct_memory_info *mem_info;
1165 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
1166 if (mem_info == NULL)
1167 return 0; /* can't find amdmct information in cbmem */
1168
1169 int single_len;
1170 int len = 0;
1171 int node;
1172 int slot;
1173
1174 /* Check all nodes for installed DIMMs */
1175 for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
1176 /* Get configured RAM bus speed */
1177 uint16_t speed;
1178 speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].Speed);
1179
1180 /* Get maximum RAM bus speed */
1181 uint16_t max_speed;
1182 max_speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].DIMMAutoSpeed);
1183
1184 /* Check all slots for installed DIMMs */
1185 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++) {
1186 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot)) {
1187 /* Found an installed DIMM; populate tables */
1188 struct smbios_type17 *t = (struct smbios_type17 *)*current;
1189 char string_buffer[256];
1190
1191 /* Initialize structure */
1192 memset(t, 0, sizeof(struct smbios_type17));
1193
1194 /* Calculate the total module size in bytes:
1195 * Primary data width * 2^(#rows) * 2^(#cols) * #banks * #ranks
1196 */
1197 uint8_t width, rows, cols, banks, ranks;
1198 width = 8;
1199 rows = mem_info->dct_stat[node].DimmRows[slot];
1200 cols = mem_info->dct_stat[node].DimmCols[slot];
1201 ranks = mem_info->dct_stat[node].DimmRanks[slot];
1202 banks = mem_info->dct_stat[node].DimmBanks[slot];
1203 uint64_t dimm_size_bytes = width * (1ULL << rows) * (1ULL << cols) * banks * ranks;
1204
1205 memset(t, 0, sizeof(struct smbios_type17));
1206 t->type = SMBIOS_MEMORY_DEVICE;
1207 t->handle = handle;
1208 t->phys_memory_array_handle = parent_handle;
1209 t->length = sizeof(struct smbios_type17) - 2;
1210 if (dimm_size_bytes > 0x800000000) {
1211 t->size = 0x7FFF;
1212 t->extended_size = dimm_size_bytes;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001213 } else {
Timothy Pearson6e523a62015-03-27 22:58:45 -05001214 t->size = dimm_size_bytes / (1024*1024);
1215 t->size &= (~0x8000); /* size specified in megabytes */
1216 }
1217 t->total_width = t->data_width = 64;
1218 if (mem_info->dct_stat[node].DimmECCPresent & (1 << slot))
1219 t->total_width += 8;
1220 t->attributes = 0;
1221 t->attributes |= ranks & 0xf; /* rank number is stored in the lowest 4 bits of the attributes field */
1222 t->form_factor = MEMORY_FORMFACTOR_DIMM;
Timothy Pearson0e545c62015-06-25 15:28:23 -05001223 if (mem_info->dct_stat[node].Dual_Node_Package) {
1224 snprintf(string_buffer, sizeof (string_buffer), "NODE %d DIMM_%s%d", node >> 1,
1225 (mem_info->dct_stat[node].Internal_Node_ID)?((slot & 0x1)?"D":"C"):((slot & 0x1)?"B":"A"), (slot >> 1) + 1);
1226 } else {
1227 snprintf(string_buffer, sizeof (string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1);
1228 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001229 t->device_locator = smbios_add_string(t->eos, string_buffer);
1230 if (IS_ENABLED(CONFIG_DIMM_DDR2))
1231 t->memory_type = MEMORY_TYPE_DDR2;
1232 else if (IS_ENABLED(CONFIG_DIMM_DDR3))
1233 t->memory_type = MEMORY_TYPE_DDR3;
1234 t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS;
1235 if (mem_info->dct_stat[node].DimmRegistered[slot])
1236 t->type_detail |= MEMORY_TYPE_DETAIL_REGISTERED;
1237 else
1238 t->type_detail |= MEMORY_TYPE_DETAIL_UNBUFFERED;
1239 t->speed = max_speed;
1240 t->clock_speed = speed;
1241 smbios_fill_dimm_manufacturer_from_id(mem_info->dct_stat[node].DimmManufacturerID[slot], t);
1242 t->part_number = smbios_add_string(t->eos, mem_info->dct_stat[node].DimmPartNumber[slot]);
1243 if (mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) {
1244 t->serial_number = smbios_add_string(t->eos, "None");
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001245 } else {
Timothy Pearson6e523a62015-03-27 22:58:45 -05001246 snprintf(string_buffer, sizeof (string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
1247 t->serial_number = smbios_add_string(t->eos, string_buffer);
1248 }
Timothy Pearson2a839352015-09-05 18:56:05 -05001249 if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
1250 /* JEDEC specifies 1.8V only, so assume that the memory is configured for 1.8V */
1251 t->minimum_voltage = 1800;
1252 t->maximum_voltage = 1800;
1253 t->configured_voltage = 1800;
1254 } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
1255#if IS_ENABLED(CONFIG_DIMM_DDR3)
1256 /* Find the maximum and minimum supported voltages */
1257 uint8_t supported_voltages = mem_info->dct_stat[node].DimmSupportedVoltages[slot];
Timothy Pearson730a0432015-10-16 13:51:51 -05001258 uint8_t configured_voltage = mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
1259
Timothy Pearson2a839352015-09-05 18:56:05 -05001260 if (supported_voltages & 0x8)
1261 t->minimum_voltage = 1150;
1262 else if (supported_voltages & 0x4)
1263 t->minimum_voltage = 1250;
1264 else if (supported_voltages & 0x2)
1265 t->minimum_voltage = 1350;
1266 else if (supported_voltages & 0x1)
1267 t->minimum_voltage = 1500;
1268
1269 if (supported_voltages & 0x1)
1270 t->maximum_voltage = 1500;
1271 else if (supported_voltages & 0x2)
1272 t->maximum_voltage = 1350;
1273 else if (supported_voltages & 0x4)
1274 t->maximum_voltage = 1250;
1275 else if (supported_voltages & 0x8)
1276 t->maximum_voltage = 1150;
1277
Timothy Pearson730a0432015-10-16 13:51:51 -05001278 if (configured_voltage & 0x8)
1279 t->configured_voltage = 1150;
1280 else if (configured_voltage & 0x4)
1281 t->configured_voltage = 1250;
1282 else if (configured_voltage & 0x2)
1283 t->configured_voltage = 1350;
1284 else if (configured_voltage & 0x1)
1285 t->configured_voltage = 1500;
Timothy Pearson2a839352015-09-05 18:56:05 -05001286#endif
1287 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001288 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1289 single_len = t->length + smbios_string_table_len(t->eos);
1290 len += single_len;
1291 *current += single_len;
1292 handle++;
1293 *count += 1;
1294 }
1295 }
1296 }
1297
1298 return len;
1299}
1300
1301static int amdfam10_get_smbios_data(device_t dev, int *handle, unsigned long *current)
1302{
1303 int len;
1304 int count = 0;
1305 len = amdfam10_get_smbios_data16(&count, *handle, current);
1306 len += amdfam10_get_smbios_data17(&count, *handle + 1, *handle, current);
1307 *handle += count;
1308 return len;
1309}
1310#endif
1311
Marc Jones8ae8c882007-12-19 01:32:08 +00001312static struct device_operations pci_domain_ops = {
Myles Watson29cc9ed2009-07-02 18:56:24 +00001313 .read_resources = amdfam10_domain_read_resources,
Myles Watson6507b392010-06-09 22:39:00 +00001314 .set_resources = amdfam10_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +00001315 .enable_resources = NULL,
1316 .init = NULL,
Myles Watson29cc9ed2009-07-02 18:56:24 +00001317 .scan_bus = amdfam10_domain_scan_bus,
Kyösti Mälkki872c9222013-07-03 09:44:28 +03001318 .ops_pci_bus = pci_bus_default_ops,
Timothy Pearson6e523a62015-03-27 22:58:45 -05001319#if CONFIG_GENERATE_SMBIOS_TABLES
1320 .get_smbios_data = amdfam10_get_smbios_data,
1321#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001322};
1323
1324static void sysconf_init(device_t dev) // first node
1325{
1326 sysconf.sblk = (pci_read_config32(dev, 0x64)>>8) & 7; // don't forget sublink1
1327 sysconf.segbit = 0;
1328 sysconf.ht_c_num = 0;
1329
1330 unsigned ht_c_index;
1331
1332 for(ht_c_index=0; ht_c_index<32; ht_c_index++) {
1333 sysconf.ht_c_conf_bus[ht_c_index] = 0;
1334 }
1335
1336 sysconf.nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) + 1;
1337#if CONFIG_MAX_PHYSICAL_CPUS > 8
1338 sysconf.nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
1339#endif
1340
1341 sysconf.enabled_apic_ext_id = 0;
1342 sysconf.lift_bsp_apicid = 0;
1343
1344 /* Find the bootstrap processors apicid */
1345 sysconf.bsp_apicid = lapicid();
1346 sysconf.apicid_offset = sysconf.bsp_apicid;
1347
Patrick Georgie1667822012-05-05 15:29:32 +02001348#if CONFIG_ENABLE_APIC_EXT_ID
Marc Jones8ae8c882007-12-19 01:32:08 +00001349 if (pci_read_config32(dev, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
1350 {
1351 sysconf.enabled_apic_ext_id = 1;
1352 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001353 #if (CONFIG_APIC_ID_OFFSET>0)
Marc Jones8ae8c882007-12-19 01:32:08 +00001354 if(sysconf.enabled_apic_ext_id) {
1355 if(sysconf.bsp_apicid == 0) {
1356 /* bsp apic id is not changed */
Stefan Reinauer08670622009-06-30 15:17:49 +00001357 sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET;
Marc Jones8ae8c882007-12-19 01:32:08 +00001358 } else {
1359 sysconf.lift_bsp_apicid = 1;
1360 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001361 }
1362 #endif
1363#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001364}
1365
Myles Watson894a3472010-06-09 22:41:35 +00001366static void add_more_links(device_t dev, unsigned total_links)
1367{
1368 struct bus *link, *last = NULL;
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001369 int link_num = -1;
Myles Watson894a3472010-06-09 22:41:35 +00001370
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001371 for (link = dev->link_list; link; link = link->next) {
1372 if (link_num < link->link_num)
1373 link_num = link->link_num;
Myles Watson894a3472010-06-09 22:41:35 +00001374 last = link;
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001375 }
Myles Watson894a3472010-06-09 22:41:35 +00001376
1377 if (last) {
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001378 int links = total_links - (link_num + 1);
Myles Watson894a3472010-06-09 22:41:35 +00001379 if (links > 0) {
1380 link = malloc(links*sizeof(*link));
1381 if (!link)
1382 die("Couldn't allocate more links!\n");
1383 memset(link, 0, links*sizeof(*link));
1384 last->next = link;
1385 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001386 } else {
Myles Watson894a3472010-06-09 22:41:35 +00001387 link = malloc(total_links*sizeof(*link));
1388 memset(link, 0, total_links*sizeof(*link));
1389 dev->link_list = link;
1390 }
1391
1392 for (link_num = link_num + 1; link_num < total_links; link_num++) {
1393 link->link_num = link_num;
1394 link->dev = dev;
1395 link->next = link + 1;
1396 last = link;
1397 link = link->next;
1398 }
1399 last->next = NULL;
1400}
1401
Stefan Reinauer4d6db952015-06-13 11:01:54 +02001402static void remap_bsp_lapic(struct bus *cpu_bus)
1403{
1404 struct device_path cpu_path;
1405 device_t cpu;
1406 u32 bsp_lapic_id = lapicid();
1407
1408 if (bsp_lapic_id) {
1409 cpu_path.type = DEVICE_PATH_APIC;
1410 cpu_path.apic.apic_id = 0;
1411 cpu = find_dev_path(cpu_bus, &cpu_path);
1412 if (cpu)
1413 cpu->path.apic.apic_id = bsp_lapic_id;
1414 }
1415}
1416
Kyösti Mälkki580e7222015-03-19 21:04:23 +02001417static void cpu_bus_scan(device_t dev)
Marc Jones8ae8c882007-12-19 01:32:08 +00001418{
1419 struct bus *cpu_bus;
1420 device_t dev_mc;
Myles Watson362db612010-04-08 15:12:18 +00001421#if CONFIG_CBB
Marc Jones8ae8c882007-12-19 01:32:08 +00001422 device_t pci_domain;
Myles Watson362db612010-04-08 15:12:18 +00001423#endif
Timothy Pearson730a0432015-10-16 13:51:51 -05001424 int nvram = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +00001425 int i,j;
1426 int nodes;
1427 unsigned nb_cfg_54;
1428 unsigned siblings;
1429 int cores_found;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +00001430 int disable_siblings;
Timothy Pearson730a0432015-10-16 13:51:51 -05001431 uint8_t disable_cu_siblings = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +00001432 unsigned ApicIdCoreIdSize;
1433
1434 nb_cfg_54 = 0;
1435 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
1436 if(ApicIdCoreIdSize) {
1437 siblings = (1<<ApicIdCoreIdSize)-1;
1438 } else {
1439 siblings = 3; //quad core
1440 }
1441
1442 disable_siblings = !CONFIG_LOGICAL_CPUS;
Patrick Georgie1667822012-05-05 15:29:32 +02001443#if CONFIG_LOGICAL_CPUS
Myles Watson4839e2c2010-04-08 15:06:44 +00001444 get_option(&disable_siblings, "multi_core");
Marc Jones8ae8c882007-12-19 01:32:08 +00001445#endif
1446
Myles Watson6507b392010-06-09 22:39:00 +00001447 // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp???
Marc Jones8ae8c882007-12-19 01:32:08 +00001448 nb_cfg_54 = read_nb_cfg_54();
1449
Stefan Reinauer08670622009-06-30 15:17:49 +00001450#if CONFIG_CBB
1451 dev_mc = dev_find_slot(0, PCI_DEVFN(CONFIG_CDB, 0)); //0x00
Marc Jones8ae8c882007-12-19 01:32:08 +00001452 if(dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001453 printk(BIOS_DEBUG, "%s found", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001454 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001455 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001456 printk(BIOS_DEBUG, "\n%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001457 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001458 printk(BIOS_DEBUG, "%s",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001459
1460 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001461 printk(BIOS_DEBUG, " but it is not under pci_domain directly ");
Marc Jones8ae8c882007-12-19 01:32:08 +00001462 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001463 printk(BIOS_DEBUG, "\n");
Marc Jones8ae8c882007-12-19 01:32:08 +00001464 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001465 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001466 if(!dev_mc) {
1467 dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0));
1468 if (dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001469 printk(BIOS_DEBUG, "%s found\n", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001470 pci_domain = dev_mc->bus->dev;
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001471 if(pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Myles Watson894a3472010-06-09 22:41:35 +00001472 if((pci_domain->link_list) && (pci_domain->link_list->children == dev_mc)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001473 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001474 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001475 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001476 while(dev_mc){
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001477 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer2b34db82009-02-28 20:10:20 +00001478 dev_mc->path.pci.devfn -= PCI_DEVFN(0x18,0);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001479 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001480 dev_mc = dev_mc->sibling;
1481 }
1482 }
1483 }
1484 }
1485 }
1486
1487#endif
1488
Stefan Reinauer08670622009-06-30 15:17:49 +00001489 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001490 if (!dev_mc) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001491 printk(BIOS_ERR, "%02x:%02x.0 not found", CONFIG_CBB, CONFIG_CDB);
Marc Jones8ae8c882007-12-19 01:32:08 +00001492 die("");
1493 }
1494
1495 sysconf_init(dev_mc);
1496
1497 nodes = sysconf.nodes;
1498
Stefan Reinauer08670622009-06-30 15:17:49 +00001499#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001500 if(nodes>32) { // need to put node 32 to node 63 to bus 0xfe
Myles Watson894a3472010-06-09 22:41:35 +00001501 if(pci_domain->link_list && !pci_domain->link_list->next) {
1502 struct bus *new_link = new_link(pci_domain);
1503 pci_domain->link_list->next = new_link;
1504 new_link->link_num = 1;
1505 new_link->dev = pci_domain;
1506 new_link->children = 0;
1507 printk(BIOS_DEBUG, "%s links now 2\n", dev_path(pci_domain));
Marc Jones8ae8c882007-12-19 01:32:08 +00001508 }
Myles Watson894a3472010-06-09 22:41:35 +00001509 pci_domain->link_list->next->secondary = CONFIG_CBB - 1;
Marc Jones8ae8c882007-12-19 01:32:08 +00001510 }
1511#endif
1512 /* Find which cpus are present */
Myles Watson894a3472010-06-09 22:41:35 +00001513 cpu_bus = dev->link_list;
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001514
1515 /* Always use the devicetree node with lapic_id 0 for BSP. */
1516 remap_bsp_lapic(cpu_bus);
1517
Timothy Pearson730a0432015-10-16 13:51:51 -05001518 if (get_option(&nvram, "compute_unit_siblings") == CB_SUCCESS)
1519 disable_cu_siblings = !!nvram;
1520
1521 if (disable_cu_siblings)
1522 printk(BIOS_DEBUG, "Disabling siblings on each compute unit as requested\n");
1523
Marc Jones8ae8c882007-12-19 01:32:08 +00001524 for(i = 0; i < nodes; i++) {
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001525 device_t cdb_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +00001526 unsigned busn, devn;
1527 struct bus *pbus;
1528
Timothy Pearson730a0432015-10-16 13:51:51 -05001529 uint8_t fam15h = 0;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001530 uint8_t rev_gte_d = 0;
1531 uint8_t dual_node = 0;
1532 uint32_t f3xe8;
Timothy Pearson730a0432015-10-16 13:51:51 -05001533 uint32_t family;
1534 uint32_t model;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001535
Stefan Reinauer08670622009-06-30 15:17:49 +00001536 busn = CONFIG_CBB;
1537 devn = CONFIG_CDB+i;
Marc Jones8ae8c882007-12-19 01:32:08 +00001538 pbus = dev_mc->bus;
Stefan Reinauer08670622009-06-30 15:17:49 +00001539#if CONFIG_CBB && (NODE_NUMS > 32)
Marc Jones8ae8c882007-12-19 01:32:08 +00001540 if(i>=32) {
1541 busn--;
1542 devn-=32;
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001543 pbus = pci_domain->link_list->next;
Marc Jones8ae8c882007-12-19 01:32:08 +00001544 }
1545#endif
1546
1547 /* Find the cpu's pci device */
Myles Watson362db612010-04-08 15:12:18 +00001548 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1549 if (!cdb_dev) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001550 /* If I am probing things in a weird order
1551 * ensure all of the cpu's pci devices are found.
1552 */
Myles Watson362db612010-04-08 15:12:18 +00001553 int fn;
1554 for(fn = 0; fn <= 5; fn++) { //FBDIMM?
1555 cdb_dev = pci_probe_dev(NULL, pbus,
1556 PCI_DEVFN(devn, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +00001557 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001558 }
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001559
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001560
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001561 /* Ok, We need to set the links for that device.
1562 * otherwise the device under it will not be scanned
1563 */
1564 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1565 if (cdb_dev)
1566 add_more_links(cdb_dev, 4);
1567
1568 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 4));
1569 if (cdb_dev)
1570 add_more_links(cdb_dev, 4);
Marc Jones8ae8c882007-12-19 01:32:08 +00001571
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001572 f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
1573
Timothy Pearson730a0432015-10-16 13:51:51 -05001574 family = model = cpuid_eax(0x80000001);
1575 model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
1576
1577 if (is_fam15h()) {
1578 /* Family 15h or later */
1579 fam15h = 1;
1580 nb_cfg_54 = 1;
1581 }
1582
1583 if ((model >= 0x8) || fam15h)
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001584 /* Revision D or later */
1585 rev_gte_d = 1;
1586
1587 if (rev_gte_d)
1588 /* Check for dual node capability */
1589 if (f3xe8 & 0x20000000)
1590 dual_node = 1;
1591
Marc Jones8ae8c882007-12-19 01:32:08 +00001592 cores_found = 0; // one core
Timothy Pearson730a0432015-10-16 13:51:51 -05001593 if (fam15h)
1594 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 5));
1595 else
1596 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001597 int enable_node = cdb_dev && cdb_dev->enabled;
1598 if (enable_node) {
Timothy Pearson730a0432015-10-16 13:51:51 -05001599 if (fam15h) {
1600 cores_found = pci_read_config32(cdb_dev, 0x84) & 0xff;
1601 } else {
1602 j = pci_read_config32(cdb_dev, 0xe8);
1603 cores_found = (j >> 12) & 3; // dev is func 3
1604 if (siblings > 3)
1605 cores_found |= (j >> 13) & 4;
1606 }
Myles Watson362db612010-04-08 15:12:18 +00001607 printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cdb_dev), cores_found);
Marc Jones8ae8c882007-12-19 01:32:08 +00001608 }
1609
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001610 if (siblings > cores_found)
1611 siblings = cores_found;
1612
Marc Jones8ae8c882007-12-19 01:32:08 +00001613 u32 jj;
1614 if(disable_siblings) {
1615 jj = 0;
1616 } else
1617 {
1618 jj = cores_found;
1619 }
1620
1621 for (j = 0; j <=jj; j++ ) {
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001622 u32 apic_id;
1623
1624 if (dual_node) {
1625 apic_id = 0;
Timothy Pearson730a0432015-10-16 13:51:51 -05001626 if (fam15h) {
1627 apic_id |= ((i >> 1) & 0x3) << 5; /* Node ID */
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001628 apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
1629 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001630 if (nb_cfg_54) {
1631 apic_id |= ((i >> 1) & 0x3) << 4; /* Node ID */
1632 apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
1633 } else {
1634 apic_id |= i & 0x3; /* Node ID */
1635 apic_id |= (((i & 0x1) * (siblings + 1)) + j) << 4; /* Core ID */
1636 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001637 }
1638 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001639 if (fam15h) {
1640 apic_id = (i * (siblings + 1)) + j;
1641 } else {
1642 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
1643 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001644 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001645
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001646#if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
1647 if(sysconf.enabled_apic_ext_id) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001648 if (apic_id != 0 || sysconf.lift_bsp_apicid) {
1649 apic_id += sysconf.apicid_offset;
Marc Jones8ae8c882007-12-19 01:32:08 +00001650 }
1651 }
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001652#endif
Timothy Pearson730a0432015-10-16 13:51:51 -05001653 if (disable_cu_siblings && (j & 0x1))
1654 continue;
1655
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001656 device_t cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
1657 if (cpu)
1658 amd_cpu_topology(cpu, i, j);
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001659 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001660 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001661}
1662
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001663static void detect_and_enable_probe_filter(device_t dev)
1664{
1665 uint32_t dword;
1666
Timothy Pearson68130f52015-08-09 02:47:51 -05001667 uint8_t nvram;
1668 uint8_t enable_probe_filter;
1669
1670 /* Check to see if the probe filter is allowed */
1671 enable_probe_filter = 1;
1672 if (get_option(&nvram, "probe_filter") == CB_SUCCESS)
1673 enable_probe_filter = !!nvram;
1674
1675 if (!enable_probe_filter)
1676 return;
1677
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001678 uint8_t fam15h = 0;
1679 uint8_t rev_gte_d = 0;
1680 uint8_t dual_node = 0;
1681 unsigned nb_cfg_54;
1682 uint32_t f3xe8;
1683 uint32_t family;
1684 uint32_t model;
1685
1686 family = model = cpuid_eax(0x80000001);
1687 model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
1688
1689 if (is_fam15h()) {
1690 /* Family 15h or later */
1691 fam15h = 1;
1692 nb_cfg_54 = 1;
1693 }
1694
1695 if ((model >= 0x8) || fam15h)
1696 /* Revision D or later */
1697 rev_gte_d = 1;
1698
1699 if (rev_gte_d)
1700 /* Check for dual node capability */
1701 if (f3xe8 & 0x20000000)
1702 dual_node = 1;
1703
1704 if (rev_gte_d && (sysconf.nodes > 1)) {
1705 /* Enable the probe filter */
1706 uint8_t i;
1707 uint8_t pfmode = 0x0;
1708
1709 uint32_t f3x58[MAX_NODES_SUPPORTED];
1710 uint32_t f3x5c[MAX_NODES_SUPPORTED];
1711
1712 printk(BIOS_DEBUG, "Enabling probe filter\n");
1713
1714 /* Disable L3 and DRAM scrubbers and configure system for probe filter support */
1715 for (i = 0; i < sysconf.nodes; i++) {
1716 device_t f2x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 2));
1717 device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3));
1718
1719 f3x58[i] = pci_read_config32(f3x_dev, 0x58);
1720 f3x5c[i] = pci_read_config32(f3x_dev, 0x5c);
1721 pci_write_config32(f3x_dev, 0x58, f3x58[i] & ~((0x1f << 24) | 0x1f));
1722 pci_write_config32(f3x_dev, 0x5c, f3x5c[i] & ~0x1);
1723
1724 dword = pci_read_config32(f2x_dev, 0x1b0);
1725 dword &= ~(0x7 << 8); /* CohPrefPrbLmt = 0x0 */
1726 pci_write_config32(f2x_dev, 0x1b0, dword);
1727
1728 msr_t msr = rdmsr_amd(BU_CFG2_MSR);
1729 msr.hi |= 1 << (42 - 32);
1730 wrmsr_amd(BU_CFG2_MSR, msr);
1731
1732 if (is_fam15h()) {
1733 uint8_t subcache_size = 0x0;
1734 uint8_t pref_so_repl = 0x0;
1735 uint32_t f3x1c4 = pci_read_config32(f3x_dev, 0x1c4);
1736 if ((f3x1c4 & 0xffff) == 0xcccc) {
1737 subcache_size = 0x1;
1738 pref_so_repl = 0x2;
1739 pfmode = 0x3;
1740 } else {
1741 pfmode = 0x2;
1742 }
1743
1744 dword = pci_read_config32(f3x_dev, 0x1d4);
1745 dword |= 0x1 << 29; /* PFLoIndexHashEn = 0x1 */
1746 dword &= ~(0x3 << 20); /* PFPreferredSORepl = pref_so_repl */
1747 dword |= (pref_so_repl & 0x3) << 20;
1748 dword |= 0x1 << 17; /* PFWayHashEn = 0x1 */
1749 dword |= 0xf << 12; /* PFSubCacheEn = 0xf */
1750 dword &= ~(0x3 << 10); /* PFSubCacheSize3 = subcache_size */
1751 dword |= (subcache_size & 0x3) << 10;
1752 dword &= ~(0x3 << 8); /* PFSubCacheSize2 = subcache_size */
1753 dword |= (subcache_size & 0x3) << 8;
1754 dword &= ~(0x3 << 6); /* PFSubCacheSize1 = subcache_size */
1755 dword |= (subcache_size & 0x3) << 6;
1756 dword &= ~(0x3 << 4); /* PFSubCacheSize0 = subcache_size */
1757 dword |= (subcache_size & 0x3) << 4;
1758 dword &= ~(0x3 << 2); /* PFWayNum = 0x2 */
1759 dword |= 0x2 << 2;
1760 pci_write_config32(f3x_dev, 0x1d4, dword);
1761 } else {
1762 pfmode = 0x2;
1763
1764 dword = pci_read_config32(f3x_dev, 0x1d4);
1765 dword |= 0x1 << 29; /* PFLoIndexHashEn = 0x1 */
1766 dword &= ~(0x3 << 20); /* PFPreferredSORepl = 0x2 */
1767 dword |= 0x2 << 20;
1768 dword |= 0xf << 12; /* PFSubCacheEn = 0xf */
1769 dword &= ~(0x3 << 10); /* PFSubCacheSize3 = 0x0 */
1770 dword &= ~(0x3 << 8); /* PFSubCacheSize2 = 0x0 */
1771 dword &= ~(0x3 << 6); /* PFSubCacheSize1 = 0x0 */
1772 dword &= ~(0x3 << 4); /* PFSubCacheSize0 = 0x0 */
1773 dword &= ~(0x3 << 2); /* PFWayNum = 0x2 */
1774 dword |= 0x2 << 2;
1775 pci_write_config32(f3x_dev, 0x1d4, dword);
1776 }
1777 }
1778
1779 udelay(40);
1780
1781 disable_cache();
1782 wbinvd();
Timothy Pearson4dc6cab2015-08-07 19:06:09 -05001783
1784 /* Enable probe filter */
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001785 for (i = 0; i < sysconf.nodes; i++) {
1786 device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3));
1787
1788 dword = pci_read_config32(f3x_dev, 0x1c4);
1789 dword |= (0x1 << 31); /* L3TagInit = 1 */
1790 pci_write_config32(f3x_dev, 0x1c4, dword);
1791 do {
1792 } while (pci_read_config32(f3x_dev, 0x1c4) & (0x1 << 31));
1793
1794 dword = pci_read_config32(f3x_dev, 0x1d4);
1795 dword &= ~0x3; /* PFMode = pfmode */
1796 dword |= pfmode & 0x3;
1797 pci_write_config32(f3x_dev, 0x1d4, dword);
1798 do {
1799 } while (!(pci_read_config32(f3x_dev, 0x1d4) & (0x1 << 19)));
1800 }
Timothy Pearson4dc6cab2015-08-07 19:06:09 -05001801
1802 if (is_fam15h()) {
1803 printk(BIOS_DEBUG, "Enabling ATM mode\n");
1804
1805 /* Enable ATM mode */
1806 for (i = 0; i < sysconf.nodes; i++) {
1807 device_t f0x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 0));
1808 device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3));
1809
1810 dword = pci_read_config32(f0x_dev, 0x68);
1811 dword |= (0x1 << 12); /* ATMModeEn = 1 */
1812 pci_write_config32(f0x_dev, 0x68, dword);
1813
1814 dword = pci_read_config32(f3x_dev, 0x1b8);
1815 dword |= (0x1 << 27); /* L3ATMModeEn = 1 */
1816 pci_write_config32(f3x_dev, 0x1b8, dword);
1817 }
1818 }
1819
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001820 enable_cache();
1821
1822 /* Reenable L3 and DRAM scrubbers */
1823 for (i = 0; i < sysconf.nodes; i++) {
1824 device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3));
1825
1826 pci_write_config32(f3x_dev, 0x58, f3x58[i]);
1827 pci_write_config32(f3x_dev, 0x5c, f3x5c[i]);
1828 }
1829
1830 }
1831}
1832
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001833static void detect_and_enable_cache_partitioning(device_t dev)
1834{
1835 uint8_t i;
1836 uint32_t dword;
1837
Timothy Pearson68130f52015-08-09 02:47:51 -05001838 uint8_t nvram;
1839 uint8_t enable_l3_cache_partitioning;
1840
1841 /* Check to see if cache partitioning is allowed */
1842 enable_l3_cache_partitioning = 0;
1843 if (get_option(&nvram, "l3_cache_partitioning") == CB_SUCCESS)
1844 enable_l3_cache_partitioning = !!nvram;
1845
1846 if (!enable_l3_cache_partitioning)
1847 return;
1848
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001849 if (is_fam15h()) {
1850 printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n");
1851
1852 uint32_t f5x80;
1853 uint8_t cu_enabled;
1854 uint8_t compute_unit_count = 0;
1855
1856 uint32_t f3xe8;
1857 uint8_t dual_node = 0;
1858
1859 for (i = 0; i < sysconf.nodes; i++) {
1860 device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3));
1861 device_t f4x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 4));
1862 device_t f5x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 5));
1863
1864 f3xe8 = pci_read_config32(f3x_dev, 0xe8);
1865
1866 /* Check for dual node capability */
1867 if (f3xe8 & 0x20000000)
1868 dual_node = 1;
1869
1870 /* Determine the number of active compute units on this node */
1871 f5x80 = pci_read_config32(f5x_dev, 0x80);
1872 cu_enabled = f5x80 & 0xf;
1873 if (cu_enabled == 0x1)
1874 compute_unit_count = 1;
1875 if (cu_enabled == 0x3)
1876 compute_unit_count = 2;
1877 if (cu_enabled == 0x7)
1878 compute_unit_count = 3;
1879 if (cu_enabled == 0xf)
1880 compute_unit_count = 4;
1881
1882 /* Disable BAN mode */
1883 dword = pci_read_config32(f3x_dev, 0x1b8);
1884 dword &= ~(0x7 << 19); /* L3BanMode = 0x0 */
1885 pci_write_config32(f3x_dev, 0x1b8, dword);
1886
1887 /* Set up cache mapping */
1888 dword = pci_read_config32(f4x_dev, 0x1d4);
1889 if (compute_unit_count == 1) {
1890 dword |= 0xf; /* ComputeUnit0SubCacheEn = 0xf */
1891 }
1892 if (compute_unit_count == 2) {
1893 dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0xc */
1894 dword |= (0xc << 4);
1895 dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */
1896 dword |= 0x3;
1897 }
1898 if (compute_unit_count == 3) {
1899 dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x8 */
1900 dword |= (0x8 << 8);
1901 dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x4 */
1902 dword |= (0x4 << 4);
1903 dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */
1904 dword |= 0x3;
1905 }
1906 if (compute_unit_count == 4) {
1907 dword &= ~(0xf << 12); /* ComputeUnit3SubCacheEn = 0x8 */
1908 dword |= (0x8 << 12);
1909 dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x4 */
1910 dword |= (0x4 << 8);
1911 dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x2 */
1912 dword |= (0x2 << 4);
1913 dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x1 */
1914 dword |= 0x1;
1915 }
1916 pci_write_config32(f4x_dev, 0x1d4, dword);
1917
1918 /* Enable cache partitioning */
1919 pci_write_config32(f4x_dev, 0x1d4, dword);
1920 if (compute_unit_count == 1) {
1921 dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x1 */
1922 dword |= (0x1 << 26);
1923 } else if (compute_unit_count == 2) {
1924 dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x3 */
1925 dword |= (0x3 << 26);
1926 } else if (compute_unit_count == 3) {
1927 dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x7 */
1928 dword |= (0x7 << 26);
1929 } else if (compute_unit_count == 4) {
1930 dword |= (0xf << 26); /* MaskUpdateForComputeUnit = 0xf */
1931 }
1932 pci_write_config32(f4x_dev, 0x1d4, dword);
1933 }
1934 }
1935}
1936
Marc Jones8ae8c882007-12-19 01:32:08 +00001937static void cpu_bus_init(device_t dev)
1938{
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001939 detect_and_enable_probe_filter(dev);
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001940 detect_and_enable_cache_partitioning(dev);
Myles Watson894a3472010-06-09 22:41:35 +00001941 initialize_cpus(dev->link_list);
Kerry Shefeed3292011-08-18 18:03:44 +08001942#if CONFIG_AMD_SB_CIMX
1943 sb_After_Pci_Init();
1944 sb_Mid_Post_Init();
1945#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001946}
1947
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001948static void cpu_bus_set_resources(struct device *dev)
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001949{
1950 struct resource *resource = find_resource(dev, 0xc0010058);
1951 if (resource) {
1952 report_resource_stored(dev, resource, " <mmconfig>");
1953 }
1954 pci_dev_set_resources(dev);
1955}
1956
Marc Jones8ae8c882007-12-19 01:32:08 +00001957static struct device_operations cpu_bus_ops = {
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001958 .read_resources = DEVICE_NOOP,
Arne Georg Gleditschd6689ed2010-09-09 14:54:07 +00001959 .set_resources = cpu_bus_set_resources,
Edward O'Callaghan812d2a42014-10-31 08:17:23 +11001960 .enable_resources = DEVICE_NOOP,
Marc Jones8ae8c882007-12-19 01:32:08 +00001961 .init = cpu_bus_init,
1962 .scan_bus = cpu_bus_scan,
1963};
1964
Marc Jones8ae8c882007-12-19 01:32:08 +00001965static void root_complex_enable_dev(struct device *dev)
1966{
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001967 static int done = 0;
1968
1969 /* Do not delay UMA setup, as a device on the PCI bus may evaluate
1970 the global uma_memory variables already in its enable function. */
1971 if (!done) {
Timothy Pearson59d0e042015-09-05 18:40:31 -05001972#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && IS_ENABLED(CONFIG_DIMM_DDR3)
1973 save_mct_information_to_nvram();
1974#endif
1975
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001976 setup_bsp_ramtop();
1977 setup_uma_memory();
1978 done = 1;
1979 }
1980
Marc Jones8ae8c882007-12-19 01:32:08 +00001981 /* Set the operations if it is a special bus type */
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001982 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001983 dev->ops = &pci_domain_ops;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001984 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001985 dev->ops = &cpu_bus_ops;
1986 }
1987}
1988
1989struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
Timothy Pearson730a0432015-10-16 13:51:51 -05001990 CHIP_NAME("AMD Family 10h/15h Root Complex")
Marc Jones8ae8c882007-12-19 01:32:08 +00001991 .enable_dev = root_complex_enable_dev,
1992};