1 // SPDX-License-Identifier: GPL-2.0+
3 * Based on acpi.c from coreboot
5 * Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com>
6 * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
12 #include <dm/uclass-internal.h>
16 #include <acpi/acpi_table.h>
17 #include <asm/acpi/global_nvs.h>
18 #include <asm/ioapic.h>
19 #include <asm/lapic.h>
20 #include <asm/mpspec.h>
21 #include <asm/tables.h>
22 #include <asm/arch/global_nvs.h>
26 * IASL compiles the dsdt entries and writes the hex values
27 * to a C array AmlCode[] (see dsdt.c).
29 extern const unsigned char AmlCode[];
31 /* ACPI RSDP address to be used in boot parameters */
32 static ulong acpi_rsdp_addr;
34 static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
35 struct acpi_xsdt *xsdt)
37 memset(rsdp, 0, sizeof(struct acpi_rsdp));
39 memcpy(rsdp->signature, RSDP_SIG, 8);
40 memcpy(rsdp->oem_id, OEM_ID, 6);
42 rsdp->length = sizeof(struct acpi_rsdp);
43 rsdp->rsdt_address = (u32)rsdt;
45 rsdp->xsdt_address = (u64)(u32)xsdt;
46 rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
48 /* Calculate checksums */
49 rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
50 rsdp->ext_checksum = table_compute_checksum((void *)rsdp,
51 sizeof(struct acpi_rsdp));
54 static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
56 struct acpi_table_header *header = &(rsdt->header);
58 /* Fill out header fields */
59 acpi_fill_header(header, "RSDT");
60 header->length = sizeof(struct acpi_rsdt);
63 /* Entries are filled in later, we come with an empty set */
66 header->checksum = table_compute_checksum((void *)rsdt,
67 sizeof(struct acpi_rsdt));
70 static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
72 struct acpi_table_header *header = &(xsdt->header);
74 /* Fill out header fields */
75 acpi_fill_header(header, "XSDT");
76 header->length = sizeof(struct acpi_xsdt);
79 /* Entries are filled in later, we come with an empty set */
82 header->checksum = table_compute_checksum((void *)xsdt,
83 sizeof(struct acpi_xsdt));
87 * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
90 static void acpi_add_table(struct acpi_rsdp *rsdp, void *table)
93 struct acpi_rsdt *rsdt;
94 struct acpi_xsdt *xsdt;
96 /* The RSDT is mandatory while the XSDT is not */
97 rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
99 /* This should always be MAX_ACPI_TABLES */
100 entries_num = ARRAY_SIZE(rsdt->entry);
102 for (i = 0; i < entries_num; i++) {
103 if (rsdt->entry[i] == 0)
107 if (i >= entries_num) {
108 debug("ACPI: Error: too many tables\n");
112 /* Add table to the RSDT */
113 rsdt->entry[i] = (u32)table;
115 /* Fix RSDT length or the kernel will assume invalid entries */
116 rsdt->header.length = sizeof(struct acpi_table_header) +
117 sizeof(u32) * (i + 1);
119 /* Re-calculate checksum */
120 rsdt->header.checksum = 0;
121 rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
122 rsdt->header.length);
124 /* The RSDT is mandatory while the XSDT is not */
125 if (!rsdp->xsdt_address)
129 * And now the same thing for the XSDT. We use the same index as for
130 * now we want the XSDT and RSDT to always be in sync in U-Boot
132 xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
134 /* Add table to the XSDT */
135 xsdt->entry[i] = (u64)(u32)table;
137 /* Fix XSDT length */
138 xsdt->header.length = sizeof(struct acpi_table_header) +
139 sizeof(u64) * (i + 1);
141 /* Re-calculate checksum */
142 xsdt->header.checksum = 0;
143 xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
144 xsdt->header.length);
147 static void acpi_create_facs(struct acpi_facs *facs)
149 memset((void *)facs, 0, sizeof(struct acpi_facs));
151 memcpy(facs->signature, "FACS", 4);
152 facs->length = sizeof(struct acpi_facs);
153 facs->hardware_signature = 0;
154 facs->firmware_waking_vector = 0;
155 facs->global_lock = 0;
157 facs->x_firmware_waking_vector_l = 0;
158 facs->x_firmware_waking_vector_h = 0;
162 static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic,
165 lapic->type = ACPI_APIC_LAPIC;
166 lapic->length = sizeof(struct acpi_madt_lapic);
167 lapic->flags = LOCAL_APIC_FLAG_ENABLED;
168 lapic->processor_id = cpu;
169 lapic->apic_id = apic;
171 return lapic->length;
174 int acpi_create_madt_lapics(u32 current)
177 int total_length = 0;
179 for (uclass_find_first_device(UCLASS_CPU, &dev);
181 uclass_find_next_device(&dev)) {
182 struct cpu_platdata *plat = dev_get_parent_platdata(dev);
183 int length = acpi_create_madt_lapic(
184 (struct acpi_madt_lapic *)current,
185 plat->cpu_id, plat->cpu_id);
187 total_length += length;
193 int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id,
194 u32 addr, u32 gsi_base)
196 ioapic->type = ACPI_APIC_IOAPIC;
197 ioapic->length = sizeof(struct acpi_madt_ioapic);
198 ioapic->reserved = 0x00;
199 ioapic->gsi_base = gsi_base;
200 ioapic->ioapic_id = id;
201 ioapic->ioapic_addr = addr;
203 return ioapic->length;
206 int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
207 u8 bus, u8 source, u32 gsirq, u16 flags)
209 irqoverride->type = ACPI_APIC_IRQ_SRC_OVERRIDE;
210 irqoverride->length = sizeof(struct acpi_madt_irqoverride);
211 irqoverride->bus = bus;
212 irqoverride->source = source;
213 irqoverride->gsirq = gsirq;
214 irqoverride->flags = flags;
216 return irqoverride->length;
219 int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
220 u8 cpu, u16 flags, u8 lint)
222 lapic_nmi->type = ACPI_APIC_LAPIC_NMI;
223 lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi);
224 lapic_nmi->flags = flags;
225 lapic_nmi->processor_id = cpu;
226 lapic_nmi->lint = lint;
228 return lapic_nmi->length;
231 static int acpi_create_madt_irq_overrides(u32 current)
233 struct acpi_madt_irqoverride *irqovr;
234 u16 sci_flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_HIGH;
237 irqovr = (void *)current;
238 length += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
240 irqovr = (void *)(current + length);
241 length += acpi_create_madt_irqoverride(irqovr, 0, 9, 9, sci_flags);
246 __weak u32 acpi_fill_madt(u32 current)
248 current += acpi_create_madt_lapics(current);
250 current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current,
251 io_apic_read(IO_APIC_ID) >> 24, IO_APIC_ADDR, 0);
253 current += acpi_create_madt_irq_overrides(current);
258 static void acpi_create_madt(struct acpi_madt *madt)
260 struct acpi_table_header *header = &(madt->header);
261 u32 current = (u32)madt + sizeof(struct acpi_madt);
263 memset((void *)madt, 0, sizeof(struct acpi_madt));
265 /* Fill out header fields */
266 acpi_fill_header(header, "APIC");
267 header->length = sizeof(struct acpi_madt);
268 header->revision = 4;
270 madt->lapic_addr = LAPIC_DEFAULT_BASE;
271 madt->flags = ACPI_MADT_PCAT_COMPAT;
273 current = acpi_fill_madt(current);
275 /* (Re)calculate length and checksum */
276 header->length = current - (u32)madt;
278 header->checksum = table_compute_checksum((void *)madt, header->length);
281 int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base,
282 u16 seg_nr, u8 start, u8 end)
284 memset(mmconfig, 0, sizeof(*mmconfig));
285 mmconfig->base_address_l = base;
286 mmconfig->base_address_h = 0;
287 mmconfig->pci_segment_group_number = seg_nr;
288 mmconfig->start_bus_number = start;
289 mmconfig->end_bus_number = end;
291 return sizeof(struct acpi_mcfg_mmconfig);
294 __weak u32 acpi_fill_mcfg(u32 current)
296 current += acpi_create_mcfg_mmconfig
297 ((struct acpi_mcfg_mmconfig *)current,
298 CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255);
303 /* MCFG is defined in the PCI Firmware Specification 3.0 */
304 static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
306 struct acpi_table_header *header = &(mcfg->header);
307 u32 current = (u32)mcfg + sizeof(struct acpi_mcfg);
309 memset((void *)mcfg, 0, sizeof(struct acpi_mcfg));
311 /* Fill out header fields */
312 acpi_fill_header(header, "MCFG");
313 header->length = sizeof(struct acpi_mcfg);
314 header->revision = 1;
316 current = acpi_fill_mcfg(current);
318 /* (Re)calculate length and checksum */
319 header->length = current - (u32)mcfg;
320 header->checksum = table_compute_checksum((void *)mcfg, header->length);
323 __weak u32 acpi_fill_csrt(u32 current)
328 static void acpi_create_csrt(struct acpi_csrt *csrt)
330 struct acpi_table_header *header = &(csrt->header);
331 u32 current = (u32)csrt + sizeof(struct acpi_csrt);
333 memset((void *)csrt, 0, sizeof(struct acpi_csrt));
335 /* Fill out header fields */
336 acpi_fill_header(header, "CSRT");
337 header->length = sizeof(struct acpi_csrt);
338 header->revision = 0;
340 current = acpi_fill_csrt(current);
342 /* (Re)calculate length and checksum */
343 header->length = current - (u32)csrt;
344 header->checksum = table_compute_checksum((void *)csrt, header->length);
347 static void acpi_create_spcr(struct acpi_spcr *spcr)
349 struct acpi_table_header *header = &(spcr->header);
350 struct serial_device_info serial_info = {0};
351 ulong serial_address, serial_offset;
359 /* Fill out header fields */
360 acpi_fill_header(header, "SPCR");
361 header->length = sizeof(struct acpi_spcr);
362 header->revision = 2;
364 /* Read the device once, here. It is reused below */
365 dev = gd->cur_serial_dev;
367 ret = serial_getinfo(dev, &serial_info);
369 serial_info.type = SERIAL_CHIP_UNKNOWN;
371 /* Encode chip type */
372 switch (serial_info.type) {
373 case SERIAL_CHIP_16550_COMPATIBLE:
374 spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
376 case SERIAL_CHIP_UNKNOWN:
378 spcr->interface_type = ACPI_DBG2_UNKNOWN;
382 /* Encode address space */
383 switch (serial_info.addr_space) {
384 case SERIAL_ADDRESS_SPACE_MEMORY:
385 space_id = ACPI_ADDRESS_SPACE_MEMORY;
387 case SERIAL_ADDRESS_SPACE_IO:
389 space_id = ACPI_ADDRESS_SPACE_IO;
393 serial_width = serial_info.reg_width * 8;
394 serial_offset = serial_info.reg_offset << serial_info.reg_shift;
395 serial_address = serial_info.addr + serial_offset;
397 /* Encode register access size */
398 switch (serial_info.reg_shift) {
400 access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
403 access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
406 access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
409 access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
412 access_size = ACPI_ACCESS_SIZE_UNDEFINED;
416 debug("UART type %u @ %lx\n", spcr->interface_type, serial_address);
419 spcr->serial_port.space_id = space_id;
420 spcr->serial_port.bit_width = serial_width;
421 spcr->serial_port.bit_offset = 0;
422 spcr->serial_port.access_size = access_size;
423 spcr->serial_port.addrl = lower_32_bits(serial_address);
424 spcr->serial_port.addrh = upper_32_bits(serial_address);
426 /* Encode baud rate */
427 switch (serial_info.baudrate) {
445 serial_config = SERIAL_DEFAULT_CONFIG;
447 ret = serial_getconfig(dev, &serial_config);
449 spcr->parity = SERIAL_GET_PARITY(serial_config);
450 spcr->stop_bits = SERIAL_GET_STOP(serial_config);
452 /* No PCI devices for now */
453 spcr->pci_device_id = 0xffff;
454 spcr->pci_vendor_id = 0xffff;
457 * SPCR has no clue if the UART base clock speed is different
458 * to the default one. However, the SPCR 1.04 defines baud rate
459 * 0 as a preconfigured state of UART and OS is supposed not
460 * to touch the configuration of the serial device.
462 if (serial_info.clock != SERIAL_DEFAULT_CLOCK)
466 header->checksum = table_compute_checksum((void *)spcr, header->length);
470 * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
472 ulong write_acpi_tables(ulong start_addr)
474 struct acpi_ctx sctx, *ctx = &sctx;
475 struct acpi_rsdp *rsdp;
476 struct acpi_rsdt *rsdt;
477 struct acpi_xsdt *xsdt;
478 struct acpi_facs *facs;
479 struct acpi_table_header *dsdt;
480 struct acpi_fadt *fadt;
481 struct acpi_mcfg *mcfg;
482 struct acpi_madt *madt;
483 struct acpi_csrt *csrt;
484 struct acpi_spcr *spcr;
489 start = map_sysmem(start_addr, 0);
490 ctx->current = start;
492 /* Align ACPI tables to 16 byte */
495 debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
497 /* We need at least an RSDP and an RSDT Table */
499 acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
501 acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
503 acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
505 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
506 * boundary (Windows checks this, but Linux does not).
510 /* clear all table memory */
511 memset((void *)start, 0, ctx->current - start);
513 acpi_write_rsdp(rsdp, rsdt, xsdt);
514 acpi_write_rsdt(rsdt);
515 acpi_write_xsdt(xsdt);
517 debug("ACPI: * FACS\n");
519 acpi_inc_align(ctx, sizeof(struct acpi_facs));
521 acpi_create_facs(facs);
523 debug("ACPI: * DSDT\n");
525 memcpy(dsdt, &AmlCode, sizeof(struct acpi_table_header));
526 acpi_inc(ctx, sizeof(struct acpi_table_header));
528 (char *)&AmlCode + sizeof(struct acpi_table_header),
529 dsdt->length - sizeof(struct acpi_table_header));
530 acpi_inc_align(ctx, dsdt->length - sizeof(struct acpi_table_header));
532 /* Pack GNVS into the ACPI table area */
533 for (i = 0; i < dsdt->length; i++) {
534 u32 *gnvs = (u32 *)((u32)dsdt + i);
535 if (*gnvs == ACPI_GNVS_ADDR) {
536 ulong addr = (ulong)map_to_sysmem(ctx->current);
538 debug("Fix up global NVS in DSDT to %#08lx\n", addr);
544 /* Update DSDT checksum since we patched the GNVS address */
546 dsdt->checksum = table_compute_checksum((void *)dsdt, dsdt->length);
548 /* Fill in platform-specific global NVS variables */
549 acpi_create_gnvs(ctx->current);
550 acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
552 debug("ACPI: * FADT\n");
554 acpi_inc_align(ctx, sizeof(struct acpi_fadt));
555 acpi_create_fadt(fadt, facs, dsdt);
556 acpi_add_table(rsdp, fadt);
558 debug("ACPI: * MADT\n");
560 acpi_create_madt(madt);
561 acpi_inc_align(ctx, madt->header.length);
562 acpi_add_table(rsdp, madt);
564 debug("ACPI: * MCFG\n");
566 acpi_create_mcfg(mcfg);
567 acpi_inc_align(ctx, mcfg->header.length);
568 acpi_add_table(rsdp, mcfg);
570 debug("ACPI: * CSRT\n");
572 acpi_create_csrt(csrt);
573 acpi_inc_align(ctx, csrt->header.length);
574 acpi_add_table(rsdp, csrt);
576 debug("ACPI: * SPCR\n");
578 acpi_create_spcr(spcr);
579 acpi_inc_align(ctx, spcr->header.length);
580 acpi_add_table(rsdp, spcr);
582 acpi_write_dev_tables(ctx);
584 addr = map_to_sysmem(ctx->current);
585 debug("current = %lx\n", addr);
587 acpi_rsdp_addr = (unsigned long)rsdp;
588 debug("ACPI: done\n");
593 ulong acpi_get_rsdp_addr(void)
595 return acpi_rsdp_addr;