cf3c20ae |
1 | /* $OpenBSD: omdog.c,v 1.5 2014/12/10 12:27:56 mikeb Exp $ */ |
2 | /* |
3 | * Copyright (c) 2013 Federico G. Schwindt <fgsch@openbsd.org> |
4 | * Copyright (c) 2007,2009 Dale Rahn <drahn@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/systm.h> |
21 | #include <sys/queue.h> |
22 | #include <sys/malloc.h> |
23 | #include <sys/device.h> |
24 | #include <sys/evcount.h> |
25 | #include <sys/socket.h> |
26 | #include <sys/timeout.h> |
27 | #include <machine/intr.h> |
28 | #include <machine/bus.h> |
29 | #include <armv7/armv7/armv7var.h> |
30 | |
31 | #define WIDR 0x00 /* Identification Register */ |
32 | #define WCLR 0x24 /* Control Register */ |
33 | #define WCLR_PRE (1 << 5) |
34 | #define WCLR_PTV (0 << 2) |
35 | #define WCRR 0x28 /* Counter Register */ |
36 | #define WLDR 0x2c /* Load Register */ |
37 | #define WTGR 0x30 /* Trigger Register */ |
38 | #define WWPS 0x34 /* Write Posting Bits Reg. */ |
39 | #define WWPS_WSPR (1 << 4) |
40 | #define WWPS_WTGR (1 << 3) |
41 | #define WWPS_WLDR (1 << 2) |
42 | #define WWPS_WCRR (1 << 1) |
43 | #define WWPS_WCLR (1 << 0) |
44 | #define WSPR 0x48 /* Start/Stop Register */ |
45 | |
46 | #define OMDOG_VAL(secs) (0xffffffff - ((secs) * (32768 / (1 << 0))) + 1) |
47 | |
48 | |
49 | struct omdog_softc { |
50 | struct device sc_dev; |
51 | bus_space_tag_t sc_iot; |
52 | bus_space_handle_t sc_ioh; |
53 | |
54 | int sc_period; |
55 | }; |
56 | |
57 | struct omdog_softc *omdog_sc; |
58 | |
59 | void omdog_attach(struct device *, struct device *, void *); |
60 | int omdog_activate(struct device *, int); |
61 | void omdog_start(struct omdog_softc *); |
62 | void omdog_stop(struct omdog_softc *); |
63 | void omdog_sync(struct omdog_softc *); |
64 | int omdog_cb(void *, int); |
65 | void omdog_reset(void); |
66 | |
67 | struct cfattach omdog_ca = { |
68 | sizeof (struct omdog_softc), NULL, omdog_attach, NULL, omdog_activate |
69 | }; |
70 | |
71 | struct cfdriver omdog_cd = { |
72 | NULL, "omdog", DV_DULL |
73 | }; |
74 | |
75 | void |
76 | omdog_attach(struct device *parent, struct device *self, void *args) |
77 | { |
78 | struct armv7_attach_args *aa = args; |
79 | struct omdog_softc *sc = (struct omdog_softc *) self; |
80 | u_int32_t rev; |
81 | |
82 | sc->sc_iot = aa->aa_iot; |
83 | if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr, |
84 | aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) |
85 | panic("%s: bus_space_map failed!", __func__); |
86 | |
87 | rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR); |
88 | |
89 | printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); |
90 | omdog_sc = sc; |
91 | |
92 | omdog_stop(sc); |
93 | |
94 | #ifndef SMALL_KERNEL |
95 | wdog_register(omdog_cb, sc); |
96 | #endif |
97 | } |
98 | |
99 | int |
100 | omdog_activate(struct device *self, int act) |
101 | { |
102 | switch (act) { |
103 | case DVACT_POWERDOWN: |
104 | #ifndef SMALL_KERNEL |
105 | wdog_shutdown(self); |
106 | #endif |
107 | break; |
108 | } |
109 | |
110 | return (0); |
111 | } |
112 | |
113 | void |
114 | omdog_start(struct omdog_softc *sc) |
115 | { |
116 | /* Write the enable sequence data BBBBh followed by 4444h */ |
117 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb); |
118 | omdog_sync(sc); |
119 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444); |
120 | omdog_sync(sc); |
121 | } |
122 | |
123 | void |
124 | omdog_stop(struct omdog_softc *sc) |
125 | { |
126 | /* Write the disable sequence data AAAAh followed by 5555h */ |
127 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa); |
128 | omdog_sync(sc); |
129 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555); |
130 | omdog_sync(sc); |
131 | } |
132 | |
133 | void |
134 | omdog_sync(struct omdog_softc *sc) |
135 | { |
136 | while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) & |
137 | (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR)) |
138 | delay(10); |
139 | } |
140 | |
141 | int |
142 | omdog_cb(void *self, int period) |
143 | { |
144 | struct omdog_softc *sc = self; |
145 | |
146 | if (sc->sc_period != 0 && sc->sc_period != period) |
147 | omdog_stop(sc); |
148 | |
149 | if (period != 0) { |
150 | if (sc->sc_period != period) { |
151 | /* Set the prescaler */ |
152 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR, |
153 | (WCLR_PRE|WCLR_PTV)); |
154 | |
155 | /* Set the reload counter */ |
156 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR, |
157 | OMDOG_VAL(period)); |
158 | } |
159 | |
160 | omdog_sync(sc); |
161 | |
162 | /* Trigger the reload */ |
163 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR, |
164 | ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR)); |
165 | |
166 | if (sc->sc_period != period) |
167 | omdog_start(sc); |
168 | } |
169 | |
170 | sc->sc_period = period; |
171 | |
172 | return (period); |
173 | } |
174 | |
175 | void |
176 | omdog_reset(void) |
177 | { |
178 | if (omdog_sc == NULL) |
179 | return; |
180 | |
181 | if (omdog_sc->sc_period != 0) |
182 | omdog_stop(omdog_sc); |
183 | |
184 | bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR, |
185 | 0xffffff80); |
186 | |
187 | omdog_start(omdog_sc); |
188 | |
189 | delay(100000); |
190 | } |