imx_wdog.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2012, 2013 The FreeBSD Foundation
5 * All rights reserved.
6 *
7 * This software was developed by Oleksandr Rybalko under sponsorship
8 * from the FreeBSD Foundation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1.	Redistributions of source code must retain the above copyright
14 *	notice, this list of conditions and the following disclaimer.
15 * 2.	Redistributions in binary form must reproduce the above copyright
16 *	notice, this list of conditions and the following disclaimer in the
17 *	documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: stable/11/sys/arm/freescale/imx/imx_wdog.c 330897 2018-03-14 03:19:51Z eadler $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/time.h>
40#include <sys/bus.h>
41#include <sys/resource.h>
42#include <sys/rman.h>
43#include <sys/watchdog.h>
44
45#include <machine/bus.h>
46#include <machine/intr.h>
47
48#include <dev/fdt/fdt_common.h>
49#include <dev/ofw/openfirm.h>
50#include <dev/ofw/ofw_bus.h>
51#include <dev/ofw/ofw_bus_subr.h>
52
53#include <arm/freescale/imx/imx_wdogreg.h>
54
55struct imx_wdog_softc {
56	struct mtx		sc_mtx;
57	device_t		sc_dev;
58	bus_space_tag_t		sc_bst;
59	bus_space_handle_t	sc_bsh;
60	struct resource		*sc_res[2];
61	uint32_t		sc_timeout;
62};
63
64static struct resource_spec imx_wdog_spec[] = {
65	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
66	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
67	{ -1, 0 }
68};
69
70static struct ofw_compat_data compat_data[] = {
71	{"fsl,imx6sx-wdt", 1},
72	{"fsl,imx6sl-wdt", 1},
73	{"fsl,imx6q-wdt",  1},
74	{"fsl,imx53-wdt",  1},
75	{"fsl,imx51-wdt",  1},
76	{"fsl,imx50-wdt",  1},
77	{"fsl,imx35-wdt",  1},
78	{"fsl,imx27-wdt",  1},
79	{"fsl,imx25-wdt",  1},
80	{"fsl,imx21-wdt",  1},
81	{NULL,             0}
82};
83
84static void	imx_watchdog(void *, u_int, int *);
85static int	imx_wdog_probe(device_t);
86static int	imx_wdog_attach(device_t);
87
88static device_method_t imx_wdog_methods[] = {
89	DEVMETHOD(device_probe,		imx_wdog_probe),
90	DEVMETHOD(device_attach,	imx_wdog_attach),
91	DEVMETHOD_END
92};
93
94static driver_t imx_wdog_driver = {
95	"imx_wdog",
96	imx_wdog_methods,
97	sizeof(struct imx_wdog_softc),
98};
99static devclass_t imx_wdog_devclass;
100DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0);
101
102#define	RD2(_sc, _r)							\
103		bus_space_read_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r))
104#define	WR2(_sc, _r, _v)						\
105		bus_space_write_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r), (_v))
106
107static void
108imx_watchdog(void *arg, u_int cmd, int *error)
109{
110	struct imx_wdog_softc *sc;
111	uint16_t reg;
112	u_int timeout;
113
114	sc = arg;
115	mtx_lock(&sc->sc_mtx);
116	if (cmd == 0) {
117		if (bootverbose)
118			device_printf(sc->sc_dev, "Can not be disabled.\n");
119		*error = EOPNOTSUPP;
120	} else {
121		timeout = (u_int)((1ULL << (cmd & WD_INTERVAL)) / 1000000000U);
122		if (timeout > 1 && timeout < 128) {
123			if (timeout != sc->sc_timeout) {
124				sc->sc_timeout = timeout;
125				reg = RD2(sc, WDOG_CR_REG);
126				reg &= ~WDOG_CR_WT_MASK;
127				reg |= (timeout << (WDOG_CR_WT_SHIFT + 1)) &
128				    WDOG_CR_WT_MASK;
129				WR2(sc, WDOG_CR_REG, reg | WDOG_CR_WDE);
130			}
131			/* Refresh counter */
132			WR2(sc, WDOG_SR_REG, WDOG_SR_STEP1);
133			WR2(sc, WDOG_SR_REG, WDOG_SR_STEP2);
134			*error = 0;
135		}
136	}
137	mtx_unlock(&sc->sc_mtx);
138}
139
140static int
141imx_wdog_probe(device_t dev)
142{
143
144	if (!ofw_bus_status_okay(dev))
145		return (ENXIO);
146
147	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
148		return (ENXIO);
149
150	device_set_desc(dev, "Freescale i.MX Watchdog");
151	return (0);
152}
153
154static int
155imx_wdog_attach(device_t dev)
156{
157	struct imx_wdog_softc *sc;
158
159	sc = device_get_softc(dev);
160	sc->sc_dev = dev;
161
162	if (bus_alloc_resources(dev, imx_wdog_spec, sc->sc_res)) {
163		device_printf(dev, "could not allocate resources\n");
164		return (ENXIO);
165	}
166
167	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "imx_wdt", MTX_DEF);
168
169	sc->sc_dev = dev;
170	sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
171	sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
172
173	/* TODO: handle interrupt */
174
175	EVENTHANDLER_REGISTER(watchdog_list, imx_watchdog, sc, 0);
176	return (0);
177}
178