xref: /openbsd/sys/arch/arm64/stand/efiboot/efiacpi.c (revision 274d7c50)
1 /*	$OpenBSD: efiacpi.c,v 1.5 2018/08/11 16:02:33 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 	/*
417 	 * MPIDR field was introduced in ACPI 5.1.  Fall back on the
418 	 * ACPI Processor UID on ACPI 5.0.
419 	 */
420 	mpidr = (gicc->length >= 76) ? gicc->mpidr : gicc->acpi_proc_uid;
421 
422 	snprintf(name, sizeof(name), "cpu@%llx", mpidr);
423 	reg = htobe64(mpidr);
424 
425 	/* Create "cpu" node. */
426 	node = fdt_find_node("/cpus");
427 	fdt_node_add_node(node, name, &child);
428 	fdt_node_add_string_property(child, "device_type", "cpu");
429 	fdt_node_add_string_property(child, "compatible", "arm,armv8");
430 	fdt_node_add_property(child, "reg", &reg, sizeof(reg));
431 	if (gicc->parking_protocol_version == 0 || psci)
432 		fdt_node_add_string_property(child, "enable-method", "psci");
433 	if ((gicc->flags & ACPI_PROC_ENABLE) == 0)
434 		fdt_node_add_string_property(child, "status", "disabled");
435 
436 	/* Stash GIC information. */
437 	gicc_base = gicc->base_address;
438 }
439 
440 void
441 efi_acpi_madt_gicd(struct acpi_madt_gicd *gicd)
442 {
443 	/* Stash GIC information. */
444 	gic_version = gicd->version;
445 	gicd_base = gicd->base_address;
446 }
447 
448 void
449 efi_acpi_madt_gic_msi(struct acpi_madt_gic_msi *msi)
450 {
451 	static uint32_t phandle = 2;
452 	void *node, *child;
453 	uint64_t reg[2];
454 	char name[32];
455 
456 	snprintf(name, sizeof(name), "v2m@%llx", msi->base_address);
457 	reg[0] = htobe64(msi->base_address);
458 	reg[1] = htobe64(0x1000);
459 
460 	/* Create "v2m" node. */
461 	node = fdt_find_node("/interrupt-controller");
462 	fdt_node_add_node(node, name, &child);
463 	fdt_node_add_string_property(child, "compatible", "arm,gic-v2m-frame");
464 	fdt_node_add_property(child, "msi-controller", NULL, 0);
465 	fdt_node_add_property(child, "reg", reg, sizeof(reg));
466 	if (msi->flags & ACPI_MADT_GIC_MSI_SPI_SELECT) {
467 		uint32_t spi_base = msi->spi_base;
468 		uint32_t spi_count = msi->spi_count;
469 
470 		fdt_node_add_property(child, "arm,msi-base-spi",
471 		    &spi_base, sizeof(spi_base));
472 		fdt_node_add_property(child, "arm,msi-num-spis",
473 		    &spi_count, sizeof(spi_count));
474 	}
475 	fdt_node_add_property(child, "phandle", &phandle, sizeof(phandle));
476 	phandle++;
477 }
478 
479 void
480 efi_acpi_madt_gicr(struct acpi_madt_gicr *gicr)
481 {
482 	/* Stash GIC information. */
483 	gicr_base = gicr->discovery_base_address;
484 	gicr_size = gicr->discovery_length;
485 }
486 
487 void
488 efi_acpi_madt_gic_its(struct acpi_madt_gic_its *its)
489 {
490 	static uint32_t phandle = 2;
491 	void *node, *child;
492 	uint64_t reg[2];
493 	char name[32];
494 
495 	snprintf(name, sizeof(name), "gic-its@%llx", its->base_address);
496 	reg[0] = htobe64(its->base_address);
497 	reg[1] = htobe64(0x20000);
498 
499 	/* Create "gic-its" node. */
500 	node = fdt_find_node("/interrupt-controller");
501 	fdt_node_add_node(node, name, &child);
502 	fdt_node_add_string_property(child, "compatible", "arm,gic-v3-its");
503 	fdt_node_add_property(child, "msi-controller", NULL, 0);
504 	fdt_node_add_property(child, "reg", reg, sizeof(reg));
505 	fdt_node_add_property(child, "phandle", &phandle, sizeof(phandle));
506 	phandle++;
507 }
508 
509 void
510 efi_acpi_madt(struct acpi_table_header *hdr)
511 {
512 	struct acpi_madt *madt = (struct acpi_madt *)hdr;
513 	char *compat;
514 	uint64_t reg[4];
515 	char *addr;
516 	void *node;
517 
518 	/* GIC support was introduced in ACPI 5.0. */
519 	if (madt->hdr_revision < 3)
520 		return;
521 
522 	addr = (char *)(madt + 1);
523 	while (addr < (char *)madt + madt->hdr.length) {
524 		union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
525 		uint8_t length = entry->madt_gicc.length;
526 
527 		if (length < 2)
528 			return;
529 
530 		if (addr + length > (char *)madt + madt->hdr_length)
531 			return;
532 
533 		switch (entry->madt_gicc.apic_type) {
534 		case ACPI_MADT_GICC:
535 			efi_acpi_madt_gicc(&entry->madt_gicc);
536 			break;
537 		case ACPI_MADT_GICD:
538 			efi_acpi_madt_gicd(&entry->madt_gicd);
539 			break;
540 		case ACPI_MADT_GIC_MSI:
541 			efi_acpi_madt_gic_msi(&entry->madt_gic_msi);
542 			break;
543 		case ACPI_MADT_GICR:
544 			efi_acpi_madt_gicr(&entry->madt_gicr);
545 			break;
546 		case ACPI_MADT_GIC_ITS:
547 			efi_acpi_madt_gic_its(&entry->madt_gic_its);
548 			break;
549 		}
550 
551 		addr += length;
552 	}
553 
554 	/*
555 	 * Now that we've collected all the necessary information, fix
556 	 * up the "interrupt-controller" node.
557 	 */
558 
559 	switch (gic_version) {
560 	case 0:
561 		/* ACPI 5.0 doesn't provide a version; assume GICv2 */
562 	case 2:
563 		/* GICv2 */
564 		compat = "arm,gic-400";
565 		reg[0] = htobe64(gicd_base);
566 		reg[1] = htobe64(0x1000);
567 		reg[2] = htobe64(gicc_base);
568 		reg[3] = htobe64(0x100);
569 		break;
570 	case 3:
571 		/* GICv3 */
572 		compat = "arm,gic-v3";
573 		reg[0] = htobe64(gicd_base);
574 		reg[1] = htobe64(0x10000);
575 		reg[2] = htobe64(gicr_base);
576 		reg[3] = htobe64(gicr_size);
577 		break;
578 	default:
579 		return;
580 	}
581 
582 	/* Update "interrupt-controller" node. */
583 	node = fdt_find_node("/interrupt-controller");
584 	fdt_node_set_string_property(node, "compatible", compat);
585 	fdt_node_set_property(node, "reg", reg, sizeof(reg));
586 	fdt_node_set_string_property(node, "status", "okay");
587 }
588 
589 void
590 efi_acpi_spcr(struct acpi_table_header *hdr)
591 {
592 	struct acpi_spcr *spcr = (struct acpi_spcr *)hdr;
593 	uint64_t reg[2], reg_shift, reg_io_width;
594 	void *node;
595 
596 	/* Minimal revision required by Server Base Boot Requirements is 2. */
597 	if (spcr->hdr_revision < 2)
598 		return;
599 
600 	/* No idea how to support anything else on ARM. */
601 	if (spcr->base_address.address_space_id != GAS_SYSTEM_MEMORY)
602 		return;
603 
604 	reg[0] = htobe64(spcr->base_address.address);
605 
606 	switch (spcr->base_address.access_size) {
607 	case GAS_ACCESS_BYTE:
608 		reg_io_width = 1;
609 		break;
610 	case GAS_ACCESS_WORD:
611 		reg_io_width = 2;
612 		break;
613 	case GAS_ACCESS_DWORD:
614 		reg_io_width = 4;
615 		break;
616 	case GAS_ACCESS_QWORD:
617 		reg_io_width = 8;
618 		break;
619 	default:
620 		return;
621 	}
622 	reg_io_width = htobe32(reg_io_width);
623 
624 	reg_shift = 0;
625 	if (spcr->base_address.register_bit_width > 8)
626 		reg_shift = 1;
627 	if (spcr->base_address.register_bit_width > 16)
628 		reg_shift = 2;
629 	if (spcr->base_address.register_bit_width > 32)
630 		reg_shift = 3;
631 	reg_shift = htobe32(reg_shift);
632 
633 	/* Update "serial" node. */
634 	node = fdt_find_node("/serial");
635 	switch (spcr->interface_type) {
636 	case SPCR_16550:
637 	case SPCR_16450:
638 		fdt_node_set_string_property(node, "compatible",
639 		    "snps,dw-apb-uart");
640 		fdt_node_add_property(node, "reg-shift",
641 		    &reg_shift, sizeof(reg_shift));
642 		fdt_node_add_property(node, "reg-io-width",
643 		    &reg_io_width, sizeof(reg_io_width));
644 		reg[1] = htobe64(0x100);
645 		break;
646 	case SPCR_ARM_PL011:
647 	case SPCR_ARM_SBSA:
648 		fdt_node_set_string_property(node, "compatible", "arm,pl011");
649 		reg[1] = htobe64(0x1000);
650 		break;
651 	default:
652 		return;
653 	}
654 	fdt_node_set_property(node, "reg", reg, sizeof(reg));
655 }
656 
657 void *
658 efi_acpi(void)
659 {
660 	extern u_char dt_blob_start[];
661 	void *fdt = dt_blob_start;
662 	struct acpi_table_header *hdr;
663 	struct acpi_rsdp *rsdp = NULL;
664 	struct acpi_xsdt *xsdt;
665 	uint64_t reg[2];
666 	int i, ntables;
667 	size_t len;
668 	void *node;
669 
670 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
671 		if (efi_guidcmp(&acpi_guid,
672 		    &ST->ConfigurationTable[i].VendorGuid) == 0)
673 			rsdp = ST->ConfigurationTable[i].VendorTable;
674 	}
675 
676 	if (rsdp == NULL)
677 		return NULL;
678 
679 	if (memcmp(rsdp->rsdp_signature, RSDP_SIG, 8) != 0 ||
680 	    rsdp->rsdp_revision < 2)
681 		return NULL;
682 
683 	xsdt = (struct acpi_xsdt *)rsdp->rsdp_xsdt;
684 	len = xsdt->hdr.length;
685 	ntables = (len - sizeof(struct acpi_table_header)) /
686 	    sizeof(xsdt->table_offsets[0]);
687 	if (ntables == 0)
688 		return NULL;
689 
690 	if (!fdt_init(fdt))
691 		return NULL;
692 
693 	for (i = 0; i < ntables; i++) {
694 		hdr = (struct acpi_table_header *)xsdt->table_offsets[i];
695 		printf("%c%c%c%c ", hdr->signature[0], hdr->signature[1],
696 		    hdr->signature[2], hdr->signature[3]);
697 		if (memcmp(hdr->signature, FADT_SIG, 4) == 0)
698 			efi_acpi_fadt(hdr);
699 		if (memcmp(hdr->signature, GTDT_SIG, 4) == 0)
700 			efi_acpi_gtdt(hdr);
701 		if (memcmp(hdr->signature, MADT_SIG, 4) == 0)
702 			efi_acpi_madt(hdr);
703 		if (memcmp(hdr->signature, SPCR_SIG, 4) == 0)
704 			efi_acpi_spcr(hdr);
705 	}
706 	printf("\n");
707 
708 	reg[0] = htobe64((uint64_t)rsdp);
709 	reg[1] = htobe64(rsdp->rsdp_length);
710 
711 	/* Update "acpi" node. */
712 	node = fdt_find_node("/acpi");
713 	fdt_node_set_property(node, "reg", reg, sizeof(reg));
714 
715 	fdt_finalize();
716 
717 	return fdt;
718 }
719