xref: /netbsd/sys/arch/arm/broadcom/bcm2835_intr.c (revision 3a1b0cdf)
1 /*	$NetBSD: bcm2835_intr.c,v 1.21 2019/09/25 16:48:06 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.21 2019/09/25 16:48:06 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/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 *);
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 bcm2836mp_icu_fdt_decode_irq(u_int *);
91 static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
92     int (*)(void *), void *);
93 static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
94 static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
95 
96 static int  bcm2835_icu_match(device_t, cfdata_t, void *);
97 static void bcm2835_icu_attach(device_t, device_t, void *);
98 
99 static void
100 bcm2835_set_priority(struct pic_softc *pic, int ipl)
101 {
102 }
103 
104 static struct pic_ops bcm2835_picops = {
105 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
106 	.pic_block_irqs = bcm2835_pic_block_irqs,
107 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
108 	.pic_establish_irq = bcm2835_pic_establish_irq,
109 	.pic_source_name = bcm2835_pic_source_name,
110 	.pic_set_priority = bcm2835_set_priority,
111 };
112 
113 static struct pic_softc bcm2835_pic = {
114 	.pic_ops = &bcm2835_picops,
115 	.pic_maxsources = BCM2835_NIRQ,
116 	.pic_name = "bcm2835 pic",
117 };
118 
119 static struct pic_ops bcm2836mp_picops = {
120 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
121 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
122 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
123 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
124 	.pic_source_name = bcm2836mp_pic_source_name,
125 #if defined(MULTIPROCESSOR)
126 	.pic_cpu_init = bcm2836mp_cpu_init,
127 	.pic_ipi_send = bcm2836mp_send_ipi,
128 #endif
129 };
130 
131 static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
132 	[0 ... BCM2836_NCPUS - 1] = {
133 		.pic_ops = &bcm2836mp_picops,
134 		.pic_maxsources = BCM2836_NIRQPERCPU,
135 		.pic_name = "bcm2836 pic",
136 	}
137 };
138 
139 static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
140 	.establish = bcm2835_icu_fdt_establish,
141 	.disestablish = bcm2835_icu_fdt_disestablish,
142 	.intrstr = bcm2835_icu_fdt_intrstr
143 };
144 
145 static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
146 	.establish = bcm2836mp_icu_fdt_establish,
147 	.disestablish = bcm2836mp_icu_fdt_disestablish,
148 	.intrstr = bcm2836mp_icu_fdt_intrstr
149 };
150 
151 struct bcm2836mp_interrupt {
152 	bool bi_done;
153 	TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
154 	int bi_irq;
155 	int bi_ipl;
156 	int bi_flags;
157 	int (*bi_func)(void *);
158 	void *bi_arg;
159 	void *bi_ihs[BCM2836_NCPUS];
160 };
161 
162 static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
163     TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
164 
165 struct bcm2835icu_softc {
166 	device_t		sc_dev;
167 	bus_space_tag_t		sc_iot;
168 	bus_space_handle_t	sc_ioh;
169 
170 	int sc_phandle;
171 };
172 
173 struct bcm2835icu_softc *bcml1icu_sc;
174 struct bcm2835icu_softc *bcmicu_sc;
175 
176 #define read_bcm2835reg(o)	\
177 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
178 
179 #define write_bcm2835reg(o, v)	\
180 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
181 
182 
183 #define bcm2835_barrier() \
184 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
185 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
186 
187 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
188 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
189 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
190 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
191 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
192 	"dma0",		"dma1",		"dma2",		"dma3",
193 	"dma4",		"dma5",		"dma6",		"dma7",
194 	"dma8",		"dma9",		"dma10",	"dma11",
195 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
196 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
197 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
198 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
199 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
200 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
201 	"gpio[3]",	"i2c",		"spi",		"pcm",
202 	"sdhost",	"uart",		"(unused 58)",	"(unused 59)",
203 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
204 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
205 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
206 };
207 
208 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
209 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
210 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
211 	"gpu",		"pmu"
212 };
213 
214 #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
215 
216 #define	BCM2835_INTBIT_PENDING1		__BIT(8)
217 #define	BCM2835_INTBIT_PENDING2		__BIT(9)
218 #define	BCM2835_INTBIT_ARM		__BITS(0,7)
219 #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
220 #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
221 
222 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
223     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
224 
225 static int
226 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
227 {
228 	const char * const compatible[] = {
229 	    "brcm,bcm2708-armctrl-ic",
230 	    "brcm,bcm2709-armctrl-ic",
231 	    "brcm,bcm2835-armctrl-ic",
232 	    "brcm,bcm2836-armctrl-ic",
233 	    "brcm,bcm2836-l1-intc",
234 	    NULL
235 	};
236 	struct fdt_attach_args * const faa = aux;
237 
238 	return of_match_compatible(faa->faa_phandle, compatible);
239 }
240 
241 static void
242 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
243 {
244 	struct bcm2835icu_softc * const sc = device_private(self);
245 	struct fdt_attach_args * const faa = aux;
246 	struct fdtbus_interrupt_controller_func *ifuncs;
247 	const int phandle = faa->faa_phandle;
248 	bus_addr_t addr;
249 	bus_size_t size;
250 	bus_space_handle_t ioh;
251 	int error;
252 
253 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
254 		aprint_error(": couldn't get registers\n");
255 		return;
256 	}
257 
258 	sc->sc_dev = self;
259 	sc->sc_iot = faa->faa_bst;
260 
261 	if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
262 		aprint_error(": couldn't map device\n");
263 		return;
264 	}
265 
266 	sc->sc_ioh = ioh;
267 	sc->sc_phandle = phandle;
268 
269 	const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
270 	if (of_match_compatible(faa->faa_phandle, local_intc)) {
271 #if defined(MULTIPROCESSOR)
272 		aprint_normal(": Multiprocessor");
273 #endif
274 		bcml1icu_sc = sc;
275 
276 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
277 		    BCM2836_LOCAL_CONTROL, 0);
278 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
279 		    BCM2836_LOCAL_PRESCALER, 0x80000000);
280 
281 		ifuncs = &bcm2836mpicu_fdt_funcs;
282 
283 		bcm2836mp_intr_init(self, curcpu());
284 		arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
285 	} else {
286 		if (bcml1icu_sc == NULL)
287 			arm_fdt_irq_set_handler(bcm2835_irq_handler);
288 		bcmicu_sc = sc;
289 		sc->sc_ioh = ioh;
290 		sc->sc_phandle = phandle;
291 		pic_add(&bcm2835_pic, BCM2835_INT_BASE);
292 		ifuncs = &bcm2835icu_fdt_funcs;
293 	}
294 
295 	error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
296 	if (error != 0) {
297 		aprint_error(": couldn't register with fdtbus: %d\n", error);
298 		return;
299 	}
300 	aprint_normal("\n");
301 }
302 
303 static void
304 bcm2835_irq_handler(void *frame)
305 {
306 	struct cpu_info * const ci = curcpu();
307 	const int oldipl = ci->ci_cpl;
308 	const cpuid_t cpuid = ci->ci_core_id;
309 	const uint32_t oldipl_mask = __BIT(oldipl);
310 	int ipl_mask = 0;
311 
312 	ci->ci_data.cpu_nintr++;
313 
314 	bcm2835_barrier();
315 	if (cpuid == 0) {
316 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
317 	}
318 #if defined(SOC_BCM2836)
319 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
320 #endif
321 
322 	/*
323 	 * Record the pending_ipls and deliver them if we can.
324 	 */
325 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
326 		pic_do_pending_ints(I32_bit, oldipl, frame);
327 }
328 
329 static void
330 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
331     uint32_t irq_mask)
332 {
333 
334 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
335 	bcm2835_barrier();
336 }
337 
338 static void
339 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
340     uint32_t irq_mask)
341 {
342 
343 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
344 	bcm2835_barrier();
345 }
346 
347 /*
348  * Called with interrupts disabled
349  */
350 static int
351 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
352 {
353 	int ipl = 0;
354 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
355 
356 	bcm2835_barrier();
357 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
358 	if (bpending == 0)
359 		return 0;
360 
361 	armirq = bpending & BCM2835_INTBIT_ARM;
362 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
363 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
364 
365 	if (armirq) {
366 		ipl |= pic_mark_pending_sources(pic,
367 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
368 	}
369 
370 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
371 		uint32_t pending1;
372 
373 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
374 		ipl |= pic_mark_pending_sources(pic,
375 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
376 	}
377 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
378 		uint32_t pending2;
379 
380 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
381 		ipl |= pic_mark_pending_sources(pic,
382 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
383 	}
384 
385 	return ipl;
386 }
387 
388 static void
389 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
390 {
391 
392 	/* Nothing really*/
393 	KASSERT(is->is_irq < BCM2835_NIRQ);
394 	KASSERT(is->is_type == IST_LEVEL);
395 }
396 
397 static void
398 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
399 {
400 
401 	strlcpy(buf, bcm2835_sources[irq], len);
402 }
403 
404 static int
405 bcm2835_icu_fdt_decode_irq(u_int *specifier)
406 {
407 	u_int base;
408 
409 	if (!specifier)
410 		return -1;
411 
412 	/* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
413 	/* 2nd cell is the irq relative to that bank */
414 
415 	const u_int bank = be32toh(specifier[0]);
416 	switch (bank) {
417 	case 0:
418 		base = BCM2835_INT_BASICBASE;
419 		break;
420 	case 1:
421 		base = BCM2835_INT_GPU0BASE;
422 		break;
423 	case 2:
424 		base = BCM2835_INT_GPU1BASE;
425 		break;
426 	default:
427 		return -1;
428 	}
429 	const u_int off = be32toh(specifier[1]);
430 
431 	return base + off;
432 }
433 
434 static void *
435 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
436     int (*func)(void *), void *arg)
437 {
438 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
439 	int irq;
440 
441 	irq = bcm2835_icu_fdt_decode_irq(specifier);
442 	if (irq == -1)
443 		return NULL;
444 
445 	return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
446 }
447 
448 static void
449 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
450 {
451 	intr_disestablish(ih);
452 }
453 
454 static bool
455 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
456 {
457 	int irq;
458 
459 	irq = bcm2835_icu_fdt_decode_irq(specifier);
460 	if (irq == -1)
461 		return false;
462 
463 	snprintf(buf, buflen, "icu irq %d", irq);
464 
465 	return true;
466 }
467 
468 #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
469 #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,7)
470 #define	BCM2836MP_GPU_IRQ	__BIT(8)
471 #define	BCM2836MP_PMU_IRQ	__BIT(9)
472 #define	BCM2836MP_ALL_IRQS	(BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
473 
474 static void
475 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
476     uint32_t irq_mask)
477 {
478 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
479 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
480 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
481 
482 	KASSERT(irqbase == 0);
483 
484 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
485 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
486 		uint32_t val = bus_space_read_4(iot, ioh,
487 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
488 		val |= mask;
489 		bus_space_write_4(iot, ioh,
490 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
491 		    val);
492 		bus_space_barrier(iot, ioh,
493 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
494 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
495 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
496 	}
497 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
498 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
499 		uint32_t val = bus_space_read_4(iot, ioh,
500 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
501 		val |= mask;
502 		bus_space_write_4(iot, ioh,
503 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
504 		    val);
505 		bus_space_barrier(iot, ioh,
506 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
507 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
508 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
509 	}
510 	if (irq_mask & BCM2836MP_PMU_IRQ) {
511 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
512 		    __BIT(cpuid));
513 		bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
514 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
515 	}
516 
517 	return;
518 }
519 
520 static void
521 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
522     uint32_t irq_mask)
523 {
524 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
525 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
526 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
527 
528 	KASSERT(irqbase == 0);
529 
530 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
531 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
532 		uint32_t val = bus_space_read_4(iot, ioh,
533 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
534 		val &= ~mask;
535 		bus_space_write_4(iot, ioh,
536 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
537 		    val);
538 	}
539 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
540 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
541 		uint32_t val = bus_space_read_4(iot, ioh,
542 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
543 		val &= ~mask;
544 		bus_space_write_4(iot, ioh,
545 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
546 		    val);
547 	}
548 	if (irq_mask & BCM2836MP_PMU_IRQ) {
549 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
550 		    __BIT(cpuid));
551 	}
552 
553 	bcm2835_barrier();
554 	return;
555 }
556 
557 static int
558 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
559 {
560 	struct cpu_info * const ci = curcpu();
561 	const cpuid_t cpuid = ci->ci_core_id;
562 	uint32_t lpending;
563 	int ipl = 0;
564 
565 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
566 
567 	bcm2835_barrier();
568 
569 	lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
570 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
571 
572 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
573 	if (lpending & BCM2836MP_ALL_IRQS) {
574 		ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
575 		    lpending & BCM2836MP_ALL_IRQS);
576 	}
577 
578 	return ipl;
579 }
580 
581 static void
582 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
583 {
584 	/* Nothing really*/
585 	KASSERT(is->is_irq >= 0);
586 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
587 }
588 
589 static void
590 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
591 {
592 
593 	irq %= BCM2836_NIRQPERCPU;
594 	strlcpy(buf, bcm2836mp_sources[irq], len);
595 }
596 
597 
598 #if defined(MULTIPROCESSOR)
599 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
600 {
601 
602 	/* Enable IRQ and not FIQ */
603 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
604 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_core_id), 1);
605 }
606 
607 static void
608 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
609 {
610 	KASSERT(pic != NULL);
611 	KASSERT(pic != &bcm2835_pic);
612 	KASSERT(pic->pic_cpus != NULL);
613 
614 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
615 
616 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
617 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
618 }
619 
620 int
621 bcm2836mp_ipi_handler(void *priv)
622 {
623 	const struct cpu_info *ci = curcpu();
624 	const cpuid_t cpuid = ci->ci_core_id;
625 	uint32_t ipimask, bit;
626 
627 	ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
628 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
629 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
630 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
631 
632 	while ((bit = ffs(ipimask)) > 0) {
633 		const u_int ipi = bit - 1;
634 		switch (ipi) {
635 		case IPI_AST:
636 			pic_ipi_ast(priv);
637 			break;
638 		case IPI_NOP:
639 			pic_ipi_nop(priv);
640 			break;
641 #ifdef __HAVE_PREEMPTION
642 		case IPI_KPREEMPT:
643 			pic_ipi_kpreempt(priv);
644 			break;
645 #endif
646 		case IPI_XCALL:
647 			pic_ipi_xcall(priv);
648 			break;
649 		case IPI_GENERIC:
650 			pic_ipi_generic(priv);
651 			break;
652 		case IPI_SHOOTDOWN:
653 			pic_ipi_shootdown(priv);
654 			break;
655 #ifdef DDB
656 		case IPI_DDB:
657 			pic_ipi_ddb(priv);
658 			break;
659 #endif
660 		}
661 		ipimask &= ~__BIT(ipi);
662 	}
663 
664 	return 1;
665 }
666 #endif
667 
668 static void
669 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
670 {
671 	const cpuid_t cpuid = ci->ci_core_id;
672 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
673 
674 #if defined(MULTIPROCESSOR)
675 	pic->pic_cpus = ci->ci_kcpuset;
676 
677 	/*
678 	 * Append "#n" to avoid duplication of .pic_name[]
679 	 * It should be a unique id for intr_get_source()
680 	 */
681 	char suffix[sizeof("#00000")];
682 	snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
683 	strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
684 #endif
685 	pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
686 
687 #if defined(MULTIPROCESSOR)
688 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
689 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
690 
691 	struct bcm2836mp_interrupt *bip;
692 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
693 		if (bip->bi_done)
694 			continue;
695 
696 		const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
697 		void *ih = intr_establish(irq, bip->bi_ipl,
698 		    IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
699 
700 		bip->bi_ihs[cpuid] = ih;
701 	}
702 #endif
703 }
704 
705 static int
706 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
707 {
708 	if (!specifier)
709 		return -1;
710 	return be32toh(specifier[0]);
711 }
712 
713 static void *
714 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
715     int (*func)(void *), void *arg)
716 {
717 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
718 	struct bcm2836mp_interrupt *bip;
719 	void *ih;
720 
721 	int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
722 	if (irq == -1)
723 		return NULL;
724 
725 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
726 		if (irq == bip->bi_irq)
727 			return NULL;
728 	}
729 
730 	bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
731 	if (bip == NULL)
732 		return NULL;
733 
734 	bip->bi_done = false;
735 	bip->bi_irq = irq;
736 	bip->bi_ipl = ipl;
737 	bip->bi_flags = IST_LEVEL | iflags;
738 	bip->bi_func = func;
739 	bip->bi_arg = arg;
740 
741 	/*
742 	 * If we're not cold and the BPs have been started then we can register the
743 	 * interupt for all CPUs now, e.g. PMU
744 	 */
745 	if (!cold) {
746 		for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
747 			ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
748 			    IST_LEVEL | iflags, func, arg);
749 			if (!ih) {
750 				kmem_free(bip, sizeof(*bip));
751 				return NULL;
752 			}
753 			bip->bi_ihs[cpuid] = ih;
754 
755 		}
756 		bip->bi_done = true;
757 		ih = bip->bi_ihs[0];
758 		goto done;
759 	}
760 
761 	/*
762 	 * Otherwise we can only establish the interrupt for the BP and
763 	 * delay until bcm2836mp_intr_init is called for each AP, e.g.
764 	 * gtmr
765 	 */
766 	ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
767 	    IST_LEVEL | iflags, func, arg);
768 	if (!ih) {
769 		kmem_free(bip, sizeof(*bip));
770 		return NULL;
771 	}
772 
773 	bip->bi_ihs[0] = ih;
774 	for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
775 		bip->bi_ihs[cpuid] = NULL;
776 
777 done:
778 	TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
779 
780 	/*
781 	 * Return the intr_establish handle for cpu 0 for API compatibility.
782 	 * Any cpu would do here as these sources don't support set_affinity
783 	 * when the handle is used in interrupt_distribute(9)
784 	 */
785 	return ih;
786 }
787 
788 static void
789 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
790 {
791 	struct bcm2836mp_interrupt *bip;
792 
793 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
794 		if (bip->bi_ihs[0] == ih)
795 			break;
796 	}
797 
798 	if (bip == NULL)
799 		return;
800 
801 	for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
802 		intr_disestablish(bip->bi_ihs[cpuid]);
803 
804 	TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
805 
806 	kmem_free(bip, sizeof(*bip));
807 }
808 
809 static bool
810 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
811     size_t buflen)
812 {
813 	int irq;
814 
815 	irq = bcm2836mp_icu_fdt_decode_irq(specifier);
816 	if (irq == -1)
817 		return false;
818 
819 	snprintf(buf, buflen, "local_intc irq %d", irq);
820 
821 	return true;
822 }
823