1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bus.h>
31
32 #include <sys/bitset.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/rman.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38
39 #include <machine/bus.h>
40 #include <machine/resource.h>
41 #include <machine/intr.h>
42
43 #include <dev/fdt/simplebus.h>
44
45 #include <dev/ofw/ofw_bus.h>
46 #include <dev/ofw/ofw_bus_subr.h>
47
48 #include <arm/arm/gic_common.h>
49
50 #include <dt-bindings/interrupt-controller/irq.h>
51
52 #include "msi_if.h"
53 #include "pic_if.h"
54
55 #define MV_AP806_GICP_MAX_NIRQS 207
56
57 MALLOC_DECLARE(M_GICP);
58 MALLOC_DEFINE(M_GICP, "gicp", "Marvell gicp driver");
59
60 struct mv_ap806_gicp_softc {
61 device_t dev;
62 device_t parent;
63 struct resource *res;
64
65 ssize_t spi_ranges_cnt;
66 uint32_t *spi_ranges;
67 struct intr_map_data_fdt *parent_map_data;
68
69 ssize_t msi_bitmap_size; /* Nr of bits in the bitmap. */
70 BITSET_DEFINE_VAR() *msi_bitmap;
71 };
72
73 static struct ofw_compat_data compat_data[] = {
74 {"marvell,ap806-gicp", 1},
75 {NULL, 0}
76 };
77
78 #define RD4(sc, reg) bus_read_4((sc)->res, (reg))
79 #define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
80
81 static msi_alloc_msi_t mv_ap806_gicp_alloc_msi;
82 static msi_release_msi_t mv_ap806_gicp_release_msi;
83 static msi_map_msi_t mv_ap806_gicp_map_msi;
84
85 static int
mv_ap806_gicp_probe(device_t dev)86 mv_ap806_gicp_probe(device_t dev)
87 {
88
89 if (!ofw_bus_status_okay(dev))
90 return (ENXIO);
91
92 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
93 return (ENXIO);
94
95 device_set_desc(dev, "Marvell GICP");
96 return (BUS_PROBE_DEFAULT);
97 }
98
99 static int
mv_ap806_gicp_attach(device_t dev)100 mv_ap806_gicp_attach(device_t dev)
101 {
102 struct mv_ap806_gicp_softc *sc;
103 phandle_t node, xref, intr_parent;
104 int i, rid;
105
106 sc = device_get_softc(dev);
107 sc->dev = dev;
108 node = ofw_bus_get_node(dev);
109
110 /* Look for our parent */
111 if ((intr_parent = ofw_bus_find_iparent(node)) == 0) {
112 device_printf(dev,
113 "Cannot find our parent interrupt controller\n");
114 return (ENXIO);
115 }
116 if ((sc->parent = OF_device_from_xref(intr_parent)) == NULL) {
117 device_printf(dev,
118 "cannot find parent interrupt controller device\n");
119 return (ENXIO);
120 }
121
122 rid = 0;
123 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
124 if (sc->res == NULL) {
125 device_printf(dev, "cannot allocate resources for device\n");
126 return (ENXIO);
127 }
128
129 sc->spi_ranges_cnt = OF_getencprop_alloc_multi(node, "marvell,spi-ranges",
130 sizeof(*sc->spi_ranges), (void **)&sc->spi_ranges);
131
132 sc->msi_bitmap_size = 0;
133 for (i = 0; i < sc->spi_ranges_cnt; i += 2)
134 sc->msi_bitmap_size += sc->spi_ranges[i + 1];
135
136 /*
137 * Create a bitmap of all MSIs that we have.
138 * Each has a correspoding SPI in the GIC.
139 * It will be used to dynamically allocate IRQs when requested.
140 */
141 sc->msi_bitmap = BITSET_ALLOC(sc->msi_bitmap_size, M_GICP, M_WAITOK);
142 BIT_FILL(sc->msi_bitmap_size, sc->msi_bitmap); /* 1 - available, 0 - used. */
143
144 xref = OF_xref_from_node(node);
145 if (intr_pic_register(dev, xref) == NULL) {
146 device_printf(dev, "Cannot register GICP\n");
147 return (ENXIO);
148 }
149 /* Allocate GIC compatible mapping entry (3 cells) */
150 sc->parent_map_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
151 INTR_MAP_DATA_FDT, sizeof(struct intr_map_data_fdt) +
152 + 3 * sizeof(phandle_t), M_WAITOK | M_ZERO);
153 OF_device_register_xref(xref, dev);
154
155 return (0);
156 }
157
158 static int
mv_ap806_gicp_detach(device_t dev)159 mv_ap806_gicp_detach(device_t dev)
160 {
161
162 return (EBUSY);
163 }
164
165 static uint32_t
mv_ap806_gicp_msi_to_spi(struct mv_ap806_gicp_softc * sc,int irq)166 mv_ap806_gicp_msi_to_spi(struct mv_ap806_gicp_softc *sc, int irq)
167 {
168 int i;
169
170 for (i = 0; i < sc->spi_ranges_cnt; i += 2) {
171 if (irq < sc->spi_ranges[i + 1]) {
172 irq += sc->spi_ranges[i];
173 break;
174 }
175 irq -= sc->spi_ranges[i + 1];
176 }
177
178 return (irq - GIC_FIRST_SPI);
179 }
180
181 static uint32_t
mv_ap806_gicp_irq_to_msi(struct mv_ap806_gicp_softc * sc,int irq)182 mv_ap806_gicp_irq_to_msi(struct mv_ap806_gicp_softc *sc, int irq)
183 {
184 int i;
185
186 for (i = 0; i < sc->spi_ranges_cnt; i += 2) {
187 if (irq >= sc->spi_ranges[i] &&
188 irq - sc->spi_ranges[i] < sc->spi_ranges[i + 1]) {
189 irq -= sc->spi_ranges[i];
190 break;
191 }
192 }
193
194 return (irq);
195 }
196
197 static struct intr_map_data *
mv_ap806_gicp_convert_map_data(struct mv_ap806_gicp_softc * sc,struct intr_map_data * data)198 mv_ap806_gicp_convert_map_data(struct mv_ap806_gicp_softc *sc,
199 struct intr_map_data *data)
200 {
201 struct intr_map_data_fdt *daf;
202 uint32_t irq_num;
203
204 daf = (struct intr_map_data_fdt *)data;
205 if (daf->ncells != 2)
206 return (NULL);
207
208 irq_num = daf->cells[0];
209 if (irq_num >= MV_AP806_GICP_MAX_NIRQS)
210 return (NULL);
211
212 /* Construct GIC compatible mapping. */
213 sc->parent_map_data->ncells = 3;
214 sc->parent_map_data->cells[0] = 0; /* SPI */
215 sc->parent_map_data->cells[1] = mv_ap806_gicp_msi_to_spi(sc, irq_num);
216 sc->parent_map_data->cells[2] = IRQ_TYPE_LEVEL_HIGH;
217
218 return ((struct intr_map_data *)sc->parent_map_data);
219 }
220
221 static int
mv_ap806_gicp_activate_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)222 mv_ap806_gicp_activate_intr(device_t dev, struct intr_irqsrc *isrc,
223 struct resource *res, struct intr_map_data *data)
224 {
225 struct mv_ap806_gicp_softc *sc;
226
227 sc = device_get_softc(dev);
228 data = mv_ap806_gicp_convert_map_data(sc, data);
229 if (data == NULL)
230 return (EINVAL);
231
232 return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
233 }
234
235 static void
mv_ap806_gicp_enable_intr(device_t dev,struct intr_irqsrc * isrc)236 mv_ap806_gicp_enable_intr(device_t dev, struct intr_irqsrc *isrc)
237 {
238 struct mv_ap806_gicp_softc *sc;
239
240 sc = device_get_softc(dev);
241
242 PIC_ENABLE_INTR(sc->parent, isrc);
243 }
244
245 static void
mv_ap806_gicp_disable_intr(device_t dev,struct intr_irqsrc * isrc)246 mv_ap806_gicp_disable_intr(device_t dev, struct intr_irqsrc *isrc)
247 {
248 struct mv_ap806_gicp_softc *sc;
249
250 sc = device_get_softc(dev);
251
252 PIC_DISABLE_INTR(sc->parent, isrc);
253 }
254
255 static int
mv_ap806_gicp_map_intr(device_t dev,struct intr_map_data * data,struct intr_irqsrc ** isrcp)256 mv_ap806_gicp_map_intr(device_t dev, struct intr_map_data *data,
257 struct intr_irqsrc **isrcp)
258 {
259
260 panic("%s: MSI interface has to be used to map an interrupt.\n",
261 __func__);
262 }
263
264 static int
mv_ap806_gicp_deactivate_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)265 mv_ap806_gicp_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
266 struct resource *res, struct intr_map_data *data)
267 {
268 struct mv_ap806_gicp_softc *sc;
269
270 sc = device_get_softc(dev);
271
272 data = mv_ap806_gicp_convert_map_data(sc, data);
273 if (data == NULL)
274 return (EINVAL);
275
276 return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
277 }
278
279 static int
mv_ap806_gicp_setup_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)280 mv_ap806_gicp_setup_intr(device_t dev, struct intr_irqsrc *isrc,
281 struct resource *res, struct intr_map_data *data)
282 {
283 struct mv_ap806_gicp_softc *sc;
284
285 sc = device_get_softc(dev);
286 data = mv_ap806_gicp_convert_map_data(sc, data);
287 if (data == NULL)
288 return (EINVAL);
289
290 return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
291 }
292
293 static int
mv_ap806_gicp_teardown_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)294 mv_ap806_gicp_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
295 struct resource *res, struct intr_map_data *data)
296 {
297 struct mv_ap806_gicp_softc *sc;
298
299 sc = device_get_softc(dev);
300 data = mv_ap806_gicp_convert_map_data(sc, data);
301 if (data == NULL)
302 return (EINVAL);
303
304 return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
305 }
306
307 static void
mv_ap806_gicp_pre_ithread(device_t dev,struct intr_irqsrc * isrc)308 mv_ap806_gicp_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
309 {
310 struct mv_ap806_gicp_softc *sc;
311
312 sc = device_get_softc(dev);
313
314 PIC_PRE_ITHREAD(sc->parent, isrc);
315 }
316
317 static void
mv_ap806_gicp_post_ithread(device_t dev,struct intr_irqsrc * isrc)318 mv_ap806_gicp_post_ithread(device_t dev, struct intr_irqsrc *isrc)
319 {
320 struct mv_ap806_gicp_softc *sc;
321
322 sc = device_get_softc(dev);
323
324 PIC_POST_ITHREAD(sc->parent, isrc);
325 }
326
327 static void
mv_ap806_gicp_post_filter(device_t dev,struct intr_irqsrc * isrc)328 mv_ap806_gicp_post_filter(device_t dev, struct intr_irqsrc *isrc)
329 {
330 struct mv_ap806_gicp_softc *sc;
331
332 sc = device_get_softc(dev);
333
334 PIC_POST_FILTER(sc->parent, isrc);
335 }
336
337 static int
mv_ap806_gicp_alloc_msi(device_t dev,device_t child,int count,int maxcount,device_t * pic,struct intr_irqsrc ** srcs)338 mv_ap806_gicp_alloc_msi(device_t dev, device_t child, int count, int maxcount,
339 device_t *pic, struct intr_irqsrc **srcs)
340 {
341 struct mv_ap806_gicp_softc *sc;
342 int i, ret, vector;
343
344 sc = device_get_softc(dev);
345
346 for (i = 0; i < count; i++) {
347 /*
348 * Find first available vector represented by first set bit
349 * in the bitmap. BIT_FFS starts the count from 1, 0 means
350 * that nothing was found.
351 */
352 vector = BIT_FFS(sc->msi_bitmap_size, sc->msi_bitmap);
353 if (vector == 0) {
354 ret = ENOMEM;
355 i--;
356 goto fail;
357 }
358 vector--;
359 BIT_CLR(sc->msi_bitmap_size, vector, sc->msi_bitmap);
360
361 /* Create GIC compatible SPI interrupt description. */
362 sc->parent_map_data->ncells = 3;
363 sc->parent_map_data->cells[0] = 0; /* SPI */
364 sc->parent_map_data->cells[1] = mv_ap806_gicp_msi_to_spi(sc, vector);
365 sc->parent_map_data->cells[2] = IRQ_TYPE_LEVEL_HIGH;
366
367 ret = PIC_MAP_INTR(sc->parent,
368 (struct intr_map_data *)sc->parent_map_data,
369 &srcs[i]);
370 if (ret != 0)
371 goto fail;
372
373 srcs[i]->isrc_dev = dev;
374 }
375
376 return (0);
377 fail:
378 mv_ap806_gicp_release_msi(dev, child, i + 1, srcs);
379 return (ret);
380 }
381
382 static int
mv_ap806_gicp_release_msi(device_t dev,device_t child,int count,struct intr_irqsrc ** srcs)383 mv_ap806_gicp_release_msi(device_t dev, device_t child, int count,
384 struct intr_irqsrc **srcs)
385 {
386 struct mv_ap806_gicp_softc *sc;
387 int i;
388
389 sc = device_get_softc(dev);
390
391 for (i = 0; i < count; i++) {
392 BIT_SET(sc->msi_bitmap_size,
393 mv_ap806_gicp_irq_to_msi(sc, srcs[i]->isrc_irq),
394 sc->msi_bitmap);
395 }
396
397 return (0);
398 }
399
400 static int
mv_ap806_gicp_map_msi(device_t dev,device_t child,struct intr_irqsrc * isrc,uint64_t * addr,uint32_t * data)401 mv_ap806_gicp_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
402 uint64_t *addr, uint32_t *data)
403 {
404 struct mv_ap806_gicp_softc *sc;
405
406 sc = device_get_softc(dev);
407
408 *addr = rman_get_start(sc->res);
409 *data = mv_ap806_gicp_irq_to_msi(sc, isrc->isrc_irq);
410
411 return (0);
412 }
413
414 static device_method_t mv_ap806_gicp_methods[] = {
415 /* Device interface */
416 DEVMETHOD(device_probe, mv_ap806_gicp_probe),
417 DEVMETHOD(device_attach, mv_ap806_gicp_attach),
418 DEVMETHOD(device_detach, mv_ap806_gicp_detach),
419
420 /* Interrupt controller interface */
421 DEVMETHOD(pic_activate_intr, mv_ap806_gicp_activate_intr),
422 DEVMETHOD(pic_disable_intr, mv_ap806_gicp_disable_intr),
423 DEVMETHOD(pic_enable_intr, mv_ap806_gicp_enable_intr),
424 DEVMETHOD(pic_map_intr, mv_ap806_gicp_map_intr),
425 DEVMETHOD(pic_deactivate_intr, mv_ap806_gicp_deactivate_intr),
426 DEVMETHOD(pic_setup_intr, mv_ap806_gicp_setup_intr),
427 DEVMETHOD(pic_teardown_intr, mv_ap806_gicp_teardown_intr),
428 DEVMETHOD(pic_post_filter, mv_ap806_gicp_post_filter),
429 DEVMETHOD(pic_post_ithread, mv_ap806_gicp_post_ithread),
430 DEVMETHOD(pic_pre_ithread, mv_ap806_gicp_pre_ithread),
431
432 /* MSI interface */
433 DEVMETHOD(msi_alloc_msi, mv_ap806_gicp_alloc_msi),
434 DEVMETHOD(msi_release_msi, mv_ap806_gicp_release_msi),
435 DEVMETHOD(msi_map_msi, mv_ap806_gicp_map_msi),
436
437 DEVMETHOD_END
438 };
439
440 static driver_t mv_ap806_gicp_driver = {
441 "mv_ap806_gicp",
442 mv_ap806_gicp_methods,
443 sizeof(struct mv_ap806_gicp_softc),
444 };
445
446 EARLY_DRIVER_MODULE(mv_ap806_gicp, simplebus, mv_ap806_gicp_driver, 0, 0,
447 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
448