xref: /openbsd-src/sys/dev/fdt/bcm2835_dog.c (revision 9f11ffb7133c203312a01e4b986886bc88c7d74b)
1 /*
2  * Copyright (c) 2015 Patrick Wildt <patrick@blueri.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <sys/param.h>
18 #include <sys/systm.h>
19 #include <sys/queue.h>
20 #include <sys/malloc.h>
21 #include <sys/device.h>
22 #include <sys/evcount.h>
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 
31 /* registers */
32 #define PM_RSTC		0x1c
33 #define PM_RSTS		0x20
34 #define PM_WDOG		0x24
35 
36 /* bits and bytes */
37 #define PM_PASSWORD		0x5a000000
38 #define PM_RSTC_CONFIGMASK	0x00000030
39 #define PM_RSTC_FULL_RESET	0x00000020
40 #define PM_RSTC_RESET		0x00000102
41 #define PM_WDOG_TIMEMASK	0x000fffff
42 
43 #define HREAD4(sc, reg)							\
44 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
45 #define HWRITE4(sc, reg, val)						\
46 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
47 #define HSET4(sc, reg, bits)						\
48 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
49 #define HCLR4(sc, reg, bits)						\
50 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
51 
52 struct bcmdog_softc {
53 	struct device		 sc_dev;
54 	bus_space_tag_t		 sc_iot;
55 	bus_space_handle_t	 sc_ioh;
56 };
57 
58 struct bcmdog_softc *bcmdog_sc;
59 
60 int	 bcmdog_match(struct device *, void *, void *);
61 void	 bcmdog_attach(struct device *, struct device *, void *);
62 int	 bcmdog_activate(struct device *, int);
63 int	 bcmdog_wdog_cb(void *, int);
64 void	 bcmdog_wdog_reset(void);
65 
66 struct cfattach	bcmdog_ca = {
67 	sizeof (struct bcmdog_softc), bcmdog_match, bcmdog_attach, NULL,
68 	bcmdog_activate
69 };
70 
71 struct cfdriver bcmdog_cd = {
72 	NULL, "bcmdog", DV_DULL
73 };
74 
75 int
76 bcmdog_match(struct device *parent, void *cfdata, void *aux)
77 {
78 	struct fdt_attach_args *fa = aux;
79 
80 	return OF_is_compatible(fa->fa_node, "brcm,bcm2835-pm-wdt");
81 }
82 
83 void
84 bcmdog_attach(struct device *parent, struct device *self, void *aux)
85 {
86 	struct bcmdog_softc *sc = (struct bcmdog_softc *)self;
87 	struct fdt_attach_args *fa = aux;
88 
89 	sc->sc_iot = fa->fa_iot;
90 
91 	if (bus_space_map(sc->sc_iot, fa->fa_reg[0].addr,
92 	    fa->fa_reg[0].size, 0, &sc->sc_ioh))
93 		panic("%s: bus_space_map failed!", __func__);
94 
95 	printf("\n");
96 
97 	bcmdog_sc = sc;
98 	cpuresetfn = bcmdog_wdog_reset;
99 
100 #ifndef SMALL_KERNEL
101 	wdog_register(bcmdog_wdog_cb, sc);
102 #endif
103 }
104 
105 int
106 bcmdog_activate(struct device *self, int act)
107 {
108 	switch (act) {
109 	case DVACT_POWERDOWN:
110 #ifndef SMALL_KERNEL
111 		wdog_shutdown(self);
112 #endif
113 		break;
114 	}
115 
116 	return 0;
117 }
118 
119 void
120 bcmdog_wdog_set(struct bcmdog_softc *sc, uint32_t period)
121 {
122 	uint32_t rstc, wdog;
123 
124 	if (period == 0) {
125 		HWRITE4(sc, PM_RSTC, PM_RSTC_RESET | PM_PASSWORD);
126 		return;
127 	}
128 
129 	rstc = HREAD4(sc, PM_RSTC) & PM_RSTC_CONFIGMASK;
130 	rstc |= PM_RSTC_FULL_RESET;
131 	rstc |= PM_PASSWORD;
132 
133 	wdog = period & PM_WDOG_TIMEMASK;
134 	wdog |= PM_PASSWORD;
135 
136 	HWRITE4(sc, PM_WDOG, wdog);
137 	HWRITE4(sc, PM_RSTC, rstc);
138 }
139 
140 int
141 bcmdog_wdog_cb(void *self, int period)
142 {
143 	struct bcmdog_softc *sc = self;
144 
145 	bcmdog_wdog_set(sc, period << 16);
146 	return period;
147 }
148 
149 void
150 bcmdog_wdog_reset(void)
151 {
152 	struct bcmdog_softc *sc = bcmdog_sc;
153 
154 	bcmdog_wdog_set(sc, 10);
155 	delay(100000);
156 }
157