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

Reply via email to