blob: 79f43db387ef46fa76dedfe888853c9a461f234f [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 *
Damien Zammit33aaa922016-02-10 14:01:36 +11004 * Copyright (C) 2016 Damien Zammit <damien@zamaudio.com>
Timothy Pearson0f3a18a2017-04-13 17:08:18 -05005 * Copyright (C) 2015 - 2017 Timothy Pearson <tpearson@raptorengineering.com>, Raptor Engineering
Marc Jones8ae8c882007-12-19 01:32:08 +00006 * Copyright (C) 2007 Advanced Micro Devices, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Marc Jones8ae8c882007-12-19 01:32:08 +000016 */
17
18#include <console/console.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020019#include <device/pci_ops.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000020#include <stdint.h>
21#include <device/device.h>
22#include <device/pci.h>
23#include <device/pci_ids.h>
24#include <device/hypertransport.h>
25#include <stdlib.h>
26#include <string.h>
Ronald G. Minnich5079a0d2012-11-27 11:32:38 -080027#include <lib.h>
Timothy Pearson6e523a62015-03-27 22:58:45 -050028#include <smbios.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000029#include <cpu/cpu.h>
Timothy Pearson0f1553b2015-08-02 21:06:39 -050030#include <delay.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000031#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>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020037#include <types.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000038
Julius Wernercd49cce2019-03-05 16:53:33 -080039#if CONFIG(LOGICAL_CPUS)
Stefan Reinauer9a16e3e2010-03-29 14:45:36 +000040#include <cpu/amd/multicore.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000041#include <pc80/mc146818rtc.h>
42#endif
43
Marc Jones8ae8c882007-12-19 01:32:08 +000044#include "northbridge.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000045#include "amdfam10.h"
Kyösti Mälkki991a71d2015-02-22 00:12:43 +020046#include "ht_config.h"
Timothy Pearson6e523a62015-03-27 22:58:45 -050047#include "chip.h"
Marc Jones8ae8c882007-12-19 01:32:08 +000048
Stefan Reinauer08670622009-06-30 15:17:49 +000049#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +000050#include <cpu/amd/model_10xxx_rev.h>
51#endif
52
Julius Wernercd49cce2019-03-05 16:53:33 -080053#if CONFIG(DIMM_DDR3)
Timothy Pearson59d0e042015-09-05 18:40:31 -050054#include "../amdmct/mct_ddr3/s3utils.h"
55#endif
56
Marc Jones8ae8c882007-12-19 01:32:08 +000057struct amdfam10_sysconf_t sysconf;
Kyösti Mälkki21c60fa2019-01-03 11:38:57 +020058u8 pirq_router_bus;
Marc Jones8ae8c882007-12-19 01:32:08 +000059
60#define FX_DEVS NODE_NUMS
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +030061static struct device *__f0_dev[FX_DEVS];
62struct device *__f1_dev[FX_DEVS];
63static struct device *__f2_dev[FX_DEVS];
64static struct device *__f4_dev[FX_DEVS];
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -060065static unsigned fx_devs = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +000066
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +030067struct device *get_node_pci(u32 nodeid, u32 fn)
Marc Jones8ae8c882007-12-19 01:32:08 +000068{
zbao49bb26a42012-08-03 15:44:42 +080069#if NODE_NUMS + CONFIG_CDB >= 32
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +020070 if ((CONFIG_CDB + nodeid) < 32) {
Stefan Reinauer08670622009-06-30 15:17:49 +000071 return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000072 } else {
Stefan Reinauer08670622009-06-30 15:17:49 +000073 return dev_find_slot(CONFIG_CBB-1, PCI_DEVFN(CONFIG_CDB + nodeid - 32, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000074 }
75
76#else
Stefan Reinauer08670622009-06-30 15:17:49 +000077 return dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB + nodeid, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +000078#endif
Marc Jones8ae8c882007-12-19 01:32:08 +000079}
Myles Watson6507b392010-06-09 22:39:00 +000080
Marc Jones8ae8c882007-12-19 01:32:08 +000081static void get_fx_devs(void)
82{
83 int i;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +020084 for (i = 0; i < FX_DEVS; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +000085 __f0_dev[i] = get_node_pci(i, 0);
86 __f1_dev[i] = get_node_pci(i, 1);
87 __f2_dev[i] = get_node_pci(i, 2);
88 __f4_dev[i] = get_node_pci(i, 4);
Myles Watson6507b392010-06-09 22:39:00 +000089 if (__f0_dev[i] != NULL && __f1_dev[i] != NULL)
90 fx_devs = i+1;
Marc Jones8ae8c882007-12-19 01:32:08 +000091 }
Myles Watson6507b392010-06-09 22:39:00 +000092 if (__f1_dev[0] == NULL || __f0_dev[0] == NULL || fx_devs == 0) {
93 die("Cannot find 0:0x18.[0|1]\n");
Marc Jones8ae8c882007-12-19 01:32:08 +000094 }
95}
96
Myles Watson6507b392010-06-09 22:39:00 +000097static u32 f1_read_config32(unsigned reg)
Marc Jones8ae8c882007-12-19 01:32:08 +000098{
Myles Watson6507b392010-06-09 22:39:00 +000099 if (fx_devs == 0)
100 get_fx_devs();
Marc Jones8ae8c882007-12-19 01:32:08 +0000101 return pci_read_config32(__f1_dev[0], reg);
102}
103
Myles Watson6507b392010-06-09 22:39:00 +0000104static void f1_write_config32(unsigned reg, u32 value)
Marc Jones8ae8c882007-12-19 01:32:08 +0000105{
106 int i;
Myles Watson6507b392010-06-09 22:39:00 +0000107 if (fx_devs == 0)
108 get_fx_devs();
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200109 for (i = 0; i < fx_devs; i++) {
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300110 struct device *dev;
Marc Jones8ae8c882007-12-19 01:32:08 +0000111 dev = __f1_dev[i];
112 if (dev && dev->enabled) {
113 pci_write_config32(dev, reg, value);
114 }
115 }
116}
117
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300118u32 amdfam10_nodeid(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000119{
120#if NODE_NUMS == 64
121 unsigned busn;
122 busn = dev->bus->secondary;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200123 if (busn != CONFIG_CBB) {
Stefan Reinauer08670622009-06-30 15:17:49 +0000124 return (dev->path.pci.devfn >> 3) - CONFIG_CDB + 32;
Marc Jones8ae8c882007-12-19 01:32:08 +0000125 } else {
Stefan Reinauer08670622009-06-30 15:17:49 +0000126 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000127 }
128
129#else
Stefan Reinauer08670622009-06-30 15:17:49 +0000130 return (dev->path.pci.devfn >> 3) - CONFIG_CDB;
Marc Jones8ae8c882007-12-19 01:32:08 +0000131#endif
132}
133
Marc Jones8ae8c882007-12-19 01:32:08 +0000134static void set_vga_enable_reg(u32 nodeid, u32 linkn)
135{
136 u32 val;
137
138 val = 1 | (nodeid<<4) | (linkn<<12);
139 /* it will routing (1)mmio 0xa0000:0xbffff (2) io 0x3b0:0x3bb,
140 0x3c0:0x3df */
141 f1_write_config32(0xf4, val);
142
143}
144
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200145typedef enum {
146 HT_ROUTE_CLOSE,
147 HT_ROUTE_SCAN,
148 HT_ROUTE_FINAL,
149} scan_state;
150
151static void ht_route_link(struct bus *link, scan_state mode)
152{
153 struct bus *parent = link->dev->bus;
154 u32 busses;
155
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200156 if (mode == HT_ROUTE_SCAN) {
157 if (parent->subordinate == 0)
158 link->secondary = 0;
159 else
160 link->secondary = parent->subordinate + 1;
161
162 link->subordinate = link->secondary;
163 }
164
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200165 /* Configure the bus numbers for this bridge: the configuration
166 * transactions will not be propagated by the bridge if it is
167 * not correctly configured
168 */
169 busses = pci_read_config32(link->dev, link->cap + 0x14);
Timothy Pearson93107be2015-09-07 03:39:15 -0500170 busses &= ~(0xff << 8);
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200171 busses |= parent->secondary & 0xff;
Timothy Pearson93107be2015-09-07 03:39:15 -0500172 if (mode == HT_ROUTE_CLOSE)
173 busses |= 0xff << 8;
174 else if (mode == HT_ROUTE_SCAN)
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200175 busses |= ((u32) link->secondary & 0xff) << 8;
Timothy Pearson93107be2015-09-07 03:39:15 -0500176 else if (mode == HT_ROUTE_FINAL)
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200177 busses |= ((u32) link->secondary & 0xff) << 8;
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200178 pci_write_config32(link->dev, link->cap + 0x14, busses);
179
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200180 if (mode == HT_ROUTE_FINAL) {
Julius Werner5d1f9a02019-03-07 17:07:26 -0800181 if (CONFIG(HT_CHAIN_DISTRIBUTE))
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200182 parent->subordinate = ALIGN_UP(link->subordinate, 8) - 1;
183 else
184 parent->subordinate = link->subordinate;
185 }
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200186}
187
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300188static void amd_g34_fixup(struct bus *link, struct device *dev)
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500189{
190 uint32_t nodeid = amdfam10_nodeid(dev);
191 uint8_t rev_gte_d = 0;
192 uint8_t dual_node = 0;
193 uint32_t f3xe8;
194
195 if (cpuid_eax(0x80000001) >= 0x8)
196 /* Revision D or later */
197 rev_gte_d = 1;
198
Timothy Pearson730a0432015-10-16 13:51:51 -0500199 if (rev_gte_d || is_fam15h()) {
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500200 f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
201
202 /* Check for dual node capability */
203 if (f3xe8 & 0x20000000)
204 dual_node = 1;
205
206 if (dual_node) {
207 /* Each G34 processor contains a defective HT link.
208 * See the BKDG Rev 3.62 section 2.7.1.5 for details.
209 */
210 f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 0xe8);
211 uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 30);
212 if (internal_node_number == 0) {
213 /* Node 0 */
214 if (link->link_num == 6) /* Link 2 Sublink 1 */
215 printk(BIOS_DEBUG, "amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT link\n", nodeid, internal_node_number);
216 } else {
217 /* Node 1 */
218 if (link->link_num == 5) /* Link 1 Sublink 1 */
219 printk(BIOS_DEBUG, "amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT link\n", nodeid, internal_node_number);
220 }
221 }
222 }
223}
224
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200225static void amdfam10_scan_chain(struct bus *link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000226{
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200227 unsigned int next_unitid;
Marc Jones8ae8c882007-12-19 01:32:08 +0000228
Marc Jones8ae8c882007-12-19 01:32:08 +0000229 /* See if there is an available configuration space mapping
230 * register in function 1.
231 */
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200232 if (get_ht_c_index(link) >= 4)
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200233 return;
Marc Jones8ae8c882007-12-19 01:32:08 +0000234
235 /* Set up the primary, secondary and subordinate bus numbers.
236 * We have no idea how many busses are behind this bridge yet,
237 * so we set the subordinate bus number to 0xff for the moment.
238 */
Kyösti Mälkkia9f43272015-02-22 09:24:59 +0200239
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200240 ht_route_link(link, HT_ROUTE_SCAN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000241
242 /* set the config map space */
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200243 set_config_map_reg(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000244
245 /* Now we can scan all of the subordinate busses i.e. the
246 * chain on the hypertranport link
247 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000248
Kyösti Mälkkied7bc2c2015-02-22 08:27:13 +0200249 next_unitid = hypertransport_scan_chain(link);
Kyösti Mälkkib39714e2015-03-12 16:16:59 +0200250
251 /* Now that nothing is overlapping it is safe to scan the children. */
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200252 pci_scan_bus(link, 0x00, ((next_unitid - 1) << 3) | 7);
Marc Jones8ae8c882007-12-19 01:32:08 +0000253
Kyösti Mälkki20968c92015-02-23 12:05:33 +0200254 ht_route_link(link, HT_ROUTE_FINAL);
255
Marc Jones8ae8c882007-12-19 01:32:08 +0000256 /* We know the number of busses behind this bridge. Set the
257 * subordinate bus number to it's real value
258 */
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200259 if (0) {
260 /* Clear the extend reg. */
261 clear_config_map_reg(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000262 }
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200263
264 set_config_map_reg(link);
265
Kyösti Mälkkid383d192015-03-19 16:49:47 +0200266 store_ht_c_conf_bus(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000267}
268
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200269/* Do sb ht chain at first, in case s2885 put sb chain
270 * (8131/8111) on link2, but put 8151 on link0.
271 */
272static void relocate_sb_ht_chain(void)
273{
274 struct device *dev;
275 struct bus *link, *prev = NULL;
276 u8 sblink;
277
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200278 dev = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
279 sblink = (pci_read_config32(dev, 0x64)>>8) & 7;
280 link = dev->link_list;
281
282 while (link) {
283 if (link->link_num == sblink) {
284 if (!prev)
285 return;
286 prev->next = link->next;
287 link->next = dev->link_list;
288 dev->link_list = link;
289 return;
290 }
291 prev = link;
292 link = link->next;
293 }
294}
295
Kyösti Mälkki0a3d4e42015-02-23 00:34:26 +0200296static void trim_ht_chain(struct device *dev)
297{
298 struct bus *link;
299
300 /* Check for connected link. */
301 for (link = dev->link_list; link; link = link->next) {
302 link->cap = 0x80 + (link->link_num * 0x20);
303 link->ht_link_up = ht_is_non_coherent_link(link);
304 }
305}
306
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300307static void amdfam10_scan_chains(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000308{
Myles Watson894a3472010-06-09 22:41:35 +0000309 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000310
Julius Wernercd49cce2019-03-05 16:53:33 -0800311#if CONFIG(CPU_AMD_SOCKET_G34_NON_AGESA)
Timothy Pearson730a0432015-10-16 13:51:51 -0500312 if (is_fam15h()) {
313 uint8_t current_link_number = 0;
314
315 for (link = dev->link_list; link; link = link->next) {
316 /* The following links have changed position in Fam15h G34 processors:
317 * Fam10 Fam15
318 * Node 0
319 * L3 --> L1
320 * L0 --> L3
321 * L1 --> L2
322 * L2 --> L0
323 * Node 1
324 * L0 --> L0
325 * L1 --> L3
326 * L2 --> L1
327 * L3 --> L2
328 */
329 if (link->link_num == 0)
330 link->link_num = 3;
331 else if (link->link_num == 1)
332 link->link_num = 2;
333 else if (link->link_num == 2)
334 link->link_num = 0;
335 else if (link->link_num == 3)
336 link->link_num = 1;
337 else if (link->link_num == 5)
338 link->link_num = 7;
339 else if (link->link_num == 6)
340 link->link_num = 5;
341 else if (link->link_num == 7)
342 link->link_num = 6;
343
344 current_link_number++;
345 if (current_link_number > 3)
346 current_link_number = 0;
347 }
348 }
349#endif
350
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200351 /* 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 +0200352 trim_ht_chain(dev);
353
Kyösti Mälkkife57eeb2015-02-02 20:07:58 +0200354 for (link = dev->link_list; link; link = link->next) {
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500355 if (link->ht_link_up) {
Julius Wernercd49cce2019-03-05 16:53:33 -0800356 if (CONFIG(CPU_AMD_MODEL_10XXX))
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500357 amd_g34_fixup(link, dev);
Kyösti Mälkki09705ab2015-03-21 11:11:58 +0200358 amdfam10_scan_chain(link);
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500359 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000360 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000361}
362
363
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300364static int reg_useable(unsigned reg, struct device *goal_dev, unsigned goal_nodeid,
Myles Watson6507b392010-06-09 22:39:00 +0000365 unsigned goal_link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000366{
367 struct resource *res;
Myles Watson6507b392010-06-09 22:39:00 +0000368 unsigned nodeid, link = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000369 int result;
370 res = 0;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200371 for (nodeid = 0; !res && (nodeid < fx_devs); nodeid++) {
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300372 struct device *dev;
Marc Jones8ae8c882007-12-19 01:32:08 +0000373 dev = __f0_dev[nodeid];
Rudolf Marek3a8565a2009-03-26 21:45:26 +0000374 if (!dev)
375 continue;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200376 for (link = 0; !res && (link < 8); link++) {
Myles Watson29cc9ed2009-07-02 18:56:24 +0000377 res = probe_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000378 }
379 }
380 result = 2;
381 if (res) {
382 result = 0;
383 if ( (goal_link == (link - 1)) &&
384 (goal_nodeid == (nodeid - 1)) &&
385 (res->flags <= 1)) {
386 result = 1;
387 }
388 }
389 return result;
390}
391
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300392static struct resource *amdfam10_find_iopair(struct device *dev, unsigned nodeid, unsigned link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000393{
394 struct resource *resource;
395 u32 free_reg, reg;
396 resource = 0;
397 free_reg = 0;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200398 for (reg = 0xc0; reg <= 0xd8; reg += 0x8) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000399 int result;
400 result = reg_useable(reg, dev, nodeid, link);
401 if (result == 1) {
402 /* I have been allocated this one */
403 break;
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500404 } else if (result > 1) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000405 /* I have a free register pair */
406 free_reg = reg;
407 }
408 }
409 if (reg > 0xd8) {
410 reg = free_reg; // if no free, the free_reg still be 0
411 }
412
413 //Ext conf space
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200414 if (!reg) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000415 //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
416 u32 index = get_io_addr_index(nodeid, link);
417 reg = 0x110+ (index<<24) + (4<<20); // index could be 0, 255
418 }
419
Myles Watson29cc9ed2009-07-02 18:56:24 +0000420 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000421
422 return resource;
423}
424
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300425static struct resource *amdfam10_find_mempair(struct device *dev, u32 nodeid, u32 link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000426{
427 struct resource *resource;
428 u32 free_reg, reg;
429 resource = 0;
430 free_reg = 0;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200431 for (reg = 0x80; reg <= 0xb8; reg += 0x8) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000432 int result;
433 result = reg_useable(reg, dev, nodeid, link);
434 if (result == 1) {
435 /* I have been allocated this one */
436 break;
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500437 } else if (result > 1) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000438 /* I have a free register pair */
439 free_reg = reg;
440 }
441 }
442 if (reg > 0xb8) {
443 reg = free_reg;
444 }
445
446 //Ext conf space
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200447 if (!reg) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000448 //because of Extend conf space, we will never run out of reg,
449 // but we need one index to differ them. so same node and
450 // same link can have multi range
451 u32 index = get_mmio_addr_index(nodeid, link);
452 reg = 0x110+ (index<<24) + (6<<20); // index could be 0, 63
453
454 }
Myles Watson29cc9ed2009-07-02 18:56:24 +0000455 resource = new_resource(dev, IOINDEX(0x1000 + reg, link));
Marc Jones8ae8c882007-12-19 01:32:08 +0000456 return resource;
457}
458
459
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300460static void amdfam10_link_read_bases(struct device *dev, u32 nodeid, u32 link)
Marc Jones8ae8c882007-12-19 01:32:08 +0000461{
462 struct resource *resource;
463
464 /* Initialize the io space constraints on the current bus */
Myles Watson6507b392010-06-09 22:39:00 +0000465 resource = amdfam10_find_iopair(dev, nodeid, link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000466 if (resource) {
467 u32 align;
Kyösti Mälkki45033592014-12-14 08:35:29 +0200468 align = log2(HT_IO_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000469 resource->base = 0;
470 resource->size = 0;
471 resource->align = align;
472 resource->gran = align;
473 resource->limit = 0xffffUL;
Myles Watson280df102009-07-07 13:26:35 +0000474 resource->flags = IORESOURCE_IO | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000475 }
476
477 /* Initialize the prefetchable memory constraints on the current bus */
478 resource = amdfam10_find_mempair(dev, nodeid, link);
479 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000480 resource->base = 0;
481 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000482 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000483 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000484 resource->limit = 0xffffffffffULL;
Myles Watson6507b392010-06-09 22:39:00 +0000485 resource->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
486 resource->flags |= IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000487 }
488
489 /* Initialize the memory constraints on the current bus */
490 resource = amdfam10_find_mempair(dev, nodeid, link);
491 if (resource) {
Myles Watson6507b392010-06-09 22:39:00 +0000492 resource->base = 0;
493 resource->size = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +0000494 resource->align = log2(HT_MEM_HOST_ALIGN);
Myles Watson6507b392010-06-09 22:39:00 +0000495 resource->gran = log2(HT_MEM_HOST_ALIGN);
Marc Jones8ae8c882007-12-19 01:32:08 +0000496 resource->limit = 0xffffffffffULL;
Myles Watson280df102009-07-07 13:26:35 +0000497 resource->flags = IORESOURCE_MEM | IORESOURCE_BRIDGE;
Marc Jones8ae8c882007-12-19 01:32:08 +0000498 }
499}
500
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300501static void amdfam10_read_resources(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000502{
Myles Watson894a3472010-06-09 22:41:35 +0000503 u32 nodeid;
504 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000505 nodeid = amdfam10_nodeid(dev);
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200506 for (link = dev->link_list; link; link = link->next) {
Myles Watson894a3472010-06-09 22:41:35 +0000507 if (link->children) {
508 amdfam10_link_read_bases(dev, nodeid, link->link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000509 }
510 }
511}
512
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300513static void amdfam10_set_resource(struct device *dev, struct resource *resource,
Marc Jones8ae8c882007-12-19 01:32:08 +0000514 u32 nodeid)
515{
516 resource_t rbase, rend;
Myles Watson894a3472010-06-09 22:41:35 +0000517 unsigned reg, link_num;
Marc Jones8ae8c882007-12-19 01:32:08 +0000518 char buf[50];
519
520 /* Make certain the resource has actually been set */
521 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
522 return;
523 }
524
525 /* If I have already stored this resource don't worry about it */
526 if (resource->flags & IORESOURCE_STORED) {
527 return;
528 }
529
530 /* Only handle PCI memory and IO resources */
531 if (!(resource->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
532 return;
533
534 /* Ensure I am actually looking at a resource of function 1 */
535 if ((resource->index & 0xffff) < 0x1000) {
536 return;
537 }
538 /* Get the base address */
539 rbase = resource->base;
540
541 /* Get the limit (rounded up) */
542 rend = resource_end(resource);
543
544 /* Get the register and link */
545 reg = resource->index & 0xfff; // 4k
Myles Watson894a3472010-06-09 22:41:35 +0000546 link_num = IOINDEX_LINK(resource->index);
Marc Jones8ae8c882007-12-19 01:32:08 +0000547
548 if (resource->flags & IORESOURCE_IO) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000549
Myles Watson894a3472010-06-09 22:41:35 +0000550 set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8);
551 store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 24), rbase>>8, rend>>8);
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500552 } else if (resource->flags & IORESOURCE_MEM) {
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200553 set_mmio_addr_reg(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8, sysconf.nodes); // [39:8]
Myles Watson894a3472010-06-09 22:41:35 +0000554 store_conf_mmio_addr(nodeid, link_num, reg, (resource->index >>24), rbase>>8, rend>>8);
Marc Jones8ae8c882007-12-19 01:32:08 +0000555 }
556 resource->flags |= IORESOURCE_STORED;
Elyes HAOUAS0d4b11a2016-10-03 21:57:21 +0200557 snprintf(buf, sizeof(buf), " <node %x link %x>",
Vladimir Serbinenkoa37383d2013-11-26 02:41:26 +0100558 nodeid, link_num);
Marc Jones8ae8c882007-12-19 01:32:08 +0000559 report_resource_stored(dev, resource, buf);
560}
561
562/**
Marc Jones8ae8c882007-12-19 01:32:08 +0000563 * I tried to reuse the resource allocation code in amdfam10_set_resource()
Stefan Reinauerabc0c852010-11-22 08:09:50 +0000564 * but it is too difficult to deal with the resource allocation magic.
Marc Jones8ae8c882007-12-19 01:32:08 +0000565 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000566
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300567static void amdfam10_create_vga_resource(struct device *dev, unsigned nodeid)
Marc Jones8ae8c882007-12-19 01:32:08 +0000568{
Myles Watson894a3472010-06-09 22:41:35 +0000569 struct bus *link;
Timothy Pearson5cac25e2015-08-14 16:31:14 -0500570 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000571
572 /* find out which link the VGA card is connected,
573 * we only deal with the 'first' vga card */
Myles Watson894a3472010-06-09 22:41:35 +0000574 for (link = dev->link_list; link; link = link->next) {
575 if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Julius Wernercd49cce2019-03-05 16:53:33 -0800576#if CONFIG(MULTIPLE_VGA_ADAPTERS)
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300577 extern struct device *vga_pri; // the primary vga device, defined in device.c
Myles Watson894a3472010-06-09 22:41:35 +0000578 printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d bus range [%d,%d]\n", vga_pri->bus->secondary,
579 link->secondary,link->subordinate);
Marc Jones8ae8c882007-12-19 01:32:08 +0000580 /* We need to make sure the vga_pri is under the link */
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600581 if ((vga_pri->bus->secondary >= link->secondary) &&
582 (vga_pri->bus->secondary <= link->subordinate))
Marc Jones8ae8c882007-12-19 01:32:08 +0000583#endif
584 break;
585 }
586 }
587
588 /* no VGA card installed */
Myles Watson894a3472010-06-09 22:41:35 +0000589 if (link == NULL)
Marc Jones8ae8c882007-12-19 01:32:08 +0000590 return;
591
Myles Watson894a3472010-06-09 22:41:35 +0000592 printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, link->link_num);
593 set_vga_enable_reg(nodeid, link->link_num);
Timothy Pearson5cac25e2015-08-14 16:31:14 -0500594
595 /* Redirect VGA memory access to MMIO
596 * This signals the Family 10h resource parser
597 * to add a new MMIO mapping to the Range 11
598 * MMIO control registers (starting at F1x1B8),
599 * and also reserves the resource in the E820 map.
600 */
601 res = new_resource(dev, IOINDEX(0x1000 + 0x1b8, link->link_num));
602 res->base = 0xa0000;
603 res->size = 0x20000;
604 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
605 amdfam10_set_resource(dev, res, nodeid);
Marc Jones8ae8c882007-12-19 01:32:08 +0000606}
607
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300608static void amdfam10_set_resources(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000609{
Myles Watson894a3472010-06-09 22:41:35 +0000610 unsigned nodeid;
611 struct bus *bus;
Myles Watsonc25cc112010-05-21 14:33:48 +0000612 struct resource *res;
Marc Jones8ae8c882007-12-19 01:32:08 +0000613
614 /* Find the nodeid */
615 nodeid = amdfam10_nodeid(dev);
616
617 amdfam10_create_vga_resource(dev, nodeid);
618
619 /* Set each resource we have found */
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200620 for (res = dev->resource_list; res; res = res->next) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000621 amdfam10_set_resource(dev, res, nodeid);
Marc Jones8ae8c882007-12-19 01:32:08 +0000622 }
623
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200624 for (bus = dev->link_list; bus; bus = bus->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000625 if (bus->children) {
626 assign_resources(bus);
627 }
628 }
629}
630
Marc Jones8ae8c882007-12-19 01:32:08 +0000631static void mcf0_control_init(struct device *dev)
632{
633}
634
Julius Wernercd49cce2019-03-05 16:53:33 -0800635#if CONFIG(HAVE_ACPI_TABLES)
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600636static const char *amdfam10_northbridge_acpi_name(const struct device *dev)
Timothy Pearson0f3a18a2017-04-13 17:08:18 -0500637{
638 return "";
639}
640#endif
641
Marc Jones8ae8c882007-12-19 01:32:08 +0000642static struct device_operations northbridge_operations = {
643 .read_resources = amdfam10_read_resources,
644 .set_resources = amdfam10_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +0000645 .enable_resources = pci_dev_enable_resources,
Marc Jones8ae8c882007-12-19 01:32:08 +0000646 .init = mcf0_control_init,
647 .scan_bus = amdfam10_scan_chains,
Julius Wernercd49cce2019-03-05 16:53:33 -0800648#if CONFIG(HAVE_ACPI_TABLES)
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200649 .write_acpi_tables = northbridge_write_acpi_tables,
650 .acpi_fill_ssdt_generator = northbridge_acpi_write_vars,
Timothy Pearson0f3a18a2017-04-13 17:08:18 -0500651 .acpi_name = amdfam10_northbridge_acpi_name,
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200652#endif
Marc Jones8ae8c882007-12-19 01:32:08 +0000653 .enable = 0,
654 .ops_pci = 0,
655};
656
Stefan Reinauer8e96ba22010-03-16 23:33:29 +0000657static const struct pci_driver mcf0_driver __pci_driver = {
Marc Jones8ae8c882007-12-19 01:32:08 +0000658 .ops = &northbridge_operations,
659 .vendor = PCI_VENDOR_ID_AMD,
660 .device = 0x1200,
661};
662
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200663static void amdfam10_nb_init(void *chip_info)
664{
665 relocate_sb_ht_chain();
666}
667
Damien Zammit33aaa922016-02-10 14:01:36 +1100668static const struct pci_driver mcf0_driver_fam15_model10 __pci_driver = {
669 .ops = &northbridge_operations,
670 .vendor = PCI_VENDOR_ID_AMD,
671 .device = 0x1400,
672};
673
Timothy Pearson730a0432015-10-16 13:51:51 -0500674static const struct pci_driver mcf0_driver_fam15 __pci_driver = {
675 .ops = &northbridge_operations,
676 .vendor = PCI_VENDOR_ID_AMD,
677 .device = 0x1600,
678};
679
Marc Jones8ae8c882007-12-19 01:32:08 +0000680struct chip_operations northbridge_amd_amdfam10_ops = {
Timothy Pearson730a0432015-10-16 13:51:51 -0500681 CHIP_NAME("AMD Family 10h/15h Northbridge")
Marc Jones8ae8c882007-12-19 01:32:08 +0000682 .enable_dev = 0,
Kyösti Mälkki98a915e2015-02-21 14:31:01 +0200683 .init = amdfam10_nb_init,
Marc Jones8ae8c882007-12-19 01:32:08 +0000684};
685
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300686static void amdfam10_domain_read_resources(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000687{
Marc Jones8ae8c882007-12-19 01:32:08 +0000688 unsigned reg;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500689 uint8_t nvram;
690 uint8_t enable_cc6;
Marc Jones8ae8c882007-12-19 01:32:08 +0000691
692 /* Find the already assigned resource pairs */
693 get_fx_devs();
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200694 for (reg = 0x80; reg <= 0xd8; reg+= 0x08) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000695 u32 base, limit;
696 base = f1_read_config32(reg);
697 limit = f1_read_config32(reg + 0x04);
698 /* Is this register allocated? */
699 if ((base & 3) != 0) {
Myles Watson362db612010-04-08 15:12:18 +0000700 unsigned nodeid, reg_link;
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300701 struct device *reg_dev;
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600702 if (reg < 0xc0) { // mmio
Marc Jones8ae8c882007-12-19 01:32:08 +0000703 nodeid = (limit & 0xf) + (base&0x30);
704 } else { // io
705 nodeid = (limit & 0xf) + ((base>>4)&0x30);
706 }
Myles Watson6507b392010-06-09 22:39:00 +0000707 reg_link = (limit >> 4) & 7;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000708 reg_dev = __f0_dev[nodeid];
709 if (reg_dev) {
710 /* Reserve the resource */
Myles Watson6507b392010-06-09 22:39:00 +0000711 struct resource *res;
712 res = new_resource(reg_dev, IOINDEX(0x1000 + reg, reg_link));
713 if (res) {
714 res->flags = 1;
Marc Jones8ae8c882007-12-19 01:32:08 +0000715 }
716 }
717 }
718 }
719 /* FIXME: do we need to check extend conf space?
720 I don't believe that much preset value */
721
Myles Watson280df102009-07-07 13:26:35 +0000722 pci_domain_read_resources(dev);
Marc Jones8ae8c882007-12-19 01:32:08 +0000723
Kyösti Mälkki6f66f412016-12-01 22:08:18 +0200724 /* We have MMCONF_SUPPORT, create the resource window. */
Elyes HAOUAS400ce552018-10-12 10:54:30 +0200725 mmconf_resource(dev, MMIO_CONF_BASE);
Timothy Pearsona6f669e2015-01-23 20:20:56 -0600726
Kyösti Mälkki6f66f412016-12-01 22:08:18 +0200727 /* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
728 ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500729
730 if (is_fam15h()) {
731 enable_cc6 = 0;
732 if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
733 enable_cc6 = !!nvram;
734
735 if (enable_cc6) {
736 uint8_t node;
737 uint8_t interleaved;
738 int8_t range;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500739 uint8_t max_node;
740 uint64_t max_range_limit;
741 uint32_t dword;
742 uint32_t dword2;
743 uint64_t qword;
744 uint8_t num_nodes;
745
746 /* Find highest DRAM range (DramLimitAddr) */
Timothy Pearson83abd812015-06-08 19:35:06 -0500747 num_nodes = 0;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500748 max_node = 0;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500749 interleaved = 0;
750 max_range_limit = 0;
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300751 struct device *node_dev;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500752 for (node = 0; node < FX_DEVS; node++) {
753 node_dev = get_node_pci(node, 0);
754 /* Test for node presence */
Timothy Pearson83abd812015-06-08 19:35:06 -0500755 if ((!node_dev) || (pci_read_config32(node_dev, PCI_VENDOR_ID) == 0xffffffff))
756 continue;
757
758 num_nodes++;
759 for (range = 0; range < 8; range++) {
760 dword = pci_read_config32(get_node_pci(node, 1), 0x40 + (range * 0x8));
761 if (!(dword & 0x3))
762 continue;
763
764 if ((dword >> 8) & 0x7)
765 interleaved = 1;
766
767 dword = pci_read_config32(get_node_pci(node, 1), 0x44 + (range * 0x8));
768 dword2 = pci_read_config32(get_node_pci(node, 1), 0x144 + (range * 0x8));
769 qword = 0xffffff;
770 qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24;
771 qword |= (((uint64_t)dword2) & 0xff) << 40;
772
773 if (qword > max_range_limit) {
Timothy Pearson83abd812015-06-08 19:35:06 -0500774 max_range_limit = qword;
775 max_node = dword & 0x7;
776 }
777 }
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500778 }
779
Timothy Pearson83abd812015-06-08 19:35:06 -0500780 /* Calculate CC6 storage area size */
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500781 if (interleaved)
Jacob Garber09c31d52019-06-04 10:30:41 -0600782 qword = (uint64_t)0x1000000 * num_nodes;
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500783 else
784 qword = 0x1000000;
785
Timothy Pearson8528e392015-08-20 15:53:25 -0500786 /* FIXME
787 * The BKDG appears to be incorrect as to the location of the CC6 save region
788 * lower boundary on non-interleaved systems, causing lockups on attempted write
789 * to the CC6 save region.
790 *
791 * For now, work around by allocating the maximum possible CC6 save region size.
792 *
793 * Determine if this is a BKDG error or a setup problem and remove this warning!
794 */
795 qword = (0x1 << 27);
796 max_range_limit = (((uint64_t)(pci_read_config32(get_node_pci(max_node, 1), 0x124) & 0x1fffff)) << 27) - 1;
797
798 printk(BIOS_INFO, "Reserving CC6 save segment base: %08llx size: %08llx\n", (max_range_limit + 1), qword);
799
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500800 /* Reserve the CC6 save segment */
Timothy Pearson83abd812015-06-08 19:35:06 -0500801 reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 10, qword >> 10);
Timothy Pearsoncfb93e72015-06-05 21:13:30 -0500802 }
803 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000804}
805
Uwe Hermann4b42a622010-10-11 19:36:13 +0000806static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
Marc Jones8ae8c882007-12-19 01:32:08 +0000807{
808 struct resource *min;
809 min = 0;
810 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
811 if (min && tolm > min->base) {
812 tolm = min->base;
813 }
814 return tolm;
815}
816
Stefan Reinauer08670622009-06-30 15:17:49 +0000817#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000818
819struct hw_mem_hole_info {
820 unsigned hole_startk;
821 int node_id;
822};
823
824static struct hw_mem_hole_info get_hw_mem_hole_info(void)
825{
826 struct hw_mem_hole_info mem_hole;
827 int i;
828
Stefan Reinauer08670622009-06-30 15:17:49 +0000829 mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
Marc Jones8ae8c882007-12-19 01:32:08 +0000830 mem_hole.node_id = -1;
831
832 for (i = 0; i < sysconf.nodes; i++) {
833 struct dram_base_mask_t d;
834 u32 hole;
835 d = get_dram_base_mask(i);
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200836 if (!(d.mask & 1)) continue; // no memory on this node
Marc Jones8ae8c882007-12-19 01:32:08 +0000837
838 hole = pci_read_config32(__f1_dev[i], 0xf0);
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200839 if (hole & 1) { // we find the hole
Marc Jones8ae8c882007-12-19 01:32:08 +0000840 mem_hole.hole_startk = (hole & (0xff<<24)) >> 10;
841 mem_hole.node_id = i; // record the node No with hole
842 break; // only one hole
843 }
844 }
845
Kyösti Mälkki2f9b3af2014-06-26 05:30:54 +0300846 /* We need to double check if there is special set on base reg and limit reg
847 * are not continuous instead of hole, it will find out its hole_startk.
848 */
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200849 if (mem_hole.node_id==-1) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000850 resource_t limitk_pri = 0;
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600851 for (i = 0; i < sysconf.nodes; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000852 struct dram_base_mask_t d;
853 resource_t base_k, limit_k;
854 d = get_dram_base_mask(i);
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200855 if (!(d.base & 1)) continue;
Marc Jones8ae8c882007-12-19 01:32:08 +0000856
857 base_k = ((resource_t)(d.base & 0x1fffff00)) <<9;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200858 if (base_k > 4 *1024 * 1024) break; // don't need to go to check
859 if (limitk_pri != base_k) { // we find the hole
Marc Jones8ae8c882007-12-19 01:32:08 +0000860 mem_hole.hole_startk = (unsigned)limitk_pri; // must beblow 4G
861 mem_hole.node_id = i;
862 break; //only one hole
863 }
864
865 limit_k = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9;
866 limitk_pri = limit_k;
867 }
868 }
869 return mem_hole;
870}
871
Marc Jones8ae8c882007-12-19 01:32:08 +0000872#endif
873
Rudolf Marek97be27e2010-12-13 19:50:25 +0000874#include <cbmem.h>
Myles Watson6c029e62010-09-13 14:50:20 +0000875
Kyösti Mälkki6b5eb1c2012-07-19 19:26:43 +0300876static void setup_uma_memory(void)
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300877{
Julius Wernercd49cce2019-03-05 16:53:33 -0800878#if CONFIG(GFXUMA)
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300879 uint32_t topmem = (uint32_t) bsp_topmem();
Timothy Pearson49168802015-03-13 12:48:31 -0500880 uma_memory_size = get_uma_memory_size(topmem);
Kyösti Mälkkidbc47392012-08-05 12:11:40 +0300881 uma_memory_base = topmem - uma_memory_size; /* TOP_MEM1 */
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300882 printk(BIOS_INFO, "%s: uma size 0x%08llx, memory start 0x%08llx\n",
883 __func__, uma_memory_size, uma_memory_base);
Kyösti Mälkki231f2612012-07-11 08:02:57 +0300884#endif
885}
886
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300887static void amdfam10_domain_set_resources(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000888{
Marc Jones8ae8c882007-12-19 01:32:08 +0000889 unsigned long mmio_basek;
890 u32 pci_tolm;
891 int i, idx;
Myles Watson894a3472010-06-09 22:41:35 +0000892 struct bus *link;
Stefan Reinauer08670622009-06-30 15:17:49 +0000893#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000894 struct hw_mem_hole_info mem_hole;
Marc Jones8ae8c882007-12-19 01:32:08 +0000895#endif
896
Marc Jones8ae8c882007-12-19 01:32:08 +0000897 pci_tolm = 0xffffffffUL;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200898 for (link = dev->link_list; link; link = link->next) {
Uwe Hermann4b42a622010-10-11 19:36:13 +0000899 pci_tolm = my_find_pci_tolm(link, pci_tolm);
Marc Jones8ae8c882007-12-19 01:32:08 +0000900 }
901
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000902 // FIXME handle interleaved nodes. If you fix this here, please fix
903 // amdk8, too.
Marc Jones8ae8c882007-12-19 01:32:08 +0000904 mmio_basek = pci_tolm >> 10;
905 /* Round mmio_basek to something the processor can support */
906 mmio_basek &= ~((1 << 6) -1);
907
Stefan Reinauer29ceae22010-04-20 11:03:41 +0000908 // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M
909 // MMIO hole. If you fix this here, please fix amdk8, too.
Myles Watson6507b392010-06-09 22:39:00 +0000910 /* Round the mmio hole to 64M */
Marc Jones8ae8c882007-12-19 01:32:08 +0000911 mmio_basek &= ~((64*1024) - 1);
912
Stefan Reinauer08670622009-06-30 15:17:49 +0000913#if CONFIG_HW_MEM_HOLE_SIZEK != 0
Marc Jones8ae8c882007-12-19 01:32:08 +0000914/* if the hw mem hole is already set in raminit stage, here we will compare
915 * mmio_basek and hole_basek. if mmio_basek is bigger that hole_basek and will
916 * use hole_basek as mmio_basek and we don't need to reset hole.
917 * otherwise We reset the hole to the mmio_basek
918 */
919
920 mem_hole = get_hw_mem_hole_info();
921
922 // Use hole_basek as mmio_basek, and we don't need to reset hole anymore
923 if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk)) {
924 mmio_basek = mem_hole.hole_startk;
Marc Jones8ae8c882007-12-19 01:32:08 +0000925 }
926
Marc Jones8ae8c882007-12-19 01:32:08 +0000927#endif
928
929 idx = 0x10;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200930 for (i = 0; i < sysconf.nodes; i++) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000931 struct dram_base_mask_t d;
932 resource_t basek, limitk, sizek; // 4 1T
933 d = get_dram_base_mask(i);
934
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200935 if (!(d.mask & 1)) continue;
Marc Jones8ae8c882007-12-19 01:32:08 +0000936 basek = ((resource_t)(d.base & 0x1fffff00)) << 9; // could overflow, we may lost 6 bit here
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200937 limitk = ((resource_t)((d.mask + 0x00000100) & 0x1fffff00)) << 9;
Marc Jones8ae8c882007-12-19 01:32:08 +0000938 sizek = limitk - basek;
939
940 /* see if we need a hole from 0xa0000 to 0xbffff */
941 if ((basek < ((8*64)+(8*16))) && (sizek > ((8*64)+(16*16)))) {
942 ram_resource(dev, (idx | i), basek, ((8*64)+(8*16)) - basek);
943 idx += 0x10;
944 basek = (8*64)+(16*16);
945 sizek = limitk - ((8*64)+(16*16));
946
947 }
948
Kyösti Mälkki26c65432014-06-26 05:30:54 +0300949 /* split the region to accommodate pci memory space */
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600950 if ((basek < 4*1024*1024) && (limitk > mmio_basek)) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000951 if (basek <= mmio_basek) {
952 unsigned pre_sizek;
953 pre_sizek = mmio_basek - basek;
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600954 if (pre_sizek > 0) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000955 ram_resource(dev, (idx | i), basek, pre_sizek);
956 idx += 0x10;
957 sizek -= pre_sizek;
958 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000959 basek = mmio_basek;
960 }
961 if ((basek + sizek) <= 4*1024*1024) {
962 sizek = 0;
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500963 } else {
Marc Jones8ae8c882007-12-19 01:32:08 +0000964 basek = 4*1024*1024;
965 sizek -= (4*1024*1024 - mmio_basek);
966 }
967 }
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000968
Marc Jones8ae8c882007-12-19 01:32:08 +0000969 ram_resource(dev, (idx | i), basek, sizek);
970 idx += 0x10;
Myles Watson08e0fb82010-03-22 16:33:25 +0000971 printk(BIOS_DEBUG, "%d: mmio_basek=%08lx, basek=%08llx, limitk=%08llx\n",
Stefan Reinauerb5fb0c52009-04-30 13:58:42 +0000972 i, mmio_basek, basek, limitk);
Marc Jones8ae8c882007-12-19 01:32:08 +0000973 }
974
Julius Wernercd49cce2019-03-05 16:53:33 -0800975#if CONFIG(GFXUMA)
Kyösti Mälkki63f8c082012-07-10 13:27:26 +0300976 uma_resource(dev, 7, uma_memory_base >> 10, uma_memory_size >> 10);
Myles Watson6c029e62010-09-13 14:50:20 +0000977#endif
978
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200979 for (link = dev->link_list; link; link = link->next) {
Myles Watson894a3472010-06-09 22:41:35 +0000980 if (link->children) {
981 assign_resources(link);
Marc Jones8ae8c882007-12-19 01:32:08 +0000982 }
983 }
984}
985
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +0300986static void amdfam10_domain_scan_bus(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +0000987{
988 u32 reg;
989 int i;
Myles Watson894a3472010-06-09 22:41:35 +0000990 struct bus *link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000991 /* Unmap all of the HT chains */
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200992 for (reg = 0xe0; reg <= 0xec; reg += 4) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000993 f1_write_config32(reg, 0);
994 }
Marc Jones8ae8c882007-12-19 01:32:08 +0000995
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200996 for (link = dev->link_list; link; link = link->next) {
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200997 link->secondary = dev->bus->subordinate;
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200998 pci_scan_bus(link, PCI_DEVFN(CONFIG_CDB, 0), 0xff);
Kyösti Mälkki6ccf1192015-03-12 05:56:22 +0200999 dev->bus->subordinate = link->subordinate;
Marc Jones8ae8c882007-12-19 01:32:08 +00001000 }
1001
1002 /* Tune the hypertransport transaction for best performance.
1003 * Including enabling relaxed ordering if it is safe.
1004 */
1005 get_fx_devs();
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001006 for (i = 0; i < fx_devs; i++) {
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001007 struct device *f0_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +00001008 f0_dev = __f0_dev[i];
1009 if (f0_dev && f0_dev->enabled) {
1010 u32 httc;
1011 httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
1012 httc &= ~HTTC_RSP_PASS_PW;
Myles Watson894a3472010-06-09 22:41:35 +00001013 if (!dev->link_list->disable_relaxed_ordering) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001014 httc |= HTTC_RSP_PASS_PW;
1015 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001016 printk(BIOS_SPEW, "%s passpw: %s\n",
Marc Jones8ae8c882007-12-19 01:32:08 +00001017 dev_path(dev),
Myles Watson894a3472010-06-09 22:41:35 +00001018 (!dev->link_list->disable_relaxed_ordering)?
Marc Jones8ae8c882007-12-19 01:32:08 +00001019 "enabled":"disabled");
1020 pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
1021 }
1022 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001023}
1024
Julius Wernercd49cce2019-03-05 16:53:33 -08001025#if CONFIG(GENERATE_SMBIOS_TABLES)
Elyes HAOUAS448d9fb2018-05-22 12:51:27 +02001026static int amdfam10_get_smbios_data16(int *count, int handle,
1027 unsigned long *current)
Timothy Pearson6e523a62015-03-27 22:58:45 -05001028{
1029 struct amdmct_memory_info *mem_info;
1030 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
1031 if (mem_info == NULL)
1032 return 0; /* can't find amdmct information in cbmem */
1033
1034 struct device *dev = get_node_pci(0, 0);
1035 struct northbridge_amd_amdfam10_config *config = dev->chip_info;
1036
1037 int node;
1038 int slot;
1039
1040 struct smbios_type16 *t = (struct smbios_type16 *)*current;
1041 int len = sizeof(struct smbios_type16);
1042
1043 memset(t, 0, sizeof(struct smbios_type16));
1044 t->type = SMBIOS_PHYS_MEMORY_ARRAY;
1045 t->handle = handle;
1046 t->length = len - 2;
1047 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
1048 t->use = MEMORY_ARRAY_USE_SYSTEM;
1049 t->memory_error_correction = MEMORY_ARRAY_ECC_NONE;
1050 if ((mem_info->ecc_enabled)
1051 && (mem_info->mct_stat.GStatus & (1 << GSB_ECCDIMMs))
1052 && !(mem_info->mct_stat.GStatus & (1 << GSB_DramECCDis)))
1053 /* Single-bit ECC enabled */
1054 t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT;
1055 t->maximum_capacity = config->maximum_memory_capacity / 1024; /* Convert to kilobytes */
1056 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1057
1058 t->number_of_memory_devices = 0;
1059 /* Check all nodes for installed DIMMs */
1060 for (node = 0; node < MAX_NODES_SUPPORTED; node++)
1061 /* Check all slots for installed DIMMs */
1062 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++)
1063 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot))
1064 /* Found an installed DIMM; increment count */
1065 t->number_of_memory_devices++;
1066
1067 *current += len;
1068 *count += 1;
1069 return len;
1070}
1071
1072static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
1073{
Timothy Pearson730a0432015-10-16 13:51:51 -05001074 if (is_fam15h()) {
Julius Wernercd49cce2019-03-05 16:53:33 -08001075 if (CONFIG(DIMM_DDR3)) {
Timothy Pearson730a0432015-10-16 13:51:51 -05001076 switch (speed) {
1077 case 0x4:
1078 return 333;
1079 case 0x6:
1080 return 400;
1081 case 0xa:
1082 return 533;
1083 case 0xe:
1084 return 667;
1085 case 0x12:
1086 return 800;
1087 case 0x16:
1088 return 933;
1089 default:
1090 return 0;
1091 }
1092 } else {
1093 return 0;
Timothy Pearson160ad6a2015-10-30 18:53:48 -05001094 }
1095 } else {
Julius Wernercd49cce2019-03-05 16:53:33 -08001096 if (CONFIG(DIMM_DDR2)) {
Timothy Pearson730a0432015-10-16 13:51:51 -05001097 switch (speed) {
1098 case 1:
1099 return 200;
1100 case 2:
1101 return 266;
1102 case 3:
1103 return 333;
1104 case 4:
1105 return 400;
1106 case 5:
1107 return 533;
1108 default:
1109 return 0;
1110 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001111 } else if (CONFIG(DIMM_DDR3)) {
Timothy Pearson730a0432015-10-16 13:51:51 -05001112 switch (speed) {
1113 case 3:
1114 return 333;
1115 case 4:
1116 return 400;
1117 case 5:
1118 return 533;
1119 case 6:
1120 return 667;
1121 case 7:
1122 return 800;
1123 default:
1124 return 0;
1125 }
1126 } else {
1127 return 0;
1128 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001129 }
1130}
1131
Elyes HAOUAS448d9fb2018-05-22 12:51:27 +02001132static int amdfam10_get_smbios_data17(int *count, int handle, int parent_handle,
1133 unsigned long *current)
Timothy Pearson6e523a62015-03-27 22:58:45 -05001134{
1135 struct amdmct_memory_info *mem_info;
1136 mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
1137 if (mem_info == NULL)
1138 return 0; /* can't find amdmct information in cbmem */
1139
1140 int single_len;
1141 int len = 0;
1142 int node;
1143 int slot;
1144
1145 /* Check all nodes for installed DIMMs */
1146 for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
1147 /* Get configured RAM bus speed */
1148 uint16_t speed;
1149 speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].Speed);
1150
1151 /* Get maximum RAM bus speed */
1152 uint16_t max_speed;
1153 max_speed = amdmct_mct_speed_enum_to_mhz(mem_info->dct_stat[node].DIMMAutoSpeed);
1154
1155 /* Check all slots for installed DIMMs */
1156 for (slot = 0; slot < MAX_DIMMS_SUPPORTED; slot++) {
1157 if (mem_info->dct_stat[node].DIMMPresent & (1 << slot)) {
1158 /* Found an installed DIMM; populate tables */
1159 struct smbios_type17 *t = (struct smbios_type17 *)*current;
1160 char string_buffer[256];
1161
1162 /* Initialize structure */
1163 memset(t, 0, sizeof(struct smbios_type17));
1164
1165 /* Calculate the total module size in bytes:
1166 * Primary data width * 2^(#rows) * 2^(#cols) * #banks * #ranks
1167 */
1168 uint8_t width, rows, cols, banks, ranks;
Timothy Pearson84da72c2016-05-07 17:26:40 -05001169 uint64_t chip_size;
1170 uint32_t chip_width;
Timothy Pearson6e523a62015-03-27 22:58:45 -05001171 rows = mem_info->dct_stat[node].DimmRows[slot];
1172 cols = mem_info->dct_stat[node].DimmCols[slot];
1173 ranks = mem_info->dct_stat[node].DimmRanks[slot];
1174 banks = mem_info->dct_stat[node].DimmBanks[slot];
Julius Wernercd49cce2019-03-05 16:53:33 -08001175#if CONFIG(DIMM_DDR3)
Timothy Pearson84da72c2016-05-07 17:26:40 -05001176 chip_size = mem_info->dct_stat[node].DimmChipSize[slot];
1177 chip_width = mem_info->dct_stat[node].DimmChipWidth[slot];
1178#else
1179 chip_size = 0;
1180 chip_width = 0;
1181#endif
1182 uint64_t dimm_size_bytes;
Julius Wernercd49cce2019-03-05 16:53:33 -08001183 if (CONFIG(DIMM_DDR3)) {
Timothy Pearson84da72c2016-05-07 17:26:40 -05001184 width = mem_info->dct_stat[node].DimmWidth[slot];
1185 dimm_size_bytes = ((width / chip_width) * chip_size * ranks) / 8;
1186 } else {
1187 width = 8;
1188 dimm_size_bytes = width * (1ULL << rows) * (1ULL << cols) * banks * ranks;
1189 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001190
1191 memset(t, 0, sizeof(struct smbios_type17));
1192 t->type = SMBIOS_MEMORY_DEVICE;
1193 t->handle = handle;
1194 t->phys_memory_array_handle = parent_handle;
1195 t->length = sizeof(struct smbios_type17) - 2;
1196 if (dimm_size_bytes > 0x800000000) {
1197 t->size = 0x7FFF;
Timothy Pearson84da72c2016-05-07 17:26:40 -05001198 t->extended_size = dimm_size_bytes >> 16;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001199 } else {
Timothy Pearson6e523a62015-03-27 22:58:45 -05001200 t->size = dimm_size_bytes / (1024*1024);
1201 t->size &= (~0x8000); /* size specified in megabytes */
1202 }
1203 t->total_width = t->data_width = 64;
1204 if (mem_info->dct_stat[node].DimmECCPresent & (1 << slot))
1205 t->total_width += 8;
1206 t->attributes = 0;
1207 t->attributes |= ranks & 0xf; /* rank number is stored in the lowest 4 bits of the attributes field */
1208 t->form_factor = MEMORY_FORMFACTOR_DIMM;
Timothy Pearson0e545c62015-06-25 15:28:23 -05001209 if (mem_info->dct_stat[node].Dual_Node_Package) {
Elyes HAOUAS0d4b11a2016-10-03 21:57:21 +02001210 snprintf(string_buffer, sizeof(string_buffer), "NODE %d DIMM_%s%d", node >> 1,
Timothy Pearson0e545c62015-06-25 15:28:23 -05001211 (mem_info->dct_stat[node].Internal_Node_ID)?((slot & 0x1)?"D":"C"):((slot & 0x1)?"B":"A"), (slot >> 1) + 1);
1212 } else {
Elyes HAOUAS0d4b11a2016-10-03 21:57:21 +02001213 snprintf(string_buffer, sizeof(string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1);
Timothy Pearson0e545c62015-06-25 15:28:23 -05001214 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001215 t->device_locator = smbios_add_string(t->eos, string_buffer);
Julius Wernercd49cce2019-03-05 16:53:33 -08001216 if (CONFIG(DIMM_DDR2))
Timothy Pearson6e523a62015-03-27 22:58:45 -05001217 t->memory_type = MEMORY_TYPE_DDR2;
Julius Wernercd49cce2019-03-05 16:53:33 -08001218 else if (CONFIG(DIMM_DDR3))
Timothy Pearson6e523a62015-03-27 22:58:45 -05001219 t->memory_type = MEMORY_TYPE_DDR3;
1220 t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS;
1221 if (mem_info->dct_stat[node].DimmRegistered[slot])
1222 t->type_detail |= MEMORY_TYPE_DETAIL_REGISTERED;
1223 else
1224 t->type_detail |= MEMORY_TYPE_DETAIL_UNBUFFERED;
1225 t->speed = max_speed;
1226 t->clock_speed = speed;
1227 smbios_fill_dimm_manufacturer_from_id(mem_info->dct_stat[node].DimmManufacturerID[slot], t);
1228 t->part_number = smbios_add_string(t->eos, mem_info->dct_stat[node].DimmPartNumber[slot]);
1229 if (mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) {
1230 t->serial_number = smbios_add_string(t->eos, "None");
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001231 } else {
Elyes HAOUAS0d4b11a2016-10-03 21:57:21 +02001232 snprintf(string_buffer, sizeof(string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
Timothy Pearson6e523a62015-03-27 22:58:45 -05001233 t->serial_number = smbios_add_string(t->eos, string_buffer);
1234 }
Julius Wernercd49cce2019-03-05 16:53:33 -08001235 if (CONFIG(DIMM_DDR2)) {
Timothy Pearson2a839352015-09-05 18:56:05 -05001236 /* JEDEC specifies 1.8V only, so assume that the memory is configured for 1.8V */
1237 t->minimum_voltage = 1800;
1238 t->maximum_voltage = 1800;
1239 t->configured_voltage = 1800;
Julius Wernercd49cce2019-03-05 16:53:33 -08001240 } else if (CONFIG(DIMM_DDR3)) {
1241#if CONFIG(DIMM_DDR3)
Timothy Pearson2a839352015-09-05 18:56:05 -05001242 /* Find the maximum and minimum supported voltages */
1243 uint8_t supported_voltages = mem_info->dct_stat[node].DimmSupportedVoltages[slot];
Timothy Pearson730a0432015-10-16 13:51:51 -05001244 uint8_t configured_voltage = mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
1245
Timothy Pearson2a839352015-09-05 18:56:05 -05001246 if (supported_voltages & 0x8)
1247 t->minimum_voltage = 1150;
1248 else if (supported_voltages & 0x4)
1249 t->minimum_voltage = 1250;
1250 else if (supported_voltages & 0x2)
1251 t->minimum_voltage = 1350;
1252 else if (supported_voltages & 0x1)
1253 t->minimum_voltage = 1500;
1254
1255 if (supported_voltages & 0x1)
1256 t->maximum_voltage = 1500;
1257 else if (supported_voltages & 0x2)
1258 t->maximum_voltage = 1350;
1259 else if (supported_voltages & 0x4)
1260 t->maximum_voltage = 1250;
1261 else if (supported_voltages & 0x8)
1262 t->maximum_voltage = 1150;
1263
Timothy Pearson730a0432015-10-16 13:51:51 -05001264 if (configured_voltage & 0x8)
1265 t->configured_voltage = 1150;
1266 else if (configured_voltage & 0x4)
1267 t->configured_voltage = 1250;
1268 else if (configured_voltage & 0x2)
1269 t->configured_voltage = 1350;
1270 else if (configured_voltage & 0x1)
1271 t->configured_voltage = 1500;
Timothy Pearson2a839352015-09-05 18:56:05 -05001272#endif
1273 }
Timothy Pearson6e523a62015-03-27 22:58:45 -05001274 t->memory_error_information_handle = 0xFFFE; /* no error information handle available */
1275 single_len = t->length + smbios_string_table_len(t->eos);
1276 len += single_len;
1277 *current += single_len;
1278 handle++;
1279 *count += 1;
1280 }
1281 }
1282 }
1283
1284 return len;
1285}
1286
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001287static int amdfam10_get_smbios_data(struct device *dev, int *handle, unsigned long *current)
Timothy Pearson6e523a62015-03-27 22:58:45 -05001288{
1289 int len;
1290 int count = 0;
1291 len = amdfam10_get_smbios_data16(&count, *handle, current);
1292 len += amdfam10_get_smbios_data17(&count, *handle + 1, *handle, current);
1293 *handle += count;
1294 return len;
1295}
1296#endif
1297
Julius Wernercd49cce2019-03-05 16:53:33 -08001298#if CONFIG(HAVE_ACPI_TABLES)
Aaron Durbinaa090cb2017-09-13 16:01:52 -06001299static const char *amdfam10_domain_acpi_name(const struct device *dev)
Timothy Pearson0f3a18a2017-04-13 17:08:18 -05001300{
1301 if (dev->path.type == DEVICE_PATH_DOMAIN)
1302 return "PCI0";
1303
1304 return NULL;
1305}
1306#endif
1307
Marc Jones8ae8c882007-12-19 01:32:08 +00001308static struct device_operations pci_domain_ops = {
Myles Watson29cc9ed2009-07-02 18:56:24 +00001309 .read_resources = amdfam10_domain_read_resources,
Myles Watson6507b392010-06-09 22:39:00 +00001310 .set_resources = amdfam10_domain_set_resources,
Myles Watson7eac4452010-06-17 16:16:56 +00001311 .enable_resources = NULL,
1312 .init = NULL,
Myles Watson29cc9ed2009-07-02 18:56:24 +00001313 .scan_bus = amdfam10_domain_scan_bus,
Julius Wernercd49cce2019-03-05 16:53:33 -08001314#if CONFIG(HAVE_ACPI_TABLES)
Timothy Pearson0f3a18a2017-04-13 17:08:18 -05001315 .acpi_name = amdfam10_domain_acpi_name,
1316#endif
Julius Wernercd49cce2019-03-05 16:53:33 -08001317#if CONFIG(GENERATE_SMBIOS_TABLES)
Timothy Pearson6e523a62015-03-27 22:58:45 -05001318 .get_smbios_data = amdfam10_get_smbios_data,
1319#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001320};
1321
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001322static void sysconf_init(struct device *dev) // first node
Marc Jones8ae8c882007-12-19 01:32:08 +00001323{
1324 sysconf.sblk = (pci_read_config32(dev, 0x64)>>8) & 7; // don't forget sublink1
1325 sysconf.segbit = 0;
1326 sysconf.ht_c_num = 0;
1327
1328 unsigned ht_c_index;
1329
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -06001330 for (ht_c_index = 0; ht_c_index < 32; ht_c_index++) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001331 sysconf.ht_c_conf_bus[ht_c_index] = 0;
1332 }
1333
1334 sysconf.nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) + 1;
1335#if CONFIG_MAX_PHYSICAL_CPUS > 8
1336 sysconf.nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
1337#endif
1338
1339 sysconf.enabled_apic_ext_id = 0;
1340 sysconf.lift_bsp_apicid = 0;
1341
1342 /* Find the bootstrap processors apicid */
1343 sysconf.bsp_apicid = lapicid();
1344 sysconf.apicid_offset = sysconf.bsp_apicid;
1345
Julius Wernercd49cce2019-03-05 16:53:33 -08001346#if CONFIG(ENABLE_APIC_EXT_ID)
Marc Jones8ae8c882007-12-19 01:32:08 +00001347 if (pci_read_config32(dev, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
1348 {
1349 sysconf.enabled_apic_ext_id = 1;
1350 }
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -06001351 #if (CONFIG_APIC_ID_OFFSET > 0)
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001352 if (sysconf.enabled_apic_ext_id) {
1353 if (sysconf.bsp_apicid == 0) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001354 /* bsp apic id is not changed */
Stefan Reinauer08670622009-06-30 15:17:49 +00001355 sysconf.apicid_offset = CONFIG_APIC_ID_OFFSET;
Marc Jones8ae8c882007-12-19 01:32:08 +00001356 } else {
1357 sysconf.lift_bsp_apicid = 1;
1358 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001359 }
1360 #endif
1361#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001362}
1363
Stefan Reinauer4d6db952015-06-13 11:01:54 +02001364static void remap_bsp_lapic(struct bus *cpu_bus)
1365{
1366 struct device_path cpu_path;
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001367 struct device *cpu;
Stefan Reinauer4d6db952015-06-13 11:01:54 +02001368 u32 bsp_lapic_id = lapicid();
1369
1370 if (bsp_lapic_id) {
1371 cpu_path.type = DEVICE_PATH_APIC;
1372 cpu_path.apic.apic_id = 0;
1373 cpu = find_dev_path(cpu_bus, &cpu_path);
1374 if (cpu)
1375 cpu->path.apic.apic_id = bsp_lapic_id;
1376 }
1377}
1378
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001379static void cpu_bus_scan(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +00001380{
1381 struct bus *cpu_bus;
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001382 struct device *dev_mc;
Myles Watson362db612010-04-08 15:12:18 +00001383#if CONFIG_CBB
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001384 struct device *pci_domain;
Myles Watson362db612010-04-08 15:12:18 +00001385#endif
Timothy Pearson730a0432015-10-16 13:51:51 -05001386 int nvram = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +00001387 int i,j;
1388 int nodes;
1389 unsigned nb_cfg_54;
1390 unsigned siblings;
1391 int cores_found;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +00001392 int disable_siblings;
Timothy Pearson730a0432015-10-16 13:51:51 -05001393 uint8_t disable_cu_siblings = 0;
Marc Jones8ae8c882007-12-19 01:32:08 +00001394 unsigned ApicIdCoreIdSize;
1395
1396 nb_cfg_54 = 0;
1397 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001398 if (ApicIdCoreIdSize) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001399 siblings = (1<<ApicIdCoreIdSize)-1;
1400 } else {
1401 siblings = 3; //quad core
1402 }
1403
Julius Werner5d1f9a02019-03-07 17:07:26 -08001404 disable_siblings = !CONFIG(LOGICAL_CPUS);
Julius Wernercd49cce2019-03-05 16:53:33 -08001405#if CONFIG(LOGICAL_CPUS)
Myles Watson4839e2c2010-04-08 15:06:44 +00001406 get_option(&disable_siblings, "multi_core");
Marc Jones8ae8c882007-12-19 01:32:08 +00001407#endif
1408
Myles Watson6507b392010-06-09 22:39:00 +00001409 // How can I get the nb_cfg_54 of every node's nb_cfg_54 in bsp???
Marc Jones8ae8c882007-12-19 01:32:08 +00001410 nb_cfg_54 = read_nb_cfg_54();
1411
Stefan Reinauer08670622009-06-30 15:17:49 +00001412#if CONFIG_CBB
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001413 dev_mc = pcidev_on_root(CONFIG_CDB, 0); //0x00
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001414 if (dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001415 printk(BIOS_DEBUG, "%s found", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001416 pci_domain = dev_mc->bus->dev;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001417 if (pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001418 printk(BIOS_DEBUG, "\n%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001419 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001420 printk(BIOS_DEBUG, "%s",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001421
1422 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001423 printk(BIOS_DEBUG, " but it is not under pci_domain directly ");
Marc Jones8ae8c882007-12-19 01:32:08 +00001424 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001425 printk(BIOS_DEBUG, "\n");
Marc Jones8ae8c882007-12-19 01:32:08 +00001426 }
Stefan Reinauer08670622009-06-30 15:17:49 +00001427 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001428 if (!dev_mc) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001429 dev_mc = pcidev_on_root(0x18, 0);
Marc Jones8ae8c882007-12-19 01:32:08 +00001430 if (dev_mc && dev_mc->bus) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001431 printk(BIOS_DEBUG, "%s found\n", dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001432 pci_domain = dev_mc->bus->dev;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001433 if (pci_domain && (pci_domain->path.type == DEVICE_PATH_DOMAIN)) {
1434 if ((pci_domain->link_list) && (pci_domain->link_list->children == dev_mc)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001435 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer08670622009-06-30 15:17:49 +00001436 dev_mc->bus->secondary = CONFIG_CBB; // move to 0xff
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001437 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -06001438 while (dev_mc) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001439 printk(BIOS_DEBUG, "%s move to ",dev_path(dev_mc));
Stefan Reinauer2b34db82009-02-28 20:10:20 +00001440 dev_mc->path.pci.devfn -= PCI_DEVFN(0x18,0);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001441 printk(BIOS_DEBUG, "%s\n",dev_path(dev_mc));
Marc Jones8ae8c882007-12-19 01:32:08 +00001442 dev_mc = dev_mc->sibling;
1443 }
1444 }
1445 }
1446 }
1447 }
1448
1449#endif
1450
Stefan Reinauer08670622009-06-30 15:17:49 +00001451 dev_mc = dev_find_slot(CONFIG_CBB, PCI_DEVFN(CONFIG_CDB, 0));
Marc Jones8ae8c882007-12-19 01:32:08 +00001452 if (!dev_mc) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +00001453 printk(BIOS_ERR, "%02x:%02x.0 not found", CONFIG_CBB, CONFIG_CDB);
Marc Jones8ae8c882007-12-19 01:32:08 +00001454 die("");
1455 }
1456
1457 sysconf_init(dev_mc);
1458
1459 nodes = sysconf.nodes;
1460
Stefan Reinauer08670622009-06-30 15:17:49 +00001461#if CONFIG_CBB && (NODE_NUMS > 32)
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -06001462 if (nodes > 32) { // need to put node 32 to node 63 to bus 0xfe
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001463 if (pci_domain->link_list && !pci_domain->link_list->next) {
Myles Watson894a3472010-06-09 22:41:35 +00001464 struct bus *new_link = new_link(pci_domain);
1465 pci_domain->link_list->next = new_link;
1466 new_link->link_num = 1;
1467 new_link->dev = pci_domain;
1468 new_link->children = 0;
1469 printk(BIOS_DEBUG, "%s links now 2\n", dev_path(pci_domain));
Marc Jones8ae8c882007-12-19 01:32:08 +00001470 }
Myles Watson894a3472010-06-09 22:41:35 +00001471 pci_domain->link_list->next->secondary = CONFIG_CBB - 1;
Marc Jones8ae8c882007-12-19 01:32:08 +00001472 }
1473#endif
1474 /* Find which cpus are present */
Myles Watson894a3472010-06-09 22:41:35 +00001475 cpu_bus = dev->link_list;
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001476
1477 /* Always use the devicetree node with lapic_id 0 for BSP. */
1478 remap_bsp_lapic(cpu_bus);
1479
Timothy Pearson730a0432015-10-16 13:51:51 -05001480 if (get_option(&nvram, "compute_unit_siblings") == CB_SUCCESS)
1481 disable_cu_siblings = !!nvram;
1482
1483 if (disable_cu_siblings)
1484 printk(BIOS_DEBUG, "Disabling siblings on each compute unit as requested\n");
1485
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001486 for (i = 0; i < nodes; i++) {
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001487 struct device *cdb_dev;
Marc Jones8ae8c882007-12-19 01:32:08 +00001488 unsigned busn, devn;
1489 struct bus *pbus;
1490
Timothy Pearson730a0432015-10-16 13:51:51 -05001491 uint8_t fam15h = 0;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001492 uint8_t rev_gte_d = 0;
1493 uint8_t dual_node = 0;
1494 uint32_t f3xe8;
Timothy Pearson730a0432015-10-16 13:51:51 -05001495 uint32_t model;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001496
Stefan Reinauer08670622009-06-30 15:17:49 +00001497 busn = CONFIG_CBB;
1498 devn = CONFIG_CDB+i;
Marc Jones8ae8c882007-12-19 01:32:08 +00001499 pbus = dev_mc->bus;
Stefan Reinauer08670622009-06-30 15:17:49 +00001500#if CONFIG_CBB && (NODE_NUMS > 32)
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -06001501 if (i >= 32) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001502 busn--;
1503 devn-=32;
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001504 pbus = pci_domain->link_list->next;
Marc Jones8ae8c882007-12-19 01:32:08 +00001505 }
1506#endif
1507
1508 /* Find the cpu's pci device */
Myles Watson362db612010-04-08 15:12:18 +00001509 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1510 if (!cdb_dev) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001511 /* If I am probing things in a weird order
1512 * ensure all of the cpu's pci devices are found.
1513 */
Myles Watson362db612010-04-08 15:12:18 +00001514 int fn;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001515 for (fn = 0; fn <= 5; fn++) { //FBDIMM?
Myles Watson362db612010-04-08 15:12:18 +00001516 cdb_dev = pci_probe_dev(NULL, pbus,
1517 PCI_DEVFN(devn, fn));
Marc Jones8ae8c882007-12-19 01:32:08 +00001518 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001519 }
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001520
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001521
Kyösti Mälkki59d60922015-02-21 23:56:07 +02001522 /* Ok, We need to set the links for that device.
1523 * otherwise the device under it will not be scanned
1524 */
1525 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 0));
1526 if (cdb_dev)
1527 add_more_links(cdb_dev, 4);
1528
1529 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 4));
1530 if (cdb_dev)
1531 add_more_links(cdb_dev, 4);
Marc Jones8ae8c882007-12-19 01:32:08 +00001532
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001533 f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
1534
Elyes HAOUAS44245692019-05-25 20:33:03 +02001535 model = cpuid_eax(0x80000001);
Timothy Pearson730a0432015-10-16 13:51:51 -05001536 model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
1537
1538 if (is_fam15h()) {
1539 /* Family 15h or later */
1540 fam15h = 1;
1541 nb_cfg_54 = 1;
1542 }
1543
1544 if ((model >= 0x8) || fam15h)
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001545 /* Revision D or later */
1546 rev_gte_d = 1;
1547
1548 if (rev_gte_d)
1549 /* Check for dual node capability */
1550 if (f3xe8 & 0x20000000)
1551 dual_node = 1;
1552
Marc Jones8ae8c882007-12-19 01:32:08 +00001553 cores_found = 0; // one core
Timothy Pearson730a0432015-10-16 13:51:51 -05001554 if (fam15h)
1555 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 5));
1556 else
1557 cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001558 int enable_node = cdb_dev && cdb_dev->enabled;
1559 if (enable_node) {
Timothy Pearson730a0432015-10-16 13:51:51 -05001560 if (fam15h) {
1561 cores_found = pci_read_config32(cdb_dev, 0x84) & 0xff;
1562 } else {
1563 j = pci_read_config32(cdb_dev, 0xe8);
1564 cores_found = (j >> 12) & 3; // dev is func 3
1565 if (siblings > 3)
1566 cores_found |= (j >> 13) & 4;
1567 }
Myles Watson362db612010-04-08 15:12:18 +00001568 printk(BIOS_DEBUG, " %s siblings=%d\n", dev_path(cdb_dev), cores_found);
Marc Jones8ae8c882007-12-19 01:32:08 +00001569 }
1570
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001571 if (siblings > cores_found)
1572 siblings = cores_found;
1573
Marc Jones8ae8c882007-12-19 01:32:08 +00001574 u32 jj;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001575 if (disable_siblings) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001576 jj = 0;
1577 } else
1578 {
1579 jj = cores_found;
1580 }
1581
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -06001582 for (j = 0; j <=jj; j++) {
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001583 u32 apic_id;
1584
1585 if (dual_node) {
1586 apic_id = 0;
Timothy Pearson730a0432015-10-16 13:51:51 -05001587 if (fam15h) {
1588 apic_id |= ((i >> 1) & 0x3) << 5; /* Node ID */
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001589 apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
1590 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001591 if (nb_cfg_54) {
1592 apic_id |= ((i >> 1) & 0x3) << 4; /* Node ID */
1593 apic_id |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */
1594 } else {
1595 apic_id |= i & 0x3; /* Node ID */
1596 apic_id |= (((i & 0x1) * (siblings + 1)) + j) << 4; /* Core ID */
1597 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001598 }
1599 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -05001600 if (fam15h) {
Timothy Pearson71f86412015-11-24 14:11:53 -06001601 apic_id = 0;
1602 apic_id |= (i & 0x7) << 4; /* Node ID */
1603 apic_id |= j & 0xf; /* Core ID */
Timothy Pearson730a0432015-10-16 13:51:51 -05001604 } else {
1605 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
1606 }
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001607 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001608
Julius Wernercd49cce2019-03-05 16:53:33 -08001609#if CONFIG(ENABLE_APIC_EXT_ID) && (CONFIG_APIC_ID_OFFSET > 0)
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +02001610 if (sysconf.enabled_apic_ext_id) {
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001611 if (apic_id != 0 || sysconf.lift_bsp_apicid) {
1612 apic_id += sysconf.apicid_offset;
Marc Jones8ae8c882007-12-19 01:32:08 +00001613 }
1614 }
Kyösti Mälkkicd9fc1a2012-07-06 19:02:56 +03001615#endif
Timothy Pearson730a0432015-10-16 13:51:51 -05001616 if (disable_cu_siblings && (j & 0x1))
1617 continue;
1618
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001619 struct device *cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
Kyösti Mälkkic33f1e92012-08-07 17:12:11 +03001620 if (cpu)
1621 amd_cpu_topology(cpu, i, j);
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001622 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001623 }
Marc Jones8ae8c882007-12-19 01:32:08 +00001624}
1625
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001626static void detect_and_enable_probe_filter(struct device *dev)
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001627{
1628 uint32_t dword;
1629
Timothy Pearson68130f52015-08-09 02:47:51 -05001630 uint8_t nvram;
1631 uint8_t enable_probe_filter;
1632
1633 /* Check to see if the probe filter is allowed */
1634 enable_probe_filter = 1;
1635 if (get_option(&nvram, "probe_filter") == CB_SUCCESS)
1636 enable_probe_filter = !!nvram;
1637
1638 if (!enable_probe_filter)
1639 return;
1640
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001641 uint8_t fam15h = 0;
1642 uint8_t rev_gte_d = 0;
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001643 uint32_t model;
1644
Elyes HAOUAS44245692019-05-25 20:33:03 +02001645 model = cpuid_eax(0x80000001);
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001646 model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
1647
1648 if (is_fam15h()) {
1649 /* Family 15h or later */
1650 fam15h = 1;
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001651 }
1652
1653 if ((model >= 0x8) || fam15h)
1654 /* Revision D or later */
1655 rev_gte_d = 1;
1656
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001657 if (rev_gte_d && (sysconf.nodes > 1)) {
1658 /* Enable the probe filter */
1659 uint8_t i;
1660 uint8_t pfmode = 0x0;
1661
1662 uint32_t f3x58[MAX_NODES_SUPPORTED];
1663 uint32_t f3x5c[MAX_NODES_SUPPORTED];
1664
1665 printk(BIOS_DEBUG, "Enabling probe filter\n");
1666
1667 /* Disable L3 and DRAM scrubbers and configure system for probe filter support */
1668 for (i = 0; i < sysconf.nodes; i++) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001669 struct device *f2x_dev = pcidev_on_root(0x18 + i, 2);
1670 struct device *f3x_dev = pcidev_on_root(0x18 + i, 3);
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001671
1672 f3x58[i] = pci_read_config32(f3x_dev, 0x58);
1673 f3x5c[i] = pci_read_config32(f3x_dev, 0x5c);
1674 pci_write_config32(f3x_dev, 0x58, f3x58[i] & ~((0x1f << 24) | 0x1f));
1675 pci_write_config32(f3x_dev, 0x5c, f3x5c[i] & ~0x1);
1676
1677 dword = pci_read_config32(f2x_dev, 0x1b0);
1678 dword &= ~(0x7 << 8); /* CohPrefPrbLmt = 0x0 */
1679 pci_write_config32(f2x_dev, 0x1b0, dword);
1680
1681 msr_t msr = rdmsr_amd(BU_CFG2_MSR);
1682 msr.hi |= 1 << (42 - 32);
1683 wrmsr_amd(BU_CFG2_MSR, msr);
1684
1685 if (is_fam15h()) {
1686 uint8_t subcache_size = 0x0;
1687 uint8_t pref_so_repl = 0x0;
1688 uint32_t f3x1c4 = pci_read_config32(f3x_dev, 0x1c4);
1689 if ((f3x1c4 & 0xffff) == 0xcccc) {
1690 subcache_size = 0x1;
1691 pref_so_repl = 0x2;
1692 pfmode = 0x3;
1693 } else {
1694 pfmode = 0x2;
1695 }
1696
1697 dword = pci_read_config32(f3x_dev, 0x1d4);
1698 dword |= 0x1 << 29; /* PFLoIndexHashEn = 0x1 */
1699 dword &= ~(0x3 << 20); /* PFPreferredSORepl = pref_so_repl */
1700 dword |= (pref_so_repl & 0x3) << 20;
1701 dword |= 0x1 << 17; /* PFWayHashEn = 0x1 */
1702 dword |= 0xf << 12; /* PFSubCacheEn = 0xf */
1703 dword &= ~(0x3 << 10); /* PFSubCacheSize3 = subcache_size */
1704 dword |= (subcache_size & 0x3) << 10;
1705 dword &= ~(0x3 << 8); /* PFSubCacheSize2 = subcache_size */
1706 dword |= (subcache_size & 0x3) << 8;
1707 dword &= ~(0x3 << 6); /* PFSubCacheSize1 = subcache_size */
1708 dword |= (subcache_size & 0x3) << 6;
1709 dword &= ~(0x3 << 4); /* PFSubCacheSize0 = subcache_size */
1710 dword |= (subcache_size & 0x3) << 4;
1711 dword &= ~(0x3 << 2); /* PFWayNum = 0x2 */
1712 dword |= 0x2 << 2;
1713 pci_write_config32(f3x_dev, 0x1d4, dword);
1714 } else {
1715 pfmode = 0x2;
1716
1717 dword = pci_read_config32(f3x_dev, 0x1d4);
1718 dword |= 0x1 << 29; /* PFLoIndexHashEn = 0x1 */
1719 dword &= ~(0x3 << 20); /* PFPreferredSORepl = 0x2 */
1720 dword |= 0x2 << 20;
1721 dword |= 0xf << 12; /* PFSubCacheEn = 0xf */
1722 dword &= ~(0x3 << 10); /* PFSubCacheSize3 = 0x0 */
1723 dword &= ~(0x3 << 8); /* PFSubCacheSize2 = 0x0 */
1724 dword &= ~(0x3 << 6); /* PFSubCacheSize1 = 0x0 */
1725 dword &= ~(0x3 << 4); /* PFSubCacheSize0 = 0x0 */
1726 dword &= ~(0x3 << 2); /* PFWayNum = 0x2 */
1727 dword |= 0x2 << 2;
1728 pci_write_config32(f3x_dev, 0x1d4, dword);
1729 }
1730 }
1731
1732 udelay(40);
1733
1734 disable_cache();
1735 wbinvd();
Timothy Pearson4dc6cab2015-08-07 19:06:09 -05001736
1737 /* Enable probe filter */
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001738 for (i = 0; i < sysconf.nodes; i++) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001739 struct device *f3x_dev = pcidev_on_root(0x18 + i, 3);
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001740
1741 dword = pci_read_config32(f3x_dev, 0x1c4);
1742 dword |= (0x1 << 31); /* L3TagInit = 1 */
1743 pci_write_config32(f3x_dev, 0x1c4, dword);
1744 do {
1745 } while (pci_read_config32(f3x_dev, 0x1c4) & (0x1 << 31));
1746
1747 dword = pci_read_config32(f3x_dev, 0x1d4);
1748 dword &= ~0x3; /* PFMode = pfmode */
1749 dword |= pfmode & 0x3;
1750 pci_write_config32(f3x_dev, 0x1d4, dword);
1751 do {
1752 } while (!(pci_read_config32(f3x_dev, 0x1d4) & (0x1 << 19)));
1753 }
Timothy Pearson4dc6cab2015-08-07 19:06:09 -05001754
1755 if (is_fam15h()) {
1756 printk(BIOS_DEBUG, "Enabling ATM mode\n");
1757
1758 /* Enable ATM mode */
1759 for (i = 0; i < sysconf.nodes; i++) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001760 struct device *f0x_dev =
1761 pcidev_on_root(0x18 + i, 0);
1762 struct device *f3x_dev =
1763 pcidev_on_root(0x18 + i, 3);
Timothy Pearson4dc6cab2015-08-07 19:06:09 -05001764
1765 dword = pci_read_config32(f0x_dev, 0x68);
1766 dword |= (0x1 << 12); /* ATMModeEn = 1 */
1767 pci_write_config32(f0x_dev, 0x68, dword);
1768
1769 dword = pci_read_config32(f3x_dev, 0x1b8);
1770 dword |= (0x1 << 27); /* L3ATMModeEn = 1 */
1771 pci_write_config32(f3x_dev, 0x1b8, dword);
1772 }
1773 }
1774
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001775 enable_cache();
1776
1777 /* Reenable L3 and DRAM scrubbers */
1778 for (i = 0; i < sysconf.nodes; i++) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001779 struct device *f3x_dev = pcidev_on_root(0x18 + i, 3);
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001780
1781 pci_write_config32(f3x_dev, 0x58, f3x58[i]);
1782 pci_write_config32(f3x_dev, 0x5c, f3x5c[i]);
1783 }
1784
1785 }
1786}
1787
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001788static void detect_and_enable_cache_partitioning(struct device *dev)
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001789{
1790 uint8_t i;
1791 uint32_t dword;
1792
Timothy Pearson68130f52015-08-09 02:47:51 -05001793 uint8_t nvram;
1794 uint8_t enable_l3_cache_partitioning;
1795
1796 /* Check to see if cache partitioning is allowed */
1797 enable_l3_cache_partitioning = 0;
1798 if (get_option(&nvram, "l3_cache_partitioning") == CB_SUCCESS)
1799 enable_l3_cache_partitioning = !!nvram;
1800
1801 if (!enable_l3_cache_partitioning)
1802 return;
1803
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001804 if (is_fam15h()) {
1805 printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n");
1806
1807 uint32_t f5x80;
1808 uint8_t cu_enabled;
1809 uint8_t compute_unit_count = 0;
1810
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001811 for (i = 0; i < sysconf.nodes; i++) {
Kyösti Mälkkic70eed12018-05-22 02:18:00 +03001812 struct device *f3x_dev = pcidev_on_root(0x18 + i, 3);
1813 struct device *f4x_dev = pcidev_on_root(0x18 + i, 4);
1814 struct device *f5x_dev = pcidev_on_root(0x18 + i, 5);
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001815
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001816 /* Determine the number of active compute units on this node */
1817 f5x80 = pci_read_config32(f5x_dev, 0x80);
1818 cu_enabled = f5x80 & 0xf;
1819 if (cu_enabled == 0x1)
1820 compute_unit_count = 1;
1821 if (cu_enabled == 0x3)
1822 compute_unit_count = 2;
1823 if (cu_enabled == 0x7)
1824 compute_unit_count = 3;
1825 if (cu_enabled == 0xf)
1826 compute_unit_count = 4;
1827
1828 /* Disable BAN mode */
1829 dword = pci_read_config32(f3x_dev, 0x1b8);
1830 dword &= ~(0x7 << 19); /* L3BanMode = 0x0 */
1831 pci_write_config32(f3x_dev, 0x1b8, dword);
1832
1833 /* Set up cache mapping */
1834 dword = pci_read_config32(f4x_dev, 0x1d4);
1835 if (compute_unit_count == 1) {
1836 dword |= 0xf; /* ComputeUnit0SubCacheEn = 0xf */
1837 }
1838 if (compute_unit_count == 2) {
1839 dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0xc */
1840 dword |= (0xc << 4);
1841 dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */
1842 dword |= 0x3;
1843 }
1844 if (compute_unit_count == 3) {
1845 dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x8 */
1846 dword |= (0x8 << 8);
1847 dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x4 */
1848 dword |= (0x4 << 4);
1849 dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */
1850 dword |= 0x3;
1851 }
1852 if (compute_unit_count == 4) {
1853 dword &= ~(0xf << 12); /* ComputeUnit3SubCacheEn = 0x8 */
1854 dword |= (0x8 << 12);
1855 dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x4 */
1856 dword |= (0x4 << 8);
1857 dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x2 */
1858 dword |= (0x2 << 4);
1859 dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x1 */
1860 dword |= 0x1;
1861 }
1862 pci_write_config32(f4x_dev, 0x1d4, dword);
1863
1864 /* Enable cache partitioning */
1865 pci_write_config32(f4x_dev, 0x1d4, dword);
1866 if (compute_unit_count == 1) {
1867 dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x1 */
1868 dword |= (0x1 << 26);
1869 } else if (compute_unit_count == 2) {
1870 dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x3 */
1871 dword |= (0x3 << 26);
1872 } else if (compute_unit_count == 3) {
1873 dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x7 */
1874 dword |= (0x7 << 26);
1875 } else if (compute_unit_count == 4) {
1876 dword |= (0xf << 26); /* MaskUpdateForComputeUnit = 0xf */
1877 }
1878 pci_write_config32(f4x_dev, 0x1d4, dword);
1879 }
1880 }
1881}
1882
Kyösti Mälkki5b3bf4a2018-05-21 22:20:53 +03001883static void cpu_bus_init(struct device *dev)
Marc Jones8ae8c882007-12-19 01:32:08 +00001884{
Timothy Pearson0f1553b2015-08-02 21:06:39 -05001885 detect_and_enable_probe_filter(dev);
Timothy Pearson5a0375a2015-08-08 20:29:27 -05001886 detect_and_enable_cache_partitioning(dev);
Myles Watson894a3472010-06-09 22:41:35 +00001887 initialize_cpus(dev->link_list);
Marc Jones8ae8c882007-12-19 01:32:08 +00001888}
1889
Marc Jones8ae8c882007-12-19 01:32:08 +00001890static struct device_operations cpu_bus_ops = {
Edward O'Callaghan2837ab22014-11-06 08:57:40 +11001891 .read_resources = DEVICE_NOOP,
Kyösti Mälkki48f82a92016-12-02 16:02:30 +02001892 .set_resources = DEVICE_NOOP,
Edward O'Callaghan812d2a42014-10-31 08:17:23 +11001893 .enable_resources = DEVICE_NOOP,
Marc Jones8ae8c882007-12-19 01:32:08 +00001894 .init = cpu_bus_init,
1895 .scan_bus = cpu_bus_scan,
1896};
1897
Marc Jones8ae8c882007-12-19 01:32:08 +00001898static void root_complex_enable_dev(struct device *dev)
1899{
Kyösti Mälkki87213b62012-08-27 20:00:33 +03001900 static int done = 0;
1901
1902 /* Do not delay UMA setup, as a device on the PCI bus may evaluate
1903 the global uma_memory variables already in its enable function. */
1904 if (!done) {
1905 setup_bsp_ramtop();
1906 setup_uma_memory();
1907 done = 1;
1908 }
1909
Marc Jones8ae8c882007-12-19 01:32:08 +00001910 /* Set the operations if it is a special bus type */
Stefan Reinauer4aff4452013-02-12 14:17:15 -08001911 if (dev->path.type == DEVICE_PATH_DOMAIN) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001912 dev->ops = &pci_domain_ops;
Timothy Pearson1c4508e2015-09-05 17:50:29 -05001913 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
Marc Jones8ae8c882007-12-19 01:32:08 +00001914 dev->ops = &cpu_bus_ops;
1915 }
1916}
1917
Timothy Pearson54e05512016-04-09 21:47:18 -05001918static void root_complex_finalize(void *chip_info) {
Julius Wernercd49cce2019-03-05 16:53:33 -08001919#if CONFIG(HAVE_ACPI_RESUME) && CONFIG(DIMM_DDR3)
Timothy Pearson54e05512016-04-09 21:47:18 -05001920 save_mct_information_to_nvram();
1921#endif
1922}
1923
Marc Jones8ae8c882007-12-19 01:32:08 +00001924struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
Timothy Pearson730a0432015-10-16 13:51:51 -05001925 CHIP_NAME("AMD Family 10h/15h Root Complex")
Marc Jones8ae8c882007-12-19 01:32:08 +00001926 .enable_dev = root_complex_enable_dev,
Timothy Pearson54e05512016-04-09 21:47:18 -05001927 .final = root_complex_finalize,
Marc Jones8ae8c882007-12-19 01:32:08 +00001928};