blob: e67a127cf4e2123ac29c6a1fe67ea7c04f7865b9 [file] [log] [blame]
Marc Jones8ae8c882007-12-19 01:32:08 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Marc Jones8ae8c882007-12-19 01:32:08 +00003 *
Timothy Pearson367fe8c2015-01-23 20:18:56 -06004 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
Marc Jones8ae8c882007-12-19 01:32:08 +00005 * Copyright (C) 2007 Advanced Micro Devices, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Marc Jones8ae8c882007-12-19 01:32:08 +000015 */
16
17#include <console/console.h>
18#include <string.h>
19#include <arch/acpi.h>
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +020020#include <arch/acpigen.h>
Marc Jones8ae8c882007-12-19 01:32:08 +000021#include <device/pci.h>
22#include <cpu/x86/msr.h>
23#include <cpu/amd/mtrr.h>
24#include <cpu/amd/amdfam10_sysconf.h>
25#include "amdfam10.h"
26
Stefan Reinauer8677a232010-12-11 20:33:41 +000027//it seems some functions can be moved arch/x86/boot/acpi.c
Marc Jones8ae8c882007-12-19 01:32:08 +000028
Marc Jones8ae8c882007-12-19 01:32:08 +000029unsigned long acpi_create_madt_lapic_nmis(unsigned long current, u16 flags, u8 lint)
30{
31 device_t cpu;
32 int cpu_index = 0;
33
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +020034 for (cpu = all_devices; cpu; cpu = cpu->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +000035 if ((cpu->path.type != DEVICE_PATH_APIC) ||
Stefan Reinauer0aa37c42013-02-12 15:20:54 -080036 (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) {
Marc Jones8ae8c882007-12-19 01:32:08 +000037 continue;
38 }
39 if (!cpu->enabled) {
40 continue;
41 }
42 current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, cpu_index, flags, lint);
43 cpu_index++;
44 }
45 return current;
46}
47
Marc Jones8ae8c882007-12-19 01:32:08 +000048unsigned long acpi_create_srat_lapics(unsigned long current)
49{
50 device_t cpu;
51 int cpu_index = 0;
52
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +020053 for (cpu = all_devices; cpu; cpu = cpu->next) {
Marc Jones8ae8c882007-12-19 01:32:08 +000054 if ((cpu->path.type != DEVICE_PATH_APIC) ||
Stefan Reinauer0aa37c42013-02-12 15:20:54 -080055 (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) {
Marc Jones8ae8c882007-12-19 01:32:08 +000056 continue;
57 }
58 if (!cpu->enabled) {
59 continue;
60 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000061 printk(BIOS_DEBUG, "SRAT: lapic cpu_index=%02x, node_id=%02x, apic_id=%02x\n", cpu_index, cpu->path.apic.node_id, cpu->path.apic.apic_id);
Stefan Reinauer2b34db82009-02-28 20:10:20 +000062 current += acpi_create_srat_lapic((acpi_srat_lapic_t *)current, cpu->path.apic.node_id, cpu->path.apic.apic_id);
Marc Jones8ae8c882007-12-19 01:32:08 +000063 cpu_index++;
64 }
65 return current;
66}
67
68static unsigned long resk(uint64_t value)
69{
70 unsigned long resultk;
71 if (value < (1ULL << 42)) {
72 resultk = value >> 10;
73 } else {
74 resultk = 0xffffffff;
75 }
76 return resultk;
77}
78
Marc Jones8ae8c882007-12-19 01:32:08 +000079struct acpi_srat_mem_state {
80 unsigned long current;
81};
82
Myles Watson7943fe62009-10-30 02:08:07 +000083static void set_srat_mem(void *gp, struct device *dev, struct resource *res)
Marc Jones8ae8c882007-12-19 01:32:08 +000084{
85 struct acpi_srat_mem_state *state = gp;
86 unsigned long basek, sizek;
87 basek = resk(res->base);
88 sizek = resk(res->size);
89
Myles Watson08e0fb82010-03-22 16:33:25 +000090 printk(BIOS_DEBUG, "set_srat_mem: dev %s, res->index=%04lx startk=%08lx, sizek=%08lx\n",
Marc Jones8ae8c882007-12-19 01:32:08 +000091 dev_path(dev), res->index, basek, sizek);
92 /*
Carl-Daniel Hailfinger1c49bc92009-01-30 02:05:20 +000093 * 0-640K must be on node 0
94 * next range is from 1M---
95 * So will cut off before 1M in the mem range
96 */
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +020097 if ((basek+sizek)<1024) return;
Marc Jones8ae8c882007-12-19 01:32:08 +000098
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -060099 if (basek < 1024) {
Marc Jones8ae8c882007-12-19 01:32:08 +0000100 sizek -= 1024 - basek;
101 basek = 1024;
102 }
103
104 // need to figure out NV
Timothy Pearson121ef602015-08-08 02:40:58 -0500105 if (res->index > 0xf) /* Exclude MMIO resources, e.g. as set in northbridge.c amdfam10_domain_read_resources() */
106 state->current += acpi_create_srat_mem((acpi_srat_mem_t *)state->current, (res->index & 0xf), basek, sizek, 1);
Marc Jones8ae8c882007-12-19 01:32:08 +0000107}
108
Vladimir Serbinenko5e597572014-10-11 23:45:40 +0200109static unsigned long acpi_fill_srat(unsigned long current)
Marc Jones8ae8c882007-12-19 01:32:08 +0000110{
111 struct acpi_srat_mem_state srat_mem_state;
112
113 /* create all subtables for processors */
114 current = acpi_create_srat_lapics(current);
115
116 /* create all subteble for memory range */
117
118 /* 0-640K must be on node 0 */
119 current += acpi_create_srat_mem((acpi_srat_mem_t *)current, 0, 0, 640, 1);//enable
120
121 srat_mem_state.current = current;
122 search_global_resources(
123 IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE,
124 set_srat_mem, &srat_mem_state);
125
126 current = srat_mem_state.current;
127 return current;
128}
129
Vladimir Serbinenko5e597572014-10-11 23:45:40 +0200130static unsigned long acpi_fill_slit(unsigned long current)
Marc Jones8ae8c882007-12-19 01:32:08 +0000131{
Martin Roth0cd338e2016-07-29 14:07:30 -0600132 /* Implement SLIT algorithm in BKDG Rev. 3.62 Section 2.3.6.1
Timothy Pearsonb337c1d2015-03-21 15:11:58 -0500133 * Fill the first 8 bytes with the node number,
134 * then fill the next num*num byte with the distance,
135 * Distance entries vary with topology; the local node
136 * is always 10.
137 *
138 * Fully connected:
139 * Set all non-local nodes to 16
140 *
141 * Partially connected; with probe filter:
142 * Set all non-local nodes to 10+(num_hops*6)
143 *
144 * Partially connected; without probe filter:
145 * Set all non-local nodes to 13
146 *
147 * FIXME
148 * The partially connected cases are not implemented;
149 * once a means is found to detect partially connected
150 * topologies, implement the remaining cases.
151 */
Marc Jones8ae8c882007-12-19 01:32:08 +0000152
153 u8 *p = (u8 *)current;
154 int nodes = sysconf.nodes;
155 int i,j;
Marc Jones8ae8c882007-12-19 01:32:08 +0000156
157 memset(p, 0, 8+nodes*nodes);
158 *p = (u8) nodes;
159 p += 8;
160
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600161 for (i = 0; i < nodes; i++) {
162 for (j = 0; j < nodes; j++) {
163 if (i == j)
Marc Jones8ae8c882007-12-19 01:32:08 +0000164 p[i*nodes+j] = 10;
Timothy Pearsonb337c1d2015-03-21 15:11:58 -0500165 else
166 p[i*nodes+j] = 16;
Marc Jones8ae8c882007-12-19 01:32:08 +0000167 }
168 }
169
170 current += 8+nodes*nodes;
171 return current;
172}
173
Myles Watsonf4cc0892010-04-14 16:50:16 +0000174void update_ssdtx(void *ssdtx, int i)
175{
176 u8 *PCI;
177 u8 *HCIN;
178 u8 *UID;
179
180 PCI = ssdtx + 0x32;
181 HCIN = ssdtx + 0x39;
182 UID = ssdtx + 0x40;
183
184 if (i < 7) {
185 *PCI = (u8) ('4' + i - 1);
186 } else {
187 *PCI = (u8) ('A' + i - 1 - 6);
188 }
189 *HCIN = (u8) i;
190 *UID = (u8) (i + 3);
191
192 /* FIXME: need to update the GSI id in the ssdtx too */
193
194}
195
Alexander Couzens5eea4582015-04-12 22:18:55 +0200196void northbridge_acpi_write_vars(device_t device)
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200197{
Timothy Pearson367fe8c2015-01-23 20:18:56 -0600198 /*
199 * If more than one physical CPU is installed, northbridge_acpi_write_vars()
200 * is called more than once and the resultant SSDT table is corrupted
201 * (duplicated entries).
202 * This prevents Linux from booting, with log messages like these:
203 * ACPI Error: [BUSN] Namespace lookup failure, AE_ALREADY_EXISTS (/dswload-353)
204 * ACPI Exception: AE_ALREADY_EXISTS, During name lookup/catalog (/psobject-222)
205 * followed by a slew of ACPI method failures and a hang when the invalid PCI
206 * resource entries are used.
207 * This routine prevents the SSDT table from being corrupted.
208 */
209 static uint8_t ssdt_generated = 0;
210 if (ssdt_generated)
211 return;
212 ssdt_generated = 1;
213
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200214 msr_t msr;
215 char pscope[] = "\\_SB.PCI0";
216 int i;
217
218 get_bus_conf(); /* it will get sblk, pci1234, hcdn, and sbdn */
219
220 acpigen_write_scope(pscope);
221
222 acpigen_write_name("BUSN");
223 acpigen_write_package(HC_NUMS);
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600224 for (i = 0; i < HC_NUMS; i++) {
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200225 acpigen_write_dword(sysconf.ht_c_conf_bus[i]);
226 }
227 // minus the opcode
228 acpigen_pop_len();
229
230 acpigen_write_name("MMIO");
231
232 acpigen_write_package(HC_NUMS * 4);
233
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600234 for (i = 0; i<(HC_NUMS*2); i++) { // FIXME: change to more chain
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200235 acpigen_write_dword(sysconf.conf_mmio_addrx[i]); //base
236 acpigen_write_dword(sysconf.conf_mmio_addr[i]); //mask
237 }
238 // minus the opcode
239 acpigen_pop_len();
240
241 acpigen_write_name("PCIO");
242
243 acpigen_write_package(HC_NUMS * 2);
244
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600245 for (i = 0; i < HC_NUMS; i++) { // FIXME: change to more chain
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200246 acpigen_write_dword(sysconf.conf_io_addrx[i]);
247 acpigen_write_dword(sysconf.conf_io_addr[i]);
248 }
249
250 // minus the opcode
251 acpigen_pop_len();
252
253 acpigen_write_name_byte("SBLK", sysconf.sblk);
254
255 msr = rdmsr(TOP_MEM);
256 acpigen_write_name_dword("TOM1", msr.lo);
257
258 msr = rdmsr(TOP_MEM2);
259 /*
260 * Since XP only implements parts of ACPI 2.0, we can't use a qword
261 * here.
262 * See http://www.acpi.info/presentations/S01USMOBS169_OS%2520new.ppt
263 * slide 22ff.
264 * Shift value right by 20 bit to make it fit into 32bit,
265 * giving us 1MB granularity and a limit of almost 4Exabyte of memory.
266 */
267 acpigen_write_name_dword("TOM2", (msr.hi << 12) | msr.lo >> 20);
268
269
270 acpigen_write_name_dword("SBDN", sysconf.sbdn);
271
272 acpigen_write_name("HCLK");
273
274 acpigen_write_package(HC_POSSIBLE_NUM);
275
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600276 for (i = 0; i < sysconf.hc_possible_num; i++) {
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200277 acpigen_write_dword(sysconf.pci1234[i]);
278 }
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600279 for (i = sysconf.hc_possible_num; i < HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200280 acpigen_write_dword(0x00000000);
281 }
282 // minus the opcode
283 acpigen_pop_len();
284
285 acpigen_write_name("HCDN");
286
287 acpigen_write_package(HC_POSSIBLE_NUM);
288
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600289 for (i = 0; i < sysconf.hc_possible_num; i++) {
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200290 acpigen_write_dword(sysconf.hcdn[i]);
291 }
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600292 for (i = sysconf.hc_possible_num; i < HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200293 acpigen_write_dword(0x20202020);
294 }
295 // minus the opcode
296 acpigen_pop_len();
297
298 acpigen_write_name_byte("CBB", CONFIG_CBB);
299
300 u8 CBST, CBB2, CBS2;
301
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200302 if (CONFIG_CBB == 0xff) {
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200303 CBST = (u8) (0x0f);
304 } else {
Elyes HAOUAS5a7e72f2016-08-23 21:36:02 +0200305 if ((sysconf.pci1234[0] >> 12) & 0xff) { //sb chain on other than bus 0
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200306 CBST = (u8) (0x0f);
Timothy Pearson2a839352015-09-05 18:56:05 -0500307 } else {
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200308 CBST = (u8) (0x00);
309 }
310 }
311
312 acpigen_write_name_byte("CBST", CBST);
313
Elyes HAOUAS04f8fd92016-09-19 10:24:34 -0600314 if ((CONFIG_CBB == 0xff) && (sysconf.nodes > 32)) {
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200315 CBS2 = 0x0f;
316 CBB2 = (u8)(CONFIG_CBB-1);
317 } else {
318 CBS2 = 0x00;
319 CBB2 = 0x00;
320 }
321
322 acpigen_write_name_byte("CBB2", CBB2);
323 acpigen_write_name_byte("CBS2", CBS2);
324
325 //minus opcode
326 acpigen_pop_len();
327}
328
Alexander Couzens83fc32f2015-04-12 22:28:37 +0200329unsigned long northbridge_write_acpi_tables(device_t device,
330 unsigned long current,
331 struct acpi_rsdp *rsdp)
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200332{
333 acpi_srat_t *srat;
334 acpi_slit_t *slit;
335
336 get_bus_conf(); /* it will get sblk, pci1234, hcdn, and sbdn */
337
338 /* SRAT */
339 current = ALIGN(current, 8);
340 printk(BIOS_DEBUG, "ACPI: * SRAT at %lx\n", current);
341 srat = (acpi_srat_t *) current;
Vladimir Serbinenko5e597572014-10-11 23:45:40 +0200342 acpi_create_srat(srat, acpi_fill_srat);
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200343 current += srat->header.length;
344 acpi_add_table(rsdp, srat);
345
346 /* SLIT */
347 current = ALIGN(current, 8);
348 printk(BIOS_DEBUG, "ACPI: * SLIT at %lx\n", current);
349 slit = (acpi_slit_t *) current;
Vladimir Serbinenko5e597572014-10-11 23:45:40 +0200350 acpi_create_slit(slit, acpi_fill_slit);
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200351 current += slit->header.length;
352 acpi_add_table(rsdp, slit);
353
354 return current;
355}