1 /* $OpenBSD: imxdog.c,v 1.4 2022/04/06 18:59:28 naddy Exp $ */
2 /*
3 * Copyright (c) 2012-2013,2021 Patrick Wildt <patrick@blueri.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/timeout.h>
22
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/fdt.h>
28
29 extern void (*cpuresetfn)(void);
30
31 /* registers */
32 #define WCR 0x00
33 #define WCR_WDE (1 << 2)
34 #define WCR_WT_SEC(x) (((x) * 2 - 1) << 8)
35 #define WCR_WT_MASK (0xff << 8)
36 #define WSR 0x02
37 #define WRSR 0x04
38 #define WICR 0x06
39 #define WMCR 0x08
40
41 #define WDOG_TIMEOUT_CALLBACK 60
42 #define WDOG_MAX_TIMEOUT_SEC 128
43
44 struct imxdog_softc {
45 struct device sc_dev;
46 bus_space_tag_t sc_iot;
47 bus_space_handle_t sc_ioh;
48 struct timeout sc_tmo;
49 };
50
51 struct imxdog_softc *imxdog_sc;
52
53 int imxdog_match(struct device *, void *, void *);
54 void imxdog_attach(struct device *, struct device *, void *);
55 void imxdog_reset(void);
56 void imxdog_timeout(void *);
57
58 const struct cfattach imxdog_ca = {
59 sizeof (struct imxdog_softc), imxdog_match, imxdog_attach
60 };
61
62 struct cfdriver imxdog_cd = {
63 NULL, "imxdog", DV_DULL
64 };
65
66 int
imxdog_match(struct device * parent,void * match,void * aux)67 imxdog_match(struct device *parent, void *match, void *aux)
68 {
69 struct fdt_attach_args *faa = aux;
70
71 return OF_is_compatible(faa->fa_node, "fsl,imx21-wdt");
72 }
73
74 void
imxdog_attach(struct device * parent,struct device * self,void * aux)75 imxdog_attach(struct device *parent, struct device *self, void *aux)
76 {
77 struct fdt_attach_args *faa = aux;
78 struct imxdog_softc *sc = (struct imxdog_softc *) self;
79 uint16_t reg;
80
81 if (faa->fa_nreg < 1)
82 return;
83
84 sc->sc_iot = faa->fa_iot;
85 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
86 faa->fa_reg[0].size, 0, &sc->sc_ioh))
87 panic("imxdog_attach: bus_space_map failed!");
88
89 printf("\n");
90
91 timeout_set(&sc->sc_tmo, imxdog_timeout, sc);
92
93 /* Adjust timeout to maximum seconds */
94 reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, WCR);
95 reg &= ~WCR_WT_MASK;
96 reg |= WCR_WT_SEC(WDOG_MAX_TIMEOUT_SEC);
97 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, reg);
98
99 /* Watchdog cannot be disabled, ping the watchdog if enabled */
100 if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, WCR) & WCR_WDE)
101 imxdog_timeout(sc);
102
103 imxdog_sc = sc;
104 if (cpuresetfn == NULL)
105 cpuresetfn = imxdog_reset;
106 }
107
108 void
imxdog_reset(void)109 imxdog_reset(void)
110 {
111 struct imxdog_softc *sc = imxdog_sc;
112
113 if (sc == NULL)
114 return;
115
116 /* disable watchdog and set timeout to 0 */
117 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, 0);
118
119 /* sequence to reset timeout counter */
120 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0x5555);
121 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0xaaaa);
122
123 /* enable watchdog */
124 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, 1);
125 /* errata TKT039676 */
126 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WCR, 1);
127
128 delay(100000);
129 }
130
131 void
imxdog_timeout(void * args)132 imxdog_timeout(void *args)
133 {
134 struct imxdog_softc *sc = args;
135
136 /* Reload timeout counter */
137 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0x5555);
138 bus_space_write_2(sc->sc_iot, sc->sc_ioh, WSR, 0xaaaa);
139
140 /* Schedule reload to trigger before counter runs out */
141 timeout_add_sec(&sc->sc_tmo, WDOG_TIMEOUT_CALLBACK);
142 }
143