1c2849e3cSSvatopluk Kraus /*-
2c2849e3cSSvatopluk Kraus * Copyright (c) 2016 Svatopluk Kraus
3c2849e3cSSvatopluk Kraus * Copyright (c) 2016 Michal Meloun
4c2849e3cSSvatopluk Kraus * All rights reserved.
5c2849e3cSSvatopluk Kraus *
6c2849e3cSSvatopluk Kraus * Redistribution and use in source and binary forms, with or without
7c2849e3cSSvatopluk Kraus * modification, are permitted provided that the following conditions
8c2849e3cSSvatopluk Kraus * are met:
9c2849e3cSSvatopluk Kraus * 1. Redistributions of source code must retain the above copyright
10c2849e3cSSvatopluk Kraus * notice, this list of conditions and the following disclaimer.
11c2849e3cSSvatopluk Kraus * 2. Redistributions in binary form must reproduce the above copyright
12c2849e3cSSvatopluk Kraus * notice, this list of conditions and the following disclaimer in the
13c2849e3cSSvatopluk Kraus * documentation and/or other materials provided with the distribution.
14c2849e3cSSvatopluk Kraus *
15c2849e3cSSvatopluk Kraus * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c2849e3cSSvatopluk Kraus * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c2849e3cSSvatopluk Kraus * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c2849e3cSSvatopluk Kraus * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c2849e3cSSvatopluk Kraus * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c2849e3cSSvatopluk Kraus * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c2849e3cSSvatopluk Kraus * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c2849e3cSSvatopluk Kraus * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c2849e3cSSvatopluk Kraus * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c2849e3cSSvatopluk Kraus * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c2849e3cSSvatopluk Kraus * SUCH DAMAGE.
26c2849e3cSSvatopluk Kraus */
27c2849e3cSSvatopluk Kraus
28c2849e3cSSvatopluk Kraus #include <sys/param.h>
29c2849e3cSSvatopluk Kraus #include <sys/bus.h>
30c2849e3cSSvatopluk Kraus #include <sys/conf.h>
31c2849e3cSSvatopluk Kraus #include <sys/kernel.h>
32c2849e3cSSvatopluk Kraus #include <sys/module.h>
33c2849e3cSSvatopluk Kraus #include <sys/rman.h>
34c2849e3cSSvatopluk Kraus #include <sys/systm.h>
35c2849e3cSSvatopluk Kraus
36c2849e3cSSvatopluk Kraus #include <machine/fdt.h>
37c2849e3cSSvatopluk Kraus #include <machine/intr.h>
38c2849e3cSSvatopluk Kraus #include <machine/resource.h>
39c2849e3cSSvatopluk Kraus
40c2849e3cSSvatopluk Kraus #include <dev/ofw/ofw_bus.h>
41c2849e3cSSvatopluk Kraus #include <dev/ofw/ofw_bus_subr.h>
42c2849e3cSSvatopluk Kraus
43c2849e3cSSvatopluk Kraus #include "pic_if.h"
44c2849e3cSSvatopluk Kraus
45c2849e3cSSvatopluk Kraus static struct ofw_compat_data compat_data[] = {
46c2849e3cSSvatopluk Kraus {"ti,omap4-wugen-mpu", 1},
47c2849e3cSSvatopluk Kraus {NULL, 0}
48c2849e3cSSvatopluk Kraus };
49c2849e3cSSvatopluk Kraus
50c2849e3cSSvatopluk Kraus struct omap4_wugen_sc {
51c2849e3cSSvatopluk Kraus device_t sc_dev;
52c2849e3cSSvatopluk Kraus struct resource *sc_mem_res;
53c2849e3cSSvatopluk Kraus device_t sc_parent;
54c2849e3cSSvatopluk Kraus };
55c2849e3cSSvatopluk Kraus
56c2849e3cSSvatopluk Kraus static int
omap4_wugen_activate_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)57895c8b1cSMichal Meloun omap4_wugen_activate_intr(device_t dev, struct intr_irqsrc *isrc,
58bff6be3eSSvatopluk Kraus struct resource *res, struct intr_map_data *data)
59c2849e3cSSvatopluk Kraus {
60c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
61c2849e3cSSvatopluk Kraus
62895c8b1cSMichal Meloun return (PIC_ACTIVATE_INTR(sc->sc_parent, isrc, res, data));
63c2849e3cSSvatopluk Kraus }
64c2849e3cSSvatopluk Kraus
65c2849e3cSSvatopluk Kraus static void
omap4_wugen_disable_intr(device_t dev,struct intr_irqsrc * isrc)66bff6be3eSSvatopluk Kraus omap4_wugen_disable_intr(device_t dev, struct intr_irqsrc *isrc)
67c2849e3cSSvatopluk Kraus {
68c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
69c2849e3cSSvatopluk Kraus
70bff6be3eSSvatopluk Kraus PIC_DISABLE_INTR(sc->sc_parent, isrc);
71c2849e3cSSvatopluk Kraus }
72c2849e3cSSvatopluk Kraus
73c2849e3cSSvatopluk Kraus static void
omap4_wugen_enable_intr(device_t dev,struct intr_irqsrc * isrc)74c2849e3cSSvatopluk Kraus omap4_wugen_enable_intr(device_t dev, struct intr_irqsrc *isrc)
75c2849e3cSSvatopluk Kraus {
76c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
77c2849e3cSSvatopluk Kraus
78c2849e3cSSvatopluk Kraus PIC_ENABLE_INTR(sc->sc_parent, isrc);
79c2849e3cSSvatopluk Kraus }
80c2849e3cSSvatopluk Kraus
81bff6be3eSSvatopluk Kraus static int
omap4_wugen_map_intr(device_t dev,struct intr_map_data * data,struct intr_irqsrc ** isrcp)82bff6be3eSSvatopluk Kraus omap4_wugen_map_intr(device_t dev, struct intr_map_data *data,
83bff6be3eSSvatopluk Kraus struct intr_irqsrc **isrcp)
84bff6be3eSSvatopluk Kraus {
85bff6be3eSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
86bff6be3eSSvatopluk Kraus
87bff6be3eSSvatopluk Kraus return (PIC_MAP_INTR(sc->sc_parent, data, isrcp));
88bff6be3eSSvatopluk Kraus }
89bff6be3eSSvatopluk Kraus
90bff6be3eSSvatopluk Kraus static int
omap4_wugen_deactivate_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)91895c8b1cSMichal Meloun omap4_wugen_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
92bff6be3eSSvatopluk Kraus struct resource *res, struct intr_map_data *data)
93bff6be3eSSvatopluk Kraus {
94bff6be3eSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
95bff6be3eSSvatopluk Kraus
96895c8b1cSMichal Meloun return (PIC_DEACTIVATE_INTR(sc->sc_parent, isrc, res, data));
97bff6be3eSSvatopluk Kraus }
98bff6be3eSSvatopluk Kraus
99bff6be3eSSvatopluk Kraus static int
omap4_wugen_setup_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)100bff6be3eSSvatopluk Kraus omap4_wugen_setup_intr(device_t dev, struct intr_irqsrc *isrc,
101bff6be3eSSvatopluk Kraus struct resource *res, struct intr_map_data *data)
102bff6be3eSSvatopluk Kraus {
103bff6be3eSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
104bff6be3eSSvatopluk Kraus
105bff6be3eSSvatopluk Kraus return (PIC_SETUP_INTR(sc->sc_parent, isrc, res, data));
106bff6be3eSSvatopluk Kraus }
107bff6be3eSSvatopluk Kraus
108bff6be3eSSvatopluk Kraus static int
omap4_wugen_teardown_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)109bff6be3eSSvatopluk Kraus omap4_wugen_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
110bff6be3eSSvatopluk Kraus struct resource *res, struct intr_map_data *data)
111bff6be3eSSvatopluk Kraus {
112bff6be3eSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
113bff6be3eSSvatopluk Kraus
114bff6be3eSSvatopluk Kraus return (PIC_TEARDOWN_INTR(sc->sc_parent, isrc, res, data));
115bff6be3eSSvatopluk Kraus }
116bff6be3eSSvatopluk Kraus
117c2849e3cSSvatopluk Kraus static void
omap4_wugen_pre_ithread(device_t dev,struct intr_irqsrc * isrc)118c2849e3cSSvatopluk Kraus omap4_wugen_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
119c2849e3cSSvatopluk Kraus {
120c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
121c2849e3cSSvatopluk Kraus
122c2849e3cSSvatopluk Kraus PIC_PRE_ITHREAD(sc->sc_parent, isrc);
123c2849e3cSSvatopluk Kraus }
124c2849e3cSSvatopluk Kraus
125c2849e3cSSvatopluk Kraus static void
omap4_wugen_post_ithread(device_t dev,struct intr_irqsrc * isrc)126c2849e3cSSvatopluk Kraus omap4_wugen_post_ithread(device_t dev, struct intr_irqsrc *isrc)
127c2849e3cSSvatopluk Kraus {
128c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
129c2849e3cSSvatopluk Kraus
130c2849e3cSSvatopluk Kraus PIC_POST_ITHREAD(sc->sc_parent, isrc);
131c2849e3cSSvatopluk Kraus }
132c2849e3cSSvatopluk Kraus
133c2849e3cSSvatopluk Kraus static void
omap4_wugen_post_filter(device_t dev,struct intr_irqsrc * isrc)134c2849e3cSSvatopluk Kraus omap4_wugen_post_filter(device_t dev, struct intr_irqsrc *isrc)
135c2849e3cSSvatopluk Kraus {
136c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
137c2849e3cSSvatopluk Kraus
138c2849e3cSSvatopluk Kraus PIC_POST_FILTER(sc->sc_parent, isrc);
139c2849e3cSSvatopluk Kraus }
140c2849e3cSSvatopluk Kraus
141c2849e3cSSvatopluk Kraus #ifdef SMP
142c2849e3cSSvatopluk Kraus static int
omap4_wugen_bind_intr(device_t dev,struct intr_irqsrc * isrc)143bff6be3eSSvatopluk Kraus omap4_wugen_bind_intr(device_t dev, struct intr_irqsrc *isrc)
144c2849e3cSSvatopluk Kraus {
145c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc = device_get_softc(dev);
146c2849e3cSSvatopluk Kraus
147bff6be3eSSvatopluk Kraus return (PIC_BIND_INTR(sc->sc_parent, isrc));
148c2849e3cSSvatopluk Kraus }
149c2849e3cSSvatopluk Kraus #endif
150c2849e3cSSvatopluk Kraus
151c2849e3cSSvatopluk Kraus static int
omap4_wugen_probe(device_t dev)152c2849e3cSSvatopluk Kraus omap4_wugen_probe(device_t dev)
153c2849e3cSSvatopluk Kraus {
154c2849e3cSSvatopluk Kraus
155c2849e3cSSvatopluk Kraus if (!ofw_bus_status_okay(dev))
156c2849e3cSSvatopluk Kraus return (ENXIO);
157c2849e3cSSvatopluk Kraus
158c2849e3cSSvatopluk Kraus if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
159c2849e3cSSvatopluk Kraus return (ENXIO);
160c2849e3cSSvatopluk Kraus
161c2849e3cSSvatopluk Kraus return (BUS_PROBE_DEFAULT);
162c2849e3cSSvatopluk Kraus }
163c2849e3cSSvatopluk Kraus
164c2849e3cSSvatopluk Kraus static int
omap4_wugen_detach(device_t dev)165c2849e3cSSvatopluk Kraus omap4_wugen_detach(device_t dev)
166c2849e3cSSvatopluk Kraus {
167c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc;
168c2849e3cSSvatopluk Kraus
169c2849e3cSSvatopluk Kraus sc = device_get_softc(dev);
170c2849e3cSSvatopluk Kraus if (sc->sc_mem_res != NULL) {
171c2849e3cSSvatopluk Kraus bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
172c2849e3cSSvatopluk Kraus sc->sc_mem_res = NULL;
173c2849e3cSSvatopluk Kraus }
174c2849e3cSSvatopluk Kraus return (0);
175c2849e3cSSvatopluk Kraus }
176c2849e3cSSvatopluk Kraus
177c2849e3cSSvatopluk Kraus static int
omap4_wugen_attach(device_t dev)178c2849e3cSSvatopluk Kraus omap4_wugen_attach(device_t dev)
179c2849e3cSSvatopluk Kraus {
180c2849e3cSSvatopluk Kraus struct omap4_wugen_sc *sc;
181c2849e3cSSvatopluk Kraus phandle_t node;
182c2849e3cSSvatopluk Kraus phandle_t parent_xref;
183c2849e3cSSvatopluk Kraus int rid, rv;
184c2849e3cSSvatopluk Kraus
185c2849e3cSSvatopluk Kraus sc = device_get_softc(dev);
186c2849e3cSSvatopluk Kraus sc->sc_dev = dev;
187c2849e3cSSvatopluk Kraus node = ofw_bus_get_node(dev);
188c2849e3cSSvatopluk Kraus
189c2849e3cSSvatopluk Kraus rv = OF_getencprop(node, "interrupt-parent", &parent_xref,
190c2849e3cSSvatopluk Kraus sizeof(parent_xref));
191c2849e3cSSvatopluk Kraus if (rv <= 0) {
192c2849e3cSSvatopluk Kraus device_printf(dev, "can't read parent node property\n");
193c2849e3cSSvatopluk Kraus goto fail;
194c2849e3cSSvatopluk Kraus }
195c2849e3cSSvatopluk Kraus sc->sc_parent = OF_device_from_xref(parent_xref);
196c2849e3cSSvatopluk Kraus if (sc->sc_parent == NULL) {
197c2849e3cSSvatopluk Kraus device_printf(dev, "can't find parent controller\n");
198c2849e3cSSvatopluk Kraus goto fail;
199c2849e3cSSvatopluk Kraus }
200c2849e3cSSvatopluk Kraus
201c2849e3cSSvatopluk Kraus rid = 0;
202c2849e3cSSvatopluk Kraus sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
203c2849e3cSSvatopluk Kraus RF_ACTIVE);
204c2849e3cSSvatopluk Kraus if (sc->sc_mem_res == NULL) {
205c2849e3cSSvatopluk Kraus device_printf(dev, "can't allocate resources\n");
206c2849e3cSSvatopluk Kraus return (ENXIO);
207c2849e3cSSvatopluk Kraus }
208c2849e3cSSvatopluk Kraus
2099346e913SAndrew Turner if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
210c2849e3cSSvatopluk Kraus device_printf(dev, "can't register PIC\n");
211c2849e3cSSvatopluk Kraus goto fail;
212c2849e3cSSvatopluk Kraus }
213c2849e3cSSvatopluk Kraus return (0);
214c2849e3cSSvatopluk Kraus
215c2849e3cSSvatopluk Kraus fail:
216c2849e3cSSvatopluk Kraus omap4_wugen_detach(dev);
217c2849e3cSSvatopluk Kraus return (ENXIO);
218c2849e3cSSvatopluk Kraus }
219c2849e3cSSvatopluk Kraus
220c2849e3cSSvatopluk Kraus static device_method_t omap4_wugen_methods[] = {
221c2849e3cSSvatopluk Kraus DEVMETHOD(device_probe, omap4_wugen_probe),
222c2849e3cSSvatopluk Kraus DEVMETHOD(device_attach, omap4_wugen_attach),
223c2849e3cSSvatopluk Kraus DEVMETHOD(device_detach, omap4_wugen_detach),
224c2849e3cSSvatopluk Kraus
225c2849e3cSSvatopluk Kraus /* Interrupt controller interface */
226895c8b1cSMichal Meloun DEVMETHOD(pic_activate_intr, omap4_wugen_activate_intr),
227bff6be3eSSvatopluk Kraus DEVMETHOD(pic_disable_intr, omap4_wugen_disable_intr),
228c2849e3cSSvatopluk Kraus DEVMETHOD(pic_enable_intr, omap4_wugen_enable_intr),
229bff6be3eSSvatopluk Kraus DEVMETHOD(pic_map_intr, omap4_wugen_map_intr),
230895c8b1cSMichal Meloun DEVMETHOD(pic_deactivate_intr, omap4_wugen_deactivate_intr),
231bff6be3eSSvatopluk Kraus DEVMETHOD(pic_setup_intr, omap4_wugen_setup_intr),
232bff6be3eSSvatopluk Kraus DEVMETHOD(pic_teardown_intr, omap4_wugen_teardown_intr),
233c2849e3cSSvatopluk Kraus DEVMETHOD(pic_pre_ithread, omap4_wugen_pre_ithread),
234c2849e3cSSvatopluk Kraus DEVMETHOD(pic_post_ithread, omap4_wugen_post_ithread),
235c2849e3cSSvatopluk Kraus DEVMETHOD(pic_post_filter, omap4_wugen_post_filter),
236c2849e3cSSvatopluk Kraus #ifdef SMP
237bff6be3eSSvatopluk Kraus DEVMETHOD(pic_bind_intr, omap4_wugen_bind_intr),
238c2849e3cSSvatopluk Kraus #endif
239c2849e3cSSvatopluk Kraus DEVMETHOD_END
240c2849e3cSSvatopluk Kraus };
241*8537e671SJohn Baldwin
242c2849e3cSSvatopluk Kraus DEFINE_CLASS_0(omap4_wugen, omap4_wugen_driver, omap4_wugen_methods,
243c2849e3cSSvatopluk Kraus sizeof(struct omap4_wugen_sc));
244*8537e671SJohn Baldwin EARLY_DRIVER_MODULE(omap4_wugen, simplebus, omap4_wugen_driver, NULL, NULL,
245c2849e3cSSvatopluk Kraus BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE + 1);
246