blob: 250c49105a7eac09743c49a67227f9be9f4ac088 [file] [log] [blame]
Angel Pons4b429832020-04-02 23:48:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Siyuan Wang3e32cc02013-07-09 17:16:20 +08002
3#include <console/console.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02004#include <device/pci_ops.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07005#include <acpi/acpi.h>
6#include <acpi/acpigen.h>
Siyuan Wang3e32cc02013-07-09 17:16:20 +08007#include <stdint.h>
8#include <device/device.h>
9#include <device/pci.h>
10#include <device/pci_ids.h>
Siyuan Wang3e32cc02013-07-09 17:16:20 +080011#include <string.h>
12#include <lib.h>
13#include <cpu/cpu.h>
Siyuan Wang3e32cc02013-07-09 17:16:20 +080014#include <cpu/x86/lapic.h>
Elyes HAOUAS400ce552018-10-12 10:54:30 +020015#include <cpu/amd/msr.h>
Siyuan Wang3e32cc02013-07-09 17:16:20 +080016#include <cpu/amd/mtrr.h>
Siyuan Wang3e32cc02013-07-09 17:16:20 +080017#include <Porting.h>
18#include <AGESA.h>
19#include <Options.h>
20#include <Topology.h>
Angel Ponsec5cf152020-11-10 20:42:07 +010021#include <northbridge/amd/nb_common.h>
Kyösti Mälkki28c4d2f2016-11-25 11:21:02 +020022#include <northbridge/amd/agesa/state_machine.h>
Kyösti Mälkkid610c582017-03-05 06:28:18 +020023#include <northbridge/amd/agesa/agesa_helper.h>
Siyuan Wang3e32cc02013-07-09 17:16:20 +080024
Kyösti Mälkki113f6702018-05-20 20:12:32 +030025#define MAX_NODE_NUMS MAX_NODES
Siyuan Wang3e32cc02013-07-09 17:16:20 +080026
Subrata Banikb1434fc2019-03-15 22:20:41 +053027static unsigned int node_nums;
28static unsigned int sblink;
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +030029static struct device *__f0_dev[MAX_NODE_NUMS];
30static struct device *__f1_dev[MAX_NODE_NUMS];
31static struct device *__f2_dev[MAX_NODE_NUMS];
32static struct device *__f4_dev[MAX_NODE_NUMS];
Subrata Banikb1434fc2019-03-15 22:20:41 +053033static unsigned int fx_devs = 0;
Siyuan Wang3e32cc02013-07-09 17:16:20 +080034
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +030035static struct device *get_node_pci(u32 nodeid, u32 fn)
Siyuan Wang3e32cc02013-07-09 17:16:20 +080036{
Kyösti Mälkki3d3152e2019-01-10 09:05:30 +020037 return pcidev_on_root(DEV_CDB + nodeid, fn);
Siyuan Wang3e32cc02013-07-09 17:16:20 +080038}
39
40static void get_fx_devs(void)
41{
42 int i;
43 for (i = 0; i < MAX_NODE_NUMS; i++) {
44 __f0_dev[i] = get_node_pci(i, 0);
45 __f1_dev[i] = get_node_pci(i, 1);
46 __f2_dev[i] = get_node_pci(i, 2);
47 __f4_dev[i] = get_node_pci(i, 4);
48 if (__f0_dev[i] != NULL && __f1_dev[i] != NULL)
Elyes Haouas3adfde92022-07-16 09:36:01 +020049 fx_devs = i + 1;
Siyuan Wang3e32cc02013-07-09 17:16:20 +080050 }
51 if (__f1_dev[0] == NULL || __f0_dev[0] == NULL || fx_devs == 0) {
52 die("Cannot find 0:0x18.[0|1]\n");
53 }
54 printk(BIOS_DEBUG, "fx_devs=0x%x\n", fx_devs);
55}
56
Subrata Banikb1434fc2019-03-15 22:20:41 +053057static u32 f1_read_config32(unsigned int reg)
Siyuan Wang3e32cc02013-07-09 17:16:20 +080058{
59 if (fx_devs == 0)
60 get_fx_devs();
61 return pci_read_config32(__f1_dev[0], reg);
62}
63
Subrata Banikb1434fc2019-03-15 22:20:41 +053064static void f1_write_config32(unsigned int reg, u32 value)
Siyuan Wang3e32cc02013-07-09 17:16:20 +080065{
66 int i;
67 if (fx_devs == 0)
68 get_fx_devs();
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +020069 for (i = 0; i < fx_devs; i++) {
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +030070 struct device *dev;
Siyuan Wang3e32cc02013-07-09 17:16:20 +080071 dev = __f1_dev[i];
72 if (dev && dev->enabled) {
73 pci_write_config32(dev, reg, value);
74 }
75 }
76}
77
Michał Żygowski88a0ce62021-05-05 09:52:59 +020078static int get_dram_base_limit(u32 nodeid, resource_t *basek, resource_t *limitk)
79{
80 u32 temp;
81
82 if (fx_devs == 0)
83 get_fx_devs();
84
85
86 temp = pci_read_config32(__f1_dev[nodeid], 0x40 + (nodeid << 3)); //[39:24] at [31:16]
87 if (!(temp & 1))
88 return 0; // this memory range is not enabled
89 /*
90 * BKDG: {DramBase[39:24], 00_0000h} <= address[39:0] so shift left by 8 bits
91 * for physical address and the convert to KiB by shifting 10 bits left
92 */
93 *basek = ((temp & 0xffff0000)) >> (10 - 8);
94 /*
95 * BKDG address[39:0] <= {DramLimit[39:24], FF_FFFFh} converted as above but
96 * ORed with 0xffff to get real limit before shifting.
97 */
98 temp = pci_read_config32(__f1_dev[nodeid], 0x44 + (nodeid << 3)); //[39:24] at [31:16]
99 *limitk = ((temp & 0xffff0000) | 0xffff) >> (10 - 8);
100 *limitk += 1; // round up last byte
101
102 return 1;
103}
104
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300105static u32 amdfam16_nodeid(struct device *dev)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800106{
Kyösti Mälkki3d3152e2019-01-10 09:05:30 +0200107 return (dev->path.pci.devfn >> 3) - DEV_CDB;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800108}
109
110static void set_vga_enable_reg(u32 nodeid, u32 linkn)
111{
112 u32 val;
113
Elyes HAOUAS27e18012017-06-27 23:14:51 +0200114 val = 1 | (nodeid << 4) | (linkn << 12);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800115 /* it will routing
116 * (1)mmio 0xa0000:0xbffff
117 * (2)io 0x3b0:0x3bb, 0x3c0:0x3df
118 */
119 f1_write_config32(0xf4, val);
120
121}
122
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300123static void read_resources(struct device *dev)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800124{
Edward O'Callaghan66c65322014-11-21 01:43:38 +1100125 /*
126 * This MMCONF resource must be reserved in the PCI_DOMAIN.
127 * It is not honored by the coreboot resource allocator if it is in
128 * the APIC_CLUSTER.
129 */
Elyes HAOUAS400ce552018-10-12 10:54:30 +0200130 mmconf_resource(dev, MMIO_CONF_BASE);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800131
Arthur Heymansd0b2aa12022-10-13 18:33:18 +0200132 /* There should be no BAR. */
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800133}
134
135/**
136 * I tried to reuse the resource allocation code in set_resource()
137 * but it is too difficult to deal with the resource allocation magic.
138 */
139
Subrata Banikb1434fc2019-03-15 22:20:41 +0530140static void create_vga_resource(struct device *dev, unsigned int nodeid)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800141{
142 struct bus *link;
143
144 /* find out which link the VGA card is connected,
145 * we only deal with the 'first' vga card */
146 for (link = dev->link_list; link; link = link->next) {
147 if (link->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Julius Wernercd49cce2019-03-05 16:53:33 -0800148#if CONFIG(MULTIPLE_VGA_ADAPTERS)
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300149 extern struct device *vga_pri; // the primary vga device, defined in device.c
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800150 printk(BIOS_DEBUG, "VGA: vga_pri bus num = %d bus range [%d,%d]\n", vga_pri->bus->secondary,
Elyes Haouas3adfde92022-07-16 09:36:01 +0200151 link->secondary, link->subordinate);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800152 /* We need to make sure the vga_pri is under the link */
Elyes HAOUAS1d8daa62016-09-18 08:50:54 +0200153 if ((vga_pri->bus->secondary >= link->secondary) &&
154 (vga_pri->bus->secondary <= link->subordinate))
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800155#endif
156 break;
157 }
158 }
159
160 /* no VGA card installed */
161 if (link == NULL)
162 return;
163
164 printk(BIOS_DEBUG, "VGA: %s (aka node %d) link %d has VGA device\n", dev_path(dev), nodeid, sblink);
165 set_vga_enable_reg(nodeid, sblink);
166}
167
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300168static void set_resources(struct device *dev)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800169{
Subrata Banikb1434fc2019-03-15 22:20:41 +0530170 unsigned int nodeid;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800171
172 /* Find the nodeid */
173 nodeid = amdfam16_nodeid(dev);
174
175 create_vga_resource(dev, nodeid); //TODO: do we need this?
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800176}
177
Vladimir Serbinenko807127f2014-11-09 13:36:18 +0100178static unsigned long acpi_fill_hest(acpi_hest_t *hest)
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200179{
180 void *addr, *current;
181
182 /* Skip the HEST header. */
183 current = (void *)(hest + 1);
184
185 addr = agesawrapper_getlateinitptr(PICK_WHEA_MCE);
186 if (addr != NULL)
Stefan Reinauer77a1d1a2015-07-21 12:48:17 -0700187 current += acpi_create_hest_error_source(hest, current, 0,
188 addr + 2, *(UINT16 *)addr - 2);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200189
190 addr = agesawrapper_getlateinitptr(PICK_WHEA_CMC);
191 if (addr != NULL)
Stefan Reinauer77a1d1a2015-07-21 12:48:17 -0700192 current += acpi_create_hest_error_source(hest, current, 1,
193 addr + 2, *(UINT16 *)addr - 2);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200194
195 return (unsigned long)current;
196}
197
Furquan Shaikh7536a392020-04-24 21:59:21 -0700198static void northbridge_fill_ssdt_generator(const struct device *device)
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200199{
200 msr_t msr;
201 char pscope[] = "\\_SB.PCI0";
202
203 acpigen_write_scope(pscope);
204 msr = rdmsr(TOP_MEM);
205 acpigen_write_name_dword("TOM1", msr.lo);
206 msr = rdmsr(TOP_MEM2);
207 /*
208 * Since XP only implements parts of ACPI 2.0, we can't use a qword
209 * here.
210 * See http://www.acpi.info/presentations/S01USMOBS169_OS%2520new.ppt
211 * slide 22ff.
212 * Shift value right by 20 bit to make it fit into 32bit,
213 * giving us 1MB granularity and a limit of almost 4Exabyte of memory.
214 */
215 acpigen_write_name_dword("TOM2", (msr.hi << 12) | msr.lo >> 20);
216 acpigen_pop_len();
217}
218
Michał Żygowski9550e972020-03-20 13:56:46 +0100219static void patch_ssdt_processor_scope(acpi_header_t *ssdt)
220{
221 unsigned int len = ssdt->length - sizeof(acpi_header_t);
222 unsigned int i;
223
224 for (i = sizeof(acpi_header_t); i < len; i++) {
225 /* Search for _PR_ scope and replace it with _SB_ */
226 if (*(uint32_t *)((unsigned long)ssdt + i) == 0x5f52505f)
227 *(uint32_t *)((unsigned long)ssdt + i) = 0x5f42535f;
228 }
229 /* Recalculate checksum */
230 ssdt->checksum = 0;
231 ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
232}
233
Furquan Shaikh0f007d82020-04-24 06:41:18 -0700234static unsigned long agesa_write_acpi_tables(const struct device *device,
Alexander Couzens83fc32f2015-04-12 22:28:37 +0200235 unsigned long current,
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200236 acpi_rsdp_t *rsdp)
237{
238 acpi_srat_t *srat;
239 acpi_slit_t *slit;
240 acpi_header_t *ssdt;
241 acpi_header_t *alib;
242 acpi_header_t *ivrs;
243 acpi_hest_t *hest;
244
245 /* HEST */
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200246 current = ALIGN_UP(current, 8);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200247 hest = (acpi_hest_t *)current;
Arthur Heymanscc66ff32022-03-23 21:33:15 +0100248 acpi_write_hest(hest, acpi_fill_hest);
249 acpi_add_table(rsdp, hest);
250 current += hest->header.length;
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200251
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200252 current = ALIGN_UP(current, 8);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200253 printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current);
254 ivrs = agesawrapper_getlateinitptr(PICK_IVRS);
255 if (ivrs != NULL) {
256 memcpy((void *)current, ivrs, ivrs->length);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200257 ivrs = (acpi_header_t *)current;
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200258 current += ivrs->length;
259 acpi_add_table(rsdp, ivrs);
260 } else {
261 printk(BIOS_DEBUG, " AGESA IVRS table NULL. Skipping.\n");
262 }
263
264 /* SRAT */
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200265 current = ALIGN_UP(current, 8);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200266 printk(BIOS_DEBUG, "ACPI: * SRAT at %lx\n", current);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200267 srat = (acpi_srat_t *)agesawrapper_getlateinitptr(PICK_SRAT);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200268 if (srat != NULL) {
269 memcpy((void *)current, srat, srat->header.length);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200270 srat = (acpi_srat_t *)current;
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200271 current += srat->header.length;
272 acpi_add_table(rsdp, srat);
273 } else {
274 printk(BIOS_DEBUG, " AGESA SRAT table NULL. Skipping.\n");
275 }
276
277 /* SLIT */
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200278 current = ALIGN_UP(current, 8);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200279 printk(BIOS_DEBUG, "ACPI: * SLIT at %lx\n", current);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200280 slit = (acpi_slit_t *)agesawrapper_getlateinitptr(PICK_SLIT);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200281 if (slit != NULL) {
282 memcpy((void *)current, slit, slit->header.length);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200283 slit = (acpi_slit_t *)current;
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200284 current += slit->header.length;
285 acpi_add_table(rsdp, slit);
286 } else {
287 printk(BIOS_DEBUG, " AGESA SLIT table NULL. Skipping.\n");
288 }
289
290 /* ALIB */
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200291 current = ALIGN_UP(current, 16);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200292 printk(BIOS_DEBUG, "ACPI: * AGESA ALIB SSDT at %lx\n", current);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200293 alib = (acpi_header_t *)agesawrapper_getlateinitptr(PICK_ALIB);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200294 if (alib != NULL) {
295 memcpy((void *)current, alib, alib->length);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200296 alib = (acpi_header_t *)current;
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200297 current += alib->length;
298 acpi_add_table(rsdp, (void *)alib);
299 }
300 else {
301 printk(BIOS_DEBUG, " AGESA ALIB SSDT table NULL. Skipping.\n");
302 }
303
304 /* this pstate ssdt may cause Blue Screen: Fixed: Keep this comment for a while. */
305 /* SSDT */
Elyes Haouasd6b6b222022-10-10 12:34:21 +0200306 current = ALIGN_UP(current, 16);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200307 printk(BIOS_DEBUG, "ACPI: * SSDT at %lx\n", current);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200308 ssdt = (acpi_header_t *)agesawrapper_getlateinitptr(PICK_PSTATE);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200309 if (ssdt != NULL) {
Michał Żygowski9550e972020-03-20 13:56:46 +0100310 patch_ssdt_processor_scope(ssdt);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200311 memcpy((void *)current, ssdt, ssdt->length);
Elyes Haouas3adfde92022-07-16 09:36:01 +0200312 ssdt = (acpi_header_t *)current;
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200313 current += ssdt->length;
314 }
315 else {
316 printk(BIOS_DEBUG, " AGESA PState table NULL. Skipping.\n");
317 }
Elyes Haouas3adfde92022-07-16 09:36:01 +0200318 acpi_add_table(rsdp, ssdt);
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200319
320 printk(BIOS_DEBUG, "ACPI: * SSDT for PState at %lx\n", current);
321
322 return current;
323}
324
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800325static struct device_operations northbridge_operations = {
326 .read_resources = read_resources,
327 .set_resources = set_resources,
328 .enable_resources = pci_dev_enable_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200329 .acpi_fill_ssdt = northbridge_fill_ssdt_generator,
Vladimir Serbinenkodb09b0622014-10-08 22:15:17 +0200330 .write_acpi_tables = agesa_write_acpi_tables,
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800331};
332
333static const struct pci_driver family16_northbridge __pci_driver = {
334 .ops = &northbridge_operations,
Felix Singer43b7f412022-03-07 04:34:52 +0100335 .vendor = PCI_VID_AMD,
336 .device = PCI_DID_AMD_16H_MODEL_000F_NB_HT,
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800337};
338
339static const struct pci_driver family10_northbridge __pci_driver = {
340 .ops = &northbridge_operations,
Felix Singer43b7f412022-03-07 04:34:52 +0100341 .vendor = PCI_VID_AMD,
342 .device = PCI_DID_AMD_10H_NB_HT,
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800343};
344
Kyösti Mälkki4ee82c62014-11-25 16:03:12 +0200345static void fam16_finalize(void *chip_info)
346{
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300347 struct device *dev;
Kyösti Mälkki4ee82c62014-11-25 16:03:12 +0200348 u32 value;
Kyösti Mälkki4ad7f5b2018-05-22 01:15:17 +0300349 dev = pcidev_on_root(0, 0); /* clear IoapicSbFeatureEn */
Kyösti Mälkki4ee82c62014-11-25 16:03:12 +0200350 pci_write_config32(dev, 0xF8, 0);
351 pci_write_config32(dev, 0xFC, 5); /* TODO: move it to dsdt.asl */
352
353 /* disable No Snoop */
Kyösti Mälkki4ad7f5b2018-05-22 01:15:17 +0300354 dev = pcidev_on_root(1, 1);
Kyösti Mälkki69f6fd42019-01-21 14:19:01 +0200355 if (dev != NULL) {
356 value = pci_read_config32(dev, 0x60);
357 value &= ~(1 << 11);
358 pci_write_config32(dev, 0x60, value);
359 }
Kyösti Mälkki4ee82c62014-11-25 16:03:12 +0200360}
361
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800362struct chip_operations northbridge_amd_agesa_family16kb_ops = {
363 CHIP_NAME("AMD FAM16 Northbridge")
364 .enable_dev = 0,
Kyösti Mälkki4ee82c62014-11-25 16:03:12 +0200365 .final = fam16_finalize,
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800366};
367
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300368static void domain_read_resources(struct device *dev)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800369{
Subrata Banikb1434fc2019-03-15 22:20:41 +0530370 unsigned int reg;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800371
372 /* Find the already assigned resource pairs */
373 get_fx_devs();
Elyes Haouas3adfde92022-07-16 09:36:01 +0200374 for (reg = 0x80; reg <= 0xd8; reg += 0x08) {
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800375 u32 base, limit;
376 base = f1_read_config32(reg);
377 limit = f1_read_config32(reg + 0x04);
378 /* Is this register allocated? */
379 if ((base & 3) != 0) {
Subrata Banikb1434fc2019-03-15 22:20:41 +0530380 unsigned int nodeid, reg_link;
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300381 struct device *reg_dev;
Elyes HAOUAS1d8daa62016-09-18 08:50:54 +0200382 if (reg < 0xc0) { // mmio
Elyes Haouas3adfde92022-07-16 09:36:01 +0200383 nodeid = (limit & 0xf) + (base & 0x30);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800384 } else { // io
Elyes Haouas3adfde92022-07-16 09:36:01 +0200385 nodeid = (limit & 0xf) + ((base >> 4) & 0x30);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800386 }
387 reg_link = (limit >> 4) & 7;
388 reg_dev = __f0_dev[nodeid];
389 if (reg_dev) {
390 /* Reserve the resource */
391 struct resource *res;
392 res = new_resource(reg_dev, IOINDEX(0x1000 + reg, reg_link));
393 if (res) {
394 res->flags = 1;
395 }
396 }
397 }
398 }
399 /* FIXME: do we need to check extend conf space?
400 I don't believe that much preset value */
401
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800402 pci_domain_read_resources(dev);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800403}
404
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800405#if CONFIG_HW_MEM_HOLE_SIZEK != 0
406struct hw_mem_hole_info {
Subrata Banikb1434fc2019-03-15 22:20:41 +0530407 unsigned int hole_startk;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800408 int node_id;
409};
410static struct hw_mem_hole_info get_hw_mem_hole_info(void)
411{
412 struct hw_mem_hole_info mem_hole;
413 int i;
414 mem_hole.hole_startk = CONFIG_HW_MEM_HOLE_SIZEK;
415 mem_hole.node_id = -1;
416 for (i = 0; i < node_nums; i++) {
Michał Żygowski88a0ce62021-05-05 09:52:59 +0200417 resource_t basek, limitk;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800418 u32 hole;
Michał Żygowski88a0ce62021-05-05 09:52:59 +0200419 if (!get_dram_base_limit(i, &basek, &limitk))
420 continue; // no memory on this node
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800421 hole = pci_read_config32(__f1_dev[i], 0xf0);
422 if (hole & 2) { // we find the hole
Elyes HAOUAS27e18012017-06-27 23:14:51 +0200423 mem_hole.hole_startk = (hole & (0xff << 24)) >> 10;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800424 mem_hole.node_id = i; // record the node No with hole
425 break; // only one hole
426 }
427 }
Kyösti Mälkki2f9b3af2014-06-26 05:30:54 +0300428
429 /* We need to double check if there is special set on base reg and limit reg
430 * are not continuous instead of hole, it will find out its hole_startk.
431 */
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800432 if (mem_hole.node_id == -1) {
433 resource_t limitk_pri = 0;
Elyes HAOUAS1d8daa62016-09-18 08:50:54 +0200434 for (i = 0; i < node_nums; i++) {
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800435 resource_t base_k, limit_k;
Michał Żygowski88a0ce62021-05-05 09:52:59 +0200436 if (!get_dram_base_limit(i, &base_k, &limit_k))
437 continue; // no memory on this node
Elyes Haouas3adfde92022-07-16 09:36:01 +0200438 if (base_k > 4 * 1024 * 1024) break; // don't need to go to check
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800439 if (limitk_pri != base_k) { // we find the hole
Martin Roth468d02c2019-10-23 21:44:42 -0600440 mem_hole.hole_startk = (unsigned int)limitk_pri; // must beblow 4G
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800441 mem_hole.node_id = i;
442 break; //only one hole
443 }
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800444 limitk_pri = limit_k;
445 }
446 }
447 return mem_hole;
448}
449#endif
450
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300451static void domain_set_resources(struct device *dev)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800452{
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800453 unsigned long mmio_basek;
454 u32 pci_tolm;
455 int i, idx;
456 struct bus *link;
457#if CONFIG_HW_MEM_HOLE_SIZEK != 0
458 struct hw_mem_hole_info mem_hole;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800459#endif
460
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800461 pci_tolm = 0xffffffffUL;
462 for (link = dev->link_list; link; link = link->next) {
463 pci_tolm = find_pci_tolm(link);
464 }
465
466 // FIXME handle interleaved nodes. If you fix this here, please fix
467 // amdk8, too.
468 mmio_basek = pci_tolm >> 10;
469 /* Round mmio_basek to something the processor can support */
Elyes Haouas3adfde92022-07-16 09:36:01 +0200470 mmio_basek &= ~((1 << 6) - 1);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800471
472 // FIXME improve mtrr.c so we don't use up all of the mtrrs with a 64M
473 // MMIO hole. If you fix this here, please fix amdk8, too.
474 /* Round the mmio hole to 64M */
Elyes Haouas3adfde92022-07-16 09:36:01 +0200475 mmio_basek &= ~((64 * 1024) - 1);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800476
477#if CONFIG_HW_MEM_HOLE_SIZEK != 0
478 /* if the hw mem hole is already set in raminit stage, here we will compare
479 * mmio_basek and hole_basek. if mmio_basek is bigger that hole_basek and will
480 * use hole_basek as mmio_basek and we don't need to reset hole.
481 * otherwise We reset the hole to the mmio_basek
482 */
483
484 mem_hole = get_hw_mem_hole_info();
485
486 // Use hole_basek as mmio_basek, and we don't need to reset hole anymore
Arthur Heymans99eab342022-03-23 21:34:20 +0100487 if ((mem_hole.node_id != -1) && (mmio_basek > mem_hole.hole_startk))
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800488 mmio_basek = mem_hole.hole_startk;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800489#endif
490
491 idx = 0x10;
492 for (i = 0; i < node_nums; i++) {
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800493 resource_t basek, limitk, sizek; // 4 1T
494
Michał Żygowski88a0ce62021-05-05 09:52:59 +0200495 if (!get_dram_base_limit(i, &basek, &limitk))
496 continue; // no memory on this node
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800497
498 sizek = limitk - basek;
499
Elyes Haouas5213b192022-02-25 18:13:03 +0100500 /* See if we need a hole from 0xa0000 (640K) to 0xbffff (768K) */
Elyes Haouas9d8df302022-02-25 18:23:01 +0100501 if (basek < 640 && sizek > 768) {
Kyösti Mälkki27d62992022-05-24 20:25:58 +0300502 ram_resource_kb(dev, (idx | i), basek, 640 - basek);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800503 idx += 0x10;
Elyes Haouas9d8df302022-02-25 18:23:01 +0100504 basek = 768;
505 sizek = limitk - basek;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800506 }
507
508 //printk(BIOS_DEBUG, "node %d : mmio_basek=%08lx, basek=%08llx, limitk=%08llx\n", i, mmio_basek, basek, limitk);
509
Kyösti Mälkki26c65432014-06-26 05:30:54 +0300510 /* split the region to accommodate pci memory space */
Elyes Haouas3adfde92022-07-16 09:36:01 +0200511 if ((basek < 4 * 1024 * 1024) && (limitk > mmio_basek)) {
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800512 if (basek <= mmio_basek) {
Subrata Banikb1434fc2019-03-15 22:20:41 +0530513 unsigned int pre_sizek;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800514 pre_sizek = mmio_basek - basek;
Elyes HAOUAS1d8daa62016-09-18 08:50:54 +0200515 if (pre_sizek > 0) {
Kyösti Mälkki27d62992022-05-24 20:25:58 +0300516 ram_resource_kb(dev, (idx | i), basek, pre_sizek);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800517 idx += 0x10;
518 sizek -= pre_sizek;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800519 }
520 basek = mmio_basek;
521 }
Elyes Haouas3adfde92022-07-16 09:36:01 +0200522 if ((basek + sizek) <= 4 * 1024 * 1024) {
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800523 sizek = 0;
524 }
525 else {
Arthur Heymansc4350382021-10-28 12:35:39 +0200526 uint64_t topmem2 = amd_topmem2();
Elyes Haouas3adfde92022-07-16 09:36:01 +0200527 basek = 4 * 1024 * 1024;
528 sizek = topmem2 / 1024 - basek;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800529 }
530 }
531
Kyösti Mälkki27d62992022-05-24 20:25:58 +0300532 ram_resource_kb(dev, (idx | i), basek, sizek);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800533 idx += 0x10;
534 printk(BIOS_DEBUG, "node %d: mmio_basek=%08lx, basek=%08llx, limitk=%08llx\n",
535 i, mmio_basek, basek, limitk);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800536 }
537
Kyösti Mälkki61be3602017-04-15 20:07:53 +0300538 add_uma_resource_below_tolm(dev, 7);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800539
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200540 for (link = dev->link_list; link; link = link->next) {
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800541 if (link->children) {
542 assign_resources(link);
543 }
544 }
545}
546
Kevin Cody-Little06d23232018-05-09 14:22:15 -0400547static const char *domain_acpi_name(const struct device *dev)
548{
549 if (dev->path.type == DEVICE_PATH_DOMAIN)
550 return "PCI0";
551
552 return NULL;
553}
554
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800555static struct device_operations pci_domain_ops = {
556 .read_resources = domain_read_resources,
557 .set_resources = domain_set_resources,
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800558 .scan_bus = pci_domain_scan_bus,
Kevin Cody-Little06d23232018-05-09 14:22:15 -0400559 .acpi_name = domain_acpi_name,
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800560};
561
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300562static void sysconf_init(struct device *dev) // first node
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800563{
Elyes Haouas3adfde92022-07-16 09:36:01 +0200564 sblink = (pci_read_config32(dev, 0x64) >> 8) & 7; // don't forget sublink1
565 node_nums = ((pci_read_config32(dev, 0x60) >> 4) & 7) + 1; //NodeCnt[2:0]
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800566}
567
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300568static void cpu_bus_scan(struct device *dev)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800569{
570 struct bus *cpu_bus;
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300571 struct device *dev_mc;
Elyes Haouas3adfde92022-07-16 09:36:01 +0200572 int i, j;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800573 int coreid_bits;
574 int core_max = 0;
Subrata Banikb1434fc2019-03-15 22:20:41 +0530575 unsigned int ApicIdCoreIdSize;
576 unsigned int core_nums;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800577 int siblings = 0;
578 unsigned int family;
579
Kyösti Mälkki3d3152e2019-01-10 09:05:30 +0200580 dev_mc = pcidev_on_root(DEV_CDB, 0);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800581 if (!dev_mc) {
Kyösti Mälkki3d3152e2019-01-10 09:05:30 +0200582 printk(BIOS_ERR, "0:%02x.0 not found", DEV_CDB);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800583 die("");
584 }
585 sysconf_init(dev_mc);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800586
587 /* Get Max Number of cores(MNC) */
Kyösti Mälkkid41feed2017-09-24 16:23:57 +0300588 coreid_bits = (cpuid_ecx(0x80000008) & 0x0000F000) >> 12;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800589 core_max = 1 << (coreid_bits & 0x000F); //mnc
590
Elyes Haouas3adfde92022-07-16 09:36:01 +0200591 ApicIdCoreIdSize = ((cpuid_ecx(0x80000008) >> 12) & 0xF);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800592 if (ApicIdCoreIdSize) {
593 core_nums = (1 << ApicIdCoreIdSize) - 1;
594 } else {
595 core_nums = 3; //quad core
596 }
597
598 /* Find which cpus are present */
599 cpu_bus = dev->link_list;
600 for (i = 0; i < node_nums; i++) {
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300601 struct device *cdb_dev;
Subrata Banikb1434fc2019-03-15 22:20:41 +0530602 unsigned int devn;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800603 struct bus *pbus;
604
Kyösti Mälkki3d3152e2019-01-10 09:05:30 +0200605 devn = DEV_CDB + i;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800606 pbus = dev_mc->bus;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800607
608 /* Find the cpu's pci device */
Kyösti Mälkki4ad7f5b2018-05-22 01:15:17 +0300609 cdb_dev = pcidev_on_root(devn, 0);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800610 if (!cdb_dev) {
611 /* If I am probing things in a weird order
612 * ensure all of the cpu's pci devices are found.
613 */
614 int fn;
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200615 for (fn = 0; fn <= 5; fn++) { //FBDIMM?
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800616 cdb_dev = pci_probe_dev(NULL, pbus,
617 PCI_DEVFN(devn, fn));
618 }
Kyösti Mälkki4ad7f5b2018-05-22 01:15:17 +0300619 cdb_dev = pcidev_on_root(devn, 0);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800620 } else {
621 /* Ok, We need to set the links for that device.
622 * otherwise the device under it will not be scanned
623 */
Kyösti Mälkki2a2d6132015-02-04 13:25:37 +0200624 add_more_links(cdb_dev, 4);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800625 }
626
627 family = cpuid_eax(1);
628 family = (family >> 20) & 0xFF;
629 if (family == 1) { //f10
630 u32 dword;
Kyösti Mälkki4ad7f5b2018-05-22 01:15:17 +0300631 cdb_dev = pcidev_on_root(devn, 3);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800632 dword = pci_read_config32(cdb_dev, 0xe8);
633 siblings = ((dword & BIT15) >> 13) | ((dword & (BIT13 | BIT12)) >> 12);
634 } else if (family == 7) {//f16
Kyösti Mälkki4ad7f5b2018-05-22 01:15:17 +0300635 cdb_dev = pcidev_on_root(devn, 5);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800636 if (cdb_dev && cdb_dev->enabled) {
637 siblings = pci_read_config32(cdb_dev, 0x84);
638 siblings &= 0xFF;
639 }
640 } else {
641 siblings = 0; //default one core
642 }
643 int enable_node = cdb_dev && cdb_dev->enabled;
644 printk(BIOS_SPEW, "%s family%xh, core_max=0x%x, core_nums=0x%x, siblings=0x%x\n",
645 dev_path(cdb_dev), 0x0f + family, core_max, core_nums, siblings);
646
Elyes HAOUAS1d8daa62016-09-18 08:50:54 +0200647 for (j = 0; j <= siblings; j++) {
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800648 extern CONST OPTIONS_CONFIG_TOPOLOGY ROMDATA TopologyConfiguration;
649 u32 modules = TopologyConfiguration.PlatformNumberOfModules;
650 u32 lapicid_start = 0;
651
652 /*
653 * APIC ID calucation is tightly coupled with AGESA v5 code.
654 * This calculation MUST match the assignment calculation done
655 * in LocalApicInitializationAtEarly() function.
656 * And reference GetLocalApicIdForCore()
657 *
Elyes HAOUASa5b0bc42020-02-20 20:04:29 +0100658 * Apply APIC enumeration rules
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800659 * For systems with >= 16 APICs, put the IO-APICs at 0..n and
660 * put the local-APICs at m..z
661 *
662 * This is needed because many IO-APIC devices only have 4 bits
663 * for their APIC id and therefore must reside at 0..15
Elyes HAOUAS6e8b3c12016-09-02 19:22:00 +0200664 */
Kyösti Mälkki50036322016-05-18 13:35:21 +0300665
Elyes HAOUAS6e8b3c12016-09-02 19:22:00 +0200666 u8 plat_num_io_apics = 3; /* FIXME */
Kyösti Mälkki50036322016-05-18 13:35:21 +0300667
668 if ((node_nums * core_max) + plat_num_io_apics >= 0x10) {
669 lapicid_start = (plat_num_io_apics - 1) / core_max;
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800670 lapicid_start = (lapicid_start + 1) * core_max;
671 printk(BIOS_SPEW, "lpaicid_start=0x%x ", lapicid_start);
672 }
Elyes Haouas3adfde92022-07-16 09:36:01 +0200673 u32 apic_id = (lapicid_start * (i / modules + 1)) + ((i % modules) ? (j + (siblings + 1)) : j);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800674 printk(BIOS_SPEW, "node 0x%x core 0x%x apicid=0x%x\n",
675 i, j, apic_id);
676
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300677 struct device *cpu = add_cpu_device(cpu_bus, apic_id, enable_node);
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800678 if (cpu)
679 amd_cpu_topology(cpu, i, j);
680 } //j
681 }
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800682}
683
Kyösti Mälkkie2c2a4c2018-05-20 20:59:52 +0300684static void cpu_bus_init(struct device *dev)
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800685{
686 initialize_cpus(dev->link_list);
687}
688
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800689static struct device_operations cpu_bus_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +0200690 .read_resources = noop_read_resources,
691 .set_resources = noop_set_resources,
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800692 .init = cpu_bus_init,
693 .scan_bus = cpu_bus_scan,
694};
695
696static void root_complex_enable_dev(struct device *dev)
697{
Siyuan Wang3e32cc02013-07-09 17:16:20 +0800698 /* Set the operations if it is a special bus type */
699 if (dev->path.type == DEVICE_PATH_DOMAIN) {
700 dev->ops = &pci_domain_ops;
701 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
702 dev->ops = &cpu_bus_ops;
703 }
704}
705
706struct chip_operations northbridge_amd_agesa_family16kb_root_complex_ops = {
707 CHIP_NAME("AMD FAM16 Root Complex")
708 .enable_dev = root_complex_enable_dev,
709};
Bruce Griffith76db07e2013-07-07 02:06:53 -0600710
711/*********************************************************************
712 * Change the vendor / device IDs to match the generic VBIOS header. *
713 *********************************************************************/
714u32 map_oprom_vendev(u32 vendev)
715{
716 u32 new_vendev = vendev;
717
Elyes HAOUAS0ce41f12018-11-13 10:03:31 +0100718 switch (vendev) {
Bruce Griffith76db07e2013-07-07 02:06:53 -0600719 case 0x10029830:
720 case 0x10029831:
721 case 0x10029832:
722 case 0x10029833:
723 case 0x10029834:
724 case 0x10029835:
725 case 0x10029836:
726 case 0x10029837:
727 case 0x10029838:
728 case 0x10029839:
729 case 0x1002983A:
730 case 0x1002983D:
731 new_vendev = 0x10029830; // This is the default value in AMD-generated VBIOS
732 break;
733 default:
734 break;
735 }
736
737 if (vendev != new_vendev)
738 printk(BIOS_NOTICE, "Mapping PCI device %8x to %8x\n", vendev, new_vendev);
739
740 return new_vendev;
741}