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