bcm2835_intr.c revision 1.39 1 /* $NetBSD: bcm2835_intr.c,v 1.39 2021/09/01 03:08:08 rin Exp $ */
2
3 /*-
4 * Copyright (c) 2012, 2015, 2019 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.39 2021/09/01 03:08:08 rin 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/kernel.h>
44 #include <sys/kmem.h>
45 #include <sys/proc.h>
46
47 #include <dev/fdt/fdtvar.h>
48
49 #include <machine/intr.h>
50
51 #include <arm/locore.h>
52
53 #include <arm/pic/picvar.h>
54 #include <arm/cortex/gtmr_var.h>
55
56 #include <arm/broadcom/bcm2835_intr.h>
57 #include <arm/broadcom/bcm2835reg.h>
58 #include <arm/broadcom/bcm2835var.h>
59
60 #include <arm/fdt/arm_fdtvar.h>
61
62 static void bcm2835_irq_handler(void *);
63 static void bcm2836mp_intr_init(void *, struct cpu_info *);
64
65 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
66 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
67 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
68 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
69 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
70 size_t);
71
72 static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
73 static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
74 static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
75 static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
76 static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
77 size_t);
78 #ifdef MULTIPROCESSOR
79 int bcm2836mp_ipi_handler(void *);
80 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
81 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
82 #endif
83
84 static int bcm2835_icu_fdt_decode_irq(u_int *);
85 static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
86 int (*)(void *), void *, const char *);
87 static void bcm2835_icu_fdt_disestablish(device_t, void *);
88 static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
89
90 static int bcm2835_icu_intr(void *);
91
92 static int bcm2836mp_icu_fdt_decode_irq(u_int *);
93 static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
94 int (*)(void *), void *, const char *);
95 static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
96 static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
97
98 static int bcm2835_icu_match(device_t, cfdata_t, void *);
99 static void bcm2835_icu_attach(device_t, device_t, void *);
100
101 static int bcm2835_int_base;
102 static int bcm2836mp_int_base[BCM2836_NCPUS];
103
104 #define BCM2835_INT_BASE bcm2835_int_base
105 #define BCM2836_INT_BASECPUN(n) bcm2836mp_int_base[(n)]
106
107 #define BCM2836_INT_CNTPSIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTPSIRQ)
108 #define BCM2836_INT_CNTPNSIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTPNSIRQ)
109 #define BCM2836_INT_CNTVIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTVIRQ)
110 #define BCM2836_INT_CNTHPIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTHPIRQ)
111 #define BCM2836_INT_MAILBOX0_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_MAILBOX0)
112
113 /* Periperal Interrupt sources */
114 #define BCM2835_NIRQ 96
115
116 #define BCM2835_INT_GPU0BASE (BCM2835_INT_BASE + 0)
117 #define BCM2835_INT_TIMER0 (BCM2835_INT_GPU0BASE + 0)
118 #define BCM2835_INT_TIMER1 (BCM2835_INT_GPU0BASE + 1)
119 #define BCM2835_INT_TIMER2 (BCM2835_INT_GPU0BASE + 2)
120 #define BCM2835_INT_TIMER3 (BCM2835_INT_GPU0BASE + 3)
121 #define BCM2835_INT_USB (BCM2835_INT_GPU0BASE + 9)
122 #define BCM2835_INT_DMA0 (BCM2835_INT_GPU0BASE + 16)
123 #define BCM2835_INT_DMA2 (BCM2835_INT_GPU0BASE + 18)
124 #define BCM2835_INT_DMA3 (BCM2835_INT_GPU0BASE + 19)
125 #define BCM2835_INT_AUX (BCM2835_INT_GPU0BASE + 29)
126 #define BCM2835_INT_ARM (BCM2835_INT_GPU0BASE + 30)
127
128 #define BCM2835_INT_GPU1BASE (BCM2835_INT_BASE + 32)
129 #define BCM2835_INT_GPIO0 (BCM2835_INT_GPU1BASE + 17)
130 #define BCM2835_INT_GPIO1 (BCM2835_INT_GPU1BASE + 18)
131 #define BCM2835_INT_GPIO2 (BCM2835_INT_GPU1BASE + 19)
132 #define BCM2835_INT_GPIO3 (BCM2835_INT_GPU1BASE + 20)
133 #define BCM2835_INT_BSC (BCM2835_INT_GPU1BASE + 21)
134 #define BCM2835_INT_SPI0 (BCM2835_INT_GPU1BASE + 22)
135 #define BCM2835_INT_PCM (BCM2835_INT_GPU1BASE + 23)
136 #define BCM2835_INT_SDHOST (BCM2835_INT_GPU1BASE + 24)
137 #define BCM2835_INT_UART0 (BCM2835_INT_GPU1BASE + 25)
138 #define BCM2835_INT_EMMC (BCM2835_INT_GPU1BASE + 30)
139
140 #define BCM2835_INT_BASICBASE (BCM2835_INT_BASE + 64)
141 #define BCM2835_INT_ARMTIMER (BCM2835_INT_BASICBASE + 0)
142 #define BCM2835_INT_ARMMAILBOX (BCM2835_INT_BASICBASE + 1)
143 #define BCM2835_INT_ARMDOORBELL0 (BCM2835_INT_BASICBASE + 2)
144 #define BCM2835_INT_ARMDOORBELL1 (BCM2835_INT_BASICBASE + 3)
145 #define BCM2835_INT_GPU0HALTED (BCM2835_INT_BASICBASE + 4)
146 #define BCM2835_INT_GPU1HALTED (BCM2835_INT_BASICBASE + 5)
147 #define BCM2835_INT_ILLEGALTYPE0 (BCM2835_INT_BASICBASE + 6)
148 #define BCM2835_INT_ILLEGALTYPE1 (BCM2835_INT_BASICBASE + 7)
149
150 static void
151 bcm2835_set_priority(struct pic_softc *pic, int ipl)
152 {
153 }
154
155 static struct pic_ops bcm2835_picops = {
156 .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
157 .pic_block_irqs = bcm2835_pic_block_irqs,
158 .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
159 .pic_establish_irq = bcm2835_pic_establish_irq,
160 .pic_source_name = bcm2835_pic_source_name,
161 .pic_set_priority = bcm2835_set_priority,
162 };
163
164 static struct pic_softc bcm2835_pic = {
165 .pic_ops = &bcm2835_picops,
166 .pic_maxsources = BCM2835_NIRQ,
167 .pic_name = "bcm2835 pic",
168 };
169
170 static struct pic_ops bcm2836mp_picops = {
171 .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
172 .pic_block_irqs = bcm2836mp_pic_block_irqs,
173 .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
174 .pic_establish_irq = bcm2836mp_pic_establish_irq,
175 .pic_source_name = bcm2836mp_pic_source_name,
176 #if defined(MULTIPROCESSOR)
177 .pic_cpu_init = bcm2836mp_cpu_init,
178 .pic_ipi_send = bcm2836mp_send_ipi,
179 #endif
180 };
181
182 static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
183 [0 ... BCM2836_NCPUS - 1] = {
184 .pic_ops = &bcm2836mp_picops,
185 .pic_maxsources = BCM2836_NIRQPERCPU,
186 .pic_name = "bcm2836 pic",
187 }
188 };
189
190 static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
191 .establish = bcm2835_icu_fdt_establish,
192 .disestablish = bcm2835_icu_fdt_disestablish,
193 .intrstr = bcm2835_icu_fdt_intrstr
194 };
195
196 static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
197 .establish = bcm2836mp_icu_fdt_establish,
198 .disestablish = bcm2836mp_icu_fdt_disestablish,
199 .intrstr = bcm2836mp_icu_fdt_intrstr
200 };
201
202 struct bcm2836mp_interrupt {
203 bool bi_done;
204 TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
205 int bi_irq;
206 int bi_ipl;
207 int bi_flags;
208 int (*bi_func)(void *);
209 void *bi_arg;
210 void *bi_ihs[BCM2836_NCPUS];
211 };
212
213 static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
214 TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
215
216 struct bcm2835icu_irqhandler;
217 struct bcm2835icu_irq;
218 struct bcm2835icu_softc;
219
220 struct bcm2835icu_irqhandler {
221 struct bcm2835icu_irq *ih_irq;
222 int (*ih_fn)(void *);
223 void *ih_arg;
224 TAILQ_ENTRY(bcm2835icu_irqhandler) ih_next;
225 };
226
227 struct bcm2835icu_irq {
228 struct bcm2835icu_softc *intr_sc;
229 void *intr_ih;
230 void *intr_arg;
231 int intr_refcnt;
232 int intr_ipl;
233 int intr_irq;
234 int intr_mpsafe;
235 TAILQ_HEAD(, bcm2835icu_irqhandler) intr_handlers;
236 };
237
238 struct bcm2835icu_softc {
239 device_t sc_dev;
240 bus_space_tag_t sc_iot;
241 bus_space_handle_t sc_ioh;
242
243 struct bcm2835icu_irq *sc_irq[BCM2835_NIRQ];
244
245 int sc_phandle;
246 };
247
248 static struct bcm2835icu_softc *bcml1icu_sc;
249 static struct bcm2835icu_softc *bcmicu_sc;
250
251 #define read_bcm2835reg(o) \
252 bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
253
254 #define write_bcm2835reg(o, v) \
255 bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
256
257
258 #define bcm2835_barrier() \
259 bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
260 BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
261
262 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
263 "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
264 "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
265 "(unused 8)", "usb", "(unused 10)", "(unused 11)",
266 "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
267 "dma0", "dma1", "dma2", "dma3",
268 "dma4", "dma5", "dma6", "dma7",
269 "dma8", "dma9", "dma10", "dma11",
270 "dma12", "aux", "(unused 30)", "(unused 31)",
271 "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
272 "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
273 "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
274 "(unused 44)", "pwa0", "pwa1", "(unused 47)",
275 "smi", "gpio[0]", "gpio[1]", "gpio[2]",
276 "gpio[3]", "i2c", "spi", "pcm",
277 "sdhost", "uart", "(unused 58)", "(unused 59)",
278 "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
279 "Timer", "Mailbox", "Doorbell0", "Doorbell1",
280 "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
281 };
282
283 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
284 "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
285 "mailbox0", "mailbox1", "mailbox2", "mailbox3",
286 "gpu", "pmu"
287 };
288
289 #define BCM2836_INTBIT_GPUPENDING __BIT(8)
290
291 #define BCM2835_INTBIT_PENDING1 __BIT(8)
292 #define BCM2835_INTBIT_PENDING2 __BIT(9)
293 #define BCM2835_INTBIT_ARM __BITS(0,7)
294 #define BCM2835_INTBIT_GPU0 __BITS(10,14)
295 #define BCM2835_INTBIT_GPU1 __BITS(15,20)
296
297 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
298 bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
299
300 static const struct device_compatible_entry compat_data[] = {
301 { .compat = "brcm,bcm2708-armctrl-ic", .value = 0 },
302 { .compat = "brcm,bcm2709-armctrl-ic", .value = 0 },
303 { .compat = "brcm,bcm2835-armctrl-ic", .value = 0 },
304 { .compat = "brcm,bcm2836-armctrl-ic", .value = 0 },
305 { .compat = "brcm,bcm2836-l1-intc", .value = 1 },
306 DEVICE_COMPAT_EOL
307 };
308
309 static int
310 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
311 {
312 struct fdt_attach_args * const faa = aux;
313
314 return of_compatible_match(faa->faa_phandle, compat_data);
315 }
316
317 static void
318 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
319 {
320 struct bcm2835icu_softc * const sc = device_private(self);
321 struct fdt_attach_args * const faa = aux;
322 struct fdtbus_interrupt_controller_func *ifuncs;
323 const struct device_compatible_entry *dce;
324 const int phandle = faa->faa_phandle;
325 bus_addr_t addr;
326 bus_size_t size;
327 bus_space_handle_t ioh;
328 int error;
329
330 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
331 aprint_error(": couldn't get registers\n");
332 return;
333 }
334
335 sc->sc_dev = self;
336 sc->sc_iot = faa->faa_bst;
337
338 if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
339 aprint_error(": couldn't map device\n");
340 return;
341 }
342
343 sc->sc_ioh = ioh;
344 sc->sc_phandle = phandle;
345
346 dce = of_compatible_lookup(faa->faa_phandle, compat_data);
347 KASSERT(dce != NULL);
348
349 if (dce->value != 0) {
350 #if defined(MULTIPROCESSOR)
351 aprint_normal(": Multiprocessor");
352 #endif
353 bcml1icu_sc = sc;
354
355 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
356 BCM2836_LOCAL_CONTROL, 0);
357 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
358 BCM2836_LOCAL_PRESCALER, 0x80000000);
359
360 ifuncs = &bcm2836mpicu_fdt_funcs;
361
362 /*
363 * XXX
364 * Register all PICs here in order to avoid pic_add() from
365 * cpu_hatch(). See port-arm/56264.
366 */
367 CPU_INFO_ITERATOR cii;
368 struct cpu_info *ci;
369 for (CPU_INFO_FOREACH(cii, ci)) {
370 const cpuid_t cpuid = ci->ci_core_id;
371 struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
372
373 KASSERT(cpuid < BCM2836_NCPUS);
374
375 #if defined(MULTIPROCESSOR)
376 pic->pic_cpus = ci->ci_kcpuset;
377 /*
378 * Append "#n" to avoid duplication of .pic_name[]
379 * It should be a unique id for intr_get_source()
380 */
381 char suffix[sizeof("#00000")];
382 snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
383 strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
384 #endif
385
386 bcm2836mp_int_base[cpuid] =
387 pic_add(pic, PIC_IRQBASE_ALLOC);
388 }
389
390 bcm2836mp_intr_init(self, curcpu());
391 arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
392 } else {
393 if (bcml1icu_sc == NULL)
394 arm_fdt_irq_set_handler(bcm2835_irq_handler);
395 bcmicu_sc = sc;
396 sc->sc_ioh = ioh;
397 sc->sc_phandle = phandle;
398 bcm2835_int_base = pic_add(&bcm2835_pic, PIC_IRQBASE_ALLOC);
399 ifuncs = &bcm2835icu_fdt_funcs;
400 }
401
402 error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
403 if (error != 0) {
404 aprint_error(": couldn't register with fdtbus: %d\n", error);
405 return;
406 }
407 aprint_normal("\n");
408 }
409
410 static void
411 bcm2835_irq_handler(void *frame)
412 {
413 struct cpu_info * const ci = curcpu();
414 const int oldipl = ci->ci_cpl;
415 const cpuid_t cpuid = ci->ci_core_id;
416 const uint32_t oldipl_mask = __BIT(oldipl);
417 int ipl_mask = 0;
418
419 KASSERT(cpuid < BCM2836_NCPUS);
420
421 ci->ci_data.cpu_nintr++;
422
423 bcm2835_barrier();
424 if (cpuid == 0) {
425 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
426 }
427 #if defined(SOC_BCM2836)
428 ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
429 #endif
430
431 /*
432 * Record the pending_ipls and deliver them if we can.
433 */
434 if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
435 pic_do_pending_ints(I32_bit, oldipl, frame);
436 }
437
438 static void
439 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
440 uint32_t irq_mask)
441 {
442
443 write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
444 bcm2835_barrier();
445 }
446
447 static void
448 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
449 uint32_t irq_mask)
450 {
451
452 write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
453 bcm2835_barrier();
454 }
455
456 /*
457 * Called with interrupts disabled
458 */
459 static int
460 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
461 {
462 int ipl = 0;
463 uint32_t bpending, gpu0irq, gpu1irq, armirq;
464
465 bcm2835_barrier();
466 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
467 if (bpending == 0)
468 return 0;
469
470 armirq = bpending & BCM2835_INTBIT_ARM;
471 gpu0irq = bpending & BCM2835_INTBIT_GPU0;
472 gpu1irq = bpending & BCM2835_INTBIT_GPU1;
473
474 if (armirq) {
475 ipl |= pic_mark_pending_sources(pic,
476 BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
477 }
478
479 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
480 uint32_t pending1;
481
482 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
483 ipl |= pic_mark_pending_sources(pic,
484 BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
485 }
486 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
487 uint32_t pending2;
488
489 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
490 ipl |= pic_mark_pending_sources(pic,
491 BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
492 }
493
494 return ipl;
495 }
496
497 static void
498 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
499 {
500
501 /* Nothing really*/
502 KASSERT(is->is_irq < BCM2835_NIRQ);
503 KASSERT(is->is_type == IST_LEVEL);
504 }
505
506 static void
507 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
508 {
509
510 strlcpy(buf, bcm2835_sources[irq], len);
511 }
512
513 static int
514 bcm2835_icu_fdt_decode_irq(u_int *specifier)
515 {
516 u_int base;
517
518 if (!specifier)
519 return -1;
520
521 /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
522 /* 2nd cell is the irq relative to that bank */
523
524 const u_int bank = be32toh(specifier[0]);
525 switch (bank) {
526 case 0:
527 base = BCM2835_INT_BASICBASE;
528 break;
529 case 1:
530 base = BCM2835_INT_GPU0BASE;
531 break;
532 case 2:
533 base = BCM2835_INT_GPU1BASE;
534 break;
535 default:
536 return -1;
537 }
538 const u_int off = be32toh(specifier[1]);
539
540 return base + off;
541 }
542
543 static void *
544 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
545 int (*func)(void *), void *arg, const char *xname)
546 {
547 struct bcm2835icu_softc * const sc = device_private(dev);
548 struct bcm2835icu_irq *firq;
549 struct bcm2835icu_irqhandler *firqh;
550 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
551 int irq, irqidx;
552
553 irq = bcm2835_icu_fdt_decode_irq(specifier);
554 if (irq == -1)
555 return NULL;
556 irqidx = irq - BCM2835_INT_BASE;
557
558 KASSERT(irqidx < BCM2835_NIRQ);
559
560 firq = sc->sc_irq[irqidx];
561 if (firq == NULL) {
562 firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
563 firq->intr_sc = sc;
564 firq->intr_refcnt = 0;
565 firq->intr_arg = arg;
566 firq->intr_ipl = ipl;
567 firq->intr_mpsafe = iflags;
568 firq->intr_irq = irq;
569 TAILQ_INIT(&firq->intr_handlers);
570 if (arg == NULL) {
571 firq->intr_ih = intr_establish_xname(irq, ipl,
572 IST_LEVEL | iflags, func, NULL, xname);
573 } else {
574 firq->intr_ih = intr_establish_xname(irq, ipl,
575 IST_LEVEL | iflags, bcm2835_icu_intr, firq, xname);
576 }
577 if (firq->intr_ih == NULL) {
578 kmem_free(firq, sizeof(*firq));
579 return NULL;
580 }
581 sc->sc_irq[irqidx] = firq;
582 } else {
583 if (firq->intr_arg == NULL || arg == NULL) {
584 device_printf(dev,
585 "cannot share irq with NULL-arg handler\n");
586 return NULL;
587 }
588 if (firq->intr_ipl != ipl) {
589 device_printf(dev,
590 "cannot share irq with different ipl\n");
591 return NULL;
592 }
593 if (firq->intr_mpsafe != iflags) {
594 device_printf(dev,
595 "cannot share irq between mpsafe/non-mpsafe\n");
596 return NULL;
597 }
598 }
599
600 firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
601 firqh->ih_irq = firq;
602 firqh->ih_fn = func;
603 firqh->ih_arg = arg;
604
605 firq->intr_refcnt++;
606 TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
607
608 /*
609 * XXX interrupt_distribute(9) assumes that any interrupt
610 * handle can be used as an input to the MD interrupt_distribute
611 * implementationm, so we are forced to return the handle
612 * we got back from intr_establish(). Upshot is that the
613 * input to bcm2835_icu_fdt_disestablish() is ambiguous for
614 * shared IRQs, rendering them un-disestablishable.
615 */
616
617 return firq->intr_ih;
618 }
619
620 static void
621 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
622 {
623 struct bcm2835icu_softc * const sc = device_private(dev);
624 struct bcm2835icu_irqhandler *firqh;
625 struct bcm2835icu_irq *firq;
626 u_int n;
627
628 for (n = 0; n < BCM2835_NIRQ; n++) {
629 firq = sc->sc_irq[n];
630 if (firq == NULL || firq->intr_ih != ih)
631 continue;
632
633 KASSERT(firq->intr_refcnt > 0);
634 KASSERT(n == (firq->intr_irq - BCM2835_INT_BASE));
635
636 /* XXX see above */
637 if (firq->intr_refcnt > 1)
638 panic("%s: cannot disestablish shared irq", __func__);
639
640 intr_disestablish(firq->intr_ih);
641
642 firqh = TAILQ_FIRST(&firq->intr_handlers);
643 TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
644 kmem_free(firqh, sizeof(*firqh));
645
646 sc->sc_irq[n] = NULL;
647 kmem_free(firq, sizeof(*firq));
648
649 return;
650 }
651
652 panic("%s: interrupt not established", __func__);
653 }
654
655 static int
656 bcm2835_icu_intr(void *priv)
657 {
658 struct bcm2835icu_irq *firq = priv;
659 struct bcm2835icu_irqhandler *firqh;
660 int handled = 0;
661
662 TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
663 handled |= firqh->ih_fn(firqh->ih_arg);
664 }
665
666 return handled;
667 }
668
669 static bool
670 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
671 {
672 int irq;
673
674 irq = bcm2835_icu_fdt_decode_irq(specifier);
675 if (irq == -1)
676 return false;
677
678 snprintf(buf, buflen, "icu irq %d", irq);
679
680 return true;
681 }
682
683 #define BCM2836MP_TIMER_IRQS __BITS(3,0)
684 #define BCM2836MP_MAILBOX_IRQS __BITS(4,7)
685 #define BCM2836MP_GPU_IRQ __BIT(8)
686 #define BCM2836MP_PMU_IRQ __BIT(9)
687 #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
688
689 static void
690 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
691 uint32_t irq_mask)
692 {
693 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
694 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
695 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
696
697 KASSERT(cpuid < BCM2836_NCPUS);
698 KASSERT(irqbase == 0);
699
700 if (irq_mask & BCM2836MP_TIMER_IRQS) {
701 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
702 uint32_t val = bus_space_read_4(iot, ioh,
703 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
704 val |= mask;
705 bus_space_write_4(iot, ioh,
706 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
707 val);
708 bus_space_barrier(iot, ioh,
709 BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
710 BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
711 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
712 }
713 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
714 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
715 uint32_t val = bus_space_read_4(iot, ioh,
716 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
717 val |= mask;
718 bus_space_write_4(iot, ioh,
719 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
720 val);
721 bus_space_barrier(iot, ioh,
722 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
723 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
724 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
725 }
726 if (irq_mask & BCM2836MP_PMU_IRQ) {
727 bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
728 __BIT(cpuid));
729 bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
730 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
731 }
732
733 return;
734 }
735
736 static void
737 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
738 uint32_t irq_mask)
739 {
740 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
741 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
742 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
743
744 KASSERT(cpuid < BCM2836_NCPUS);
745 KASSERT(irqbase == 0);
746
747 if (irq_mask & BCM2836MP_TIMER_IRQS) {
748 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
749 uint32_t val = bus_space_read_4(iot, ioh,
750 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
751 val &= ~mask;
752 bus_space_write_4(iot, ioh,
753 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
754 val);
755 }
756 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
757 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
758 uint32_t val = bus_space_read_4(iot, ioh,
759 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
760 val &= ~mask;
761 bus_space_write_4(iot, ioh,
762 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
763 val);
764 }
765 if (irq_mask & BCM2836MP_PMU_IRQ) {
766 bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
767 __BIT(cpuid));
768 }
769
770 bcm2835_barrier();
771 return;
772 }
773
774 static int
775 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
776 {
777 struct cpu_info * const ci = curcpu();
778 const cpuid_t cpuid = ci->ci_core_id;
779 uint32_t lpending;
780 int ipl = 0;
781
782 KASSERT(cpuid < BCM2836_NCPUS);
783 KASSERT(pic == &bcm2836mp_pic[cpuid]);
784
785 bcm2835_barrier();
786
787 lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
788 BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
789
790 lpending &= ~BCM2836_INTBIT_GPUPENDING;
791 const uint32_t allirqs = lpending & BCM2836MP_ALL_IRQS;
792 if (allirqs) {
793 ipl |= pic_mark_pending_sources(pic, 0, allirqs);
794 }
795
796 return ipl;
797 }
798
799 static void
800 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
801 {
802 /* Nothing really*/
803 KASSERT(is->is_irq >= 0);
804 KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
805 }
806
807 static void
808 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
809 {
810
811 irq %= BCM2836_NIRQPERCPU;
812 strlcpy(buf, bcm2836mp_sources[irq], len);
813 }
814
815
816 #if defined(MULTIPROCESSOR)
817 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
818 {
819 const cpuid_t cpuid = ci->ci_core_id;
820
821 KASSERT(cpuid < BCM2836_NCPUS);
822
823 /* Enable IRQ and not FIQ */
824 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
825 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid), 1);
826 }
827
828 static void
829 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
830 {
831 KASSERT(pic != NULL);
832 KASSERT(pic != &bcm2835_pic);
833 KASSERT(pic->pic_cpus != NULL);
834
835 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
836 KASSERT(cpuid < BCM2836_NCPUS);
837
838 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
839 BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
840 }
841
842 int
843 bcm2836mp_ipi_handler(void *priv)
844 {
845 const struct cpu_info *ci = curcpu();
846 const cpuid_t cpuid = ci->ci_core_id;
847 uint32_t ipimask, bit;
848
849 KASSERT(cpuid < BCM2836_NCPUS);
850
851 ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
852 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
853 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
854 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
855
856 while ((bit = ffs(ipimask)) > 0) {
857 const u_int ipi = bit - 1;
858 switch (ipi) {
859 case IPI_AST:
860 pic_ipi_ast(priv);
861 break;
862 case IPI_NOP:
863 pic_ipi_nop(priv);
864 break;
865 #ifdef __HAVE_PREEMPTION
866 case IPI_KPREEMPT:
867 pic_ipi_kpreempt(priv);
868 break;
869 #endif
870 case IPI_XCALL:
871 pic_ipi_xcall(priv);
872 break;
873 case IPI_GENERIC:
874 pic_ipi_generic(priv);
875 break;
876 case IPI_SHOOTDOWN:
877 pic_ipi_shootdown(priv);
878 break;
879 #ifdef DDB
880 case IPI_DDB:
881 pic_ipi_ddb(priv);
882 break;
883 #endif
884 }
885 ipimask &= ~__BIT(ipi);
886 }
887
888 return 1;
889 }
890 #endif
891
892 static void
893 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
894 {
895 const cpuid_t cpuid = ci->ci_core_id;
896
897 KASSERT(cpuid < BCM2836_NCPUS);
898
899 #if defined(MULTIPROCESSOR)
900 intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
901 IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
902
903 struct bcm2836mp_interrupt *bip;
904 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
905 if (bip->bi_done)
906 continue;
907
908 const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
909 void *ih = intr_establish(irq, bip->bi_ipl,
910 IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
911
912 bip->bi_ihs[cpuid] = ih;
913 }
914 #endif
915 }
916
917 static int
918 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
919 {
920
921 if (!specifier)
922 return -1;
923 return be32toh(specifier[0]);
924 }
925
926 static void *
927 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
928 int (*func)(void *), void *arg, const char *xname)
929 {
930 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
931 struct bcm2836mp_interrupt *bip;
932 void *ih;
933
934 int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
935 if (irq == -1)
936 return NULL;
937
938 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
939 if (irq == bip->bi_irq)
940 return NULL;
941 }
942
943 bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
944 if (bip == NULL)
945 return NULL;
946
947 bip->bi_done = false;
948 bip->bi_irq = irq;
949 bip->bi_ipl = ipl;
950 bip->bi_flags = IST_LEVEL | iflags;
951 bip->bi_func = func;
952 bip->bi_arg = arg;
953
954 /*
955 * If we're not cold and the BPs have been started then we can
956 * register the interrupt for all CPUs now, e.g. PMU
957 */
958 if (!cold) {
959 for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
960 ih = intr_establish_xname(
961 BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
962 IST_LEVEL | iflags, func, arg, xname);
963 if (!ih) {
964 kmem_free(bip, sizeof(*bip));
965 return NULL;
966 }
967 bip->bi_ihs[cpuid] = ih;
968
969 }
970 bip->bi_done = true;
971 ih = bip->bi_ihs[0];
972 goto done;
973 }
974
975 /*
976 * Otherwise we can only establish the interrupt for the BP and
977 * delay until bcm2836mp_intr_init is called for each AP, e.g.
978 * gtmr
979 */
980 ih = intr_establish_xname(BCM2836_INT_BASECPUN(0) + irq, ipl,
981 IST_LEVEL | iflags, func, arg, xname);
982 if (!ih) {
983 kmem_free(bip, sizeof(*bip));
984 return NULL;
985 }
986
987 bip->bi_ihs[0] = ih;
988 for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
989 bip->bi_ihs[cpuid] = NULL;
990
991 done:
992 TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
993
994 /*
995 * Return the intr_establish handle for cpu 0 for API compatibility.
996 * Any cpu would do here as these sources don't support set_affinity
997 * when the handle is used in interrupt_distribute(9)
998 */
999 return ih;
1000 }
1001
1002 static void
1003 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
1004 {
1005 struct bcm2836mp_interrupt *bip;
1006
1007 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
1008 if (bip->bi_ihs[0] == ih)
1009 break;
1010 }
1011
1012 if (bip == NULL)
1013 return;
1014
1015 for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
1016 intr_disestablish(bip->bi_ihs[cpuid]);
1017
1018 TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
1019
1020 kmem_free(bip, sizeof(*bip));
1021 }
1022
1023 static bool
1024 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
1025 size_t buflen)
1026 {
1027 int irq;
1028
1029 irq = bcm2836mp_icu_fdt_decode_irq(specifier);
1030 if (irq == -1)
1031 return false;
1032
1033 snprintf(buf, buflen, "local_intc irq %d", irq);
1034
1035 return true;
1036 }
1037