bcm2835_intr.c revision 1.17 1 /* $NetBSD: bcm2835_intr.c,v 1.17 2019/02/10 08:39:48 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nick Hudson
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.17 2019/02/10 08:39:48 skrll Exp $");
34
35 #define _INTR_PRIVATE
36
37 #include "opt_bcm283x.h"
38
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/cpu.h>
42 #include <sys/device.h>
43 #include <sys/proc.h>
44
45 #include <dev/fdt/fdtvar.h>
46
47 #include <machine/intr.h>
48
49 #include <arm/locore.h>
50
51 #include <arm/pic/picvar.h>
52 #include <arm/cortex/gtmr_var.h>
53
54 #include <arm/broadcom/bcm2835_intr.h>
55 #include <arm/broadcom/bcm2835reg.h>
56 #include <arm/broadcom/bcm2835var.h>
57
58 #include <arm/fdt/arm_fdtvar.h>
59
60 static void bcm2835_irq_handler(void *);
61 static void bcm2836mp_intr_init(void *, struct cpu_info *);
62
63 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
64 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
65 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
66 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
67 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
68 size_t);
69
70 static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
71 static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
72 static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
73 static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
74 static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
75 size_t);
76 #ifdef MULTIPROCESSOR
77 int bcm2836mp_ipi_handler(void *);
78 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
79 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
80 #endif
81
82 static int bcm2835_icu_fdt_decode_irq(u_int *);
83 static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
84 int (*)(void *), void *);
85 static void bcm2835_icu_fdt_disestablish(device_t, void *);
86 static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
87
88 static int bcm2836mp_icu_fdt_decode_irq(u_int *);
89 static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
90 int (*)(void *), void *);
91 static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
92 static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
93
94 static int bcm2835_icu_match(device_t, cfdata_t, void *);
95 static void bcm2835_icu_attach(device_t, device_t, void *);
96
97 static void
98 bcm2835_set_priority(struct pic_softc *pic, int ipl)
99 {
100 }
101
102 static struct pic_ops bcm2835_picops = {
103 .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
104 .pic_block_irqs = bcm2835_pic_block_irqs,
105 .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
106 .pic_establish_irq = bcm2835_pic_establish_irq,
107 .pic_source_name = bcm2835_pic_source_name,
108 .pic_set_priority = bcm2835_set_priority,
109 };
110
111 struct pic_softc bcm2835_pic = {
112 .pic_ops = &bcm2835_picops,
113 .pic_maxsources = BCM2835_NIRQ,
114 .pic_name = "bcm2835 pic",
115 };
116
117 static struct pic_ops bcm2836mp_picops = {
118 .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
119 .pic_block_irqs = bcm2836mp_pic_block_irqs,
120 .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
121 .pic_establish_irq = bcm2836mp_pic_establish_irq,
122 .pic_source_name = bcm2836mp_pic_source_name,
123 #if defined(MULTIPROCESSOR)
124 .pic_cpu_init = bcm2836mp_cpu_init,
125 .pic_ipi_send = bcm2836mp_send_ipi,
126 #endif
127 };
128
129 struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
130 [0 ... BCM2836_NCPUS - 1] = {
131 .pic_ops = &bcm2836mp_picops,
132 .pic_maxsources = BCM2836_NIRQPERCPU,
133 .pic_name = "bcm2836 pic",
134 }
135 };
136
137 static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
138 .establish = bcm2835_icu_fdt_establish,
139 .disestablish = bcm2835_icu_fdt_disestablish,
140 .intrstr = bcm2835_icu_fdt_intrstr
141 };
142
143 static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
144 .establish = bcm2836mp_icu_fdt_establish,
145 .disestablish = bcm2836mp_icu_fdt_disestablish,
146 .intrstr = bcm2836mp_icu_fdt_intrstr
147 };
148
149 struct bcm2835icu_softc {
150 device_t sc_dev;
151 bus_space_tag_t sc_iot;
152 bus_space_handle_t sc_ioh;
153
154 int sc_phandle;
155 };
156
157 struct bcm2835icu_softc *bcml1icu_sc;
158 struct bcm2835icu_softc *bcmicu_sc;
159
160 #define read_bcm2835reg(o) \
161 bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
162
163 #define write_bcm2835reg(o, v) \
164 bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
165
166
167 #define bcm2835_barrier() \
168 bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
169 BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
170
171 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
172 "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
173 "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
174 "(unused 8)", "usb", "(unused 10)", "(unused 11)",
175 "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
176 "dma0", "dma1", "dma2", "dma3",
177 "dma4", "dma5", "dma6", "dma7",
178 "dma8", "dma9", "dma10", "dma11",
179 "dma12", "aux", "(unused 30)", "(unused 31)",
180 "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
181 "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
182 "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
183 "(unused 44)", "pwa0", "pwa1", "(unused 47)",
184 "smi", "gpio[0]", "gpio[1]", "gpio[2]",
185 "gpio[3]", "i2c", "spi", "pcm",
186 "sdhost", "uart", "(unused 58)", "(unused 59)",
187 "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
188 "Timer", "Mailbox", "Doorbell0", "Doorbell1",
189 "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
190 };
191
192 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
193 "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
194 "mailbox0", "mailbox1", "mailbox2", "mailbox3",
195 "gpu", "pmu"
196 };
197
198 #define BCM2836_INTBIT_GPUPENDING __BIT(8)
199
200 #define BCM2835_INTBIT_PENDING1 __BIT(8)
201 #define BCM2835_INTBIT_PENDING2 __BIT(9)
202 #define BCM2835_INTBIT_ARM __BITS(0,7)
203 #define BCM2835_INTBIT_GPU0 __BITS(10,14)
204 #define BCM2835_INTBIT_GPU1 __BITS(15,20)
205
206 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
207 bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
208
209 static int
210 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
211 {
212 const char * const compatible[] = {
213 "brcm,bcm2708-armctrl-ic",
214 "brcm,bcm2709-armctrl-ic",
215 "brcm,bcm2835-armctrl-ic",
216 "brcm,bcm2836-armctrl-ic",
217 "brcm,bcm2836-l1-intc",
218 NULL
219 };
220 struct fdt_attach_args * const faa = aux;
221
222 return of_match_compatible(faa->faa_phandle, compatible);
223 }
224
225 static void
226 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
227 {
228 struct bcm2835icu_softc * const sc = device_private(self);
229 struct fdt_attach_args * const faa = aux;
230 struct fdtbus_interrupt_controller_func *ifuncs;
231 const int phandle = faa->faa_phandle;
232 bus_addr_t addr;
233 bus_size_t size;
234 bus_space_handle_t ioh;
235 int error;
236
237 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
238 aprint_error(": couldn't get registers\n");
239 return;
240 }
241
242 sc->sc_dev = self;
243 sc->sc_iot = faa->faa_bst;
244
245 if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
246 aprint_error(": couldn't map device\n");
247 return;
248 }
249
250 sc->sc_ioh = ioh;
251 sc->sc_phandle = phandle;
252
253 const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
254 if (of_match_compatible(faa->faa_phandle, local_intc)) {
255 #if defined(MULTIPROCESSOR)
256 aprint_normal(": Multiprocessor");
257 #endif
258 bcml1icu_sc = sc;
259
260 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
261 BCM2836_LOCAL_CONTROL, 0);
262 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
263 BCM2836_LOCAL_PRESCALER, 0x80000000);
264
265 ifuncs = &bcm2836mpicu_fdt_funcs;
266
267 bcm2836mp_intr_init(self, curcpu());
268 arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
269 } else {
270 if (bcml1icu_sc == NULL)
271 arm_fdt_irq_set_handler(bcm2835_irq_handler);
272 bcmicu_sc = sc;
273 sc->sc_ioh = ioh;
274 sc->sc_phandle = phandle;
275 pic_add(&bcm2835_pic, BCM2835_INT_BASE);
276 ifuncs = &bcm2835icu_fdt_funcs;
277 }
278
279 error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
280 if (error != 0) {
281 aprint_error(": couldn't register with fdtbus: %d\n", error);
282 return;
283 }
284 aprint_normal("\n");
285 }
286
287 static void
288 bcm2835_irq_handler(void *frame)
289 {
290 struct cpu_info * const ci = curcpu();
291 const int oldipl = ci->ci_cpl;
292 const cpuid_t cpuid = ci->ci_core_id;
293 const uint32_t oldipl_mask = __BIT(oldipl);
294 int ipl_mask = 0;
295
296 ci->ci_data.cpu_nintr++;
297
298 bcm2835_barrier();
299 if (cpuid == 0) {
300 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
301 }
302 #if defined(SOC_BCM2836)
303 ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
304 #endif
305
306 /*
307 * Record the pending_ipls and deliver them if we can.
308 */
309 if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
310 pic_do_pending_ints(I32_bit, oldipl, frame);
311 }
312
313 static void
314 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
315 uint32_t irq_mask)
316 {
317
318 write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
319 bcm2835_barrier();
320 }
321
322 static void
323 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
324 uint32_t irq_mask)
325 {
326
327 write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
328 bcm2835_barrier();
329 }
330
331 /*
332 * Called with interrupts disabled
333 */
334 static int
335 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
336 {
337 int ipl = 0;
338 uint32_t bpending, gpu0irq, gpu1irq, armirq;
339
340 bcm2835_barrier();
341 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
342 if (bpending == 0)
343 return 0;
344
345 armirq = bpending & BCM2835_INTBIT_ARM;
346 gpu0irq = bpending & BCM2835_INTBIT_GPU0;
347 gpu1irq = bpending & BCM2835_INTBIT_GPU1;
348
349 if (armirq) {
350 ipl |= pic_mark_pending_sources(pic,
351 BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
352 }
353
354 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
355 uint32_t pending1;
356
357 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
358 ipl |= pic_mark_pending_sources(pic,
359 BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
360 }
361 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
362 uint32_t pending2;
363
364 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
365 ipl |= pic_mark_pending_sources(pic,
366 BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
367 }
368
369 return ipl;
370 }
371
372 static void
373 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
374 {
375
376 /* Nothing really*/
377 KASSERT(is->is_irq < BCM2835_NIRQ);
378 KASSERT(is->is_type == IST_LEVEL);
379 }
380
381 static void
382 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
383 {
384
385 strlcpy(buf, bcm2835_sources[irq], len);
386 }
387
388 static int
389 bcm2835_icu_fdt_decode_irq(u_int *specifier)
390 {
391 u_int base;
392
393 if (!specifier)
394 return -1;
395
396 /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
397 /* 2nd cell is the irq relative to that bank */
398
399 const u_int bank = be32toh(specifier[0]);
400 switch (bank) {
401 case 0:
402 base = BCM2835_INT_BASICBASE;
403 break;
404 case 1:
405 base = BCM2835_INT_GPU0BASE;
406 break;
407 case 2:
408 base = BCM2835_INT_GPU1BASE;
409 break;
410 default:
411 return -1;
412 }
413 const u_int off = be32toh(specifier[1]);
414
415 return base + off;
416 }
417
418 static void *
419 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
420 int (*func)(void *), void *arg)
421 {
422 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
423 int irq;
424
425 irq = bcm2835_icu_fdt_decode_irq(specifier);
426 if (irq == -1)
427 return NULL;
428
429 return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
430 }
431
432 static void
433 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
434 {
435 intr_disestablish(ih);
436 }
437
438 static bool
439 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
440 {
441 int irq;
442
443 irq = bcm2835_icu_fdt_decode_irq(specifier);
444 if (irq == -1)
445 return false;
446
447 snprintf(buf, buflen, "icu irq %d", irq);
448
449 return true;
450 }
451
452 #define BCM2836MP_TIMER_IRQS __BITS(3,0)
453 #define BCM2836MP_MAILBOX_IRQS __BITS(4,4)
454
455 #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
456
457 static void
458 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
459 uint32_t irq_mask)
460 {
461 struct cpu_info * const ci = curcpu();
462 const cpuid_t cpuid = ci->ci_core_id;
463 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
464 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
465
466 KASSERT(pic == &bcm2836mp_pic[cpuid]);
467 KASSERT(irqbase == 0);
468
469 if (irq_mask & BCM2836MP_TIMER_IRQS) {
470 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
471 uint32_t val = bus_space_read_4(iot, ioh,
472 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
473 val |= mask;
474 bus_space_write_4(iot, ioh,
475 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
476 val);
477 bus_space_barrier(iot, ioh,
478 BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
479 BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
480 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
481 }
482 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
483 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
484 uint32_t val = bus_space_read_4(iot, ioh,
485 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
486 val |= mask;
487 bus_space_write_4(iot, ioh,
488 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
489 val);
490 bus_space_barrier(iot, ioh,
491 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
492 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
493 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
494 }
495
496 return;
497 }
498
499 static void
500 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
501 uint32_t irq_mask)
502 {
503 struct cpu_info * const ci = curcpu();
504 const cpuid_t cpuid = ci->ci_core_id;
505 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
506 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
507
508 KASSERT(pic == &bcm2836mp_pic[cpuid]);
509 KASSERT(irqbase == 0);
510
511 if (irq_mask & BCM2836MP_TIMER_IRQS) {
512 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
513 uint32_t val = bus_space_read_4(iot, ioh,
514 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
515 val &= ~mask;
516 bus_space_write_4(iot, ioh,
517 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
518 val);
519 }
520 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
521 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
522 uint32_t val = bus_space_read_4(iot, ioh,
523 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
524 val &= ~mask;
525 bus_space_write_4(iot, ioh,
526 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
527 val);
528 }
529
530 bcm2835_barrier();
531 return;
532 }
533
534 static int
535 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
536 {
537 struct cpu_info * const ci = curcpu();
538 const cpuid_t cpuid = ci->ci_core_id;
539 uint32_t lpending;
540 int ipl = 0;
541
542 KASSERT(pic == &bcm2836mp_pic[cpuid]);
543
544 bcm2835_barrier();
545
546 lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
547 BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
548
549 lpending &= ~BCM2836_INTBIT_GPUPENDING;
550 if (lpending & BCM2836MP_ALL_IRQS) {
551 ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
552 lpending & BCM2836MP_ALL_IRQS);
553 }
554
555 return ipl;
556 }
557
558 static void
559 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
560 {
561 /* Nothing really*/
562 KASSERT(is->is_irq >= 0);
563 KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
564 }
565
566 static void
567 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
568 {
569
570 irq %= BCM2836_NIRQPERCPU;
571 strlcpy(buf, bcm2836mp_sources[irq], len);
572 }
573
574
575 #if defined(MULTIPROCESSOR)
576 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
577 {
578
579 /* Enable IRQ and not FIQ */
580 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
581 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_core_id), 1);
582 }
583
584 static void
585 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
586 {
587 KASSERT(pic != NULL);
588 KASSERT(pic != &bcm2835_pic);
589 KASSERT(pic->pic_cpus != NULL);
590
591 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
592
593 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
594 BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
595 }
596
597 int
598 bcm2836mp_ipi_handler(void *priv)
599 {
600 const struct cpu_info *ci = curcpu();
601 const cpuid_t cpuid = ci->ci_core_id;
602 uint32_t ipimask, bit;
603
604 ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
605 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
606 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
607 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
608
609 while ((bit = ffs(ipimask)) > 0) {
610 const u_int ipi = bit - 1;
611 switch (ipi) {
612 case IPI_AST:
613 pic_ipi_ast(priv);
614 break;
615 case IPI_NOP:
616 pic_ipi_nop(priv);
617 break;
618 #ifdef __HAVE_PREEMPTION
619 case IPI_KPREEMPT:
620 pic_ipi_kpreempt(priv);
621 break;
622 #endif
623 case IPI_XCALL:
624 pic_ipi_xcall(priv);
625 break;
626 case IPI_GENERIC:
627 pic_ipi_generic(priv);
628 break;
629 case IPI_SHOOTDOWN:
630 pic_ipi_shootdown(priv);
631 break;
632 #ifdef DDB
633 case IPI_DDB:
634 pic_ipi_ddb(priv);
635 break;
636 #endif
637 }
638 ipimask &= ~__BIT(ipi);
639 }
640
641 return 1;
642 }
643 #endif
644
645 static void
646 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
647 {
648 const cpuid_t cpuid = ci->ci_core_id;
649 struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
650
651 #if defined(MULTIPROCESSOR)
652 pic->pic_cpus = ci->ci_kcpuset;
653 #endif
654 pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
655
656 #if defined(MULTIPROCESSOR)
657 intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
658 IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
659 #endif
660 /* clock interrupt will attach with gtmr */
661 if (cpuid == 0)
662 return;
663 #if defined(SOC_BCM2836)
664 intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
665 IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
666
667 #endif
668 }
669
670 static int
671 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
672 {
673 if (!specifier)
674 return -1;
675 return be32toh(specifier[0]) + BCM2836_INT_LOCALBASE;
676 }
677
678 static void *
679 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
680 int (*func)(void *), void *arg)
681 {
682 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
683 int irq;
684
685 irq = bcm2836mp_icu_fdt_decode_irq(specifier);
686 if (irq == -1)
687 return NULL;
688
689 return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
690 }
691
692 static void
693 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
694 {
695 intr_disestablish(ih);
696 }
697
698 static bool
699 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
700 size_t buflen)
701 {
702 int irq;
703
704 irq = bcm2836mp_icu_fdt_decode_irq(specifier);
705 if (irq == -1)
706 return false;
707
708 snprintf(buf, buflen, "local_intc irq %d", irq);
709
710 return true;
711 }
712