]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/mv/mv_cp110_icu.c
Remove spurious newline
[FreeBSD/FreeBSD.git] / sys / arm / mv / mv_cp110_icu.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Rubicon Communications, LLC (Netgate)
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  * $FreeBSD$
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/rman.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42
43 #include <machine/bus.h>
44 #include <machine/resource.h>
45 #include <machine/intr.h>
46
47 #include <dev/fdt/simplebus.h>
48
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
51
52 #include "pic_if.h"
53
54 #define ICU_GRP_NSR             0x0
55 #define ICU_GRP_SR              0x1
56 #define ICU_GRP_SEI             0x4
57 #define ICU_GRP_REI             0x5
58
59 #define ICU_SETSPI_NSR_AL       0x10
60 #define ICU_SETSPI_NSR_AH       0x14
61 #define ICU_CLRSPI_NSR_AL       0x18
62 #define ICU_CLRSPI_NSR_AH       0x1c
63 #define ICU_INT_CFG(x)  (0x100 + (x) * 4)
64 #define  ICU_INT_ENABLE         (1 << 24)
65 #define  ICU_INT_EDGE           (1 << 28)
66 #define  ICU_INT_GROUP_SHIFT    29
67 #define  ICU_INT_MASK           0x3ff
68
69 #define MV_CP110_ICU_MAX_NIRQS  207
70
71 struct mv_cp110_icu_softc {
72         device_t                dev;
73         device_t                parent;
74         struct resource         *res;
75 };
76
77 static struct resource_spec mv_cp110_icu_res_spec[] = {
78         { SYS_RES_MEMORY,       0,      RF_ACTIVE | RF_SHAREABLE },
79         { -1, 0 }
80 };
81
82 static struct ofw_compat_data compat_data[] = {
83         {"marvell,cp110-icu", 1},
84         {NULL,             0}
85 };
86
87 #define RD4(sc, reg)            bus_read_4((sc)->res, (reg))
88 #define WR4(sc, reg, val)       bus_write_4((sc)->res, (reg), (val))
89
90 static int
91 mv_cp110_icu_probe(device_t dev)
92 {
93
94         if (!ofw_bus_status_okay(dev))
95                 return (ENXIO);
96
97         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
98                 return (ENXIO);
99
100         device_set_desc(dev, "Marvell Interrupt Consolidation Unit");
101         return (BUS_PROBE_DEFAULT);
102 }
103
104 static int
105 mv_cp110_icu_attach(device_t dev)
106 {
107         struct mv_cp110_icu_softc *sc;
108         phandle_t node, msi_parent;
109
110         sc = device_get_softc(dev);
111         sc->dev = dev;
112         node = ofw_bus_get_node(dev);
113
114         if (OF_getencprop(node, "msi-parent", &msi_parent,
115             sizeof(phandle_t)) <= 0) {
116                 device_printf(dev, "cannot find msi-parent property\n");
117                 return (ENXIO);
118         }
119
120         if ((sc->parent = OF_device_from_xref(msi_parent)) == NULL) {
121                 device_printf(dev, "cannot find msi-parent device\n");
122                 return (ENXIO);
123         }
124         if (bus_alloc_resources(dev, mv_cp110_icu_res_spec, &sc->res) != 0) {
125                 device_printf(dev, "cannot allocate resources for device\n");
126                 return (ENXIO);
127         }
128
129         if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
130                 device_printf(dev, "Cannot register ICU\n");
131                 goto fail;
132         }
133         return (0);
134
135 fail:
136         bus_release_resources(dev, mv_cp110_icu_res_spec, &sc->res);
137         return (ENXIO);
138 }
139
140 static int
141 mv_cp110_icu_detach(device_t dev)
142 {
143
144         return (EBUSY);
145 }
146
147 static int
148 mv_cp110_icu_activate_intr(device_t dev, struct intr_irqsrc *isrc,
149     struct resource *res, struct intr_map_data *data)
150 {
151         struct mv_cp110_icu_softc *sc;
152
153         sc = device_get_softc(dev);
154
155         return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
156 }
157
158 static void
159 mv_cp110_icu_enable_intr(device_t dev, struct intr_irqsrc *isrc)
160 {
161         struct mv_cp110_icu_softc *sc;
162
163         sc = device_get_softc(dev);
164
165         PIC_ENABLE_INTR(sc->parent, isrc);
166 }
167
168 static void
169 mv_cp110_icu_disable_intr(device_t dev, struct intr_irqsrc *isrc)
170 {
171         struct mv_cp110_icu_softc *sc;
172
173         sc = device_get_softc(dev);
174
175         PIC_DISABLE_INTR(sc->parent, isrc);
176 }
177
178 static int
179 mv_cp110_icu_map_intr(device_t dev, struct intr_map_data *data,
180     struct intr_irqsrc **isrcp)
181 {
182         struct mv_cp110_icu_softc *sc;
183         struct intr_map_data_fdt *daf;
184         uint32_t reg;
185
186         sc = device_get_softc(dev);
187
188         if (data->type != INTR_MAP_DATA_FDT)
189                 return (ENOTSUP);
190
191         daf = (struct intr_map_data_fdt *)data;
192         if (daf->ncells != 3 || daf->cells[0] >= MV_CP110_ICU_MAX_NIRQS)
193                 return (EINVAL);
194
195         reg = RD4(sc, ICU_INT_CFG(daf->cells[1]));
196
197         if ((reg & ICU_INT_ENABLE) == 0) {
198                 reg |= ICU_INT_ENABLE;
199                 WR4(sc, ICU_INT_CFG(daf->cells[1]), reg);
200         }
201
202         daf->cells[1] = reg & ICU_INT_MASK;
203         return (PIC_MAP_INTR(sc->parent, data, isrcp));
204 }
205
206 static int
207 mv_cp110_icu_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
208     struct resource *res, struct intr_map_data *data)
209 {
210         struct mv_cp110_icu_softc *sc;
211
212         sc = device_get_softc(dev);
213
214         return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
215 }
216
217 static int
218 mv_cp110_icu_setup_intr(device_t dev, struct intr_irqsrc *isrc,
219     struct resource *res, struct intr_map_data *data)
220 {
221         struct mv_cp110_icu_softc *sc;
222
223         sc = device_get_softc(dev);
224
225         return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
226 }
227
228 static int
229 mv_cp110_icu_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
230     struct resource *res, struct intr_map_data *data)
231 {
232         struct mv_cp110_icu_softc *sc;
233
234         sc = device_get_softc(dev);
235
236         return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
237 }
238
239 static void
240 mv_cp110_icu_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
241 {
242         struct mv_cp110_icu_softc *sc;
243
244         sc = device_get_softc(dev);
245
246         PIC_PRE_ITHREAD(sc->parent, isrc);
247 }
248
249 static void
250 mv_cp110_icu_post_ithread(device_t dev, struct intr_irqsrc *isrc)
251 {
252         struct mv_cp110_icu_softc *sc;
253
254         sc = device_get_softc(dev);
255
256         PIC_POST_ITHREAD(sc->parent, isrc);
257 }
258
259 static void
260 mv_cp110_icu_post_filter(device_t dev, struct intr_irqsrc *isrc)
261 {
262         struct mv_cp110_icu_softc *sc;
263
264         sc = device_get_softc(dev);
265
266         PIC_POST_FILTER(sc->parent, isrc);
267 }
268
269 static device_method_t mv_cp110_icu_methods[] = {
270         /* Device interface */
271         DEVMETHOD(device_probe,         mv_cp110_icu_probe),
272         DEVMETHOD(device_attach,        mv_cp110_icu_attach),
273         DEVMETHOD(device_detach,        mv_cp110_icu_detach),
274
275         /* Interrupt controller interface */
276         DEVMETHOD(pic_activate_intr,    mv_cp110_icu_activate_intr),
277         DEVMETHOD(pic_disable_intr,     mv_cp110_icu_disable_intr),
278         DEVMETHOD(pic_enable_intr,      mv_cp110_icu_enable_intr),
279         DEVMETHOD(pic_map_intr,         mv_cp110_icu_map_intr),
280         DEVMETHOD(pic_deactivate_intr,  mv_cp110_icu_deactivate_intr),
281         DEVMETHOD(pic_setup_intr,       mv_cp110_icu_setup_intr),
282         DEVMETHOD(pic_teardown_intr,    mv_cp110_icu_teardown_intr),
283         DEVMETHOD(pic_post_filter,      mv_cp110_icu_post_filter),
284         DEVMETHOD(pic_post_ithread,     mv_cp110_icu_post_ithread),
285         DEVMETHOD(pic_pre_ithread,      mv_cp110_icu_pre_ithread),
286
287         DEVMETHOD_END
288 };
289
290 static devclass_t mv_cp110_icu_devclass;
291
292 static driver_t mv_cp110_icu_driver = {
293         "mv_cp110_icu",
294         mv_cp110_icu_methods,
295         sizeof(struct mv_cp110_icu_softc),
296 };
297
298 EARLY_DRIVER_MODULE(mv_cp110_icu, simplebus, mv_cp110_icu_driver,
299     mv_cp110_icu_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);