xref: /openbsd/sys/dev/fdt/imxdog.c (revision 5dea098c)
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
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
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
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
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