1239922Sgonzo/*-
2239922Sgonzo * Copyright (c) 2012 Alexander Rybalko <ray@freebsd.org>
3239922Sgonzo * All rights reserved.
4239922Sgonzo *
5239922Sgonzo * Redistribution and use in source and binary forms, with or without
6239922Sgonzo * modification, are permitted provided that the following conditions
7239922Sgonzo * are met:
8239922Sgonzo * 1. Redistributions of source code must retain the above copyright
9239922Sgonzo *    notice, this list of conditions and the following disclaimer.
10239922Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11239922Sgonzo *    notice, this list of conditions and the following disclaimer in the
12239922Sgonzo *    documentation and/or other materials provided with the distribution.
13239922Sgonzo *
14239922Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15239922Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16239922Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17239922Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18239922Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19239922Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20239922Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21239922Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22239922Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239922Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239922Sgonzo * SUCH DAMAGE.
25239922Sgonzo */
26239922Sgonzo#include <sys/cdefs.h>
27239922Sgonzo__FBSDID("$FreeBSD$");
28239922Sgonzo
29239922Sgonzo#include <sys/param.h>
30239922Sgonzo#include <sys/systm.h>
31239922Sgonzo#include <sys/watchdog.h>
32239922Sgonzo#include <sys/bus.h>
33239922Sgonzo#include <sys/kernel.h>
34239922Sgonzo#include <sys/module.h>
35239922Sgonzo#include <sys/rman.h>
36239922Sgonzo
37239922Sgonzo#include <dev/fdt/fdt_common.h>
38239922Sgonzo#include <dev/ofw/openfirm.h>
39239922Sgonzo#include <dev/ofw/ofw_bus.h>
40239922Sgonzo#include <dev/ofw/ofw_bus_subr.h>
41239922Sgonzo
42239922Sgonzo#include <machine/bus.h>
43239922Sgonzo#include <machine/cpufunc.h>
44239922Sgonzo#include <machine/machdep.h>
45239922Sgonzo#include <machine/fdt.h>
46239922Sgonzo
47239922Sgonzo#include <arm/broadcom/bcm2835/bcm2835_wdog.h>
48239922Sgonzo
49239922Sgonzo#define	BCM2835_PASWORD		0x5a
50239922Sgonzo
51239922Sgonzo#define BCM2835_WDOG_RESET	0
52239922Sgonzo#define BCM2835_PASSWORD_MASK	0xff000000
53239922Sgonzo#define BCM2835_PASSWORD_SHIFT	24
54239922Sgonzo#define BCM2835_WDOG_TIME_MASK	0x000fffff
55239922Sgonzo#define BCM2835_WDOG_TIME_SHIFT	0
56239922Sgonzo
57239922Sgonzo#define	READ(_sc, _r) bus_space_read_4((_sc)->bst, (_sc)->bsh, (_r))
58239922Sgonzo#define	WRITE(_sc, _r, _v) bus_space_write_4((_sc)->bst, (_sc)->bsh, (_r), (_v))
59239922Sgonzo
60239922Sgonzo#define BCM2835_RSTC_WRCFG_CLR		0xffffffcf
61239922Sgonzo#define BCM2835_RSTC_WRCFG_SET		0x00000030
62239922Sgonzo#define BCM2835_RSTC_WRCFG_FULL_RESET	0x00000020
63239922Sgonzo#define BCM2835_RSTC_RESET		0x00000102
64239922Sgonzo
65239922Sgonzo#define	BCM2835_RSTC_REG	0x00
66239922Sgonzo#define	BCM2835_RSTS_REG	0x04
67239922Sgonzo#define	BCM2835_WDOG_REG	0x08
68239922Sgonzo
69239922Sgonzostatic struct bcmwd_softc *bcmwd_lsc = NULL;
70239922Sgonzo
71239922Sgonzostruct bcmwd_softc {
72239922Sgonzo	device_t		dev;
73239922Sgonzo	struct resource *	res;
74239922Sgonzo	bus_space_tag_t		bst;
75239922Sgonzo	bus_space_handle_t	bsh;
76239922Sgonzo	int			wdog_armed;
77239922Sgonzo	int			wdog_period;
78239922Sgonzo	char			wdog_passwd;
79239922Sgonzo};
80239922Sgonzo
81239922Sgonzo#ifdef notyet
82239922Sgonzostatic void bcmwd_watchdog_fn(void *private, u_int cmd, int *error);
83239922Sgonzo#endif
84239922Sgonzo
85239922Sgonzostatic int
86239922Sgonzobcmwd_probe(device_t dev)
87239922Sgonzo{
88239922Sgonzo
89239922Sgonzo	if (ofw_bus_is_compatible(dev, "broadcom,bcm2835-wdt")) {
90239922Sgonzo		device_set_desc(dev, "BCM2708/2835 Watchdog");
91239922Sgonzo		return (BUS_PROBE_DEFAULT);
92239922Sgonzo	}
93239922Sgonzo
94239922Sgonzo	return (ENXIO);
95239922Sgonzo}
96239922Sgonzo
97239922Sgonzostatic int
98239922Sgonzobcmwd_attach(device_t dev)
99239922Sgonzo{
100239922Sgonzo	struct bcmwd_softc *sc;
101239922Sgonzo	int rid;
102239922Sgonzo
103239922Sgonzo	if (bcmwd_lsc != NULL)
104239922Sgonzo		return (ENXIO);
105239922Sgonzo
106239922Sgonzo	sc = device_get_softc(dev);
107239922Sgonzo	sc->wdog_period = 7;
108239922Sgonzo	sc->wdog_passwd = BCM2835_PASWORD;
109239922Sgonzo	sc->wdog_armed = 0;
110239922Sgonzo	sc->dev = dev;
111239922Sgonzo
112239922Sgonzo	rid = 0;
113239922Sgonzo	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
114239922Sgonzo	if (sc->res == NULL) {
115239922Sgonzo		device_printf(dev, "could not allocate memory resource\n");
116239922Sgonzo		return (ENXIO);
117239922Sgonzo	}
118239922Sgonzo
119239922Sgonzo	sc->bst = rman_get_bustag(sc->res);
120239922Sgonzo	sc->bsh = rman_get_bushandle(sc->res);
121239922Sgonzo
122239922Sgonzo	bcmwd_lsc = sc;
123239922Sgonzo#ifdef notyet
124239922Sgonzo	EVENTHANDLER_REGISTER(watchdog_list, bcmwd_watchdog_fn, sc, 0);
125239922Sgonzo#endif
126239922Sgonzo	return (0);
127239922Sgonzo}
128239922Sgonzo
129239922Sgonzo#ifdef notyet
130239922Sgonzostatic void
131239922Sgonzobcmwd_watchdog_fn(void *private, u_int cmd, int *error)
132239922Sgonzo{
133239922Sgonzo	/* XXX: not yet */
134239922Sgonzo}
135239922Sgonzo#endif
136239922Sgonzo
137239922Sgonzovoid
138239922Sgonzobcmwd_watchdog_reset()
139239922Sgonzo{
140239922Sgonzo
141239922Sgonzo	if (bcmwd_lsc == NULL)
142239922Sgonzo		return;
143239922Sgonzo
144239922Sgonzo	WRITE(bcmwd_lsc, BCM2835_WDOG_REG,
145239922Sgonzo	    (BCM2835_PASWORD << BCM2835_PASSWORD_SHIFT) | 10);
146239922Sgonzo
147239922Sgonzo	WRITE(bcmwd_lsc, BCM2835_RSTC_REG,
148239922Sgonzo	    (READ(bcmwd_lsc, BCM2835_RSTC_REG) & BCM2835_RSTC_WRCFG_CLR) |
149239922Sgonzo		(BCM2835_PASWORD << BCM2835_PASSWORD_SHIFT) |
150239922Sgonzo		BCM2835_RSTC_WRCFG_FULL_RESET);
151239922Sgonzo}
152239922Sgonzo
153239922Sgonzostatic device_method_t bcmwd_methods[] = {
154239922Sgonzo	DEVMETHOD(device_probe, bcmwd_probe),
155239922Sgonzo	DEVMETHOD(device_attach, bcmwd_attach),
156239922Sgonzo
157239922Sgonzo	DEVMETHOD_END
158239922Sgonzo};
159239922Sgonzo
160239922Sgonzostatic driver_t bcmwd_driver = {
161239922Sgonzo	"bcmwd",
162239922Sgonzo	bcmwd_methods,
163239922Sgonzo	sizeof(struct bcmwd_softc),
164239922Sgonzo};
165239922Sgonzostatic devclass_t bcmwd_devclass;
166239922Sgonzo
167239922SgonzoDRIVER_MODULE(bcmwd, simplebus, bcmwd_driver, bcmwd_devclass, 0, 0);
168