1/*	$OpenBSD: dwdog.c,v 1.3 2021/10/24 17:52:26 mpi Exp $	*/
2/*
3 * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
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
22#include <machine/bus.h>
23#include <machine/fdt.h>
24
25#include <armv7/armv7/armv7_machdep.h>
26
27#include <dev/ofw/openfirm.h>
28#include <dev/ofw/fdt.h>
29
30/* Registers */
31#define WDT_CR			0x0000
32#define  WDT_CR_WDT_EN		(1 << 0)
33#define  WDT_CR_RESP_MODE	(1 << 1)
34#define WDT_TORR		0x0004
35#define WDT_CCVR		0x0008
36#define WDT_CRR			0x000c
37#define  WDT_CRR_KICK		0x76
38#define WDT_STAT		0x0010
39#define WDT_EOI			0x0014
40
41#define HREAD4(sc, reg)							\
42	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
43#define HWRITE4(sc, reg, val)						\
44	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
45#define HSET4(sc, reg, bits)						\
46	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
47#define HCLR4(sc, reg, bits)						\
48	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
49
50struct dwdog_softc {
51	struct device		sc_dev;
52	bus_space_tag_t		sc_iot;
53	bus_space_handle_t	sc_ioh;
54};
55
56int	dwdog_match(struct device *, void *, void *);
57void	dwdog_attach(struct device *, struct device *, void *);
58
59const struct cfattach dwdog_ca = {
60	sizeof(struct dwdog_softc), dwdog_match, dwdog_attach
61};
62
63struct cfdriver dwdog_cd = {
64	NULL, "dwdog", DV_DULL
65};
66
67void	dwdog_reset(void);
68
69int
70dwdog_match(struct device *parent, void *match, void *aux)
71{
72	struct fdt_attach_args *faa = aux;
73
74	return OF_is_compatible(faa->fa_node, "snps,dw-wdt");
75}
76
77void
78dwdog_attach(struct device *parent, struct device *self, void *aux)
79{
80	struct dwdog_softc *sc = (struct dwdog_softc *)self;
81	struct fdt_attach_args *faa = aux;
82
83	if (faa->fa_nreg < 1) {
84		printf(": no registers\n");
85		return;
86	}
87
88	sc->sc_iot = faa->fa_iot;
89
90	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
91	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
92		printf(": can't map registers\n");
93	}
94
95	printf("\n");
96
97	if (cpuresetfn == NULL)
98		cpuresetfn = dwdog_reset;
99}
100
101void
102dwdog_reset(void)
103{
104	struct dwdog_softc *sc = dwdog_cd.cd_devs[0];
105
106	/*
107	 * Generate system reset when timer expires and select
108	 * smallest timeout.
109	 */
110	HCLR4(sc, WDT_CR, WDT_CR_RESP_MODE | WDT_CR_WDT_EN);
111	HWRITE4(sc, WDT_TORR, 0);
112	HSET4(sc, WDT_CR, WDT_CR_WDT_EN);
113
114	/* Kick the dog! */
115	HWRITE4(sc, WDT_CRR, WDT_CRR_KICK);
116
117	delay(1000000);
118}
119