1*19131de3Sandvar /* $NetBSD: cycv_rstmgr.c,v 1.5 2022/01/01 13:47:19 andvar Exp $ */
2c8bd03e7Saymeric
3c8bd03e7Saymeric /* This file is in the public domain. */
4c8bd03e7Saymeric
5c8bd03e7Saymeric #include <sys/cdefs.h>
6*19131de3Sandvar __KERNEL_RCSID(0, "$NetBSD: cycv_rstmgr.c,v 1.5 2022/01/01 13:47:19 andvar Exp $");
7c8bd03e7Saymeric
8c8bd03e7Saymeric #include <sys/param.h>
9c8bd03e7Saymeric #include <sys/bus.h>
10c8bd03e7Saymeric #include <sys/device.h>
11c8bd03e7Saymeric #include <sys/intr.h>
12c8bd03e7Saymeric #include <sys/systm.h>
13c8bd03e7Saymeric #include <sys/kernel.h>
14c8bd03e7Saymeric #include <sys/atomic.h>
15c8bd03e7Saymeric #include <sys/kmem.h>
16c8bd03e7Saymeric
17c8bd03e7Saymeric #include <arm/altera/cycv_reg.h>
18c8bd03e7Saymeric #include <arm/altera/cycv_var.h>
19c8bd03e7Saymeric
20c8bd03e7Saymeric #include <dev/fdt/fdtvar.h>
21c8bd03e7Saymeric
22c8bd03e7Saymeric static int cycv_rstmgr_match(device_t, cfdata_t, void *);
23c8bd03e7Saymeric static void cycv_rstmgr_attach(device_t, device_t, void *);
24c8bd03e7Saymeric
25c8bd03e7Saymeric static void *cycv_rst_acquire(device_t, const void *, size_t);
26c8bd03e7Saymeric static void cycv_rst_release(device_t, void *);
27c8bd03e7Saymeric static int cycv_rst_reset_assert(device_t, void *);
28c8bd03e7Saymeric static int cycv_rst_reset_deassert(device_t, void *);
29c8bd03e7Saymeric
30c8bd03e7Saymeric static const struct fdtbus_reset_controller_func cycv_rstmgr_funcs = {
31c8bd03e7Saymeric cycv_rst_acquire, cycv_rst_release,
32c8bd03e7Saymeric cycv_rst_reset_assert, cycv_rst_reset_deassert
33c8bd03e7Saymeric };
34c8bd03e7Saymeric
35c8bd03e7Saymeric struct cycv_rstmgr_softc {
36c8bd03e7Saymeric device_t sc_dev;
37c8bd03e7Saymeric
38c8bd03e7Saymeric bus_space_tag_t sc_bst;
39c8bd03e7Saymeric bus_space_handle_t sc_bsh;
40c8bd03e7Saymeric };
41c8bd03e7Saymeric
42c8bd03e7Saymeric struct cycv_reset {
43c8bd03e7Saymeric bus_addr_t address;
44c8bd03e7Saymeric uint32_t mask;
45c8bd03e7Saymeric };
46c8bd03e7Saymeric
47c8bd03e7Saymeric CFATTACH_DECL_NEW(cycvrstmgr, sizeof (struct cycv_rstmgr_softc),
48c8bd03e7Saymeric cycv_rstmgr_match, cycv_rstmgr_attach, NULL, NULL);
49c8bd03e7Saymeric
50c8bd03e7Saymeric static struct cycv_rstmgr_softc *cycv_rstmgr_sc;
51c8bd03e7Saymeric
526e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
536e54367aSthorpej { .compat = "altr,rst-mgr" },
546e54367aSthorpej DEVICE_COMPAT_EOL
556e54367aSthorpej };
566e54367aSthorpej
57c8bd03e7Saymeric static int
cycv_rstmgr_match(device_t parent,cfdata_t cf,void * aux)58c8bd03e7Saymeric cycv_rstmgr_match(device_t parent, cfdata_t cf, void *aux)
59c8bd03e7Saymeric {
60c8bd03e7Saymeric struct fdt_attach_args *faa = aux;
61c8bd03e7Saymeric
626e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
63c8bd03e7Saymeric }
64c8bd03e7Saymeric
65c8bd03e7Saymeric static void
cycv_rstmgr_attach(device_t parent,device_t self,void * aux)66c8bd03e7Saymeric cycv_rstmgr_attach(device_t parent, device_t self, void *aux)
67c8bd03e7Saymeric {
68c8bd03e7Saymeric struct cycv_rstmgr_softc *sc = device_private(self);
69c8bd03e7Saymeric struct fdt_attach_args *faa = aux;
70c8bd03e7Saymeric int phandle = faa->faa_phandle;
71c8bd03e7Saymeric bus_addr_t addr;
72c8bd03e7Saymeric bus_size_t size;
73c8bd03e7Saymeric int error;
74c8bd03e7Saymeric
75c8bd03e7Saymeric if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
76c8bd03e7Saymeric aprint_error(": couldn't get registers\n");
77c8bd03e7Saymeric return;
78c8bd03e7Saymeric }
79c8bd03e7Saymeric
80c8bd03e7Saymeric sc->sc_dev = self;
81c8bd03e7Saymeric sc->sc_bst = faa->faa_bst;
82c8bd03e7Saymeric error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
83c8bd03e7Saymeric if (error) {
84be5f8c7eSskrll aprint_error(": couldn't map %#" PRIxBUSADDR ": %d",
85be5f8c7eSskrll addr, error);
86c8bd03e7Saymeric return;
87c8bd03e7Saymeric }
88c8bd03e7Saymeric
89c8bd03e7Saymeric aprint_normal(": reset manager\n");
90c8bd03e7Saymeric
91c8bd03e7Saymeric fdtbus_register_reset_controller(self, phandle, &cycv_rstmgr_funcs);
92c8bd03e7Saymeric cycv_rstmgr_sc = sc;
93c8bd03e7Saymeric }
94c8bd03e7Saymeric
95c8bd03e7Saymeric static void *
cycv_rst_acquire(device_t dev,const void * data,size_t len)96c8bd03e7Saymeric cycv_rst_acquire(device_t dev, const void *data, size_t len) {
97c8bd03e7Saymeric struct cycv_reset *reset = NULL;
98c8bd03e7Saymeric uint32_t value;
99c8bd03e7Saymeric
100c8bd03e7Saymeric if (len != sizeof value)
101c8bd03e7Saymeric goto err_decode;
102c8bd03e7Saymeric
103c8bd03e7Saymeric value = of_decode_int(data);
104c8bd03e7Saymeric if (value < 0 || value >
105e8e17c6bSaymeric (CYCV_RSTMGR_MISCMODRST - CYCV_RSTMGR_MPUMODRST + 4) / 4 * 32)
106c8bd03e7Saymeric goto err_decode;
107c8bd03e7Saymeric
108c8bd03e7Saymeric reset = kmem_alloc(sizeof *reset, KM_SLEEP);
109e8e17c6bSaymeric reset->address = CYCV_RSTMGR_MPUMODRST + value / 32 * 4;
110c8bd03e7Saymeric reset->mask = 1 << (value % 32);
111c8bd03e7Saymeric
112c8bd03e7Saymeric if (0) {
113c8bd03e7Saymeric err_decode:
114*19131de3Sandvar aprint_debug_dev(dev, "couldn't decode reset\n");
115c8bd03e7Saymeric }
116c8bd03e7Saymeric return reset;
117c8bd03e7Saymeric }
118c8bd03e7Saymeric
119c8bd03e7Saymeric static void
cycv_rst_release(device_t dev,void * r)120c8bd03e7Saymeric cycv_rst_release(device_t dev, void *r) {
121c8bd03e7Saymeric kmem_free(r, sizeof (struct cycv_reset));
122c8bd03e7Saymeric }
123c8bd03e7Saymeric
124c8bd03e7Saymeric static void
cycv_rst_reset_set(device_t dev,struct cycv_reset * reset,int set)125c8bd03e7Saymeric cycv_rst_reset_set(device_t dev, struct cycv_reset *reset, int set) {
126c8bd03e7Saymeric struct cycv_rstmgr_softc *sc = device_private(dev);
127c8bd03e7Saymeric uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, reset->address);
128c8bd03e7Saymeric
129c8bd03e7Saymeric if (set)
130c8bd03e7Saymeric val |= reset->mask;
131c8bd03e7Saymeric else
132c8bd03e7Saymeric val &= ~reset->mask;
133c8bd03e7Saymeric
134c8bd03e7Saymeric bus_space_write_4(sc->sc_bst, sc->sc_bsh, reset->address, val);
135c8bd03e7Saymeric }
136c8bd03e7Saymeric
137c8bd03e7Saymeric static int
cycv_rst_reset_assert(device_t dev,void * r)138c8bd03e7Saymeric cycv_rst_reset_assert(device_t dev, void *r) {
139c8bd03e7Saymeric
140c8bd03e7Saymeric cycv_rst_reset_set(dev, r, 1);
141c8bd03e7Saymeric
142c8bd03e7Saymeric return 0;
143c8bd03e7Saymeric }
144c8bd03e7Saymeric
145c8bd03e7Saymeric static int
cycv_rst_reset_deassert(device_t dev,void * r)146c8bd03e7Saymeric cycv_rst_reset_deassert(device_t dev, void *r) {
147c8bd03e7Saymeric
148c8bd03e7Saymeric cycv_rst_reset_set(dev, r, 0);
149c8bd03e7Saymeric
150c8bd03e7Saymeric return 0;
151c8bd03e7Saymeric }
152