xref: /openbsd/sys/arch/arm64/stand/efiboot/efiacpi.c (revision e5dd7070)
1 /*	$OpenBSD: efiacpi.c,v 1.8 2020/05/11 16:12:46 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 
21 #include <efi.h>
22 #include <efiapi.h>
23 
24 #include "eficall.h"
25 #include "fdt.h"
26 #include "libsa.h"
27 
28 #define	efi_guidcmp(_a, _b)	memcmp((_a), (_b), sizeof(EFI_GUID))
29 
30 #define fdt_node_add_string_property(n, p, s) \
31     fdt_node_add_property((n), (p), (s), strlen((s)) + 1)
32 #define fdt_node_set_string_property(n, p, s) \
33     fdt_node_set_property((n), (p), (s), strlen((s)) + 1)
34 
35 extern EFI_SYSTEM_TABLE		*ST;
36 
37 /* ACPI tables */
38 
39 struct acpi_rsdp1 {
40 	uint8_t		signature[8];
41 #define	RSDP_SIG	"RSD PTR "
42 #define	rsdp_signature	rsdp1.signature
43 	uint8_t		checksum;	/* make sum == 0 */
44 #define	rsdp_checksum	rsdp1.checksum
45 	uint8_t		oemid[6];
46 #define	rsdp_oemid	rsdp1.oemid
47 	uint8_t		revision;	/* 0 for 1, 2 for 2 */
48 #define	rsdp_revision	rsdp1.revision
49 	uint32_t	rsdt;		/* physical */
50 #define	rsdp_rsdt	rsdp1.rsdt
51 } __packed;
52 
53 struct acpi_rsdp {
54 	struct acpi_rsdp1 rsdp1;
55 	/*
56 	 * The following values are only valid
57 	 * when rsdp_revision == 2
58 	 */
59 	uint32_t	rsdp_length;		/* length of rsdp */
60 	uint64_t	rsdp_xsdt;		/* physical */
61 	uint8_t		rsdp_extchecksum;	/* entire table */
62 	uint8_t		rsdp_reserved[3];	/* must be zero */
63 } __packed;
64 
65 struct acpi_table_header {
66 	uint8_t		signature[4];
67 #define	hdr_signature		hdr.signature
68 	uint32_t	length;
69 #define	hdr_length		hdr.length
70 	uint8_t		revision;
71 #define	hdr_revision		hdr.revision
72 	uint8_t		checksum;
73 #define	hdr_checksum		hdr.checksum
74 	uint8_t		oemid[6];
75 #define hdr_oemid		hdr.oemid
76 	uint8_t		oemtableid[8];
77 #define hdr_oemtableid		hdr.oemtableid
78 	uint32_t	oemrevision;
79 #define	hdr_oemrevision		hdr.oemrevision
80 	uint8_t		aslcompilerid[4];
81 #define hdr_aslcompilerid	hdr.aslcompilerid
82 	uint32_t	aslcompilerrevision;
83 #define	hdr_aslcompilerrevision	hdr.aslcompilerrevision
84 } __packed;
85 
86 struct acpi_xsdt {
87 	struct acpi_table_header	hdr;
88 #define XSDT_SIG	"XSDT"
89 	uint64_t			table_offsets[1];
90 } __packed;
91 
92 struct acpi_gas {
93 	uint8_t		address_space_id;
94 #define GAS_SYSTEM_MEMORY	0
95 #define GAS_SYSTEM_IOSPACE	1
96 #define GAS_PCI_CFG_SPACE	2
97 #define GAS_EMBEDDED		3
98 #define GAS_SMBUS		4
99 #define GAS_FUNCTIONAL_FIXED	127
100 	uint8_t		register_bit_width;
101 	uint8_t		register_bit_offset;
102 	uint8_t		access_size;
103 #define GAS_ACCESS_UNDEFINED	0
104 #define GAS_ACCESS_BYTE		1
105 #define GAS_ACCESS_WORD		2
106 #define GAS_ACCESS_DWORD	3
107 #define GAS_ACCESS_QWORD	4
108 	uint64_t	address;
109 } __packed;
110 
111 struct acpi_fadt {
112 	struct acpi_table_header	hdr;
113 #define	FADT_SIG	"FACP"
114 	uint32_t	firmware_ctl;	/* phys addr FACS */
115 	uint32_t	dsdt;		/* phys addr DSDT */
116 	uint8_t		int_model;	/* interrupt model (hdr_revision < 3) */
117 #define	FADT_INT_DUAL_PIC	0
118 #define	FADT_INT_MULTI_APIC	1
119 	uint8_t		pm_profile;	/* power mgmt profile */
120 #define	FADT_PM_UNSPEC		0
121 #define	FADT_PM_DESKTOP		1
122 #define	FADT_PM_MOBILE		2
123 #define	FADT_PM_WORKSTATION	3
124 #define	FADT_PM_ENT_SERVER	4
125 #define	FADT_PM_SOHO_SERVER	5
126 #define	FADT_PM_APPLIANCE	6
127 #define	FADT_PM_PERF_SERVER	7
128 	uint16_t	sci_int;	/* SCI interrupt */
129 	uint32_t	smi_cmd;	/* SMI command port */
130 	uint8_t		acpi_enable;	/* value to enable */
131 	uint8_t		acpi_disable;	/* value to disable */
132 	uint8_t		s4bios_req;	/* value for S4 */
133 	uint8_t		pstate_cnt;	/* value for performance (hdr_revision > 2) */
134 	uint32_t	pm1a_evt_blk;	/* power management 1a */
135 	uint32_t	pm1b_evt_blk;	/* power mangement 1b */
136 	uint32_t	pm1a_cnt_blk;	/* pm control 1a */
137 	uint32_t	pm1b_cnt_blk;	/* pm control 1b */
138 	uint32_t	pm2_cnt_blk;	/* pm control 2 */
139 	uint32_t	pm_tmr_blk;
140 	uint32_t	gpe0_blk;
141 	uint32_t	gpe1_blk;
142 	uint8_t		pm1_evt_len;
143 	uint8_t		pm1_cnt_len;
144 	uint8_t		pm2_cnt_len;
145 	uint8_t		pm_tmr_len;
146 	uint8_t		gpe0_blk_len;
147 	uint8_t		gpe1_blk_len;
148 	uint8_t		gpe1_base;
149 	uint8_t		cst_cnt;	/* (hdr_revision > 2) */
150 	uint16_t	p_lvl2_lat;
151 	uint16_t	p_lvl3_lat;
152 	uint16_t	flush_size;
153 	uint16_t	flush_stride;
154 	uint8_t		duty_offset;
155 	uint8_t		duty_width;
156 	uint8_t		day_alrm;
157 	uint8_t		mon_alrm;
158 	uint8_t		century;
159 	uint16_t	iapc_boot_arch;	/* (hdr_revision > 2) */
160 #define	FADT_LEGACY_DEVICES		0x0001	/* Legacy devices supported */
161 #define	FADT_i8042			0x0002	/* Keyboard controller present */
162 #define	FADT_NO_VGA			0x0004	/* Do not probe VGA */
163 	uint8_t		reserved1;
164 	uint32_t	flags;
165 #define	FADT_WBINVD			0x00000001
166 #define	FADT_WBINVD_FLUSH		0x00000002
167 #define	FADT_PROC_C1			0x00000004
168 #define	FADT_P_LVL2_UP			0x00000008
169 #define	FADT_PWR_BUTTON			0x00000010
170 #define	FADT_SLP_BUTTON			0x00000020
171 #define	FADT_FIX_RTC			0x00000040
172 #define	FADT_RTC_S4			0x00000080
173 #define	FADT_TMR_VAL_EXT		0x00000100
174 #define	FADT_DCK_CAP			0x00000200
175 #define	FADT_RESET_REG_SUP		0x00000400
176 #define	FADT_SEALED_CASE		0x00000800
177 #define	FADT_HEADLESS			0x00001000
178 #define	FADT_CPU_SW_SLP			0x00002000
179 #define	FADT_PCI_EXP_WAK		0x00004000
180 #define	FADT_USE_PLATFORM_CLOCK		0x00008000
181 #define	FADT_S4_RTC_STS_VALID		0x00010000
182 #define	FADT_REMOTE_POWER_ON_CAPABLE	0x00020000
183 #define	FADT_FORCE_APIC_CLUSTER_MODEL	0x00040000
184 #define	FADT_FORCE_APIC_PHYS_DEST_MODE	0x00080000
185 #define	FADT_HW_REDUCED_ACPI		0x00100000
186 #define	FADT_POWER_S0_IDLE_CAPABLE	0x00200000
187 	/*
188 	 * Following values only exist when rev > 1
189 	 * If the extended addresses exists, they
190 	 * must be used in preferense to the non-
191 	 * extended values above
192 	 */
193 	struct acpi_gas	reset_reg;
194 	uint8_t		reset_value;
195 	uint16_t	arm_boot_arch;	/* (hdr_revision > 3) */
196 #define	FADT_PSCI_COMPLIANT		0x0001	/* PSCI is implemented */
197 #define	FADT_PSCI_USE_HVC		0x0002	/* HVC used as PSCI conduit */
198 	uint8_t		reserved2;
199 	uint64_t	x_firmware_ctl;
200 	uint64_t	x_dsdt;
201 	struct acpi_gas	x_pm1a_evt_blk;
202 	struct acpi_gas	x_pm1b_evt_blk;
203 	struct acpi_gas	x_pm1a_cnt_blk;
204 	struct acpi_gas	x_pm1b_cnt_blk;
205 	struct acpi_gas	x_pm2_cnt_blk;
206 	struct acpi_gas	x_pm_tmr_blk;
207 	struct acpi_gas	x_gpe0_blk;
208 	struct acpi_gas	x_gpe1_blk;
209 	struct acpi_gas sleep_control_reg;
210 	struct acpi_gas sleep_status_reg;
211 } __packed;
212 
213 struct acpi_gtdt {
214 	struct acpi_table_header	hdr;
215 #define GTDT_SIG	"GTDT"
216 	uint64_t	cnt_ctrl_base;
217 	uint32_t	reserved;
218 	uint32_t	sec_el1_interrupt;
219 	uint32_t	sec_el1_flags;
220 #define ACPI_GTDT_TIMER_TRIGGER_EDGE	0x1
221 #define ACPI_GTDT_TIMER_POLARITY_LOW	0x2
222 #define ACPI_GTDT_TIMER_ALWAYS_ON	0x4
223 	uint32_t	nonsec_el1_interrupt;
224 	uint32_t	nonsec_el1_flags;
225 	uint32_t	virt_interrupt;
226 	uint32_t	virt_flags;
227 	uint32_t	nonsec_el2_interrupt;
228 	uint32_t	nonsec_el2_flags;
229 	uint64_t	cnt_read_base;
230 	uint32_t	platform_timer_count;
231 	uint32_t	plaform_timer_offset;
232 } __packed;
233 
234 struct acpi_madt {
235 	struct acpi_table_header	hdr;
236 #define MADT_SIG	"APIC"
237 	uint32_t	local_apic_address;
238 	uint32_t	flags;
239 #define ACPI_APIC_PCAT_COMPAT	0x00000001
240 } __packed;
241 
242 struct acpi_madt_gicc {
243 	uint8_t		apic_type;
244 #define ACPI_MADT_GICC		11
245 	uint8_t		length;
246 	uint16_t	reserved1;
247 	uint32_t	gic_id;
248 	uint32_t	acpi_proc_uid;
249 	uint32_t	flags;
250 #define	ACPI_PROC_ENABLE	0x00000001
251 	uint32_t	parking_protocol_version;
252 	uint32_t	performance_interrupt;
253 	uint64_t	parked_address;
254 	uint64_t	base_address;
255 	uint64_t	gicv_base_address;
256 	uint64_t	gich_base_address;
257 	uint32_t	maintenance_interrupt;
258 	uint64_t	gicr_base_address;
259 	uint64_t	mpidr;
260 	uint8_t		efficiency_class;
261 	uint8_t		reserved2[3];
262 } __packed;
263 
264 struct acpi_madt_gicd {
265 	uint8_t		apic_type;
266 #define ACPI_MADT_GICD		12
267 	uint8_t		length;
268 	uint16_t	reserved1;
269 	uint32_t	gic_id;
270 	uint64_t	base_address;
271 	uint32_t	interrupt_base;
272 	uint8_t		version;
273 	uint8_t		reserved2[3];
274 } __packed;
275 
276 struct acpi_madt_gic_msi {
277 	uint8_t		apic_type;
278 #define ACPI_MADT_GIC_MSI	13
279 	uint8_t		length;
280 	uint16_t	reserved1;
281 	uint32_t	msi_frame_id;
282 	uint64_t	base_address;
283 	uint32_t	flags;
284 #define ACPI_MADT_GIC_MSI_SPI_SELECT	0x00000001
285 	uint16_t	spi_count;
286 	uint16_t	spi_base;
287 } __packed;
288 
289 struct acpi_madt_gicr {
290 	uint8_t		apic_type;
291 #define ACPI_MADT_GICR		14
292 	uint8_t		length;
293 	uint16_t	reserved1;
294 	uint64_t	discovery_base_address;
295 	uint32_t	discovery_length;
296 } __packed;
297 
298 struct acpi_madt_gic_its {
299 	uint8_t		apic_type;
300 #define ACPI_MADT_GIC_ITS	15
301 	uint8_t		length;
302 	uint16_t	reserved1;
303 	uint32_t	gic_its_id;
304 	uint64_t	base_address;
305 	uint32_t	reserved2;
306 } __packed;
307 
308 union acpi_madt_entry {
309 	struct acpi_madt_gicc		madt_gicc;
310 	struct acpi_madt_gicd		madt_gicd;
311 	struct acpi_madt_gic_msi	madt_gic_msi;
312 	struct acpi_madt_gicr		madt_gicr;
313 	struct acpi_madt_gic_its	madt_gic_its;
314 } __packed;
315 
316 struct acpi_spcr {
317 	struct acpi_table_header	hdr;
318 #define SPCR_SIG	"SPCR"
319 	uint8_t		interface_type;
320 #define SPCR_16550	0
321 #define SPCR_16450	1
322 #define SPCR_ARM_PL011	3
323 #define SPCR_ARM_SBSA	14
324 	uint8_t		reserved1[3];
325 	struct acpi_gas	base_address;
326 	uint8_t		interrupt_type;
327 	uint8_t		irq;
328 	uint32_t	gsiv;
329 	uint8_t		baud_rate;
330 	uint8_t		parity;
331 	uint8_t		stop_bits;
332 	uint8_t		flow_control;
333 	uint8_t		terminal_type;
334 	uint8_t		reserved2;
335 	uint16_t	pci_device_id;
336 	uint16_t	pci_vendor_id;
337 	uint8_t		pci_bus;
338 	uint8_t		pci_device;
339 	uint8_t		pci_function;
340 	uint32_t	pci_flags;
341 	uint8_t		pci_segment;
342 	uint32_t	reserved3;
343 };
344 
345 /* We'll never see ACPI 1.0 tables on ARM. */
346 static EFI_GUID acpi_guid = ACPI_20_TABLE_GUID;
347 
348 static int psci = 0;
349 
350 void
351 efi_acpi_fadt(struct acpi_table_header *hdr)
352 {
353 	struct acpi_fadt *fadt = (struct acpi_fadt *)hdr;
354 	void *node;
355 
356 	/*
357 	 * The PSCI flags were introduced in ACPI 5.1.  The relevant
358 	 * field is set to zero for ACPU 5.0.
359 	 */
360 	if (fadt->hdr_revision < 5)
361 		return;
362 
363 	psci = fadt->arm_boot_arch & FADT_PSCI_COMPLIANT;
364 
365 	node = fdt_find_node("/psci");
366 	if (fadt->arm_boot_arch & FADT_PSCI_COMPLIANT)
367 		fdt_node_set_string_property(node, "status", "okay");
368 	if (fadt->arm_boot_arch & FADT_PSCI_USE_HVC)
369 		fdt_node_set_string_property(node, "method", "hvc");
370 }
371 
372 void
373 efi_acpi_gtdt(struct acpi_table_header *hdr)
374 {
375 	struct acpi_gtdt *gtdt = (struct acpi_gtdt *)hdr;
376 	const uint32_t map[] = { 0x4, 0x1, 0x8, 0x2 };
377 	const uint32_t mask = ACPI_GTDT_TIMER_TRIGGER_EDGE |
378 	    ACPI_GTDT_TIMER_POLARITY_LOW;
379 	uint32_t interrupts[12];
380 	void *node;
381 
382 	/* All interrupts are supposed to be PPIs. */
383 	interrupts[0] = htobe32(1);
384 	interrupts[1] = htobe32(gtdt->sec_el1_interrupt - 16);
385 	interrupts[2] = htobe32(map[gtdt->sec_el1_flags & mask]);
386 	interrupts[3] = htobe32(1);
387 	interrupts[4] = htobe32(gtdt->nonsec_el1_interrupt - 16);
388 	interrupts[5] = htobe32(map[gtdt->nonsec_el1_flags & mask]);
389 	interrupts[6] = htobe32(1);
390 	interrupts[7] = htobe32(gtdt->virt_interrupt - 16);
391 	interrupts[8] = htobe32(map[gtdt->virt_flags & mask]);
392 	interrupts[9] = htobe32(1);
393 	interrupts[10] = htobe32(gtdt->nonsec_el2_interrupt - 16);
394 	interrupts[11] = htobe32(map[gtdt->virt_flags & mask]);
395 
396 	node = fdt_find_node("/timer");
397 	fdt_node_set_property(node, "interrupts",
398 	    interrupts, sizeof(interrupts));
399 	fdt_node_set_string_property(node, "status", "okay");
400 }
401 
402 static int gic_version;
403 static uint64_t gicc_base;
404 static uint64_t gicd_base;
405 static uint64_t gicr_base;
406 static uint32_t gicr_size;
407 
408 void
409 efi_acpi_madt_gicc(struct acpi_madt_gicc *gicc)
410 {
411 	uint64_t mpidr = gicc->mpidr;
412 	void *node, *child;
413 	uint64_t reg;
414 	char name[32];
415 
416 	/* Skip disabled CPUs. */
417 	if ((gicc->flags & ACPI_PROC_ENABLE) == 0)
418 		return;
419 
420 	/*
421 	 * MPIDR field was introduced in ACPI 5.1.  Fall back on the
422 	 * ACPI Processor UID on ACPI 5.0.
423 	 */
424 	mpidr = (gicc->length >= 76) ? gicc->mpidr : gicc->acpi_proc_uid;
425 
426 	snprintf(name, sizeof(name), "cpu@%llx", mpidr);
427 	reg = htobe64(mpidr);
428 
429 	/* Create "cpu" node. */
430 	node = fdt_find_node("/cpus");
431 	fdt_node_add_node(node, name, &child);
432 	fdt_node_add_string_property(child, "device_type", "cpu");
433 	fdt_node_add_string_property(child, "compatible", "arm,armv8");
434 	fdt_node_add_property(child, "reg", &reg, sizeof(reg));
435 	if (gicc->parking_protocol_version == 0 || psci)
436 		fdt_node_add_string_property(child, "enable-method", "psci");
437 
438 	/* Stash GIC information. */
439 	gicc_base = gicc->base_address;
440 }
441 
442 void
443 efi_acpi_madt_gicd(struct acpi_madt_gicd *gicd)
444 {
445 	/* Stash GIC information. */
446 	gic_version = gicd->version;
447 	gicd_base = gicd->base_address;
448 }
449 
450 void
451 efi_acpi_madt_gic_msi(struct acpi_madt_gic_msi *msi)
452 {
453 	static uint32_t phandle = 2;
454 	void *node, *child;
455 	uint64_t reg[2];
456 	char name[32];
457 
458 	snprintf(name, sizeof(name), "v2m@%llx", msi->base_address);
459 	reg[0] = htobe64(msi->base_address);
460 	reg[1] = htobe64(0x1000);
461 
462 	/* Create "v2m" node. */
463 	node = fdt_find_node("/interrupt-controller");
464 	fdt_node_add_node(node, name, &child);
465 	fdt_node_add_string_property(child, "compatible", "arm,gic-v2m-frame");
466 	fdt_node_add_property(child, "msi-controller", NULL, 0);
467 	fdt_node_add_property(child, "reg", reg, sizeof(reg));
468 	if (msi->flags & ACPI_MADT_GIC_MSI_SPI_SELECT) {
469 		uint32_t spi_base = msi->spi_base;
470 		uint32_t spi_count = msi->spi_count;
471 
472 		fdt_node_add_property(child, "arm,msi-base-spi",
473 		    &spi_base, sizeof(spi_base));
474 		fdt_node_add_property(child, "arm,msi-num-spis",
475 		    &spi_count, sizeof(spi_count));
476 	}
477 	fdt_node_add_property(child, "phandle", &phandle, sizeof(phandle));
478 	phandle++;
479 }
480 
481 void
482 efi_acpi_madt_gicr(struct acpi_madt_gicr *gicr)
483 {
484 	/* Stash GIC information. */
485 	gicr_base = gicr->discovery_base_address;
486 	gicr_size = gicr->discovery_length;
487 }
488 
489 void
490 efi_acpi_madt_gic_its(struct acpi_madt_gic_its *its)
491 {
492 	static uint32_t phandle = 2;
493 	void *node, *child;
494 	uint64_t reg[2];
495 	char name[32];
496 
497 	snprintf(name, sizeof(name), "gic-its@%llx", its->base_address);
498 	reg[0] = htobe64(its->base_address);
499 	reg[1] = htobe64(0x20000);
500 
501 	/* Create "gic-its" node. */
502 	node = fdt_find_node("/interrupt-controller");
503 	fdt_node_add_node(node, name, &child);
504 	fdt_node_add_string_property(child, "compatible", "arm,gic-v3-its");
505 	fdt_node_add_property(child, "msi-controller", NULL, 0);
506 	fdt_node_add_property(child, "reg", reg, sizeof(reg));
507 	fdt_node_add_property(child, "phandle", &phandle, sizeof(phandle));
508 	phandle++;
509 }
510 
511 void
512 efi_acpi_madt(struct acpi_table_header *hdr)
513 {
514 	struct acpi_madt *madt = (struct acpi_madt *)hdr;
515 	char *compat;
516 	uint64_t reg[4];
517 	char *addr;
518 	void *node;
519 
520 	/* GIC support was introduced in ACPI 5.0. */
521 	if (madt->hdr_revision < 3)
522 		return;
523 
524 	addr = (char *)(madt + 1);
525 	while (addr < (char *)madt + madt->hdr.length) {
526 		union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
527 		uint8_t length = entry->madt_gicc.length;
528 
529 		if (length < 2)
530 			return;
531 
532 		if (addr + length > (char *)madt + madt->hdr_length)
533 			return;
534 
535 		switch (entry->madt_gicc.apic_type) {
536 		case ACPI_MADT_GICC:
537 			efi_acpi_madt_gicc(&entry->madt_gicc);
538 			break;
539 		case ACPI_MADT_GICD:
540 			efi_acpi_madt_gicd(&entry->madt_gicd);
541 			break;
542 		case ACPI_MADT_GIC_MSI:
543 			efi_acpi_madt_gic_msi(&entry->madt_gic_msi);
544 			break;
545 		case ACPI_MADT_GICR:
546 			efi_acpi_madt_gicr(&entry->madt_gicr);
547 			break;
548 		case ACPI_MADT_GIC_ITS:
549 			efi_acpi_madt_gic_its(&entry->madt_gic_its);
550 			break;
551 		}
552 
553 		addr += length;
554 	}
555 
556 	/*
557 	 * Now that we've collected all the necessary information, fix
558 	 * up the "interrupt-controller" node.
559 	 */
560 
561 	switch (gic_version) {
562 	case 0:
563 		/* ACPI 5.0 doesn't provide a version; assume GICv2 */
564 	case 2:
565 		/* GICv2 */
566 		compat = "arm,gic-400";
567 		reg[0] = htobe64(gicd_base);
568 		reg[1] = htobe64(0x1000);
569 		reg[2] = htobe64(gicc_base);
570 		reg[3] = htobe64(0x100);
571 		break;
572 	case 3:
573 		/* GICv3 */
574 		compat = "arm,gic-v3";
575 		reg[0] = htobe64(gicd_base);
576 		reg[1] = htobe64(0x10000);
577 		reg[2] = htobe64(gicr_base);
578 		reg[3] = htobe64(gicr_size);
579 		break;
580 	default:
581 		return;
582 	}
583 
584 	/* Update "interrupt-controller" node. */
585 	node = fdt_find_node("/interrupt-controller");
586 	fdt_node_set_string_property(node, "compatible", compat);
587 	fdt_node_set_property(node, "reg", reg, sizeof(reg));
588 	fdt_node_set_string_property(node, "status", "okay");
589 }
590 
591 static int serial = 0;
592 
593 void
594 efi_acpi_spcr(struct acpi_table_header *hdr)
595 {
596 	struct acpi_spcr *spcr = (struct acpi_spcr *)hdr;
597 	uint64_t reg[2], reg_shift, reg_io_width;
598 	void *node;
599 
600 	/* Minimal revision required by Server Base Boot Requirements is 2. */
601 	if (spcr->hdr_revision < 2)
602 		return;
603 
604 	/* No idea how to support anything else on ARM. */
605 	if (spcr->base_address.address_space_id != GAS_SYSTEM_MEMORY)
606 		return;
607 
608 	reg[0] = htobe64(spcr->base_address.address);
609 
610 	switch (spcr->base_address.access_size) {
611 	case GAS_ACCESS_BYTE:
612 		reg_io_width = 1;
613 		break;
614 	case GAS_ACCESS_WORD:
615 		reg_io_width = 2;
616 		break;
617 	case GAS_ACCESS_DWORD:
618 		reg_io_width = 4;
619 		break;
620 	case GAS_ACCESS_QWORD:
621 		reg_io_width = 8;
622 		break;
623 	default:
624 		return;
625 	}
626 	reg_io_width = htobe32(reg_io_width);
627 
628 	reg_shift = 0;
629 	if (spcr->base_address.register_bit_width > 8)
630 		reg_shift = 1;
631 	if (spcr->base_address.register_bit_width > 16)
632 		reg_shift = 2;
633 	if (spcr->base_address.register_bit_width > 32)
634 		reg_shift = 3;
635 	reg_shift = htobe32(reg_shift);
636 
637 	/* Update "serial" node. */
638 	node = fdt_find_node("/serial");
639 	switch (spcr->interface_type) {
640 	case SPCR_16550:
641 	case SPCR_16450:
642 		fdt_node_set_string_property(node, "compatible",
643 		    "snps,dw-apb-uart");
644 		fdt_node_add_property(node, "reg-shift",
645 		    &reg_shift, sizeof(reg_shift));
646 		fdt_node_add_property(node, "reg-io-width",
647 		    &reg_io_width, sizeof(reg_io_width));
648 		reg[1] = htobe64(0x100);
649 		break;
650 	case SPCR_ARM_PL011:
651 	case SPCR_ARM_SBSA:
652 		fdt_node_set_string_property(node, "compatible", "arm,pl011");
653 		reg[1] = htobe64(0x1000);
654 		break;
655 	default:
656 		return;
657 	}
658 	fdt_node_set_property(node, "reg", reg, sizeof(reg));
659 	serial = 1;
660 }
661 
662 void *
663 efi_acpi(void)
664 {
665 	extern uint64_t dma_constraint[2];
666 	extern u_char dt_blob_start[];
667 	void *fdt = dt_blob_start;
668 	struct acpi_table_header *hdr;
669 	struct acpi_rsdp *rsdp = NULL;
670 	struct acpi_xsdt *xsdt;
671 	uint64_t reg[2];
672 	int i, ntables;
673 	size_t len;
674 	void *node;
675 
676 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
677 		if (efi_guidcmp(&acpi_guid,
678 		    &ST->ConfigurationTable[i].VendorGuid) == 0)
679 			rsdp = ST->ConfigurationTable[i].VendorTable;
680 	}
681 
682 	if (rsdp == NULL)
683 		return NULL;
684 
685 	if (memcmp(rsdp->rsdp_signature, RSDP_SIG, 8) != 0 ||
686 	    rsdp->rsdp_revision < 2)
687 		return NULL;
688 
689 	xsdt = (struct acpi_xsdt *)rsdp->rsdp_xsdt;
690 	len = xsdt->hdr.length;
691 	ntables = (len - sizeof(struct acpi_table_header)) /
692 	    sizeof(xsdt->table_offsets[0]);
693 	if (ntables == 0)
694 		return NULL;
695 
696 	if (!fdt_init(fdt))
697 		return NULL;
698 
699 	for (i = 0; i < ntables; i++) {
700 		hdr = (struct acpi_table_header *)xsdt->table_offsets[i];
701 		printf("%c%c%c%c ", hdr->signature[0], hdr->signature[1],
702 		    hdr->signature[2], hdr->signature[3]);
703 		if (memcmp(hdr->signature, FADT_SIG, 4) == 0)
704 			efi_acpi_fadt(hdr);
705 		if (memcmp(hdr->signature, GTDT_SIG, 4) == 0)
706 			efi_acpi_gtdt(hdr);
707 		if (memcmp(hdr->signature, MADT_SIG, 4) == 0)
708 			efi_acpi_madt(hdr);
709 		if (memcmp(hdr->signature, SPCR_SIG, 4) == 0)
710 			efi_acpi_spcr(hdr);
711 	}
712 	printf("\n");
713 
714 	reg[0] = htobe64((uint64_t)rsdp);
715 	reg[1] = htobe64(rsdp->rsdp_length);
716 
717 	/* Update "acpi" node. */
718 	node = fdt_find_node("/acpi");
719 	fdt_node_set_property(node, "reg", reg, sizeof(reg));
720 
721 	/* Use framebuffer if SPCR is absent or unusable. */
722 	if (!serial)
723 		cnset(ttydev("fb0"));
724 
725 	/* Raspberry Pi 4 is "special". */
726 	if (memcmp(xsdt->hdr_oemid, "RPIFDN", 6) == 0 &&
727 	    memcmp(xsdt->hdr_oemtableid, "RPI4", 4) == 0)
728 		dma_constraint[1] = htobe64(0x3bffffff);
729 
730 	fdt_finalize();
731 
732 	return fdt;
733 }
734