diff options
author | imp <imp@FreeBSD.org> | 2006-08-09 20:58:55 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2006-08-09 20:58:55 +0000 |
commit | 8d1199edcd061900495e9a07ad11c0266ddf9759 (patch) | |
tree | 790784262cbd38d7df4be2972bbfb47961120587 /sys/arm | |
parent | 7d2b35a6351cedb0d7ab9a72f118984f901518bc (diff) | |
download | FreeBSD-src-8d1199edcd061900495e9a07ad11c0266ddf9759.zip FreeBSD-src-8d1199edcd061900495e9a07ad11c0266ddf9759.tar.gz |
Hook into the watchdog device, if present. Also, turn off the
watchdog timer stuff when we boot because the boot blocks are turning
it on...
Diffstat (limited to 'sys/arm')
-rw-r--r-- | sys/arm/at91/at91_st.c | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/sys/arm/at91/at91_st.c b/sys/arm/at91/at91_st.c index 3d4c7fd..7b63af1 100644 --- a/sys/arm/at91/at91_st.c +++ b/sys/arm/at91/at91_st.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/resource.h> #include <sys/rman.h> #include <sys/timetc.h> +#include <sys/watchdog.h> #include <machine/bus.h> #include <machine/cpu.h> @@ -48,7 +49,8 @@ __FBSDID("$FreeBSD$"); static struct at91st_softc { bus_space_tag_t sc_st; bus_space_handle_t sc_sh; - device_t dev; + device_t sc_dev; + eventhandler_tag sc_wet; /* watchdog event handler tag */ } *timer_softc; #define RD4(off) \ @@ -56,6 +58,8 @@ static struct at91st_softc { #define WR4(off, val) \ bus_space_write_4(timer_softc->sc_st, timer_softc->sc_sh, (off), (val)) +static void at91st_watchdog(void *, u_int, int *); + static inline int st_crtr(void) { @@ -97,7 +101,7 @@ at91st_attach(device_t dev) timer_softc = device_get_softc(dev); timer_softc->sc_st = sc->sc_st; - timer_softc->dev = dev; + timer_softc->sc_dev = dev; if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_ST_BASE, AT91RM92_ST_SIZE, &timer_softc->sc_sh) != 0) panic("couldn't subregion timer registers"); @@ -108,6 +112,13 @@ at91st_attach(device_t dev) WR4(ST_RTMR, 1); /* Disable all interrupts */ WR4(ST_IDR, 0xffffffff); + /* disable watchdog timer */ + WR4(ST_WDMR, 0); + + timer_softc->sc_wet = EVENTHANDLER_REGISTER(watchdog_list, + at91st_watchdog, dev, 0); + device_printf(dev, + "watchdog registered, timeout intervall max. 64 sec\n"); return (0); } @@ -140,6 +151,33 @@ at91st_get_timecount(struct timecounter *tc) #endif } +/* + * t below is in a weird unit. The watchdog is set to 2^t + * nanoseconds. Since our watchdog timer can't really do that too + * well, we approximate it by assuming that the timeout interval for + * the lsb is 2^22 ns, which is 4.194ms. This is an overestimation of + * the actual time (3.906ms), but close enough for watchdogging. + * These approximations, though a violation of the spec, improve the + * performance of the application which typically specifies things as + * WD_TO_32SEC. In that last case, we'd wait 32s before the wdog + * reset. The spec says we should wait closer to 34s, but given how + * it is likely to be used, and the extremely coarse nature time + * interval, I think this is the best solution. + */ +static void +at91st_watchdog(void *argp, u_int cmd, int *error) +{ + uint32_t wdog; + int t; + + wdog = 0; + t = cmd & WD_INTERVAL; + if (cmd != 0 && t >= 22 && t <= 37) + wdog = (1 << (t - 22)) | ST_WDMR_RSTEN; + WR4(ST_WDMR, wdog); + WR4(ST_CR, ST_CR_WDRST); +} + static void clock_intr(void *arg) { @@ -161,7 +199,7 @@ cpu_initclocks(void) struct resource *irq; int rid = 0; void *ih; - device_t dev = timer_softc->dev; + device_t dev = timer_softc->sc_dev; if (32768 % hz) { printf("Cannot get %d Hz clock; using 128Hz\n", hz); @@ -229,4 +267,3 @@ void cpu_stopprofclock(void) { } - |