blob: 7ade5c9d38e982104b09f58218ebe4c659e8b862 [file] [log] [blame]
Saket Sinha867bcb62015-08-22 12:20:55 +05301/*
2 * Based on acpi.c from coreboot
3 *
4 * Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include <common.h>
10#include <cpu.h>
11#include <dm.h>
12#include <dm/uclass-internal.h>
13#include <dm/lists.h>
14#include <asm/acpi_table.h>
15#include <asm/cpu.h>
16#include <asm/ioapic.h>
17#include <asm/lapic.h>
18#include <asm/tables.h>
19#include <asm/pci.h>
20
21/*
22 * IASL compiles the dsdt entries and
23 * writes the hex values to AmlCode array.
24 * CamelCase cannot be handled here.
25 */
26extern const unsigned char AmlCode[];
27
28/**
29* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
30* and checksum.
31*/
32static void acpi_add_table(struct acpi_rsdp *rsdp, void *table)
33{
34 int i, entries_num;
35 struct acpi_rsdt *rsdt;
36 struct acpi_xsdt *xsdt = NULL;
37
38 /* The RSDT is mandatory while the XSDT is not */
39 rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
40
41 if (rsdp->xsdt_address)
42 xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
43
44 /* This should always be MAX_ACPI_TABLES */
45 entries_num = ARRAY_SIZE(rsdt->entry);
46
47 for (i = 0; i < entries_num; i++) {
48 if (rsdt->entry[i] == 0)
49 break;
50 }
51
52 if (i >= entries_num) {
Bin Mengdca4d1a2016-05-07 07:46:12 -070053 debug("ACPI: Error: too many tables\n");
Saket Sinha867bcb62015-08-22 12:20:55 +053054 return;
55 }
56
57 /* Add table to the RSDT */
58 rsdt->entry[i] = (u32)table;
59
60 /* Fix RSDT length or the kernel will assume invalid entries */
Bin Meng8a8c0352016-05-07 07:46:21 -070061 rsdt->header.length = sizeof(struct acpi_table_header) +
62 (sizeof(u32) * (i + 1));
Saket Sinha867bcb62015-08-22 12:20:55 +053063
64 /* Re-calculate checksum */
65 rsdt->header.checksum = 0;
66 rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
67 rsdt->header.length);
68
69 /*
70 * And now the same thing for the XSDT. We use the same index as for
71 * now we want the XSDT and RSDT to always be in sync in U-Boot
72 */
73 if (xsdt) {
74 /* Add table to the XSDT */
75 xsdt->entry[i] = (u64)(u32)table;
76
77 /* Fix XSDT length */
Bin Meng8a8c0352016-05-07 07:46:21 -070078 xsdt->header.length = sizeof(struct acpi_table_header) +
Saket Sinha867bcb62015-08-22 12:20:55 +053079 (sizeof(u64) * (i + 1));
80
81 /* Re-calculate checksum */
82 xsdt->header.checksum = 0;
83 xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
84 xsdt->header.length);
85 }
86}
87
88static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic,
89 u8 cpu, u8 apic)
90{
Bin Meng8a8c0352016-05-07 07:46:21 -070091 lapic->type = ACPI_APIC_LAPIC; /* Local APIC structure */
Saket Sinha867bcb62015-08-22 12:20:55 +053092 lapic->length = sizeof(struct acpi_madt_lapic);
93 lapic->flags = LOCAL_APIC_FLAG_ENABLED; /* Processor/LAPIC enabled */
94 lapic->processor_id = cpu;
95 lapic->apic_id = apic;
96
97 return lapic->length;
98}
99
100unsigned long acpi_create_madt_lapics(unsigned long current)
101{
102 struct udevice *dev;
103
104 for (uclass_find_first_device(UCLASS_CPU, &dev);
105 dev;
106 uclass_find_next_device(&dev)) {
107 struct cpu_platdata *plat = dev_get_parent_platdata(dev);
108
109 current += acpi_create_madt_lapic(
110 (struct acpi_madt_lapic *)current,
111 plat->cpu_id, plat->cpu_id);
112 }
113 return current;
114}
115
116int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr,
117 u32 gsi_base)
118{
Bin Meng8a8c0352016-05-07 07:46:21 -0700119 ioapic->type = ACPI_APIC_IOAPIC;
Saket Sinha867bcb62015-08-22 12:20:55 +0530120 ioapic->length = sizeof(struct acpi_madt_ioapic);
121 ioapic->reserved = 0x00;
122 ioapic->gsi_base = gsi_base;
123 ioapic->ioapic_id = id;
124 ioapic->ioapic_addr = addr;
125
126 return ioapic->length;
127}
128
129int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
130 u8 bus, u8 source, u32 gsirq, u16 flags)
131{
Bin Meng8a8c0352016-05-07 07:46:21 -0700132 irqoverride->type = ACPI_APIC_IRQ_SRC_OVERRIDE;
Saket Sinha867bcb62015-08-22 12:20:55 +0530133 irqoverride->length = sizeof(struct acpi_madt_irqoverride);
134 irqoverride->bus = bus;
135 irqoverride->source = source;
136 irqoverride->gsirq = gsirq;
137 irqoverride->flags = flags;
138
139 return irqoverride->length;
140}
141
142int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
143 u8 cpu, u16 flags, u8 lint)
144{
Bin Meng8a8c0352016-05-07 07:46:21 -0700145 lapic_nmi->type = ACPI_APIC_LAPIC_NMI;
Saket Sinha867bcb62015-08-22 12:20:55 +0530146 lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi);
147 lapic_nmi->flags = flags;
148 lapic_nmi->processor_id = cpu;
149 lapic_nmi->lint = lint;
150
151 return lapic_nmi->length;
152}
153
Bin Meng8a8c0352016-05-07 07:46:21 -0700154static void fill_header(struct acpi_table_header *header, char *signature,
155 int length)
Saket Sinha867bcb62015-08-22 12:20:55 +0530156{
157 memcpy(header->signature, signature, length);
158 memcpy(header->oem_id, OEM_ID, 6);
Bin Meng8a8c0352016-05-07 07:46:21 -0700159 memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
160 memcpy(header->aslc_id, ASLC_ID, 4);
Saket Sinha867bcb62015-08-22 12:20:55 +0530161}
162
163static void acpi_create_madt(struct acpi_madt *madt)
164{
Bin Meng8a8c0352016-05-07 07:46:21 -0700165 struct acpi_table_header *header = &(madt->header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530166 unsigned long current = (unsigned long)madt + sizeof(struct acpi_madt);
167
168 memset((void *)madt, 0, sizeof(struct acpi_madt));
169
170 /* Fill out header fields */
171 fill_header(header, "APIC", 4);
172 header->length = sizeof(struct acpi_madt);
173
174 /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
175 header->revision = ACPI_REV_ACPI_2_0;
176
177 madt->lapic_addr = LAPIC_DEFAULT_BASE;
Bin Meng8a8c0352016-05-07 07:46:21 -0700178 madt->flags = ACPI_MADT_PCAT_COMPAT;
Saket Sinha867bcb62015-08-22 12:20:55 +0530179
180 current = acpi_fill_madt(current);
181
182 /* (Re)calculate length and checksum */
183 header->length = current - (unsigned long)madt;
184
185 header->checksum = table_compute_checksum((void *)madt, header->length);
186}
187
188static int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig,
189 u32 base, u16 seg_nr, u8 start, u8 end)
190{
191 memset(mmconfig, 0, sizeof(*mmconfig));
Bin Meng8a8c0352016-05-07 07:46:21 -0700192 mmconfig->base_address_l = base;
193 mmconfig->base_address_h = 0;
Saket Sinha867bcb62015-08-22 12:20:55 +0530194 mmconfig->pci_segment_group_number = seg_nr;
195 mmconfig->start_bus_number = start;
196 mmconfig->end_bus_number = end;
197
198 return sizeof(struct acpi_mcfg_mmconfig);
199}
200
201static unsigned long acpi_fill_mcfg(unsigned long current)
202{
203 current += acpi_create_mcfg_mmconfig
204 ((struct acpi_mcfg_mmconfig *)current,
205 CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255);
206
207 return current;
208}
209
210/* MCFG is defined in the PCI Firmware Specification 3.0 */
211static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
212{
Bin Meng8a8c0352016-05-07 07:46:21 -0700213 struct acpi_table_header *header = &(mcfg->header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530214 unsigned long current = (unsigned long)mcfg + sizeof(struct acpi_mcfg);
215
216 memset((void *)mcfg, 0, sizeof(struct acpi_mcfg));
217
218 /* Fill out header fields */
219 fill_header(header, "MCFG", 4);
220 header->length = sizeof(struct acpi_mcfg);
221
222 /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
223 header->revision = ACPI_REV_ACPI_2_0;
224
225 current = acpi_fill_mcfg(current);
226
227 /* (Re)calculate length and checksum */
228 header->length = current - (unsigned long)mcfg;
229 header->checksum = table_compute_checksum((void *)mcfg, header->length);
230}
231
232static void acpi_create_facs(struct acpi_facs *facs)
233{
234 memset((void *)facs, 0, sizeof(struct acpi_facs));
235
236 memcpy(facs->signature, "FACS", 4);
237 facs->length = sizeof(struct acpi_facs);
238 facs->hardware_signature = 0;
239 facs->firmware_waking_vector = 0;
240 facs->global_lock = 0;
241 facs->flags = 0;
242 facs->x_firmware_waking_vector_l = 0;
243 facs->x_firmware_waking_vector_h = 0;
244 facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */
245}
246
247static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
248{
Bin Meng8a8c0352016-05-07 07:46:21 -0700249 struct acpi_table_header *header = &(rsdt->header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530250
251 /* Fill out header fields */
252 fill_header(header, "RSDT", 4);
253 header->length = sizeof(struct acpi_rsdt);
254
255 /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
256 header->revision = ACPI_REV_ACPI_2_0;
257
258 /* Entries are filled in later, we come with an empty set */
259
260 /* Fix checksum */
261 header->checksum = table_compute_checksum((void *)rsdt,
262 sizeof(struct acpi_rsdt));
263}
264
265static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
266{
Bin Meng8a8c0352016-05-07 07:46:21 -0700267 struct acpi_table_header *header = &(xsdt->header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530268
269 /* Fill out header fields */
270 fill_header(header, "XSDT", 4);
271 header->length = sizeof(struct acpi_xsdt);
272
273 /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
274 header->revision = ACPI_REV_ACPI_2_0;
275
276 /* Entries are filled in later, we come with an empty set */
277
278 /* Fix checksum */
279 header->checksum = table_compute_checksum((void *)xsdt,
280 sizeof(struct acpi_xsdt));
281}
282
283static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
284 struct acpi_xsdt *xsdt)
285{
286 memset(rsdp, 0, sizeof(struct acpi_rsdp));
287
288 memcpy(rsdp->signature, RSDP_SIG, 8);
289 memcpy(rsdp->oem_id, OEM_ID, 6);
290
291 rsdp->length = sizeof(struct acpi_rsdp);
292 rsdp->rsdt_address = (u32)rsdt;
293
294 /*
295 * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2
296 *
297 * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
298 * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
299 * revision 0)
300 */
301 if (xsdt == NULL) {
302 rsdp->revision = ACPI_RSDP_REV_ACPI_1_0;
303 } else {
304 rsdp->xsdt_address = (u64)(u32)xsdt;
305 rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
306 }
307
308 /* Calculate checksums */
309 rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
310 rsdp->ext_checksum = table_compute_checksum((void *)rsdp,
311 sizeof(struct acpi_rsdp));
312}
313
Bin Meng8a8c0352016-05-07 07:46:21 -0700314static void acpi_create_ssdt_generator(struct acpi_table_header *ssdt,
Saket Sinha867bcb62015-08-22 12:20:55 +0530315 const char *oem_table_id)
316{
Bin Meng8a8c0352016-05-07 07:46:21 -0700317 unsigned long current = (unsigned long)ssdt +
318 sizeof(struct acpi_table_header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530319
Bin Meng8a8c0352016-05-07 07:46:21 -0700320 memset((void *)ssdt, 0, sizeof(struct acpi_table_header));
Saket Sinha867bcb62015-08-22 12:20:55 +0530321
322 memcpy(&ssdt->signature, "SSDT", 4);
323 /* Access size in ACPI 2.0c/3.0/4.0/5.0 */
324 ssdt->revision = ACPI_REV_ACPI_3_0;
325 memcpy(&ssdt->oem_id, OEM_ID, 6);
326 memcpy(&ssdt->oem_table_id, oem_table_id, 8);
327 ssdt->oem_revision = OEM_REVISION;
Bin Meng8a8c0352016-05-07 07:46:21 -0700328 memcpy(&ssdt->aslc_id, ASLC_ID, 4);
329 ssdt->aslc_revision = ASL_COMPILER_REVISION;
330 ssdt->length = sizeof(struct acpi_table_header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530331
332 /* (Re)calculate length and checksum */
333 ssdt->length = current - (unsigned long)ssdt;
334 ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length);
335}
336
Miao Yanfa287b12016-01-20 01:57:06 -0800337/*
338 * QEMU's version of write_acpi_tables is defined in
339 * arch/x86/cpu/qemu/fw_cfg.c
340 */
Bin Meng358bb3f2016-02-27 22:58:00 -0800341u32 write_acpi_tables(u32 start)
Saket Sinha867bcb62015-08-22 12:20:55 +0530342{
Bin Meng358bb3f2016-02-27 22:58:00 -0800343 u32 current;
Saket Sinha867bcb62015-08-22 12:20:55 +0530344 struct acpi_rsdp *rsdp;
345 struct acpi_rsdt *rsdt;
346 struct acpi_xsdt *xsdt;
347 struct acpi_facs *facs;
Bin Meng8a8c0352016-05-07 07:46:21 -0700348 struct acpi_table_header *dsdt;
Saket Sinha867bcb62015-08-22 12:20:55 +0530349 struct acpi_fadt *fadt;
350 struct acpi_mcfg *mcfg;
351 struct acpi_madt *madt;
Bin Meng8a8c0352016-05-07 07:46:21 -0700352 struct acpi_table_header *ssdt;
Saket Sinha867bcb62015-08-22 12:20:55 +0530353
354 current = start;
355
356 /* Align ACPI tables to 16byte */
357 current = ALIGN(current, 16);
358
Bin Mengdca4d1a2016-05-07 07:46:12 -0700359 debug("ACPI: Writing ACPI tables at %x\n", start);
Saket Sinha867bcb62015-08-22 12:20:55 +0530360
361 /* We need at least an RSDP and an RSDT Table */
362 rsdp = (struct acpi_rsdp *)current;
363 current += sizeof(struct acpi_rsdp);
364 current = ALIGN(current, 16);
365 rsdt = (struct acpi_rsdt *)current;
366 current += sizeof(struct acpi_rsdt);
367 current = ALIGN(current, 16);
368 xsdt = (struct acpi_xsdt *)current;
369 current += sizeof(struct acpi_xsdt);
370 current = ALIGN(current, 16);
371
372 /* clear all table memory */
373 memset((void *)start, 0, current - start);
374
375 acpi_write_rsdp(rsdp, rsdt, xsdt);
376 acpi_write_rsdt(rsdt);
377 acpi_write_xsdt(xsdt);
378
379 debug("ACPI: * FACS\n");
380 facs = (struct acpi_facs *)current;
381 current += sizeof(struct acpi_facs);
382 current = ALIGN(current, 16);
383
384 acpi_create_facs(facs);
385
386 debug("ACPI: * DSDT\n");
Bin Meng8a8c0352016-05-07 07:46:21 -0700387 dsdt = (struct acpi_table_header *)current;
388 memcpy(dsdt, &AmlCode, sizeof(struct acpi_table_header));
389 if (dsdt->length >= sizeof(struct acpi_table_header)) {
390 current += sizeof(struct acpi_table_header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530391 memcpy((char *)current,
Bin Meng8a8c0352016-05-07 07:46:21 -0700392 (char *)&AmlCode + sizeof(struct acpi_table_header),
393 dsdt->length - sizeof(struct acpi_table_header));
394 current += dsdt->length - sizeof(struct acpi_table_header);
Saket Sinha867bcb62015-08-22 12:20:55 +0530395
396 /* (Re)calculate length and checksum */
397 dsdt->length = current - (unsigned long)dsdt;
398 dsdt->checksum = 0;
399 dsdt->checksum = table_compute_checksum((void *)dsdt,
400 dsdt->length);
401 }
402 current = ALIGN(current, 16);
403
404 debug("ACPI: * FADT\n");
405 fadt = (struct acpi_fadt *)current;
406 current += sizeof(struct acpi_fadt);
407 current = ALIGN(current, 16);
408 acpi_create_fadt(fadt, facs, dsdt);
409 acpi_add_table(rsdp, fadt);
410
411 debug("ACPI: * MCFG\n");
412 mcfg = (struct acpi_mcfg *)current;
413 acpi_create_mcfg(mcfg);
414 if (mcfg->header.length > sizeof(struct acpi_mcfg)) {
415 current += mcfg->header.length;
416 current = ALIGN(current, 16);
417 acpi_add_table(rsdp, mcfg);
418 }
419
420 debug("ACPI: * MADT\n");
421 madt = (struct acpi_madt *)current;
422 acpi_create_madt(madt);
423 if (madt->header.length > sizeof(struct acpi_madt)) {
424 current += madt->header.length;
425 acpi_add_table(rsdp, madt);
426 }
427 current = ALIGN(current, 16);
428
429 debug("ACPI: * SSDT\n");
Bin Meng8a8c0352016-05-07 07:46:21 -0700430 ssdt = (struct acpi_table_header *)current;
431 acpi_create_ssdt_generator(ssdt, OEM_TABLE_ID);
432 if (ssdt->length > sizeof(struct acpi_table_header)) {
Saket Sinha867bcb62015-08-22 12:20:55 +0530433 current += ssdt->length;
434 acpi_add_table(rsdp, ssdt);
435 current = ALIGN(current, 16);
436 }
437
Bin Mengdca4d1a2016-05-07 07:46:12 -0700438 debug("current = %x\n", current);
Saket Sinha867bcb62015-08-22 12:20:55 +0530439
Bin Mengdca4d1a2016-05-07 07:46:12 -0700440 debug("ACPI: done\n");
Saket Sinha867bcb62015-08-22 12:20:55 +0530441
442 return current;
443}