xref: /netbsd-src/sys/arch/arm/fdt/acpi_fdt.c (revision 07ede9138182120d2cfa2ddb484613c658d0e777)
1*07ede913Sjmcneill /* $NetBSD: acpi_fdt.c,v 1.25 2024/12/08 20:55:18 jmcneill Exp $ */
26a4c7307Sjmcneill 
36a4c7307Sjmcneill /*-
46a4c7307Sjmcneill  * Copyright (c) 2015-2017 Jared McNeill <jmcneill@invisible.ca>
56a4c7307Sjmcneill  * All rights reserved.
66a4c7307Sjmcneill  *
76a4c7307Sjmcneill  * Redistribution and use in source and binary forms, with or without
86a4c7307Sjmcneill  * modification, are permitted provided that the following conditions
96a4c7307Sjmcneill  * are met:
106a4c7307Sjmcneill  * 1. Redistributions of source code must retain the above copyright
116a4c7307Sjmcneill  *    notice, this list of conditions and the following disclaimer.
126a4c7307Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
136a4c7307Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
146a4c7307Sjmcneill  *    documentation and/or other materials provided with the distribution.
156a4c7307Sjmcneill  *
166a4c7307Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
176a4c7307Sjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
186a4c7307Sjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
196a4c7307Sjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
206a4c7307Sjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
216a4c7307Sjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
226a4c7307Sjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
236a4c7307Sjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
246a4c7307Sjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
256a4c7307Sjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
266a4c7307Sjmcneill  * SUCH DAMAGE.
276a4c7307Sjmcneill  */
286a4c7307Sjmcneill 
29193d42ddSjmcneill #include "pci.h"
3056949079Sjmcneill #include "opt_efi.h"
3156949079Sjmcneill 
326a4c7307Sjmcneill #include <sys/cdefs.h>
33*07ede913Sjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_fdt.c,v 1.25 2024/12/08 20:55:18 jmcneill Exp $");
346a4c7307Sjmcneill 
356a4c7307Sjmcneill #include <sys/param.h>
366a4c7307Sjmcneill #include <sys/bus.h>
376a4c7307Sjmcneill #include <sys/device.h>
386a4c7307Sjmcneill #include <sys/intr.h>
396a4c7307Sjmcneill #include <sys/systm.h>
406a4c7307Sjmcneill #include <sys/kernel.h>
416a4c7307Sjmcneill #include <sys/lwp.h>
426a4c7307Sjmcneill #include <sys/kmem.h>
436a4c7307Sjmcneill #include <sys/queue.h>
446a4c7307Sjmcneill 
456a4c7307Sjmcneill #include <dev/fdt/fdtvar.h>
466a4c7307Sjmcneill 
476a4c7307Sjmcneill #include <dev/acpi/acpivar.h>
486a4c7307Sjmcneill #include <dev/pci/pcivar.h>
49ddb82ceeSjmcneill #include <dev/smbiosvar.h>
506a4c7307Sjmcneill 
51c6f4a721Sjmcneill #include <arm/arm/psci.h>
52c6f4a721Sjmcneill 
53e2ed649eSjmcneill #include <arm/acpi/acpi_pci_machdep.h>
54e2ed649eSjmcneill 
5556949079Sjmcneill #ifdef EFI_RUNTIME
5656949079Sjmcneill #include <arm/arm/efi_runtime.h>
5756949079Sjmcneill #endif
5856949079Sjmcneill 
596a4c7307Sjmcneill static int	acpi_fdt_match(device_t, cfdata_t, void *);
606a4c7307Sjmcneill static void	acpi_fdt_attach(device_t, device_t, void *);
616a4c7307Sjmcneill 
62c6f4a721Sjmcneill static void	acpi_fdt_poweroff(device_t);
63c6f4a721Sjmcneill 
64ddb82ceeSjmcneill static void	acpi_fdt_smbios_init(device_t);
659d2e6730Sjmcneill 
664ed488bfSjmcneill extern struct arm32_bus_dma_tag acpi_coherent_dma_tag;
67e85f76feSjmcneill 
689d2e6730Sjmcneill static uint64_t smbios_table = 0;
699d2e6730Sjmcneill 
706e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
716e54367aSthorpej 	{ .compat = "netbsd,acpi" },
726e54367aSthorpej 	DEVICE_COMPAT_EOL
736a4c7307Sjmcneill };
746a4c7307Sjmcneill 
75c6f4a721Sjmcneill static const struct fdtbus_power_controller_func acpi_fdt_power_funcs = {
76c6f4a721Sjmcneill 	.poweroff = acpi_fdt_poweroff,
77c6f4a721Sjmcneill };
78c6f4a721Sjmcneill 
796a4c7307Sjmcneill CFATTACH_DECL_NEW(acpi_fdt, 0, acpi_fdt_match, acpi_fdt_attach, NULL, NULL);
806a4c7307Sjmcneill 
816a4c7307Sjmcneill static int
826a4c7307Sjmcneill acpi_fdt_match(device_t parent, cfdata_t cf, void *aux)
836a4c7307Sjmcneill {
846a4c7307Sjmcneill 	struct fdt_attach_args * const faa = aux;
856a4c7307Sjmcneill 
866e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
876a4c7307Sjmcneill }
886a4c7307Sjmcneill 
896a4c7307Sjmcneill static void
906a4c7307Sjmcneill acpi_fdt_attach(device_t parent, device_t self, void *aux)
916a4c7307Sjmcneill {
92ddb82ceeSjmcneill 	extern void platform_init(void); /* XXX */
936a4c7307Sjmcneill 	struct fdt_attach_args * const faa = aux;
946a4c7307Sjmcneill 	struct acpibus_attach_args aa;
956a4c7307Sjmcneill 
966a4c7307Sjmcneill 	aprint_naive("\n");
9756949079Sjmcneill 	aprint_normal("\n");
9856949079Sjmcneill 
99ddb82ceeSjmcneill 	acpi_fdt_smbios_init(self);
100ddb82ceeSjmcneill 	platform_init();
101ddb82ceeSjmcneill 
102c6f4a721Sjmcneill 	fdtbus_register_power_controller(self, faa->faa_phandle,
103c6f4a721Sjmcneill 	    &acpi_fdt_power_funcs);
104c6f4a721Sjmcneill 
1056a4c7307Sjmcneill 	if (!acpi_probe())
106f32ed43cSjmcneill 		panic("ACPI subsystem failed to initialize");
1076a4c7307Sjmcneill 
108ddb82ceeSjmcneill 	platform_init();
109ddb82ceeSjmcneill 
110193d42ddSjmcneill 	memset(&aa, 0, sizeof(aa));
111193d42ddSjmcneill #if NPCI > 0
1126a4c7307Sjmcneill 	aa.aa_pciflags =
113e2ed649eSjmcneill 	    /*PCI_FLAGS_IO_OKAY |*/ PCI_FLAGS_MEM_OKAY |
1146a4c7307Sjmcneill 	    PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY |
1156a4c7307Sjmcneill 	    PCI_FLAGS_MWI_OKAY;
116187fa5a9Sjmcneill #ifdef __HAVE_PCI_MSI_MSIX
1178537f778Sjmcneill 	aa.aa_pciflags |= PCI_FLAGS_MSI_OKAY | PCI_FLAGS_MSIX_OKAY;
118187fa5a9Sjmcneill #endif
119193d42ddSjmcneill #endif
120193d42ddSjmcneill 
121193d42ddSjmcneill 	aa.aa_memt = faa->faa_bst;
1223d25b0deSjmcneill 	aa.aa_dmat = NULL;
1233d25b0deSjmcneill 	aa.aa_dmat64 = NULL;
124c7fb772bSthorpej 	config_found(self, &aa, NULL, CFARGS_NONE);
1256a4c7307Sjmcneill }
126c6f4a721Sjmcneill 
127c6f4a721Sjmcneill static void
128c6f4a721Sjmcneill acpi_fdt_poweroff(device_t dev)
129c6f4a721Sjmcneill {
130c6f4a721Sjmcneill 	delay(500000);
131*07ede913Sjmcneill 
132*07ede913Sjmcneill 	if (psci_available()) {
133c6f4a721Sjmcneill 		psci_system_off();
134c6f4a721Sjmcneill 	}
1359d2e6730Sjmcneill 
136*07ede913Sjmcneill #ifdef EFI_RUNTIME
137*07ede913Sjmcneill 	arm_efirt_reset(EFI_RESET_SHUTDOWN);
138*07ede913Sjmcneill #endif
139*07ede913Sjmcneill }
140*07ede913Sjmcneill 
141100cc283Sjmcneill static int
142100cc283Sjmcneill acpi_fdt_smbios_version(void)
143100cc283Sjmcneill {
144100cc283Sjmcneill 	uint8_t *hdr;
145100cc283Sjmcneill 	int smbver;
146100cc283Sjmcneill 
147100cc283Sjmcneill 	if (smbios_table == 0) {
148100cc283Sjmcneill 		return 0;
149100cc283Sjmcneill 	}
150100cc283Sjmcneill 
151100cc283Sjmcneill 	hdr = AcpiOsMapMemory(smbios_table, 24);
152100cc283Sjmcneill 	if (hdr == NULL) {
153100cc283Sjmcneill 		return 0;
154100cc283Sjmcneill 	}
155100cc283Sjmcneill 	if (smbios3_check_header(hdr)) {
156100cc283Sjmcneill 		smbver = 3;
157100cc283Sjmcneill 	} else if (smbios2_check_header(hdr)) {
158100cc283Sjmcneill 		smbver = 2;
159100cc283Sjmcneill 	} else {
160100cc283Sjmcneill 		smbver = 0;
161100cc283Sjmcneill 	}
162100cc283Sjmcneill 	AcpiOsUnmapMemory(hdr, 24);
163100cc283Sjmcneill 	return smbver;
164100cc283Sjmcneill }
165100cc283Sjmcneill 
1669d2e6730Sjmcneill static void
167ddb82ceeSjmcneill acpi_fdt_smbios_init(device_t dev)
168ddb82ceeSjmcneill {
169ddb82ceeSjmcneill 	uint8_t *ptr;
170100cc283Sjmcneill 	int smbver;
171ddb82ceeSjmcneill 
172ddb82ceeSjmcneill 	const int chosen = OF_finddevice("/chosen");
173ddb82ceeSjmcneill 	if (chosen >= 0) {
174ddb82ceeSjmcneill 		of_getprop_uint64(chosen, "netbsd,smbios-table", &smbios_table);
175ddb82ceeSjmcneill 	}
176ddb82ceeSjmcneill 	if (smbios_table == 0) {
177ddb82ceeSjmcneill 		return;
178ddb82ceeSjmcneill 	}
179ddb82ceeSjmcneill 
180065fe7e8Sjmcneill 	smbios_entry.hdrphys = smbios_table;
181065fe7e8Sjmcneill 
182100cc283Sjmcneill 	smbver = acpi_fdt_smbios_version();
183100cc283Sjmcneill 	if (smbver == 3) {
184100cc283Sjmcneill 		struct smb3hdr *sh = AcpiOsMapMemory(smbios_table, sizeof(*sh));
185ddb82ceeSjmcneill 		if (sh == NULL) {
186ddb82ceeSjmcneill 			return;
187ddb82ceeSjmcneill 		}
188ddb82ceeSjmcneill 
189ddb82ceeSjmcneill 		ptr = AcpiOsMapMemory(sh->addr, sh->size);
190ddb82ceeSjmcneill 		if (ptr != NULL) {
191065fe7e8Sjmcneill 			smbios_entry.tabphys = sh->addr;
192ddb82ceeSjmcneill 			smbios_entry.addr = ptr;
193ddb82ceeSjmcneill 			smbios_entry.len = sh->size;
194ddb82ceeSjmcneill 			smbios_entry.rev = sh->eprev;
195ddb82ceeSjmcneill 			smbios_entry.mjr = sh->majrev;
196ddb82ceeSjmcneill 			smbios_entry.min = sh->minrev;
197ddb82ceeSjmcneill 			smbios_entry.doc = sh->docrev;
198ddb82ceeSjmcneill 			smbios_entry.count = UINT16_MAX;
199ddb82ceeSjmcneill 		}
200100cc283Sjmcneill 
201100cc283Sjmcneill 		aprint_normal_dev(dev, "SMBIOS rev. %d.%d.%d @ 0x%lx\n",
202100cc283Sjmcneill 		    sh->majrev, sh->minrev, sh->docrev, (u_long)sh->addr);
203ddb82ceeSjmcneill 		AcpiOsUnmapMemory(sh, sizeof(*sh));
204100cc283Sjmcneill 	} else if (smbver == 2) {
205100cc283Sjmcneill 		struct smbhdr *sh = AcpiOsMapMemory(smbios_table, sizeof(*sh));
206100cc283Sjmcneill 		if (sh == NULL) {
207100cc283Sjmcneill 			return;
208100cc283Sjmcneill 		}
209100cc283Sjmcneill 
210100cc283Sjmcneill 		ptr = AcpiOsMapMemory(sh->addr, sh->size);
211100cc283Sjmcneill 		if (ptr != NULL) {
212065fe7e8Sjmcneill 			smbios_entry.tabphys = sh->addr;
213100cc283Sjmcneill 			smbios_entry.addr = ptr;
214100cc283Sjmcneill 			smbios_entry.len = sh->size;
215100cc283Sjmcneill 			smbios_entry.rev = 0;
216100cc283Sjmcneill 			smbios_entry.mjr = sh->majrev;
217100cc283Sjmcneill 			smbios_entry.min = sh->minrev;
218100cc283Sjmcneill 			smbios_entry.doc = 0;
219100cc283Sjmcneill 			smbios_entry.count = sh->count;
220100cc283Sjmcneill 		}
221100cc283Sjmcneill 
222100cc283Sjmcneill 		aprint_normal_dev(dev, "SMBIOS rev. %d.%d @ 0x%lx (%d entries)\n",
223100cc283Sjmcneill 		    sh->majrev, sh->minrev, (u_long)sh->addr, sh->count);
224100cc283Sjmcneill 		AcpiOsUnmapMemory(sh, sizeof(*sh));
225100cc283Sjmcneill 	}
226ddb82ceeSjmcneill }
227