From fb6d2f89c4c7c1a1881d596452c107fa0904f347 Mon Sep 17 00:00:00 2001 From: patrick Date: Fri, 28 May 2021 13:03:55 +0000 Subject: [PATCH] Once i.MX's watchdog is enabled, it can never be disabled. Some 64-bit i.MX machines with a recent U-Boot come up with the watchdog enabled, so we have to regularly ping it to make sure the watchdog doesn't reset us. The watchdog's timeout can be configured in 0.5s steps to a maximum of 128s. Set it to the maximum, and schedule a timeout which reloads the counter every 120s. This only needs to be done if the watchdog is enabled when we boot up. Tested on Cubox-i (armv7) and MNT Reform (arm64) ok kettenis@ --- sys/dev/fdt/imxdog.c | 60 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/sys/dev/fdt/imxdog.c b/sys/dev/fdt/imxdog.c index 69663afe217..82f4a1267e2 100644 --- a/sys/dev/fdt/imxdog.c +++ b/sys/dev/fdt/imxdog.c @@ -1,6 +1,6 @@ -/* $OpenBSD: imxdog.c,v 1.1 2021/05/28 11:50:18 patrick Exp $ */ +/* $OpenBSD: imxdog.c,v 1.2 2021/05/28 13:03:55 patrick Exp $ */ /* - * Copyright (c) 2012-2013 Patrick Wildt + * Copyright (c) 2012-2013,2021 Patrick Wildt * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,26 +18,34 @@ #include #include #include +#include #include #include -#include - #include #include +extern void (*cpuresetfn)(void); + /* registers */ #define WCR 0x00 +#define WCR_WDE (1 << 2) +#define WCR_WT_SEC(x) (((x) * 2 - 1) << 8) +#define WCR_WT_MASK (0xff << 8) #define WSR 0x02 #define WRSR 0x04 #define WICR 0x06 #define WMCR 0x08 +#define WDOG_TIMEOUT_CALLBACK 120 +#define WDOG_MAX_TIMEOUT_SEC 128 + struct imxdog_softc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + struct timeout sc_tmo; }; struct imxdog_softc *imxdog_sc; @@ -45,6 +53,7 @@ struct imxdog_softc *imxdog_sc; int imxdog_match(struct device *, void *, void *); void imxdog_attach(struct device *, struct device *, void *); void imxdog_reset(void); +void imxdog_timeout(void *); struct cfattach imxdog_ca = { sizeof (struct imxdog_softc), imxdog_match, imxdog_attach @@ -67,6 +76,7 @@ imxdog_attach(struct device *parent, struct device *self, void *aux) { struct fdt_attach_args *faa = aux; struct imxdog_softc *sc = (struct imxdog_softc *) self; + uint16_t reg; if (faa->fa_nreg < 1) return; @@ -78,27 +88,55 @@ imxdog_attach(struct device *parent, struct device *self, void *aux) printf("\n"); + timeout_set(&sc->sc_tmo, imxdog_timeout, sc); + + /* Adjust timeout to maximum seconds */ + reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, WCR); + reg &= ~WCR_WT_MASK; + reg |= WCR_WT_SEC(WDOG_MAX_TIMEOUT_SEC); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, reg); + + /* Watchdog cannot be disabled, ping the watchdog if enabled */ + if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, WCR) & WCR_WDE) + imxdog_timeout(sc); + imxdog_sc = sc; - cpuresetfn = imxdog_reset; + if (cpuresetfn == NULL) + cpuresetfn = imxdog_reset; } void imxdog_reset(void) { - if (imxdog_sc == NULL) + struct imxdog_softc *sc = imxdog_sc; + + if (sc == NULL) return; /* disable watchdog and set timeout to 0 */ - bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WCR, 0); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, 0); /* sequence to reset timeout counter */ - bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WSR, 0x5555); - bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WSR, 0xaaaa); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0x5555); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0xaaaa); /* enable watchdog */ - bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WCR, 1); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, 1); /* errata TKT039676 */ - bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WCR, 1); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, 1); delay(100000); } + +void +imxdog_timeout(void *args) +{ + struct imxdog_softc *sc = args; + + /* Reload timeout counter */ + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0x5555); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0xaaaa); + + /* Schedule reload to trigger before counter runs out */ + timeout_add_sec(&sc->sc_tmo, WDOG_TIMEOUT_CALLBACK); +} -- 2.20.1