Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.21
      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