Index: head/sys/conf/files.arm64 =================================================================== --- head/sys/conf/files.arm64 (revision 309673) +++ head/sys/conf/files.arm64 (revision 309674) @@ -1,192 +1,192 @@ # $FreeBSD$ cloudabi64_vdso.o optional compat_cloudabi64 \ dependency "$S/contrib/cloudabi/cloudabi_vdso_aarch64.S" \ compile-with "${CC} -x assembler-with-cpp -shared -nostdinc -nostdlib -Wl,-T$S/compat/cloudabi/cloudabi_vdso.lds $S/contrib/cloudabi/cloudabi_vdso_aarch64.S -o ${.TARGET}" \ no-obj no-implicit-rule \ clean "cloudabi64_vdso.o" # cloudabi64_vdso_blob.o optional compat_cloudabi64 \ dependency "cloudabi64_vdso.o" \ compile-with "${OBJCOPY} --input-target binary --output-target elf64-littleaarch64 --binary-architecture aarch64 cloudabi64_vdso.o ${.TARGET}" \ no-implicit-rule \ clean "cloudabi64_vdso_blob.o" # arm/allwinner/a10_ehci.c optional ehci aw_ehci fdt arm/allwinner/a10_gpio.c optional gpio aw_gpio fdt arm/allwinner/a10_mmc.c optional mmc aw_mmc fdt arm/allwinner/a64/a64_padconf.c optional soc_allwinner_a64 fdt arm/allwinner/a64/a64_r_padconf.c optional soc_allwinner_a64 fdt arm/allwinner/aw_ccu.c optional aw_ccu fdt arm/allwinner/aw_nmi.c optional aw_nmi fdt \ compile-with "${NORMAL_C} -I$S/gnu/dts/include" arm/allwinner/aw_reset.c optional aw_ccu fdt arm/allwinner/aw_rsb.c optional aw_rsb fdt arm/allwinner/aw_rtc.c optional aw_rtc fdt arm/allwinner/aw_sid.c optional aw_sid fdt arm/allwinner/aw_thermal.c optional aw_thermal fdt arm/allwinner/aw_usbphy.c optional ehci aw_usbphy fdt arm/allwinner/aw_wdog.c optional aw_wdog fdt arm/allwinner/axp81x.c optional axp81x fdt arm/allwinner/clk/aw_ahbclk.c optional aw_ccu fdt arm/allwinner/clk/aw_apbclk.c optional aw_ccu fdt arm/allwinner/clk/aw_axiclk.c optional aw_ccu fdt arm/allwinner/clk/aw_cpuclk.c optional aw_ccu fdt arm/allwinner/clk/aw_gate.c optional aw_ccu fdt arm/allwinner/clk/aw_modclk.c optional aw_ccu fdt arm/allwinner/clk/aw_pll.c optional aw_ccu fdt \ compile-with "${NORMAL_C} -I$S/gnu/dts/include" arm/allwinner/clk/aw_thsclk.c optional aw_ccu fdt arm/allwinner/clk/aw_usbclk.c optional aw_ccu fdt arm/allwinner/if_awg.c optional awg fdt arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt arm/annapurna/alpine/alpine_pci.c optional al_pci fdt arm/annapurna/alpine/alpine_pci_msix.c optional al_pci fdt arm/annapurna/alpine/alpine_serdes.c optional al_serdes fdt \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" arm/arm/generic_timer.c standard arm/arm/gic.c standard arm/arm/gic_fdt.c optional fdt arm/arm/pmu.c standard arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq fdt \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_cpufreq.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_dma.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_fbd.c optional vt soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_ft5406.c optional evdev bcm2835_ft5406 soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_intr.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_mbox.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_rng.c optional random soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_vcio.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2835_wdog.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm2836.c optional soc_brcm_bcm2837 fdt arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt soc_brcm_bcm2837 arm64/acpica/acpi_machdep.c optional acpi arm64/acpica/OsdEnvironment.c optional acpi arm64/acpica/acpi_wakeup.c optional acpi arm64/acpica/pci_cfgreg.c optional acpi pci arm64/arm64/autoconf.c standard arm64/arm64/bus_machdep.c standard arm64/arm64/bus_space_asm.S standard arm64/arm64/busdma_bounce.c standard arm64/arm64/busdma_machdep.c standard arm64/arm64/bzero.S standard arm64/arm64/clock.c standard arm64/arm64/copyinout.S standard arm64/arm64/copystr.c standard arm64/arm64/cpufunc_asm.S standard arm64/arm64/db_disasm.c optional ddb arm64/arm64/db_interface.c optional ddb arm64/arm64/db_trace.c optional ddb arm64/arm64/debug_monitor.c optional ddb arm64/arm64/disassem.c optional ddb arm64/arm64/dump_machdep.c standard arm64/arm64/elf_machdep.c standard arm64/arm64/exception.S standard arm64/arm64/gicv3_its.c optional intrng arm64/arm64/gic_v3.c standard arm64/arm64/gic_v3_fdt.c optional fdt arm64/arm64/identcpu.c standard arm64/arm64/in_cksum.c optional inet | inet6 arm64/arm64/locore.S standard no-obj arm64/arm64/machdep.c standard arm64/arm64/mem.c standard arm64/arm64/memcpy.S standard arm64/arm64/memmove.S standard arm64/arm64/minidump_machdep.c standard arm64/arm64/mp_machdep.c optional smp arm64/arm64/nexus.c standard arm64/arm64/ofw_machdep.c optional fdt arm64/arm64/pmap.c standard arm64/arm64/stack_machdep.c optional ddb | stack arm64/arm64/support.S standard arm64/arm64/swtch.S standard arm64/arm64/sys_machdep.c standard arm64/arm64/trap.c standard arm64/arm64/uio_machdep.c standard arm64/arm64/uma_machdep.c standard arm64/arm64/unwind.c optional ddb | kdtrace_hooks | stack arm64/arm64/vfp.c standard arm64/arm64/vm_machdep.c standard arm64/cavium/thunder_pcie_fdt.c optional soc_cavm_thunderx pci fdt arm64/cavium/thunder_pcie_pem.c optional soc_cavm_thunderx pci arm64/cavium/thunder_pcie_pem_fdt.c optional soc_cavm_thunderx pci fdt arm64/cavium/thunder_pcie_common.c optional soc_cavm_thunderx pci arm64/cloudabi64/cloudabi64_sysvec.c optional compat_cloudabi64 contrib/vchiq/interface/compat/vchi_bsd.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_arm.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_connected.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_core.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_shim.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_util.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" crypto/armv8/armv8_crypto.c optional armv8crypto armv8_crypto_wrap.o optional armv8crypto \ dependency "$S/crypto/armv8/armv8_crypto_wrap.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc:N-mgeneral-regs-only} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -march=armv8a+crypto ${.IMPSRC}" \ no-implicit-rule \ clean "armv8_crypto_wrap.o" crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/acpica/acpi_if.m optional acpi dev/ahci/ahci_generic.c optional ahci fdt dev/cpufreq/cpufreq_dt.c optional cpufreq fdt dev/hwpmc/hwpmc_arm64.c optional hwpmc dev/hwpmc/hwpmc_arm64_md.c optional hwpmc dev/mbox/mbox_if.m optional soc_brcm_bcm2837 dev/mmc/host/dwmmc.c optional dwmmc fdt dev/mmc/host/dwmmc_hisi.c optional dwmmc fdt soc_hisi_hi6220 dev/ofw/ofw_cpu.c optional fdt dev/ofw/ofwpci.c optional fdt pci dev/pci/pci_host_generic.c optional pci dev/pci/pci_host_generic_fdt.c optional pci fdt -dev/psci/psci.c optional psci fdt +dev/psci/psci.c optional psci dev/psci/psci_arm64.S optional psci dev/uart/uart_cpu_arm64.c optional uart dev/uart/uart_dev_pl011.c optional uart pl011 dev/usb/controller/dwc_otg_hisi.c optional dwcotg fdt soc_hisi_hi6220 dev/usb/controller/generic_ehci.c optional ehci acpi dev/usb/controller/generic_ohci.c optional ohci fdt dev/usb/controller/generic_usb_if.m optional ohci fdt dev/vnic/mrml_bridge.c optional vnic fdt dev/vnic/nic_main.c optional vnic pci dev/vnic/nicvf_main.c optional vnic pci pci_iov dev/vnic/nicvf_queues.c optional vnic pci pci_iov dev/vnic/thunder_bgx_fdt.c optional vnic fdt dev/vnic/thunder_bgx.c optional vnic pci dev/vnic/thunder_mdio_fdt.c optional vnic fdt dev/vnic/thunder_mdio.c optional vnic dev/vnic/lmac_if.m optional inet | inet6 | vnic kern/kern_clocksource.c standard kern/msi_if.m optional intrng kern/pic_if.m optional intrng kern/subr_devmap.c standard kern/subr_intr.c optional intrng libkern/bcmp.c standard libkern/ffs.c standard libkern/ffsl.c standard libkern/ffsll.c standard libkern/fls.c standard libkern/flsl.c standard libkern/flsll.c standard libkern/memset.c standard cddl/contrib/opensolaris/common/atomic/aarch64/opensolaris_atomic.S optional zfs | dtrace compile-with "${CDDL_C}" cddl/dev/dtrace/aarch64/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}" cddl/dev/dtrace/aarch64/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}" cddl/dev/fbt/aarch64/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" Index: head/sys/dev/psci/psci.c =================================================================== --- head/sys/dev/psci/psci.c (revision 309673) +++ head/sys/dev/psci/psci.c (revision 309674) @@ -1,308 +1,502 @@ /*- * Copyright (c) 2014 Robin Randhawa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * This implements support for ARM's Power State Co-ordination Interface * [PSCI]. The implementation adheres to version 0.2 of the PSCI specification * but also supports v0.1. PSCI standardizes operations such as system reset, CPU * on/off/suspend. PSCI requires a compliant firmware implementation. * * The PSCI specification used for this implementation is available at: * * . * * TODO: * - Add support for remaining PSCI calls [this implementation only * supports get_version, system_reset and cpu_on]. */ #include __FBSDID("$FreeBSD$"); +#include "opt_acpi.h" +#include "opt_platform.h" + #include #include #include #include #include #include #include #include +#include +#ifdef DEV_ACPI +#include +#include +#endif + +#ifdef FDT #include #include #include #include +#endif #include struct psci_softc { device_t dev; psci_callfn_t psci_call; uint32_t psci_fnids[PSCI_FN_MAX]; }; +#ifdef FDT static int psci_v0_1_init(device_t dev); +#endif static int psci_v0_2_init(device_t dev); struct psci_softc *psci_softc = NULL; +#ifdef __arm__ +#define USE_ACPI 0 +#define USE_FDT 1 +#elif defined(__aarch64__) +#define USE_ACPI (arm64_bus_method == ARM64_BUS_ACPI) +#define USE_FDT (arm64_bus_method == ARM64_BUS_FDT) +#else +#error Unknown architecture +#endif + +#ifdef FDT static struct ofw_compat_data compat_data[] = { {"arm,psci-0.2", (uintptr_t)psci_v0_2_init}, {"arm,psci", (uintptr_t)psci_v0_1_init}, {NULL, 0} }; +#endif -static int psci_probe(device_t dev); -static int psci_attach(device_t dev); +static int psci_attach(device_t, psci_initfn_t); static void psci_shutdown(void *, int); -static device_method_t psci_methods[] = { - DEVMETHOD(device_probe, psci_probe), - DEVMETHOD(device_attach, psci_attach), +#ifdef FDT +static int psci_fdt_probe(device_t dev); +static int psci_fdt_attach(device_t dev); +static device_method_t psci_fdt_methods[] = { + DEVMETHOD(device_probe, psci_fdt_probe), + DEVMETHOD(device_attach, psci_fdt_attach), + DEVMETHOD_END }; -static driver_t psci_driver = { +static driver_t psci_fdt_driver = { "psci", - psci_methods, + psci_fdt_methods, sizeof(struct psci_softc), }; -static devclass_t psci_devclass; +static devclass_t psci_fdt_devclass; -EARLY_DRIVER_MODULE(psci, simplebus, psci_driver, psci_devclass, 0, 0, +EARLY_DRIVER_MODULE(psci, simplebus, psci_fdt_driver, psci_fdt_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); -EARLY_DRIVER_MODULE(psci, ofwbus, psci_driver, psci_devclass, 0, 0, +EARLY_DRIVER_MODULE(psci, ofwbus, psci_fdt_driver, psci_fdt_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); static psci_callfn_t -psci_get_callfn(phandle_t node) +psci_fdt_get_callfn(phandle_t node) { char method[16]; if ((OF_getprop(node, "method", method, sizeof(method))) > 0) { if (strcmp(method, "hvc") == 0) return (psci_hvc_despatch); else if (strcmp(method, "smc") == 0) return (psci_smc_despatch); else printf("psci: PSCI conduit \"%s\" invalid\n", method); } else printf("psci: PSCI conduit not supplied in the device tree\n"); return (NULL); } static int -psci_probe(device_t dev) +psci_fdt_probe(device_t dev) { const struct ofw_compat_data *ocd; if (!ofw_bus_status_okay(dev)) return (ENXIO); ocd = ofw_bus_search_compatible(dev, compat_data); if (ocd->ocd_str == NULL) return (ENXIO); device_set_desc(dev, "ARM Power State Co-ordination Interface Driver"); return (BUS_PROBE_SPECIFIC); } static int -psci_attach(device_t dev) +psci_fdt_attach(device_t dev) { struct psci_softc *sc = device_get_softc(dev); const struct ofw_compat_data *ocd; psci_initfn_t psci_init; phandle_t node; - if (psci_softc != NULL) - return (ENXIO); - ocd = ofw_bus_search_compatible(dev, compat_data); psci_init = (psci_initfn_t)ocd->ocd_data; - KASSERT(psci_init != NULL, ("PSCI init function cannot be NULL")); node = ofw_bus_get_node(dev); - sc->psci_call = psci_get_callfn(node); + sc->psci_call = psci_fdt_get_callfn(node); + + return (psci_attach(dev, psci_init)); +} +#endif + +#ifdef DEV_ACPI +static void psci_acpi_identify(driver_t *, device_t); +static int psci_acpi_probe(device_t); +static int psci_acpi_attach(device_t); + +static device_method_t psci_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, psci_acpi_identify), + DEVMETHOD(device_probe, psci_acpi_probe), + DEVMETHOD(device_attach, psci_acpi_attach), + + DEVMETHOD_END +}; + +static driver_t psci_acpi_driver = { + "psci", + psci_acpi_methods, + sizeof(struct psci_softc), +}; + +static devclass_t psci_acpi_devclass; + +EARLY_DRIVER_MODULE(psci, acpi, psci_acpi_driver, psci_acpi_devclass, 0, 0, + BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); + +static int +psci_acpi_bootflags(void) +{ + ACPI_TABLE_FADT *fadt; + vm_paddr_t physaddr; + int flags; + + physaddr = acpi_find_table(ACPI_SIG_FADT); + if (physaddr == 0) + return (0); + + fadt = acpi_map_table(physaddr, ACPI_SIG_FADT); + if (fadt == NULL) { + printf("psci: Unable to map the FADT\n"); + return (0); + } + + flags = fadt->ArmBootFlags; + + acpi_unmap_table(fadt); + return (flags); +} + +static psci_callfn_t +psci_acpi_get_callfn(int flags) +{ + + if ((flags & ACPI_FADT_PSCI_COMPLIANT) != 0) { + if ((flags & ACPI_FADT_PSCI_USE_HVC) != 0) + return (psci_hvc_despatch); + else + return (psci_smc_despatch); + } else { + printf("psci: PSCI conduit not supplied in the device tree\n"); + } + + return (NULL); +} + +static void +psci_acpi_identify(driver_t *driver, device_t parent) +{ + device_t dev; + int flags; + + flags = psci_acpi_bootflags(); + if ((flags & ACPI_FADT_PSCI_COMPLIANT) != 0) { + dev = BUS_ADD_CHILD(parent, + BUS_PASS_CPU + BUS_PASS_ORDER_FIRST, "psci", -1); + + if (dev != NULL) + acpi_set_private(dev, (void *)(uintptr_t)flags); + } +} + +static int +psci_acpi_probe(device_t dev) +{ + uintptr_t flags; + + flags = (uintptr_t)acpi_get_private(dev); + if ((flags & ACPI_FADT_PSCI_COMPLIANT) == 0) + return (ENXIO); + + device_set_desc(dev, "ARM Power State Co-ordination Interface Driver"); + return (BUS_PROBE_SPECIFIC); +} + +static int +psci_acpi_attach(device_t dev) +{ + struct psci_softc *sc = device_get_softc(dev); + uintptr_t flags; + + flags = (uintptr_t)acpi_get_private(dev); + if ((flags & ACPI_FADT_PSCI_USE_HVC) != 0) + sc->psci_call = psci_hvc_despatch; + else + sc->psci_call = psci_smc_despatch; + + return (psci_attach(dev, psci_v0_2_init)); +} +#endif + +static int +psci_attach(device_t dev, psci_initfn_t psci_init) +{ + struct psci_softc *sc = device_get_softc(dev); + + if (psci_softc != NULL) + return (ENXIO); + if (sc->psci_call == NULL) return (ENXIO); + KASSERT(psci_init != NULL, ("PSCI init function cannot be NULL")); if (psci_init(dev)) return (ENXIO); psci_softc = sc; return (0); } static int psci_get_version(struct psci_softc *sc) { uint32_t fnid; /* PSCI version wasn't supported in v0.1. */ fnid = sc->psci_fnids[PSCI_FN_VERSION]; if (fnid) return (sc->psci_call(fnid, 0, 0, 0)); return (PSCI_RETVAL_NOT_SUPPORTED); } +#ifdef FDT +static int +psci_fdt_callfn(psci_callfn_t *callfn) +{ + phandle_t node; + + node = ofw_bus_find_compatible(OF_peer(0), "arm,psci-0.2"); + if (node == 0) + /* TODO: Handle psci 0.1 */ + return (PSCI_MISSING); + + *callfn = psci_fdt_get_callfn(node); + return (0); +} +#endif + +#ifdef DEV_ACPI +static int +psci_acpi_callfn(psci_callfn_t *callfn) +{ + int flags; + + flags = psci_acpi_bootflags(); + if ((flags & ACPI_FADT_PSCI_COMPLIANT) == 0) + return (PSCI_MISSING); + + *callfn = psci_acpi_get_callfn(flags); + return (0); +} +#endif + int psci_cpu_on(unsigned long cpu, unsigned long entry, unsigned long context_id) { psci_callfn_t callfn; - phandle_t node; uint32_t fnid; + int error; if (psci_softc == NULL) { - node = ofw_bus_find_compatible(OF_peer(0), "arm,psci-0.2"); - if (node == 0) - /* TODO: Handle psci 0.1 */ - return (PSCI_MISSING); - fnid = PSCI_FNID_CPU_ON; - callfn = psci_get_callfn(node); + callfn = NULL; +#ifdef FDT + if (USE_FDT) { + error = psci_fdt_callfn(&callfn); + if (error != 0) + return (error); + } +#endif +#ifdef DEV_ACPI + if (callfn == NULL && USE_ACPI) { + error = psci_acpi_callfn(&callfn); + if (error != 0) + return (error); + } +#endif + if (callfn == NULL) return (PSCI_MISSING); } else { callfn = psci_softc->psci_call; fnid = psci_softc->psci_fnids[PSCI_FN_CPU_ON]; } /* PSCI v0.1 and v0.2 both support cpu_on. */ return (callfn(fnid, cpu, entry, context_id)); } static void psci_shutdown(void *xsc, int howto) { uint32_t fn = 0; + if (psci_softc == NULL) + return; + /* PSCI system_off and system_reset werent't supported in v0.1. */ if ((howto & RB_POWEROFF) != 0) fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_OFF]; else if ((howto & RB_HALT) == 0) fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_RESET]; if (fn) psci_softc->psci_call(fn, 0, 0, 0); /* System reset and off do not return. */ } +#ifdef FDT +/* Only support PSCI 0.1 on FDT */ static int psci_v0_1_init(device_t dev) { struct psci_softc *sc = device_get_softc(dev); int psci_fn; uint32_t psci_fnid; phandle_t node; int len; /* Zero out the function ID table - Is this needed ? */ for (psci_fn = PSCI_FN_VERSION, psci_fnid = PSCI_FNID_VERSION; psci_fn < PSCI_FN_MAX; psci_fn++, psci_fnid++) sc->psci_fnids[psci_fn] = 0; /* PSCI v0.1 doesn't specify function IDs. Get them from DT */ node = ofw_bus_get_node(dev); if ((len = OF_getproplen(node, "cpu_suspend")) > 0) { OF_getencprop(node, "cpu_suspend", &psci_fnid, len); sc->psci_fnids[PSCI_FN_CPU_SUSPEND] = psci_fnid; } if ((len = OF_getproplen(node, "cpu_on")) > 0) { OF_getencprop(node, "cpu_on", &psci_fnid, len); sc->psci_fnids[PSCI_FN_CPU_ON] = psci_fnid; } if ((len = OF_getproplen(node, "cpu_off")) > 0) { OF_getencprop(node, "cpu_off", &psci_fnid, len); sc->psci_fnids[PSCI_FN_CPU_OFF] = psci_fnid; } if ((len = OF_getproplen(node, "migrate")) > 0) { OF_getencprop(node, "migrate", &psci_fnid, len); sc->psci_fnids[PSCI_FN_MIGRATE] = psci_fnid; } if (bootverbose) device_printf(dev, "PSCI version 0.1 available\n"); return(0); } +#endif static int psci_v0_2_init(device_t dev) { struct psci_softc *sc = device_get_softc(dev); int version; /* PSCI v0.2 specifies explicit function IDs. */ sc->psci_fnids[PSCI_FN_VERSION] = PSCI_FNID_VERSION; sc->psci_fnids[PSCI_FN_CPU_SUSPEND] = PSCI_FNID_CPU_SUSPEND; sc->psci_fnids[PSCI_FN_CPU_OFF] = PSCI_FNID_CPU_OFF; sc->psci_fnids[PSCI_FN_CPU_ON] = PSCI_FNID_CPU_ON; sc->psci_fnids[PSCI_FN_AFFINITY_INFO] = PSCI_FNID_AFFINITY_INFO; sc->psci_fnids[PSCI_FN_MIGRATE] = PSCI_FNID_MIGRATE; sc->psci_fnids[PSCI_FN_MIGRATE_INFO_TYPE] = PSCI_FNID_MIGRATE_INFO_TYPE; sc->psci_fnids[PSCI_FN_MIGRATE_INFO_UP_CPU] = PSCI_FNID_MIGRATE_INFO_UP_CPU; sc->psci_fnids[PSCI_FN_SYSTEM_OFF] = PSCI_FNID_SYSTEM_OFF; sc->psci_fnids[PSCI_FN_SYSTEM_RESET] = PSCI_FNID_SYSTEM_RESET; version = psci_get_version(sc); if (version == PSCI_RETVAL_NOT_SUPPORTED) return (1); if ((PSCI_VER_MAJOR(version) == 0 && PSCI_VER_MINOR(version) == 2) || (PSCI_VER_MAJOR(version) == 1 && PSCI_VER_MINOR(version) == 0)) { if (bootverbose) device_printf(dev, "PSCI version 0.2 available\n"); /* * We only register this for v0.2 since v0.1 doesn't support * system_reset. */ EVENTHANDLER_REGISTER(shutdown_final, psci_shutdown, sc, SHUTDOWN_PRI_LAST); return (0); } device_printf(dev, "PSCI version number mismatched with DT\n"); return (1); }