]> xenbits.xensource.com Git - people/royger/freebsd.git/commitdiff
Add ACPI support to the PSCI driver. This checks the Fixed ACPI Description
authorandrew <andrew@FreeBSD.org>
Wed, 7 Dec 2016 14:24:53 +0000 (14:24 +0000)
committerandrew <andrew@FreeBSD.org>
Wed, 7 Dec 2016 14:24:53 +0000 (14:24 +0000)
Table to find if the hardware supports PSCI, and if so what method the
kernel should use to interact with it.

Obtained from: ABT Systems Ltd
Sponsored by: The FreeBSD Foundation

sys/conf/files.arm64
sys/dev/psci/psci.c

index 4e950f9290fff2454164a629f78a1efb415121d6..4351bdcf31ec5dd127beca04a4a71a50fba03c64 100644 (file)
@@ -156,7 +156,7 @@ 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
index f7050976c8c62d1032aad6bf2149a26c593cf942..4452fb45955dd2792de86ad9df74ddb386d17088 100644 (file)
@@ -43,6 +43,9 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_acpi.h"
+#include "opt_platform.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
@@ -52,11 +55,19 @@ __FBSDID("$FreeBSD$");
 #include <sys/reboot.h>
 
 #include <machine/bus.h>
+#include <machine/machdep.h>
+
+#ifdef DEV_ACPI
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+#endif
 
+#ifdef FDT
 #include <dev/fdt/fdt_common.h>
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
+#endif
 
 #include <dev/psci/psci.h>
 
@@ -67,43 +78,60 @@ struct psci_softc {
        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];
 
@@ -121,7 +149,7 @@ psci_get_callfn(phandle_t node)
 }
 
 static int
-psci_probe(device_t dev)
+psci_fdt_probe(device_t dev)
 {
        const struct ofw_compat_data *ocd;
 
@@ -138,25 +166,144 @@ psci_probe(device_t dev)
 }
 
 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);
 
@@ -178,21 +325,62 @@ psci_get_version(struct psci_softc *sc)
        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 {
@@ -209,6 +397,9 @@ 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];
@@ -221,6 +412,8 @@ psci_shutdown(void *xsc, int howto)
        /* 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)
 {
@@ -264,6 +457,7 @@ psci_v0_1_init(device_t dev)
 
        return(0);
 }
+#endif
 
 static int
 psci_v0_2_init(device_t dev)