geode.c revision 1.4.4.1 1 /* $NetBSD: geode.c,v 1.4.4.1 2006/04/19 02:32:50 elad Exp $ */
2
3 /*-
4 * Copyright (c) 2005 David Young. All rights reserved.
5 *
6 * This code was written by David Young.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by David Young.
19 * 4. The name of David Young may not be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
27 * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 * OF SUCH DAMAGE.
35 */
36 /*-
37 * Copyright (c) 2002 The NetBSD Foundation, Inc.
38 * All rights reserved.
39 *
40 * This code is derived from software contributed to The NetBSD Foundation
41 * by Jason R. Thorpe.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the NetBSD
54 * Foundation, Inc. and its contributors.
55 * 4. Neither the name of The NetBSD Foundation nor the names of its
56 * contributors may be used to endorse or promote products derived
57 * from this software without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 * POSSIBILITY OF SUCH DAMAGE.
70 */
71
72 /*
73 * Device driver for the watchdog timer built into the
74 * AMD Geode SC1100 processor.
75 */
76
77 #include <sys/cdefs.h>
78
79 __KERNEL_RCSID(0, "$NetBSD: geode.c,v 1.4.4.1 2006/04/19 02:32:50 elad Exp $");
80
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/device.h>
84 #include <sys/wdog.h>
85 #include <uvm/uvm_extern.h>
86 #include <machine/bus.h>
87 #include <dev/pci/pcivar.h>
88 #include <dev/pci/pcidevs.h>
89 #include <arch/i386/pci/geodereg.h>
90 #include <dev/sysmon/sysmonvar.h>
91
92 #ifdef GEODE_DEBUG
93 #define GEODE_DPRINTF(__x) printf __x
94 #else /* GEODE_DEBUG */
95 #define GEODE_DPRINTF(__x) /* nothing */
96 #endif
97
98 struct geode_wdog_softc {
99 struct device sc_dev;
100 bus_space_tag_t sc_iot;
101 bus_space_handle_t sc_ioh;
102 uint16_t sc_countdown;
103 uint8_t sc_prescale;
104
105 struct sysmon_wdog sc_smw;
106 };
107
108 static void
109 geode_wdog_disable(struct geode_wdog_softc *sc)
110 {
111 uint16_t wdcnfg;
112
113 /* cancel any pending countdown */
114 sc->sc_countdown = 0;
115 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SC1100_GCB_WDTO, 0);
116 /* power-down clock */
117 wdcnfg = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
118 SC1100_GCB_WDCNFG);
119
120 GEODE_DPRINTF(("%s: wdcnfg %#04" PRIx16 " -> ", __func__, wdcnfg));
121
122 wdcnfg |= SC1100_WDCNFG_WD32KPD;
123 wdcnfg &= ~(SC1100_WDCNFG_WDTYPE2_MASK | SC1100_WDCNFG_WDTYPE1_MASK);
124 /* This no-op is for the reader's benefit. */
125 wdcnfg |= SC1100_WDCNFG_WDTYPE1_NOACTION |
126 SC1100_WDCNFG_WDTYPE2_NOACTION;
127 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SC1100_GCB_WDCNFG, wdcnfg);
128
129 GEODE_DPRINTF(("%#04" PRIx16 "\n", wdcnfg));
130 }
131
132 static void
133 geode_wdog_enable(struct geode_wdog_softc *sc)
134 {
135 uint16_t wdcnfg;
136
137 /* power-up clock and set prescale */
138 wdcnfg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SC1100_GCB_WDCNFG);
139
140 GEODE_DPRINTF(("%s: wdcnfg %#04" PRIx16 " -> ", __func__, wdcnfg));
141
142 wdcnfg &= ~(SC1100_WDCNFG_WD32KPD | SC1100_WDCNFG_WDPRES_MASK |
143 SC1100_WDCNFG_WDTYPE1_MASK | SC1100_WDCNFG_WDTYPE2_MASK);
144 wdcnfg |= SHIFTIN(sc->sc_prescale, SC1100_WDCNFG_WDPRES_MASK);
145 wdcnfg |= SC1100_WDCNFG_WDTYPE1_RESET | SC1100_WDCNFG_WDTYPE2_NOACTION;
146
147 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SC1100_GCB_WDCNFG, wdcnfg);
148
149 GEODE_DPRINTF(("%#04" PRIx16 "\n", wdcnfg));
150 }
151
152 static void
153 geode_wdog_reset(struct geode_wdog_softc *sc)
154 {
155 /* set countdown */
156 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SC1100_GCB_WDTO,
157 sc->sc_countdown);
158 }
159
160 static int
161 geode_wdog_tickle(struct sysmon_wdog *smw)
162 {
163 int s;
164 struct geode_wdog_softc *sc = smw->smw_cookie;
165
166 s = splhigh();
167 geode_wdog_reset(sc);
168 splx(s);
169 return 0;
170 }
171
172 static int
173 geode_wdog_setmode(struct sysmon_wdog *smw)
174 {
175 struct geode_wdog_softc *sc = smw->smw_cookie;
176 uint32_t ticks;
177 int prescale, s;
178
179 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
180 s = splhigh();
181 geode_wdog_disable(sc);
182 splx(s);
183 return 0;
184 }
185 if (smw->smw_period == WDOG_PERIOD_DEFAULT)
186 smw->smw_period = 32;
187 else if (smw->smw_period > SC1100_WDIVL_MAX) /* too big? */
188 return EINVAL;
189
190 GEODE_DPRINTF(("%s: period %u\n", __func__, smw->smw_period));
191
192 ticks = smw->smw_period * SC1100_WDCLK_HZ;
193
194 GEODE_DPRINTF(("%s: ticks0 %" PRIu32 "\n", __func__, ticks));
195
196 for (prescale = 0; ticks > UINT16_MAX; prescale++)
197 ticks /= 2;
198
199 GEODE_DPRINTF(("%s: ticks %" PRIu32 "\n", __func__, ticks));
200 GEODE_DPRINTF(("%s: prescale %d\n", __func__, prescale));
201
202 KASSERT(prescale <= SC1100_WDCNFG_WDPRES_MAX);
203 KASSERT(ticks <= UINT16_MAX);
204
205 s = splhigh();
206
207 sc->sc_prescale = (uint8_t)prescale;
208 sc->sc_countdown = (uint16_t)ticks;
209
210 geode_wdog_enable(sc);
211
212 geode_wdog_reset(sc);
213
214 splx(s);
215 return 0;
216 }
217
218 static int
219 geode_wdog_match(struct device *parent, struct cfdata *match, void *aux)
220 {
221 struct pci_attach_args *pa = aux;
222
223 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS &&
224 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_SC1100_XBUS)
225 return (10); /* XXX beat pchb? -dyoung */
226
227 return (0);
228 }
229
230 static void
231 geode_wdog_attach(struct device *parent, struct device *self, void *aux)
232 {
233 struct geode_wdog_softc *sc = (void *) self;
234 struct pci_attach_args *pa = aux;
235 uint32_t cba;
236 uint8_t wdsts;
237
238 aprint_naive(": Watchdog Timer\n");
239 aprint_normal(": AMD Geode SC1100 Watchdog Timer\n");
240
241 cba = pci_conf_read(pa->pa_pc, pa->pa_tag, SC1100_XBUS_CBA_SCRATCHPAD);
242 sc->sc_iot = pa->pa_iot;
243 if (bus_space_map(sc->sc_iot, (bus_addr_t)cba, SC1100_GCB_SIZE, 0,
244 &sc->sc_ioh) != 0) {
245 aprint_error("%s: unable to map registers\n",
246 sc->sc_dev.dv_xname);
247 return;
248 }
249
250 GEODE_DPRINTF(("%s: mapped %u bytes at %#08" PRIx32 "\n",
251 sc->sc_dev.dv_xname, SC1100_GCB_SIZE, cba));
252
253 /*
254 * Determine cause of the last reset, and issue a warning if it
255 * was due to watchdog expiry.
256 */
257 wdsts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SC1100_GCB_WDSTS);
258
259 GEODE_DPRINTF(("%s: status %#02" PRIx8 "\n", sc->sc_dev.dv_xname,
260 wdsts));
261
262 if (wdsts & SC1100_WDSTS_WDRST)
263 aprint_error(
264 "%s: WARNING: LAST RESET DUE TO WATCHDOG EXPIRATION!\n",
265 sc->sc_dev.dv_xname);
266
267 /* reset WDOVF by writing 1 to it */
268 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SC1100_GCB_WDSTS,
269 wdsts & SC1100_WDSTS_WDOVF);
270
271 /*
272 * Hook up the watchdog timer.
273 */
274 sc->sc_smw.smw_name = sc->sc_dev.dv_xname;
275 sc->sc_smw.smw_cookie = sc;
276 sc->sc_smw.smw_setmode = geode_wdog_setmode;
277 sc->sc_smw.smw_tickle = geode_wdog_tickle;
278 sc->sc_smw.smw_period = 32;
279 if (sysmon_wdog_register(&sc->sc_smw) != 0)
280 aprint_error("%s: unable to register watchdog with sysmon\n",
281 sc->sc_dev.dv_xname);
282
283 /* cancel any pending countdown */
284 geode_wdog_disable(sc);
285 }
286
287 CFATTACH_DECL(geodewdog, sizeof(struct geode_wdog_softc),
288 geode_wdog_match, geode_wdog_attach, NULL, NULL);
289