1 /* $OpenBSD: psci.c,v 1.1 2017/01/25 10:14:40 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2016 Jonathan Gray <jsg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/device.h> 21 #include <sys/systm.h> 22 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/fdt.h> 28 29 extern void (*cpuresetfn)(void); 30 extern void (*powerdownfn)(void); 31 32 #define SYSTEM_OFF 0x84000008 33 #define SYSTEM_RESET 0x84000009 34 35 struct psci_softc { 36 struct device sc_dev; 37 void (*callfn)(uint32_t, uint32_t, uint32_t, uint32_t); 38 }; 39 40 struct psci_softc *psci_sc; 41 42 int psci_match(struct device *, void *, void *); 43 void psci_attach(struct device *, struct device *, void *); 44 void psci_reset(void); 45 void psci_powerdown(void); 46 47 extern void hvc_call(uint32_t, uint32_t, uint32_t, uint32_t); 48 extern void smc_call(uint32_t, uint32_t, uint32_t, uint32_t); 49 50 struct cfattach psci_ca = { 51 sizeof(struct psci_softc), psci_match, psci_attach 52 }; 53 54 struct cfdriver psci_cd = { 55 NULL, "psci", DV_DULL 56 }; 57 58 int 59 psci_match(struct device *parent, void *match, void *aux) 60 { 61 struct fdt_attach_args *faa = aux; 62 63 /* reset and shutdown added in 0.2 */ 64 return OF_is_compatible(faa->fa_node, "arm,psci-0.2"); 65 } 66 67 void 68 psci_attach(struct device *parent, struct device *self, void *aux) 69 { 70 struct psci_softc *sc = (struct psci_softc *) self; 71 struct fdt_attach_args *faa = aux; 72 char method[128]; 73 74 if (OF_getprop(faa->fa_node, "method", method, sizeof(method))) { 75 if (strcmp(method, "hvc") == 0) 76 sc->callfn = hvc_call; 77 else if (strcmp(method, "smc") == 0) 78 sc->callfn = smc_call; 79 } 80 81 printf("\n"); 82 83 psci_sc = sc; 84 cpuresetfn = psci_reset; 85 powerdownfn = psci_powerdown; 86 } 87 88 void 89 psci_reset(void) 90 { 91 struct psci_softc *sc = psci_sc; 92 if (sc->callfn) 93 (*sc->callfn)(SYSTEM_RESET, 0, 0, 0); 94 } 95 96 void 97 psci_powerdown(void) 98 { 99 struct psci_softc *sc = psci_sc; 100 if (sc->callfn) 101 (*sc->callfn)(SYSTEM_OFF, 0, 0, 0); 102 } 103