xref: /openbsd-src/sys/dev/fdt/psci.c (revision 4406bb04d649dace9fa40db5bcf61778a7f5deec)
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