xref: /freebsd/sys/dev/amdsbwd/amdsbwd.c (revision b0b1dbdd)
1 /*-
2  * Copyright (c) 2009 Andriy Gapon <avg@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * This is a driver for watchdog timer present in AMD SB600/SB7xx/SB8xx
29  * southbridges.
30  * Please see the following specifications for the descriptions of the
31  * registers and flags:
32  * - AMD SB600 Register Reference Guide, Public Version,  Rev. 3.03 (SB600 RRG)
33  *   http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/46155_sb600_rrg_pub_3.03.pdf
34  * - AMD SB700/710/750 Register Reference Guide (RRG)
35  *   http://developer.amd.com/assets/43009_sb7xx_rrg_pub_1.00.pdf
36  * - AMD SB700/710/750 Register Programming Requirements (RPR)
37  *   http://developer.amd.com/assets/42413_sb7xx_rpr_pub_1.00.pdf
38  * - AMD SB800-Series Southbridges Register Reference Guide (RRG)
39  *   http://support.amd.com/us/Embedded_TechDocs/45482.pdf
40  * Please see the following for Watchdog Resource Table specification:
41  * - Watchdog Timer Hardware Requirements for Windows Server 2003 (WDRT)
42  *   http://www.microsoft.com/whdc/system/sysinternals/watchdog.mspx
43  * AMD SB600/SB7xx/SB8xx watchdog hardware seems to conform to the above
44  * specifications, but the table hasn't been spotted in the wild yet.
45  */
46 
47 #include <sys/cdefs.h>
48 __FBSDID("$FreeBSD$");
49 
50 #include <sys/param.h>
51 #include <sys/kernel.h>
52 #include <sys/module.h>
53 #include <sys/systm.h>
54 #include <sys/sysctl.h>
55 #include <sys/bus.h>
56 #include <machine/bus.h>
57 #include <sys/rman.h>
58 #include <machine/resource.h>
59 #include <sys/watchdog.h>
60 
61 #include <dev/pci/pcivar.h>
62 #include <dev/amdsbwd/amd_chipset.h>
63 #include <isa/isavar.h>
64 
65 /*
66  * Registers in the Watchdog IO space.
67  * See SB7xx RRG 2.3.4, WDRT.
68  */
69 #define	AMDSB_WD_CTRL			0x00
70 #define		AMDSB_WD_RUN		0x01
71 #define		AMDSB_WD_FIRED		0x02
72 #define		AMDSB_WD_SHUTDOWN	0x04
73 #define		AMDSB_WD_DISABLE	0x08
74 #define		AMDSB_WD_RESERVED	0x70
75 #define		AMDSB_WD_RELOAD		0x80
76 #define	AMDSB_WD_COUNT			0x04
77 #define		AMDSB_WD_COUNT_MASK	0xffff
78 #define	AMDSB_WDIO_REG_WIDTH		4
79 
80 #define	amdsbwd_verbose_printf(dev, ...)	\
81 	do {						\
82 		if (bootverbose)			\
83 			device_printf(dev, __VA_ARGS__);\
84 	} while (0)
85 
86 struct amdsbwd_softc {
87 	device_t		dev;
88 	eventhandler_tag	ev_tag;
89 	struct resource		*res_ctrl;
90 	struct resource		*res_count;
91 	int			rid_ctrl;
92 	int			rid_count;
93 	int			ms_per_tick;
94 	int			max_ticks;
95 	int			active;
96 	unsigned int		timeout;
97 };
98 
99 static void	amdsbwd_identify(driver_t *driver, device_t parent);
100 static int	amdsbwd_probe(device_t dev);
101 static int	amdsbwd_attach(device_t dev);
102 static int	amdsbwd_detach(device_t dev);
103 
104 static device_method_t amdsbwd_methods[] = {
105 	DEVMETHOD(device_identify,	amdsbwd_identify),
106 	DEVMETHOD(device_probe,		amdsbwd_probe),
107 	DEVMETHOD(device_attach,	amdsbwd_attach),
108 	DEVMETHOD(device_detach,	amdsbwd_detach),
109 #if 0
110 	DEVMETHOD(device_shutdown,	amdsbwd_detach),
111 #endif
112 	DEVMETHOD_END
113 };
114 
115 static devclass_t	amdsbwd_devclass;
116 static driver_t		amdsbwd_driver = {
117 	"amdsbwd",
118 	amdsbwd_methods,
119 	sizeof(struct amdsbwd_softc)
120 };
121 
122 DRIVER_MODULE(amdsbwd, isa, amdsbwd_driver, amdsbwd_devclass, NULL, NULL);
123 
124 
125 static uint8_t
126 pmio_read(struct resource *res, uint8_t reg)
127 {
128 	bus_write_1(res, 0, reg);	/* Index */
129 	return (bus_read_1(res, 1));	/* Data */
130 }
131 
132 static void
133 pmio_write(struct resource *res, uint8_t reg, uint8_t val)
134 {
135 	bus_write_1(res, 0, reg);	/* Index */
136 	bus_write_1(res, 1, val);	/* Data */
137 }
138 
139 static uint32_t
140 wdctrl_read(struct amdsbwd_softc *sc)
141 {
142 	return (bus_read_4(sc->res_ctrl, 0));
143 }
144 
145 static void
146 wdctrl_write(struct amdsbwd_softc *sc, uint32_t val)
147 {
148 	bus_write_4(sc->res_ctrl, 0, val);
149 }
150 
151 static __unused uint32_t
152 wdcount_read(struct amdsbwd_softc *sc)
153 {
154 	return (bus_read_4(sc->res_count, 0));
155 }
156 
157 static void
158 wdcount_write(struct amdsbwd_softc *sc, uint32_t val)
159 {
160 	bus_write_4(sc->res_count, 0, val);
161 }
162 
163 static void
164 amdsbwd_tmr_enable(struct amdsbwd_softc *sc)
165 {
166 	uint32_t val;
167 
168 	val = wdctrl_read(sc);
169 	val |= AMDSB_WD_RUN;
170 	wdctrl_write(sc, val);
171 	sc->active = 1;
172 	amdsbwd_verbose_printf(sc->dev, "timer enabled\n");
173 }
174 
175 static void
176 amdsbwd_tmr_disable(struct amdsbwd_softc *sc)
177 {
178 	uint32_t val;
179 
180 	val = wdctrl_read(sc);
181 	val &= ~AMDSB_WD_RUN;
182 	wdctrl_write(sc, val);
183 	sc->active = 0;
184 	amdsbwd_verbose_printf(sc->dev, "timer disabled\n");
185 }
186 
187 static void
188 amdsbwd_tmr_reload(struct amdsbwd_softc *sc)
189 {
190 	uint32_t val;
191 
192 	val = wdctrl_read(sc);
193 	val |= AMDSB_WD_RELOAD;
194 	wdctrl_write(sc, val);
195 }
196 
197 static void
198 amdsbwd_tmr_set(struct amdsbwd_softc *sc, uint16_t timeout)
199 {
200 
201 	timeout &= AMDSB_WD_COUNT_MASK;
202 	wdcount_write(sc, timeout);
203 	sc->timeout = timeout;
204 	amdsbwd_verbose_printf(sc->dev, "timeout set to %u ticks\n", timeout);
205 }
206 
207 static void
208 amdsbwd_event(void *arg, unsigned int cmd, int *error)
209 {
210 	struct amdsbwd_softc *sc = arg;
211 	unsigned int timeout;
212 
213 	/* convert from power-of-two-ns to WDT ticks */
214 	cmd &= WD_INTERVAL;
215 	if (cmd < WD_TO_1SEC)
216 		cmd = 0;
217 	if (cmd) {
218 		timeout = ((uint64_t)1 << (cmd - WD_TO_1MS)) / sc->ms_per_tick;
219 		if (timeout > sc->max_ticks)
220 			timeout = sc->max_ticks;
221 		if (timeout != sc->timeout) {
222 			amdsbwd_tmr_set(sc, timeout);
223 			if (!sc->active)
224 				amdsbwd_tmr_enable(sc);
225 		}
226 		amdsbwd_tmr_reload(sc);
227 		*error = 0;
228 	} else {
229 		if (sc->active)
230 			amdsbwd_tmr_disable(sc);
231 	}
232 }
233 
234 static void
235 amdsbwd_identify(driver_t *driver, device_t parent)
236 {
237 	device_t		child;
238 	device_t		smb_dev;
239 
240 	if (resource_disabled("amdsbwd", 0))
241 		return;
242 	if (device_find_child(parent, "amdsbwd", -1) != NULL)
243 		return;
244 
245 	/*
246 	 * Try to identify SB600/SB7xx by PCI Device ID of SMBus device
247 	 * that should be present at bus 0, device 20, function 0.
248 	 */
249 	smb_dev = pci_find_bsf(0, 20, 0);
250 	if (smb_dev == NULL)
251 		return;
252 	if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID &&
253 	    pci_get_devid(smb_dev) != AMDFCH_SMBUS_DEVID &&
254 	    pci_get_devid(smb_dev) != AMDCZ_SMBUS_DEVID)
255 		return;
256 
257 	child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1);
258 	if (child == NULL)
259 		device_printf(parent, "add amdsbwd child failed\n");
260 }
261 
262 
263 static void
264 amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr)
265 {
266 	uint8_t	val;
267 	int	i;
268 
269 	/* Report cause of previous reset for user's convenience. */
270 	val = pmio_read(pmres, AMDSB_PM_RESET_STATUS0);
271 	if (val != 0)
272 		amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
273 	val = pmio_read(pmres, AMDSB_PM_RESET_STATUS1);
274 	if (val != 0)
275 		amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
276 	if ((val & AMDSB_WD_RST_STS) != 0)
277 		device_printf(dev, "Previous Reset was caused by Watchdog\n");
278 
279 	/* Find base address of memory mapped WDT registers. */
280 	for (*addr = 0, i = 0; i < 4; i++) {
281 		*addr <<= 8;
282 		*addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i);
283 	}
284 	*addr &= ~0x07u;
285 
286 	/* Set watchdog timer tick to 1s. */
287 	val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
288 	val &= ~AMDSB_WDT_RES_MASK;
289 	val |= AMDSB_WDT_RES_1S;
290 	pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
291 
292 	/* Enable watchdog device (in stopped state). */
293 	val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
294 	val &= ~AMDSB_WDT_DISABLE;
295 	pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
296 
297 	/*
298 	 * XXX TODO: Ensure that watchdog decode is enabled
299 	 * (register 0x41, bit 3).
300 	 */
301 	device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer");
302 }
303 
304 static void
305 amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr)
306 {
307 	uint8_t	val;
308 	int	i;
309 
310 	/* Report cause of previous reset for user's convenience. */
311 	val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS0);
312 	if (val != 0)
313 		amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
314 	val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS1);
315 	if (val != 0)
316 		amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
317 	if ((val & AMDSB8_WD_RST_STS) != 0)
318 		device_printf(dev, "Previous Reset was caused by Watchdog\n");
319 
320 	/* Find base address of memory mapped WDT registers. */
321 	for (*addr = 0, i = 0; i < 4; i++) {
322 		*addr <<= 8;
323 		*addr |= pmio_read(pmres, AMDSB8_PM_WDT_EN + 3 - i);
324 	}
325 	*addr &= ~0x07u;
326 
327 	/* Set watchdog timer tick to 1s. */
328 	val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
329 	val &= ~AMDSB8_WDT_RES_MASK;
330 	val |= AMDSB8_WDT_1HZ;
331 	pmio_write(pmres, AMDSB8_PM_WDT_CTRL, val);
332 #ifdef AMDSBWD_DEBUG
333 	val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
334 	amdsbwd_verbose_printf(dev, "AMDSB8_PM_WDT_CTRL value = %#04x\n", val);
335 #endif
336 
337 	/*
338 	 * Enable watchdog device (in stopped state)
339 	 * and decoding of its address.
340 	 */
341 	val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
342 	val &= ~AMDSB8_WDT_DISABLE;
343 	val |= AMDSB8_WDT_DEC_EN;
344 	pmio_write(pmres, AMDSB8_PM_WDT_EN, val);
345 #ifdef AMDSBWD_DEBUG
346 	val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
347 	device_printf(dev, "AMDSB8_PM_WDT_EN value = %#04x\n", val);
348 #endif
349 	device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer");
350 }
351 
352 static void
353 amdsbwd_probe_fch41(device_t dev, struct resource *pmres, uint32_t *addr)
354 {
355 	uint8_t	val;
356 
357 	val = pmio_read(pmres, AMDFCH41_PM_ISA_CTRL);
358 	if ((val & AMDFCH41_MMIO_EN) != 0) {
359 		/* Fixed offset for the watchdog within ACPI MMIO range. */
360 		amdsbwd_verbose_printf(dev, "ACPI MMIO range is enabled\n");
361 		*addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_WDT_OFF;
362 	} else {
363 		/*
364 		 * Enable decoding of watchdog MMIO address.
365 		 */
366 		val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0);
367 		val |= AMDFCH41_WDT_EN;
368 		pmio_write(pmres, AMDFCH41_PM_DECODE_EN0, val);
369 #ifdef AMDSBWD_DEBUG
370 		val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0);
371 		device_printf(dev, "AMDFCH41_PM_DECODE_EN0 value = %#04x\n",
372 		    val);
373 #endif
374 
375 		/* Special fixed MMIO range for the watchdog. */
376 		*addr = AMDFCH41_WDT_FIXED_ADDR;
377 	}
378 
379 	/*
380 	 * Set watchdog timer tick to 1s and
381 	 * enable the watchdog device (in stopped state).
382 	 */
383 	val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3);
384 	val &= ~AMDFCH41_WDT_RES_MASK;
385 	val |= AMDFCH41_WDT_RES_1S;
386 	val &= ~AMDFCH41_WDT_EN_MASK;
387 	val |= AMDFCH41_WDT_ENABLE;
388 	pmio_write(pmres, AMDFCH41_PM_DECODE_EN3, val);
389 #ifdef AMDSBWD_DEBUG
390 	val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3);
391 	amdsbwd_verbose_printf(dev, "AMDFCH41_PM_DECODE_EN3 value = %#04x\n",
392 	    val);
393 #endif
394 	device_set_desc(dev, "AMD FCH Rev 41h+ Watchdog Timer");
395 }
396 
397 static int
398 amdsbwd_probe(device_t dev)
399 {
400 	struct resource		*res;
401 	device_t		smb_dev;
402 	uint32_t		addr;
403 	int			rid;
404 	int			rc;
405 	uint32_t		devid;
406 	uint8_t			revid;
407 
408 	/* Do not claim some ISA PnP device by accident. */
409 	if (isa_get_logicalid(dev) != 0)
410 		return (ENXIO);
411 
412 	rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX,
413 	    AMDSB_PMIO_WIDTH);
414 	if (rc != 0) {
415 		device_printf(dev, "bus_set_resource for IO failed\n");
416 		return (ENXIO);
417 	}
418 	rid = 0;
419 	res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
420 	    RF_ACTIVE | RF_SHAREABLE);
421 	if (res == NULL) {
422 		device_printf(dev, "bus_alloc_resource for IO failed\n");
423 		return (ENXIO);
424 	}
425 
426 	smb_dev = pci_find_bsf(0, 20, 0);
427 	KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
428 	devid = pci_get_devid(smb_dev);
429 	revid = pci_get_revid(smb_dev);
430 	if (devid == AMDSB_SMBUS_DEVID && revid < AMDSB8_SMBUS_REVID)
431 		amdsbwd_probe_sb7xx(dev, res, &addr);
432 	else if (devid == AMDSB_SMBUS_DEVID ||
433 	    (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) ||
434 	    (devid == AMDCZ_SMBUS_DEVID  && revid < AMDCZ49_SMBUS_REVID))
435 		amdsbwd_probe_sb8xx(dev, res, &addr);
436 	else
437 		amdsbwd_probe_fch41(dev, res, &addr);
438 
439 	bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
440 	bus_delete_resource(dev, SYS_RES_IOPORT, rid);
441 
442 	amdsbwd_verbose_printf(dev, "memory base address = %#010x\n", addr);
443 	rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + AMDSB_WD_CTRL,
444 	    AMDSB_WDIO_REG_WIDTH);
445 	if (rc != 0) {
446 		device_printf(dev, "bus_set_resource for control failed\n");
447 		return (ENXIO);
448 	}
449 	rc = bus_set_resource(dev, SYS_RES_MEMORY, 1, addr + AMDSB_WD_COUNT,
450 	    AMDSB_WDIO_REG_WIDTH);
451 	if (rc != 0) {
452 		device_printf(dev, "bus_set_resource for count failed\n");
453 		return (ENXIO);
454 	}
455 
456 	return (0);
457 }
458 
459 static int
460 amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc)
461 {
462 
463 	sc->max_ticks = UINT16_MAX;
464 	sc->rid_ctrl = 0;
465 	sc->rid_count = 1;
466 
467 	sc->ms_per_tick = 1000;
468 
469 	sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
470 	    &sc->rid_ctrl, RF_ACTIVE);
471 	if (sc->res_ctrl == NULL) {
472 		device_printf(dev, "bus_alloc_resource for ctrl failed\n");
473 		return (ENXIO);
474 	}
475 	sc->res_count = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
476 	    &sc->rid_count, RF_ACTIVE);
477 	if (sc->res_count == NULL) {
478 		device_printf(dev, "bus_alloc_resource for count failed\n");
479 		return (ENXIO);
480 	}
481 	return (0);
482 }
483 
484 static int
485 amdsbwd_attach(device_t dev)
486 {
487 	struct amdsbwd_softc	*sc;
488 	int			rc;
489 
490 	sc = device_get_softc(dev);
491 	sc->dev = dev;
492 
493 	rc = amdsbwd_attach_sb(dev, sc);
494 	if (rc != 0)
495 		goto fail;
496 
497 #ifdef AMDSBWD_DEBUG
498 	device_printf(dev, "wd ctrl = %#04x\n", wdctrl_read(sc));
499 	device_printf(dev, "wd count = %#04x\n", wdcount_read(sc));
500 #endif
501 
502 	/* Setup initial state of Watchdog Control. */
503 	wdctrl_write(sc, AMDSB_WD_FIRED);
504 
505 	if (wdctrl_read(sc) & AMDSB_WD_DISABLE) {
506 		device_printf(dev, "watchdog hardware is disabled\n");
507 		goto fail;
508 	}
509 
510 	sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, amdsbwd_event, sc,
511 	    EVENTHANDLER_PRI_ANY);
512 
513 	return (0);
514 
515 fail:
516 	amdsbwd_detach(dev);
517 	return (ENXIO);
518 }
519 
520 static int
521 amdsbwd_detach(device_t dev)
522 {
523 	struct amdsbwd_softc *sc;
524 
525 	sc = device_get_softc(dev);
526 	if (sc->ev_tag != NULL)
527 		EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
528 
529 	if (sc->active)
530 		amdsbwd_tmr_disable(sc);
531 
532 	if (sc->res_ctrl != NULL)
533 		bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl,
534 		    sc->res_ctrl);
535 
536 	if (sc->res_count != NULL)
537 		bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_count,
538 		    sc->res_count);
539 
540 	return (0);
541 }
542 
543