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