blob: c0534343f1f8ec2d8dd7a6a75aaedeb8bed8ac6c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Saket Sinha867bcb62015-08-22 12:20:55 +05302/*
3 * Based on acpi.c from coreboot
4 *
5 * Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com>
Bin Mengab5efd52016-05-07 07:46:25 -07006 * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
Saket Sinha867bcb62015-08-22 12:20:55 +05307 */
8
Simon Glass2da4b692020-09-22 12:45:34 -06009#define LOG_CATEGORY LOGC_ACPI
10
Saket Sinha867bcb62015-08-22 12:20:55 +053011#include <common.h>
Simon Glass9179c352020-09-22 12:45:32 -060012#include <bloblist.h>
Saket Sinha867bcb62015-08-22 12:20:55 +053013#include <cpu.h>
14#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060015#include <log.h>
Saket Sinha867bcb62015-08-22 12:20:55 +053016#include <dm/uclass-internal.h>
Simon Glass86e17782020-04-26 09:19:47 -060017#include <mapmem.h>
Andy Shevchenkob288cd92018-11-20 23:52:38 +020018#include <serial.h>
Simon Glass351fef52020-07-07 13:12:07 -060019#include <acpi/acpigen.h>
Simon Glassf37979e2020-09-22 12:45:10 -060020#include <acpi/acpi_device.h>
Simon Glass776cc202020-04-08 16:57:36 -060021#include <acpi/acpi_table.h>
Bin Meng79c2c252016-06-17 02:13:16 -070022#include <asm/acpi/global_nvs.h>
Andy Shevchenkob156da92017-07-21 22:32:04 +030023#include <asm/ioapic.h>
Simon Glass401d1c42020-10-30 21:38:53 -060024#include <asm/global_data.h>
Saket Sinha867bcb62015-08-22 12:20:55 +053025#include <asm/lapic.h>
Andy Shevchenkob156da92017-07-21 22:32:04 +030026#include <asm/mpspec.h>
Saket Sinha867bcb62015-08-22 12:20:55 +053027#include <asm/tables.h>
Bin Meng79c2c252016-06-17 02:13:16 -070028#include <asm/arch/global_nvs.h>
Simon Glass86e17782020-04-26 09:19:47 -060029#include <dm/acpi.h>
Simon Glass8d7ff122020-07-07 21:32:05 -060030#include <linux/err.h>
Saket Sinha867bcb62015-08-22 12:20:55 +053031
Bin Mengab5efd52016-05-07 07:46:25 -070032static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic,
33 u8 cpu, u8 apic)
34{
35 lapic->type = ACPI_APIC_LAPIC;
36 lapic->length = sizeof(struct acpi_madt_lapic);
37 lapic->flags = LOCAL_APIC_FLAG_ENABLED;
38 lapic->processor_id = cpu;
39 lapic->apic_id = apic;
40
41 return lapic->length;
42}
43
Bin Mengfc4f5cc2016-05-07 07:46:30 -070044int acpi_create_madt_lapics(u32 current)
Bin Mengab5efd52016-05-07 07:46:25 -070045{
46 struct udevice *dev;
George McCollister8a1a7592016-06-07 13:40:18 -050047 int total_length = 0;
Simon Glass4ff35912020-09-22 12:45:31 -060048 int cpu_num = 0;
Bin Mengab5efd52016-05-07 07:46:25 -070049
50 for (uclass_find_first_device(UCLASS_CPU, &dev);
51 dev;
52 uclass_find_next_device(&dev)) {
Simon Glass8a8d24b2020-12-03 16:55:23 -070053 struct cpu_plat *plat = dev_get_parent_plat(dev);
Simon Glass4ff35912020-09-22 12:45:31 -060054 int length;
55
56 length = acpi_create_madt_lapic(
57 (struct acpi_madt_lapic *)current, cpu_num++,
58 plat->cpu_id);
Bin Mengfc4f5cc2016-05-07 07:46:30 -070059 current += length;
George McCollister8a1a7592016-06-07 13:40:18 -050060 total_length += length;
Bin Mengab5efd52016-05-07 07:46:25 -070061 }
62
George McCollister8a1a7592016-06-07 13:40:18 -050063 return total_length;
Bin Mengab5efd52016-05-07 07:46:25 -070064}
65
66int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id,
67 u32 addr, u32 gsi_base)
68{
69 ioapic->type = ACPI_APIC_IOAPIC;
70 ioapic->length = sizeof(struct acpi_madt_ioapic);
71 ioapic->reserved = 0x00;
72 ioapic->gsi_base = gsi_base;
73 ioapic->ioapic_id = id;
74 ioapic->ioapic_addr = addr;
75
76 return ioapic->length;
77}
78
79int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
80 u8 bus, u8 source, u32 gsirq, u16 flags)
81{
82 irqoverride->type = ACPI_APIC_IRQ_SRC_OVERRIDE;
83 irqoverride->length = sizeof(struct acpi_madt_irqoverride);
84 irqoverride->bus = bus;
85 irqoverride->source = source;
86 irqoverride->gsirq = gsirq;
87 irqoverride->flags = flags;
88
89 return irqoverride->length;
90}
91
92int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
93 u8 cpu, u16 flags, u8 lint)
94{
95 lapic_nmi->type = ACPI_APIC_LAPIC_NMI;
96 lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi);
97 lapic_nmi->flags = flags;
98 lapic_nmi->processor_id = cpu;
99 lapic_nmi->lint = lint;
100
101 return lapic_nmi->length;
102}
103
Andy Shevchenkob156da92017-07-21 22:32:04 +0300104static int acpi_create_madt_irq_overrides(u32 current)
105{
106 struct acpi_madt_irqoverride *irqovr;
107 u16 sci_flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_HIGH;
108 int length = 0;
109
110 irqovr = (void *)current;
111 length += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
112
113 irqovr = (void *)(current + length);
114 length += acpi_create_madt_irqoverride(irqovr, 0, 9, 9, sci_flags);
115
116 return length;
117}
118
119__weak u32 acpi_fill_madt(u32 current)
120{
121 current += acpi_create_madt_lapics(current);
122
123 current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current,
124 io_apic_read(IO_APIC_ID) >> 24, IO_APIC_ADDR, 0);
125
126 current += acpi_create_madt_irq_overrides(current);
127
128 return current;
129}
130
Simon Glassc797f98b2021-12-01 09:02:58 -0700131int acpi_write_madt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
Bin Mengab5efd52016-05-07 07:46:25 -0700132{
Simon Glassc797f98b2021-12-01 09:02:58 -0700133 struct acpi_table_header *header;
134 struct acpi_madt *madt;
135 u32 current;
Bin Mengab5efd52016-05-07 07:46:25 -0700136
Simon Glassc797f98b2021-12-01 09:02:58 -0700137 madt = ctx->current;
138
139 memset(madt, '\0', sizeof(struct acpi_madt));
140 header = &madt->header;
Bin Mengab5efd52016-05-07 07:46:25 -0700141
142 /* Fill out header fields */
143 acpi_fill_header(header, "APIC");
144 header->length = sizeof(struct acpi_madt);
Simon Glass22a73962020-07-16 21:22:37 -0600145 header->revision = ACPI_MADT_REV_ACPI_3_0;
Bin Mengab5efd52016-05-07 07:46:25 -0700146
147 madt->lapic_addr = LAPIC_DEFAULT_BASE;
148 madt->flags = ACPI_MADT_PCAT_COMPAT;
149
Simon Glassc797f98b2021-12-01 09:02:58 -0700150 current = (u32)madt + sizeof(struct acpi_madt);
Bin Mengab5efd52016-05-07 07:46:25 -0700151 current = acpi_fill_madt(current);
152
153 /* (Re)calculate length and checksum */
Bin Meng7e79a6b2016-05-07 07:46:26 -0700154 header->length = current - (u32)madt;
Bin Mengab5efd52016-05-07 07:46:25 -0700155
156 header->checksum = table_compute_checksum((void *)madt, header->length);
Simon Glassc797f98b2021-12-01 09:02:58 -0700157 acpi_add_table(ctx, madt);
158 acpi_inc(ctx, madt->header.length);
159
160 return 0;
Bin Mengab5efd52016-05-07 07:46:25 -0700161}
Simon Glassc797f98b2021-12-01 09:02:58 -0700162ACPI_WRITER(5x86, NULL, acpi_write_madt, 0);
Bin Mengab5efd52016-05-07 07:46:25 -0700163
Andy Shevchenkoace77622017-07-21 22:32:05 +0300164int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base,
165 u16 seg_nr, u8 start, u8 end)
Bin Mengab5efd52016-05-07 07:46:25 -0700166{
167 memset(mmconfig, 0, sizeof(*mmconfig));
168 mmconfig->base_address_l = base;
169 mmconfig->base_address_h = 0;
170 mmconfig->pci_segment_group_number = seg_nr;
171 mmconfig->start_bus_number = start;
172 mmconfig->end_bus_number = end;
173
174 return sizeof(struct acpi_mcfg_mmconfig);
175}
176
Andy Shevchenkoace77622017-07-21 22:32:05 +0300177__weak u32 acpi_fill_mcfg(u32 current)
Bin Mengab5efd52016-05-07 07:46:25 -0700178{
179 current += acpi_create_mcfg_mmconfig
180 ((struct acpi_mcfg_mmconfig *)current,
181 CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255);
182
183 return current;
184}
185
Simon Glass77bb1c62020-09-22 12:45:33 -0600186/**
187 * acpi_create_tcpa() - Create a TCPA table
188 *
Simon Glass77bb1c62020-09-22 12:45:33 -0600189 * Trusted Computing Platform Alliance Capabilities Table
190 * TCPA PC Specific Implementation SpecificationTCPA is defined in the PCI
191 * Firmware Specification 3.0
192 */
Simon Glassef55f482021-12-01 09:02:59 -0700193int acpi_write_tcpa(struct acpi_ctx *ctx, const struct acpi_writer *entry)
Simon Glass77bb1c62020-09-22 12:45:33 -0600194{
Simon Glassef55f482021-12-01 09:02:59 -0700195 struct acpi_table_header *header;
196 struct acpi_tcpa *tcpa;
197 u32 current;
Simon Glass77bb1c62020-09-22 12:45:33 -0600198 int size = 0x10000; /* Use this as the default size */
199 void *log;
200 int ret;
201
Simon Glassef55f482021-12-01 09:02:59 -0700202 if (!IS_ENABLED(CONFIG_TPM_V1))
203 return -ENOENT;
Simon Glass77bb1c62020-09-22 12:45:33 -0600204 if (!CONFIG_IS_ENABLED(BLOBLIST))
205 return -ENXIO;
Simon Glassef55f482021-12-01 09:02:59 -0700206
207 tcpa = ctx->current;
208 header = &tcpa->header;
Simon Glass77bb1c62020-09-22 12:45:33 -0600209 memset(tcpa, '\0', sizeof(struct acpi_tcpa));
210
211 /* Fill out header fields */
212 acpi_fill_header(header, "TCPA");
213 header->length = sizeof(struct acpi_tcpa);
214 header->revision = 1;
215
216 ret = bloblist_ensure_size_ret(BLOBLISTT_TCPA_LOG, &size, &log);
217 if (ret)
218 return log_msg_ret("blob", ret);
219
220 tcpa->platform_class = 0;
221 tcpa->laml = size;
Simon Glassef55f482021-12-01 09:02:59 -0700222 tcpa->lasa = map_to_sysmem(log);
Simon Glass77bb1c62020-09-22 12:45:33 -0600223
224 /* (Re)calculate length and checksum */
Simon Glassef55f482021-12-01 09:02:59 -0700225 current = (u32)tcpa + sizeof(struct acpi_tcpa);
Simon Glass77bb1c62020-09-22 12:45:33 -0600226 header->length = current - (u32)tcpa;
Simon Glassef55f482021-12-01 09:02:59 -0700227 header->checksum = table_compute_checksum(tcpa, header->length);
228
229 acpi_inc(ctx, tcpa->header.length);
230 acpi_add_table(ctx, tcpa);
Simon Glass77bb1c62020-09-22 12:45:33 -0600231
232 return 0;
233}
Simon Glassef55f482021-12-01 09:02:59 -0700234ACPI_WRITER(5tcpa, "TCPA", acpi_write_tcpa, 0);
Simon Glass77bb1c62020-09-22 12:45:33 -0600235
Simon Glass9179c352020-09-22 12:45:32 -0600236static int get_tpm2_log(void **ptrp, int *sizep)
237{
238 const int tpm2_default_log_len = 0x10000;
239 int size;
240 int ret;
241
242 *sizep = 0;
243 size = tpm2_default_log_len;
244 ret = bloblist_ensure_size_ret(BLOBLISTT_TPM2_TCG_LOG, &size, ptrp);
245 if (ret)
246 return log_msg_ret("blob", ret);
247 *sizep = size;
248
249 return 0;
250}
251
Simon Glass9aacd832021-12-01 09:02:57 -0700252static int acpi_write_tpm2(struct acpi_ctx *ctx,
253 const struct acpi_writer *entry)
Simon Glass9179c352020-09-22 12:45:32 -0600254{
Simon Glass9aacd832021-12-01 09:02:57 -0700255 struct acpi_table_header *header;
256 struct acpi_tpm2 *tpm2;
Simon Glass9179c352020-09-22 12:45:32 -0600257 int tpm2_log_len;
258 void *lasa;
259 int ret;
260
Simon Glass9aacd832021-12-01 09:02:57 -0700261 if (!IS_ENABLED(CONFIG_TPM_V2))
262 return log_msg_ret("none", -ENOENT);
263
264 tpm2 = ctx->current;
265 header = &tpm2->header;
266 memset(tpm2, '\0', sizeof(struct acpi_tpm2));
Simon Glass9179c352020-09-22 12:45:32 -0600267
268 /*
269 * Some payloads like SeaBIOS depend on log area to use TPM2.
270 * Get the memory size and address of TPM2 log area or initialize it.
271 */
272 ret = get_tpm2_log(&lasa, &tpm2_log_len);
273 if (ret)
Simon Glass9aacd832021-12-01 09:02:57 -0700274 return log_msg_ret("log", ret);
Simon Glass9179c352020-09-22 12:45:32 -0600275
276 /* Fill out header fields. */
277 acpi_fill_header(header, "TPM2");
278 memcpy(header->aslc_id, ASLC_ID, 4);
279
280 header->length = sizeof(struct acpi_tpm2);
281 header->revision = acpi_get_table_revision(ACPITAB_TPM2);
282
Simon Glass9aacd832021-12-01 09:02:57 -0700283 /* Hard to detect for U-Boot. Just set it to 0 */
Simon Glass9179c352020-09-22 12:45:32 -0600284 tpm2->platform_class = 0;
285
286 /* Must be set to 0 for FIFO-interface support */
287 tpm2->control_area = 0;
288 tpm2->start_method = 6;
289 memset(tpm2->msp, 0, sizeof(tpm2->msp));
290
291 /* Fill the log area size and start address fields. */
292 tpm2->laml = tpm2_log_len;
Simon Glass9aacd832021-12-01 09:02:57 -0700293 tpm2->lasa = map_to_sysmem(lasa);
Simon Glass9179c352020-09-22 12:45:32 -0600294
295 /* Calculate checksum. */
Simon Glass9aacd832021-12-01 09:02:57 -0700296 header->checksum = table_compute_checksum(tpm2, header->length);
297
298 acpi_inc(ctx, tpm2->header.length);
299 acpi_add_table(ctx, tpm2);
Simon Glass9179c352020-09-22 12:45:32 -0600300
301 return 0;
302}
Simon Glass9aacd832021-12-01 09:02:57 -0700303ACPI_WRITER(5tpm2, "TPM2", acpi_write_tpm2, 0);
Simon Glass9179c352020-09-22 12:45:32 -0600304
Simon Glass85b81612021-12-01 09:03:00 -0700305int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry)
Andy Shevchenkoddd2a422019-07-14 19:23:57 +0300306{
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200307 struct serial_device_info serial_info = {0};
308 ulong serial_address, serial_offset;
Simon Glass85b81612021-12-01 09:03:00 -0700309 struct acpi_table_header *header;
310 struct acpi_spcr *spcr;
Simon Glass67d1b052018-12-28 14:23:08 -0700311 struct udevice *dev;
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200312 uint serial_config;
313 uint serial_width;
314 int access_size;
315 int space_id;
Andy Shevchenkoedf18a82019-02-28 17:19:54 +0200316 int ret = -ENODEV;
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200317
Simon Glass85b81612021-12-01 09:03:00 -0700318 spcr = ctx->current;
319 header = &spcr->header;
320
321 memset(spcr, '\0', sizeof(struct acpi_spcr));
Wolfgang Wallner40edea32020-09-16 16:57:53 +0200322
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200323 /* Fill out header fields */
324 acpi_fill_header(header, "SPCR");
325 header->length = sizeof(struct acpi_spcr);
326 header->revision = 2;
327
Simon Glassa61cbad2018-12-28 14:23:10 -0700328 /* Read the device once, here. It is reused below */
Andy Shevchenkoedf18a82019-02-28 17:19:54 +0200329 dev = gd->cur_serial_dev;
330 if (dev)
Simon Glassa61cbad2018-12-28 14:23:10 -0700331 ret = serial_getinfo(dev, &serial_info);
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200332 if (ret)
333 serial_info.type = SERIAL_CHIP_UNKNOWN;
334
335 /* Encode chip type */
336 switch (serial_info.type) {
337 case SERIAL_CHIP_16550_COMPATIBLE:
338 spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
339 break;
340 case SERIAL_CHIP_UNKNOWN:
341 default:
342 spcr->interface_type = ACPI_DBG2_UNKNOWN;
343 break;
344 }
345
346 /* Encode address space */
347 switch (serial_info.addr_space) {
348 case SERIAL_ADDRESS_SPACE_MEMORY:
349 space_id = ACPI_ADDRESS_SPACE_MEMORY;
350 break;
351 case SERIAL_ADDRESS_SPACE_IO:
352 default:
353 space_id = ACPI_ADDRESS_SPACE_IO;
354 break;
355 }
356
357 serial_width = serial_info.reg_width * 8;
358 serial_offset = serial_info.reg_offset << serial_info.reg_shift;
359 serial_address = serial_info.addr + serial_offset;
360
361 /* Encode register access size */
362 switch (serial_info.reg_shift) {
363 case 0:
364 access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
365 break;
366 case 1:
367 access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
368 break;
369 case 2:
370 access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
371 break;
372 case 3:
373 access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
374 break;
375 default:
376 access_size = ACPI_ACCESS_SIZE_UNDEFINED;
377 break;
378 }
379
380 debug("UART type %u @ %lx\n", spcr->interface_type, serial_address);
381
382 /* Fill GAS */
383 spcr->serial_port.space_id = space_id;
384 spcr->serial_port.bit_width = serial_width;
385 spcr->serial_port.bit_offset = 0;
386 spcr->serial_port.access_size = access_size;
387 spcr->serial_port.addrl = lower_32_bits(serial_address);
388 spcr->serial_port.addrh = upper_32_bits(serial_address);
389
390 /* Encode baud rate */
391 switch (serial_info.baudrate) {
392 case 9600:
393 spcr->baud_rate = 3;
394 break;
395 case 19200:
396 spcr->baud_rate = 4;
397 break;
398 case 57600:
399 spcr->baud_rate = 6;
400 break;
401 case 115200:
402 spcr->baud_rate = 7;
403 break;
404 default:
405 spcr->baud_rate = 0;
406 break;
407 }
408
Simon Glassa61cbad2018-12-28 14:23:10 -0700409 serial_config = SERIAL_DEFAULT_CONFIG;
410 if (dev)
Simon Glass67d1b052018-12-28 14:23:08 -0700411 ret = serial_getconfig(dev, &serial_config);
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200412
413 spcr->parity = SERIAL_GET_PARITY(serial_config);
414 spcr->stop_bits = SERIAL_GET_STOP(serial_config);
415
416 /* No PCI devices for now */
417 spcr->pci_device_id = 0xffff;
418 spcr->pci_vendor_id = 0xffff;
419
Andy Shevchenko98036fb2020-02-27 17:21:56 +0200420 /*
421 * SPCR has no clue if the UART base clock speed is different
422 * to the default one. However, the SPCR 1.04 defines baud rate
423 * 0 as a preconfigured state of UART and OS is supposed not
424 * to touch the configuration of the serial device.
425 */
426 if (serial_info.clock != SERIAL_DEFAULT_CLOCK)
427 spcr->baud_rate = 0;
428
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200429 /* Fix checksum */
430 header->checksum = table_compute_checksum((void *)spcr, header->length);
Simon Glass85b81612021-12-01 09:03:00 -0700431
432 acpi_add_table(ctx, spcr);
433 acpi_inc(ctx, spcr->header.length);
434
435 return 0;
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200436}
Simon Glass85b81612021-12-01 09:03:00 -0700437ACPI_WRITER(5spcr, "SPCR", acpi_write_spcr, 0);
Andy Shevchenkob288cd92018-11-20 23:52:38 +0200438
Simon Glass32af3262021-12-01 09:02:53 -0700439int acpi_write_gnvs(struct acpi_ctx *ctx, const struct acpi_writer *entry)
440{
441 ulong addr;
442
443 if (!IS_ENABLED(CONFIG_ACPI_GNVS_EXTERNAL)) {
444 int i;
445
446 /* We need the DSDT to be done */
447 if (!ctx->dsdt)
448 return log_msg_ret("dsdt", -EAGAIN);
449
450 /* Pack GNVS into the ACPI table area */
451 for (i = 0; i < ctx->dsdt->length; i++) {
452 u32 *gnvs = (u32 *)((u32)ctx->dsdt + i);
453
454 if (*gnvs == ACPI_GNVS_ADDR) {
455 *gnvs = map_to_sysmem(ctx->current);
456 log_debug("Fix up global NVS in DSDT to %#08x\n",
457 *gnvs);
458 break;
459 }
460 }
461
462 /*
463 * Recalculate the length and update the DSDT checksum since we
464 * patched the GNVS address. Set the checksum to zero since it
465 * is part of the region being checksummed.
466 */
467 ctx->dsdt->checksum = 0;
468 ctx->dsdt->checksum = table_compute_checksum((void *)ctx->dsdt,
469 ctx->dsdt->length);
470 }
471
472 /* Fill in platform-specific global NVS variables */
473 addr = acpi_create_gnvs(ctx->current);
474 if (IS_ERR_VALUE(addr))
475 return log_msg_ret("gnvs", (int)addr);
476
477 acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
478
479 return 0;
480}
481ACPI_WRITER(4gnvs, "GNVS", acpi_write_gnvs, 0);
482
Simon Glassd9531372021-12-01 09:02:56 -0700483/* MCFG is defined in the PCI Firmware Specification 3.0 */
484int acpi_write_mcfg(struct acpi_ctx *ctx, const struct acpi_writer *entry)
485{
486 struct acpi_table_header *header;
487 struct acpi_mcfg *mcfg;
488 u32 current;
489
490 mcfg = ctx->current;
491 header = &mcfg->header;
492
493 current = (u32)mcfg + sizeof(struct acpi_mcfg);
494
495 memset(mcfg, '\0', sizeof(struct acpi_mcfg));
496
497 /* Fill out header fields */
498 acpi_fill_header(header, "MCFG");
499 header->length = sizeof(struct acpi_mcfg);
500 header->revision = 1;
501
502 /* (Re)calculate length and checksum */
503 header->length = current - (u32)mcfg;
504 header->checksum = table_compute_checksum(mcfg, header->length);
505
506 acpi_inc(ctx, mcfg->header.length);
507 acpi_add_table(ctx, mcfg);
508
509 return 0;
510}
511ACPI_WRITER(5mcfg, "MCFG", acpi_write_mcfg, 0);
512
Simon Glassd2628982020-09-22 12:45:09 -0600513/**
514 * acpi_write_hpet() - Write out a HPET table
515 *
516 * Write out the table for High-Precision Event Timers
517 *
518 * @hpet: Place to put HPET table
519 */
520static int acpi_create_hpet(struct acpi_hpet *hpet)
521{
522 struct acpi_table_header *header = &hpet->header;
523 struct acpi_gen_regaddr *addr = &hpet->addr;
524
525 /*
526 * See IA-PC HPET (High Precision Event Timers) Specification v1.0a
527 * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf
528 */
529 memset((void *)hpet, '\0', sizeof(struct acpi_hpet));
530
531 /* Fill out header fields. */
532 acpi_fill_header(header, "HPET");
533
534 header->aslc_revision = ASL_REVISION;
535 header->length = sizeof(struct acpi_hpet);
536 header->revision = acpi_get_table_revision(ACPITAB_HPET);
537
538 /* Fill out HPET address */
539 addr->space_id = 0; /* Memory */
540 addr->bit_width = 64;
541 addr->bit_offset = 0;
542 addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff;
543 addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32;
544
545 hpet->id = *(u32 *)CONFIG_HPET_ADDRESS;
546 hpet->number = 0;
547 hpet->min_tick = 0; /* HPET_MIN_TICKS */
548
549 header->checksum = table_compute_checksum(hpet,
550 sizeof(struct acpi_hpet));
551
552 return 0;
553}
554
555int acpi_write_hpet(struct acpi_ctx *ctx)
556{
557 struct acpi_hpet *hpet;
558 int ret;
559
560 log_debug("ACPI: * HPET\n");
561
562 hpet = ctx->current;
563 acpi_inc_align(ctx, sizeof(struct acpi_hpet));
564 acpi_create_hpet(hpet);
565 ret = acpi_add_table(ctx, hpet);
566 if (ret)
567 return log_msg_ret("add", ret);
568
569 return 0;
570}
Simon Glassf37979e2020-09-22 12:45:10 -0600571
572int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
573 uint access_size)
574{
575 struct acpi_dbg2_header *dbg2 = ctx->current;
576 char path[ACPI_PATH_MAX];
577 struct acpi_gen_regaddr address;
578 phys_addr_t addr;
579 int ret;
580
581 if (!device_active(dev)) {
582 log_info("Device not enabled\n");
583 return -EACCES;
584 }
585 /*
586 * PCI devices don't remember their resource allocation information in
587 * U-Boot at present. We assume that MMIO is used for the UART and that
588 * the address space is 32 bytes: ns16550 uses 8 registers of up to
589 * 32-bits each. This is only for debugging so it is not a big deal.
590 */
591 addr = dm_pci_read_bar32(dev, 0);
Simon Glass98bf7402020-11-04 09:57:41 -0700592 log_debug("UART addr %lx\n", (ulong)addr);
Simon Glassf37979e2020-09-22 12:45:10 -0600593
594 memset(&address, '\0', sizeof(address));
595 address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
596 address.addrl = (uint32_t)addr;
597 address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
598 address.access_size = access_size;
599
600 ret = acpi_device_path(dev, path, sizeof(path));
601 if (ret)
602 return log_msg_ret("path", ret);
603 acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
604 ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
605
606 acpi_inc_align(ctx, dbg2->header.length);
607 acpi_add_table(ctx, dbg2);
608
609 return 0;
610}
Simon Glass540f0ba2020-09-22 12:45:16 -0600611
612void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs,
613 void *dsdt)
614{
615 struct acpi_table_header *header = &fadt->header;
616
617 memset((void *)fadt, '\0', sizeof(struct acpi_fadt));
618
619 acpi_fill_header(header, "FACP");
620 header->length = sizeof(struct acpi_fadt);
621 header->revision = 4;
622 memcpy(header->oem_id, OEM_ID, 6);
623 memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
624 memcpy(header->aslc_id, ASLC_ID, 4);
625 header->aslc_revision = 1;
626
627 fadt->firmware_ctrl = (unsigned long)facs;
628 fadt->dsdt = (unsigned long)dsdt;
629
630 fadt->x_firmware_ctl_l = (unsigned long)facs;
631 fadt->x_firmware_ctl_h = 0;
632 fadt->x_dsdt_l = (unsigned long)dsdt;
633 fadt->x_dsdt_h = 0;
634
635 fadt->preferred_pm_profile = ACPI_PM_MOBILE;
636
637 /* Use ACPI 3.0 revision */
638 fadt->header.revision = 4;
639}
640
641void acpi_create_dmar_drhd(struct acpi_ctx *ctx, uint flags, uint segment,
642 u64 bar)
643{
644 struct dmar_entry *drhd = ctx->current;
645
646 memset(drhd, '\0', sizeof(*drhd));
647 drhd->type = DMAR_DRHD;
648 drhd->length = sizeof(*drhd); /* will be fixed up later */
649 drhd->flags = flags;
650 drhd->segment = segment;
651 drhd->bar = bar;
652 acpi_inc(ctx, drhd->length);
653}
654
655void acpi_create_dmar_rmrr(struct acpi_ctx *ctx, uint segment, u64 bar,
656 u64 limit)
657{
658 struct dmar_rmrr_entry *rmrr = ctx->current;
659
660 memset(rmrr, '\0', sizeof(*rmrr));
661 rmrr->type = DMAR_RMRR;
662 rmrr->length = sizeof(*rmrr); /* will be fixed up later */
663 rmrr->segment = segment;
664 rmrr->bar = bar;
665 rmrr->limit = limit;
666 acpi_inc(ctx, rmrr->length);
667}
668
669void acpi_dmar_drhd_fixup(struct acpi_ctx *ctx, void *base)
670{
671 struct dmar_entry *drhd = base;
672
673 drhd->length = ctx->current - base;
674}
675
676void acpi_dmar_rmrr_fixup(struct acpi_ctx *ctx, void *base)
677{
678 struct dmar_rmrr_entry *rmrr = base;
679
680 rmrr->length = ctx->current - base;
681}
682
683static int acpi_create_dmar_ds(struct acpi_ctx *ctx, enum dev_scope_type type,
684 uint enumeration_id, pci_dev_t bdf)
685{
686 /* we don't support longer paths yet */
687 const size_t dev_scope_length = sizeof(struct dev_scope) + 2;
688 struct dev_scope *ds = ctx->current;
689
690 memset(ds, '\0', dev_scope_length);
691 ds->type = type;
692 ds->length = dev_scope_length;
693 ds->enumeration = enumeration_id;
694 ds->start_bus = PCI_BUS(bdf);
695 ds->path[0].dev = PCI_DEV(bdf);
696 ds->path[0].fn = PCI_FUNC(bdf);
697
698 return ds->length;
699}
700
701int acpi_create_dmar_ds_pci_br(struct acpi_ctx *ctx, pci_dev_t bdf)
702{
703 return acpi_create_dmar_ds(ctx, SCOPE_PCI_SUB, 0, bdf);
704}
705
706int acpi_create_dmar_ds_pci(struct acpi_ctx *ctx, pci_dev_t bdf)
707{
708 return acpi_create_dmar_ds(ctx, SCOPE_PCI_ENDPOINT, 0, bdf);
709}
710
711int acpi_create_dmar_ds_ioapic(struct acpi_ctx *ctx, uint enumeration_id,
712 pci_dev_t bdf)
713{
714 return acpi_create_dmar_ds(ctx, SCOPE_IOAPIC, enumeration_id, bdf);
715}
716
717int acpi_create_dmar_ds_msi_hpet(struct acpi_ctx *ctx, uint enumeration_id,
718 pci_dev_t bdf)
719{
720 return acpi_create_dmar_ds(ctx, SCOPE_MSI_HPET, enumeration_id, bdf);
721}