Add ACPI support to the PSCI driver. This checks the Fixed ACPI Description
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
This commit is contained in:
parent
20a9f7715e
commit
2b5014f6fe
@ -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
|
||||
|
@ -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;
|
||||
|
||||
ocd = ofw_bus_search_compatible(dev, compat_data);
|
||||
psci_init = (psci_initfn_t)ocd->ocd_data;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
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);
|
||||
|
||||
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);
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user