xref: /freebsd/sys/arm/ti/omap4/omap4_wugen.c (revision edca4938f74db18d091868237592abbf7e718669)
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 
129 static void
130 omap4_wugen_post_ithread(device_t dev, struct intr_irqsrc *isrc)
131 {
132 	struct omap4_wugen_sc *sc = device_get_softc(dev);
133 
134 	PIC_POST_ITHREAD(sc->sc_parent, isrc);
135 }
136 
137 static void
138 omap4_wugen_post_filter(device_t dev, struct intr_irqsrc *isrc)
139 {
140 	struct omap4_wugen_sc *sc = device_get_softc(dev);
141 
142 	PIC_POST_FILTER(sc->sc_parent, isrc);
143 }
144 
145 #ifdef SMP
146 static int
147 omap4_wugen_bind_intr(device_t dev, struct intr_irqsrc *isrc)
148 {
149 	struct omap4_wugen_sc *sc = device_get_softc(dev);
150 
151 	return (PIC_BIND_INTR(sc->sc_parent, isrc));
152 }
153 #endif
154 
155 static int
156 omap4_wugen_probe(device_t dev)
157 {
158 
159 	if (!ofw_bus_status_okay(dev))
160 		return (ENXIO);
161 
162 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
163 		return (ENXIO);
164 
165 	return (BUS_PROBE_DEFAULT);
166 }
167 
168 static int
169 omap4_wugen_detach(device_t dev)
170 {
171 	struct omap4_wugen_sc *sc;
172 
173 	sc = device_get_softc(dev);
174 	if (sc->sc_mem_res != NULL) {
175 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
176 		sc->sc_mem_res = NULL;
177 	}
178 	return (0);
179 }
180 
181 static int
182 omap4_wugen_attach(device_t dev)
183 {
184 	struct omap4_wugen_sc *sc;
185 	phandle_t node;
186 	phandle_t parent_xref;
187 	int rid, rv;
188 
189 	sc = device_get_softc(dev);
190 	sc->sc_dev = dev;
191 	node = ofw_bus_get_node(dev);
192 
193 	rv = OF_getencprop(node, "interrupt-parent", &parent_xref,
194 	    sizeof(parent_xref));
195 	if (rv <= 0) {
196 		device_printf(dev, "can't read parent node property\n");
197 		goto fail;
198 	}
199 	sc->sc_parent = OF_device_from_xref(parent_xref);
200 	if (sc->sc_parent == NULL) {
201 		device_printf(dev, "can't find parent controller\n");
202 		goto fail;
203 	}
204 
205 	rid = 0;
206 	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
207 	    RF_ACTIVE);
208 	if (sc->sc_mem_res == NULL) {
209 		device_printf(dev, "can't allocate resources\n");
210 		return (ENXIO);
211 	}
212 
213 	if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
214 		device_printf(dev, "can't register PIC\n");
215 		goto fail;
216 	}
217 	return (0);
218 
219 fail:
220 	omap4_wugen_detach(dev);
221 	return (ENXIO);
222 }
223 
224 static device_method_t omap4_wugen_methods[] = {
225 	DEVMETHOD(device_probe,		omap4_wugen_probe),
226 	DEVMETHOD(device_attach,	omap4_wugen_attach),
227 	DEVMETHOD(device_detach,	omap4_wugen_detach),
228 
229 	/* Interrupt controller interface */
230 	DEVMETHOD(pic_activate_intr,	omap4_wugen_activate_intr),
231 	DEVMETHOD(pic_disable_intr,	omap4_wugen_disable_intr),
232 	DEVMETHOD(pic_enable_intr,	omap4_wugen_enable_intr),
233 	DEVMETHOD(pic_map_intr,		omap4_wugen_map_intr),
234 	DEVMETHOD(pic_deactivate_intr,	omap4_wugen_deactivate_intr),
235 	DEVMETHOD(pic_setup_intr,	omap4_wugen_setup_intr),
236 	DEVMETHOD(pic_teardown_intr,	omap4_wugen_teardown_intr),
237 	DEVMETHOD(pic_pre_ithread,	omap4_wugen_pre_ithread),
238 	DEVMETHOD(pic_post_ithread,	omap4_wugen_post_ithread),
239 	DEVMETHOD(pic_post_filter,	omap4_wugen_post_filter),
240 #ifdef SMP
241 	DEVMETHOD(pic_bind_intr,	omap4_wugen_bind_intr),
242 #endif
243 	DEVMETHOD_END
244 };
245 devclass_t omap4_wugen_devclass;
246 DEFINE_CLASS_0(omap4_wugen, omap4_wugen_driver, omap4_wugen_methods,
247     sizeof(struct omap4_wugen_sc));
248 EARLY_DRIVER_MODULE(omap4_wugen, simplebus, omap4_wugen_driver,
249     omap4_wugen_devclass, NULL, NULL,
250     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE + 1);
251