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