Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.24
      1 /*	$NetBSD: bcm2835_intr.c,v 1.24 2019/09/25 16:57:10 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.24 2019/09/25 16:57:10 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 static struct bcm2835icu_softc *bcml1icu_sc;
    174 static 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 	KASSERT(cpuid < BCM2836_NCPUS);
    313 
    314 	ci->ci_data.cpu_nintr++;
    315 
    316 	bcm2835_barrier();
    317 	if (cpuid == 0) {
    318 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    319 	}
    320 #if defined(SOC_BCM2836)
    321 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
    322 #endif
    323 
    324 	/*
    325 	 * Record the pending_ipls and deliver them if we can.
    326 	 */
    327 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    328 		pic_do_pending_ints(I32_bit, oldipl, frame);
    329 }
    330 
    331 static void
    332 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    333     uint32_t irq_mask)
    334 {
    335 
    336 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    337 	bcm2835_barrier();
    338 }
    339 
    340 static void
    341 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    342     uint32_t irq_mask)
    343 {
    344 
    345 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    346 	bcm2835_barrier();
    347 }
    348 
    349 /*
    350  * Called with interrupts disabled
    351  */
    352 static int
    353 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    354 {
    355 	int ipl = 0;
    356 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    357 
    358 	bcm2835_barrier();
    359 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    360 	if (bpending == 0)
    361 		return 0;
    362 
    363 	armirq = bpending & BCM2835_INTBIT_ARM;
    364 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    365 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    366 
    367 	if (armirq) {
    368 		ipl |= pic_mark_pending_sources(pic,
    369 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
    370 	}
    371 
    372 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    373 		uint32_t pending1;
    374 
    375 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    376 		ipl |= pic_mark_pending_sources(pic,
    377 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
    378 	}
    379 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    380 		uint32_t pending2;
    381 
    382 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    383 		ipl |= pic_mark_pending_sources(pic,
    384 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
    385 	}
    386 
    387 	return ipl;
    388 }
    389 
    390 static void
    391 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    392 {
    393 
    394 	/* Nothing really*/
    395 	KASSERT(is->is_irq < BCM2835_NIRQ);
    396 	KASSERT(is->is_type == IST_LEVEL);
    397 }
    398 
    399 static void
    400 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    401 {
    402 
    403 	strlcpy(buf, bcm2835_sources[irq], len);
    404 }
    405 
    406 static int
    407 bcm2835_icu_fdt_decode_irq(u_int *specifier)
    408 {
    409 	u_int base;
    410 
    411 	if (!specifier)
    412 		return -1;
    413 
    414 	/* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
    415 	/* 2nd cell is the irq relative to that bank */
    416 
    417 	const u_int bank = be32toh(specifier[0]);
    418 	switch (bank) {
    419 	case 0:
    420 		base = BCM2835_INT_BASICBASE;
    421 		break;
    422 	case 1:
    423 		base = BCM2835_INT_GPU0BASE;
    424 		break;
    425 	case 2:
    426 		base = BCM2835_INT_GPU1BASE;
    427 		break;
    428 	default:
    429 		return -1;
    430 	}
    431 	const u_int off = be32toh(specifier[1]);
    432 
    433 	return base + off;
    434 }
    435 
    436 static void *
    437 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    438     int (*func)(void *), void *arg)
    439 {
    440 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    441 	int irq;
    442 
    443 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    444 	if (irq == -1)
    445 		return NULL;
    446 
    447 	return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
    448 }
    449 
    450 static void
    451 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
    452 {
    453 	intr_disestablish(ih);
    454 }
    455 
    456 static bool
    457 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
    458 {
    459 	int irq;
    460 
    461 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    462 	if (irq == -1)
    463 		return false;
    464 
    465 	snprintf(buf, buflen, "icu irq %d", irq);
    466 
    467 	return true;
    468 }
    469 
    470 #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    471 #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,7)
    472 #define	BCM2836MP_GPU_IRQ	__BIT(8)
    473 #define	BCM2836MP_PMU_IRQ	__BIT(9)
    474 #define	BCM2836MP_ALL_IRQS	(BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
    475 
    476 static void
    477 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    478     uint32_t irq_mask)
    479 {
    480 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    481 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    482 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    483 
    484 	KASSERT(cpuid < BCM2836_NCPUS);
    485 	KASSERT(irqbase == 0);
    486 
    487 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    488 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    489 		uint32_t val = bus_space_read_4(iot, ioh,
    490 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    491 		val |= mask;
    492 		bus_space_write_4(iot, ioh,
    493 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    494 		    val);
    495 		bus_space_barrier(iot, ioh,
    496 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    497 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    498 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    499 	}
    500 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    501 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    502 		uint32_t val = bus_space_read_4(iot, ioh,
    503 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    504 		val |= mask;
    505 		bus_space_write_4(iot, ioh,
    506 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    507 		    val);
    508 		bus_space_barrier(iot, ioh,
    509 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    510 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    511 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    512 	}
    513 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    514 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
    515 		    __BIT(cpuid));
    516 		bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
    517 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    518 	}
    519 
    520 	return;
    521 }
    522 
    523 static void
    524 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    525     uint32_t irq_mask)
    526 {
    527 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    528 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    529 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    530 
    531 	KASSERT(cpuid < BCM2836_NCPUS);
    532 	KASSERT(irqbase == 0);
    533 
    534 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    535 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    536 		uint32_t val = bus_space_read_4(iot, ioh,
    537 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    538 		val &= ~mask;
    539 		bus_space_write_4(iot, ioh,
    540 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    541 		    val);
    542 	}
    543 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    544 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    545 		uint32_t val = bus_space_read_4(iot, ioh,
    546 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    547 		val &= ~mask;
    548 		bus_space_write_4(iot, ioh,
    549 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    550 		    val);
    551 	}
    552 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    553 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
    554 		    __BIT(cpuid));
    555 	}
    556 
    557 	bcm2835_barrier();
    558 	return;
    559 }
    560 
    561 static int
    562 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    563 {
    564 	struct cpu_info * const ci = curcpu();
    565 	const cpuid_t cpuid = ci->ci_core_id;
    566 	uint32_t lpending;
    567 	int ipl = 0;
    568 
    569 	KASSERT(cpuid < BCM2836_NCPUS);
    570 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    571 
    572 	bcm2835_barrier();
    573 
    574 	lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    575 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    576 
    577 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    578 	if (lpending & BCM2836MP_ALL_IRQS) {
    579 		ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
    580 		    lpending & BCM2836MP_ALL_IRQS);
    581 	}
    582 
    583 	return ipl;
    584 }
    585 
    586 static void
    587 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    588 {
    589 	/* Nothing really*/
    590 	KASSERT(is->is_irq >= 0);
    591 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
    592 }
    593 
    594 static void
    595 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    596 {
    597 
    598 	irq %= BCM2836_NIRQPERCPU;
    599 	strlcpy(buf, bcm2836mp_sources[irq], len);
    600 }
    601 
    602 
    603 #if defined(MULTIPROCESSOR)
    604 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
    605 {
    606 	const cpuid_t cpuid = ci->ci_core_id;
    607 
    608 	KASSERT(cpuid < BCM2836_NCPUS);
    609 
    610 	/* Enable IRQ and not FIQ */
    611 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    612 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid), 1);
    613 }
    614 
    615 static void
    616 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
    617 {
    618 	KASSERT(pic != NULL);
    619 	KASSERT(pic != &bcm2835_pic);
    620 	KASSERT(pic->pic_cpus != NULL);
    621 
    622 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    623 	KASSERT(cpuid < BCM2836_NCPUS);
    624 
    625 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    626 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
    627 }
    628 
    629 int
    630 bcm2836mp_ipi_handler(void *priv)
    631 {
    632 	const struct cpu_info *ci = curcpu();
    633 	const cpuid_t cpuid = ci->ci_core_id;
    634 	uint32_t ipimask, bit;
    635 
    636 	KASSERT(cpuid < BCM2836_NCPUS);
    637 
    638 	ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    639 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
    640 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    641 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
    642 
    643 	while ((bit = ffs(ipimask)) > 0) {
    644 		const u_int ipi = bit - 1;
    645 		switch (ipi) {
    646 		case IPI_AST:
    647 			pic_ipi_ast(priv);
    648 			break;
    649 		case IPI_NOP:
    650 			pic_ipi_nop(priv);
    651 			break;
    652 #ifdef __HAVE_PREEMPTION
    653 		case IPI_KPREEMPT:
    654 			pic_ipi_kpreempt(priv);
    655 			break;
    656 #endif
    657 		case IPI_XCALL:
    658 			pic_ipi_xcall(priv);
    659 			break;
    660 		case IPI_GENERIC:
    661 			pic_ipi_generic(priv);
    662 			break;
    663 		case IPI_SHOOTDOWN:
    664 			pic_ipi_shootdown(priv);
    665 			break;
    666 #ifdef DDB
    667 		case IPI_DDB:
    668 			pic_ipi_ddb(priv);
    669 			break;
    670 #endif
    671 		}
    672 		ipimask &= ~__BIT(ipi);
    673 	}
    674 
    675 	return 1;
    676 }
    677 #endif
    678 
    679 static void
    680 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
    681 {
    682 	const cpuid_t cpuid = ci->ci_core_id;
    683 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
    684 
    685 	KASSERT(cpuid < BCM2836_NCPUS);
    686 
    687 #if defined(MULTIPROCESSOR)
    688 	pic->pic_cpus = ci->ci_kcpuset;
    689 
    690 	/*
    691 	 * Append "#n" to avoid duplication of .pic_name[]
    692 	 * It should be a unique id for intr_get_source()
    693 	 */
    694 	char suffix[sizeof("#00000")];
    695 	snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
    696 	strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
    697 #endif
    698 	pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
    699 
    700 #if defined(MULTIPROCESSOR)
    701 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
    702 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
    703 
    704 	struct bcm2836mp_interrupt *bip;
    705 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    706 		if (bip->bi_done)
    707 			continue;
    708 
    709 		const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
    710 		void *ih = intr_establish(irq, bip->bi_ipl,
    711 		    IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
    712 
    713 		bip->bi_ihs[cpuid] = ih;
    714 	}
    715 #endif
    716 }
    717 
    718 static int
    719 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
    720 {
    721 
    722 	if (!specifier)
    723 		return -1;
    724 	return be32toh(specifier[0]);
    725 }
    726 
    727 static void *
    728 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    729     int (*func)(void *), void *arg)
    730 {
    731 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    732 	struct bcm2836mp_interrupt *bip;
    733 	void *ih;
    734 
    735 	int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    736 	if (irq == -1)
    737 		return NULL;
    738 
    739 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    740 		if (irq == bip->bi_irq)
    741 			return NULL;
    742 	}
    743 
    744 	bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
    745 	if (bip == NULL)
    746 		return NULL;
    747 
    748 	bip->bi_done = false;
    749 	bip->bi_irq = irq;
    750 	bip->bi_ipl = ipl;
    751 	bip->bi_flags = IST_LEVEL | iflags;
    752 	bip->bi_func = func;
    753 	bip->bi_arg = arg;
    754 
    755 	/*
    756 	 * If we're not cold and the BPs have been started then we can register the
    757 	 * interupt for all CPUs now, e.g. PMU
    758 	 */
    759 	if (!cold) {
    760 		for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
    761 			ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
    762 			    IST_LEVEL | iflags, func, arg);
    763 			if (!ih) {
    764 				kmem_free(bip, sizeof(*bip));
    765 				return NULL;
    766 			}
    767 			bip->bi_ihs[cpuid] = ih;
    768 
    769 		}
    770 		bip->bi_done = true;
    771 		ih = bip->bi_ihs[0];
    772 		goto done;
    773 	}
    774 
    775 	/*
    776 	 * Otherwise we can only establish the interrupt for the BP and
    777 	 * delay until bcm2836mp_intr_init is called for each AP, e.g.
    778 	 * gtmr
    779 	 */
    780 	ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
    781 	    IST_LEVEL | iflags, func, arg);
    782 	if (!ih) {
    783 		kmem_free(bip, sizeof(*bip));
    784 		return NULL;
    785 	}
    786 
    787 	bip->bi_ihs[0] = ih;
    788 	for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
    789 		bip->bi_ihs[cpuid] = NULL;
    790 
    791 done:
    792 	TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
    793 
    794 	/*
    795 	 * Return the intr_establish handle for cpu 0 for API compatibility.
    796 	 * Any cpu would do here as these sources don't support set_affinity
    797 	 * when the handle is used in interrupt_distribute(9)
    798 	 */
    799 	return ih;
    800 }
    801 
    802 static void
    803 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
    804 {
    805 	struct bcm2836mp_interrupt *bip;
    806 
    807 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    808 		if (bip->bi_ihs[0] == ih)
    809 			break;
    810 	}
    811 
    812 	if (bip == NULL)
    813 		return;
    814 
    815 	for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
    816 		intr_disestablish(bip->bi_ihs[cpuid]);
    817 
    818 	TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
    819 
    820 	kmem_free(bip, sizeof(*bip));
    821 }
    822 
    823 static bool
    824 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
    825     size_t buflen)
    826 {
    827 	int irq;
    828 
    829 	irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    830 	if (irq == -1)
    831 		return false;
    832 
    833 	snprintf(buf, buflen, "local_intc irq %d", irq);
    834 
    835 	return true;
    836 }
    837