Add psci 2.0 features to spin up/down/suspend processors. This change uses extern weak symbols to determine if the platform supports the cpu_on/cpu_off/cpu_suspend features. If available, it saves the fdt provided argument values.
Some PSCI calls will return an int status, so the callfn has been updated to return that status (eg cpu_on fail) diff --git a/sys/dev/fdt/psci.c b/sys/dev/fdt/psci.c index fceafd0e9ba..3177ff06beb 100644 --- a/sys/dev/fdt/psci.c +++ b/sys/dev/fdt/psci.c @@ -29,12 +29,19 @@ extern void (*cpuresetfn)(void); extern void (*powerdownfn)(void); +extern int (*cpu_suspend_fn)(void) __attribute__((weak)) ; +extern int (*cpu_off_fn)(void) __attribute__((weak)) ; +extern int (*cpu_on_fn)(uint64_t, uint64_t) __attribute__((weak)) ; + #define SYSTEM_OFF 0x84000008 #define SYSTEM_RESET 0x84000009 struct psci_softc { struct device sc_dev; - void (*callfn)(uint32_t, uint32_t, uint32_t, uint32_t); + int (*callfn)(uint32_t, uint32_t, uint32_t, uint32_t); + int sc_cpu_on; + int sc_cpu_off; + int sc_cpu_suspend; }; struct psci_softc *psci_sc; @@ -43,9 +50,12 @@ int psci_match(struct device *, void *, void *); void psci_attach(struct device *, struct device *, void *); void psci_reset(void); void psci_powerdown(void); +int psci_cpu_suspend(void); +int psci_cpu_off(void); +int psci_cpu_on(uint64_t, uint64_t); -extern void hvc_call(uint32_t, uint32_t, uint32_t, uint32_t); -extern void smc_call(uint32_t, uint32_t, uint32_t, uint32_t); +extern int hvc_call(uint32_t, uint32_t, uint32_t, uint32_t); +extern int smc_call(uint32_t, uint32_t, uint32_t, uint32_t); struct cfattach psci_ca = { sizeof(struct psci_softc), psci_match, psci_attach @@ -83,6 +93,24 @@ psci_attach(struct device *parent, struct device *self, void *aux) psci_sc = sc; cpuresetfn = psci_reset; powerdownfn = psci_powerdown; + + if (&cpu_suspend_fn != NULL) { + sc->sc_cpu_suspend = OF_getpropint(faa->fa_node, "cpu_suspend", 0); + if (sc->sc_cpu_suspend != 0) + cpu_suspend_fn = psci_cpu_suspend; + } + + if (&cpu_on_fn != NULL) { + sc->sc_cpu_on = OF_getpropint(faa->fa_node, "cpu_on", 0); + if (sc->sc_cpu_on != 0) + cpu_on_fn = psci_cpu_on; + } + + if (&cpu_off_fn != NULL) { + sc->sc_cpu_off = OF_getpropint(faa->fa_node, "cpu_off", 0); + if (sc->sc_cpu_off != 0) + cpu_off_fn = psci_cpu_off; + } } void @@ -100,3 +128,31 @@ psci_powerdown(void) if (sc->callfn) (*sc->callfn)(SYSTEM_OFF, 0, 0, 0); } + +int +psci_cpu_suspend() +{ + struct psci_softc *sc = psci_sc; + if (sc->callfn) + return (*sc->callfn)(sc->sc_cpu_suspend, 0, 0, 0); + return -1; +} + +int +psci_cpu_off() +{ + struct psci_softc *sc = psci_sc; + if (sc->callfn) + return (*sc->callfn)(sc->sc_cpu_off, 0, 0, 0); + return -1; + +} + +int +psci_cpu_on(uint64_t mpidr, uint64_t pc) +{ + struct psci_softc *sc = psci_sc; + if (sc->callfn) + return (*sc->callfn)(sc->sc_cpu_on, mpidr, pc, 0); + return -1; +} Dale Rahn dr...@dalerahn.com