aboutsummaryrefslogtreecommitdiff
path: root/sys/i386/i386/geode.c
diff options
context:
space:
mode:
authorPoul-Henning Kamp <phk@FreeBSD.org>2004-02-28 22:33:28 +0000
committerPoul-Henning Kamp <phk@FreeBSD.org>2004-02-28 22:33:28 +0000
commit961af6677bda00818b01a9facec086b5c07e8af6 (patch)
tree2b8983be56ed8514c852e4e993f0d81519db45f1 /sys/i386/i386/geode.c
parent3d6e5ccb062a34f83ec0883e510bf6cef349fe82 (diff)
downloadsrc-961af6677bda00818b01a9facec086b5c07e8af6.tar.gz
src-961af6677bda00818b01a9facec086b5c07e8af6.zip
Add support for the watchdog in Geode SC1100 which is used in embedded
systems like the Soekris NET4801
Notes
Notes: svn path=/head/; revision=126387
Diffstat (limited to 'sys/i386/i386/geode.c')
-rw-r--r--sys/i386/i386/geode.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/sys/i386/i386/geode.c b/sys/i386/i386/geode.c
index e6b571151a9c..eb6a037de8b0 100644
--- a/sys/i386/i386/geode.c
+++ b/sys/i386/i386/geode.c
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/timetc.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/watchdog.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
@@ -77,6 +78,39 @@ static struct timecounter geode_timecounter = {
1000
};
+/*
+ * The GEODE watchdog runs from a 32kHz frequency. One period of that is
+ * 31250 nanoseconds which we round down to 2^14 nanoseconds. The watchdog
+ * consists of a power-of-two prescaler and a 16 bit counter, so the math
+ * is quite simple. The max timeout is 14 + 16 + 13 = 2^43 nsec ~= 2h26m.
+ */
+static void
+geode_watchdog(void *foo __unused, u_int cmd, int *error)
+{
+ u_int u, p, r;
+
+ u = cmd & WD_INTERVAL;
+ if (cmd && u >= 14 && u <= 43) {
+ u -= 14;
+ if (u > 16) {
+ p = u - 16;
+ u -= p;
+ } else {
+ p = 0;
+ }
+ if (u == 16)
+ u = (1 << u) - 1;
+ else
+ u = 1 << u;
+ r = inw(cba + 2) & 0xff00;
+ outw(cba + 2, p | 0xf0 | r);
+ outw(cba, u);
+ *error = 0;
+ } else {
+ outw(cba, 0);
+ }
+}
+
static int
geode_probe(device_t self)
{
@@ -94,6 +128,8 @@ geode_probe(device_t self)
printf("Geode rev: %02x %02x\n",
inb(cba + 0x3c), inb(cba + 0x3d));
tc_init(&geode_timecounter);
+ EVENTHANDLER_REGISTER(watchdog_list, geode_watchdog,
+ NULL, 0);
}
} else if (pci_get_devid(self) == 0x0510100b) {
gpio = pci_read_config(self, PCIR_BAR(0), 4);