Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.18
      1 /*	$NetBSD: bcm2835_intr.c,v 1.18 2019/03/01 08:05:46 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.18 2019/03/01 08:05:46 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 static 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 static 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