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