Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.2.2.2
      1  1.2.2.2  jdolecek /*	$NetBSD: bcm2835_intr.c,v 1.2.2.2 2017/12/03 11:35:52 jdolecek Exp $	*/
      2      1.1     skrll 
      3      1.1     skrll /*-
      4  1.2.2.2  jdolecek  * Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
      5      1.1     skrll  * All rights reserved.
      6      1.1     skrll  *
      7      1.1     skrll  * This code is derived from software contributed to The NetBSD Foundation
      8      1.1     skrll  * by Nick Hudson
      9      1.1     skrll  *
     10      1.1     skrll  * Redistribution and use in source and binary forms, with or without
     11      1.1     skrll  * modification, are permitted provided that the following conditions
     12      1.1     skrll  * are met:
     13      1.1     skrll  * 1. Redistributions of source code must retain the above copyright
     14      1.1     skrll  *    notice, this list of conditions and the following disclaimer.
     15      1.1     skrll  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1     skrll  *    notice, this list of conditions and the following disclaimer in the
     17      1.1     skrll  *    documentation and/or other materials provided with the distribution.
     18      1.1     skrll  *
     19      1.1     skrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20      1.1     skrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21      1.1     skrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22      1.1     skrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23      1.1     skrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24      1.1     skrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25      1.1     skrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26      1.1     skrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27      1.1     skrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28      1.1     skrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29      1.1     skrll  * POSSIBILITY OF SUCH DAMAGE.
     30      1.1     skrll  */
     31      1.1     skrll 
     32      1.1     skrll #include <sys/cdefs.h>
     33  1.2.2.2  jdolecek __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.2.2.2 2017/12/03 11:35:52 jdolecek Exp $");
     34      1.1     skrll 
     35      1.1     skrll #define _INTR_PRIVATE
     36      1.1     skrll 
     37  1.2.2.2  jdolecek #include "opt_bcm283x.h"
     38  1.2.2.2  jdolecek 
     39      1.1     skrll #include <sys/param.h>
     40  1.2.2.2  jdolecek #include <sys/bus.h>
     41  1.2.2.2  jdolecek #include <sys/cpu.h>
     42      1.1     skrll #include <sys/device.h>
     43  1.2.2.2  jdolecek #include <sys/proc.h>
     44      1.1     skrll 
     45      1.1     skrll #include <machine/intr.h>
     46  1.2.2.2  jdolecek 
     47  1.2.2.2  jdolecek #include <arm/locore.h>
     48      1.1     skrll 
     49      1.1     skrll #include <arm/pic/picvar.h>
     50  1.2.2.2  jdolecek #include <arm/cortex/gtmr_var.h>
     51      1.1     skrll 
     52      1.1     skrll #include <arm/broadcom/bcm_amba.h>
     53      1.1     skrll #include <arm/broadcom/bcm2835reg.h>
     54  1.2.2.2  jdolecek #include <arm/broadcom/bcm2835var.h>
     55      1.1     skrll 
     56      1.1     skrll static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     57      1.1     skrll static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     58      1.1     skrll static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     59      1.1     skrll static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     60      1.1     skrll static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     61      1.1     skrll     size_t);
     62      1.1     skrll 
     63  1.2.2.2  jdolecek #if defined(BCM2836)
     64  1.2.2.2  jdolecek static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     65  1.2.2.2  jdolecek static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     66  1.2.2.2  jdolecek static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
     67  1.2.2.2  jdolecek static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
     68  1.2.2.2  jdolecek static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
     69  1.2.2.2  jdolecek     size_t);
     70  1.2.2.2  jdolecek #ifdef MULTIPROCESSOR
     71  1.2.2.2  jdolecek int bcm2836mp_ipi_handler(void *);
     72  1.2.2.2  jdolecek static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
     73  1.2.2.2  jdolecek static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
     74  1.2.2.2  jdolecek #endif
     75  1.2.2.2  jdolecek #endif
     76  1.2.2.2  jdolecek 
     77      1.1     skrll static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     78      1.1     skrll static void bcm2835_icu_attach(device_t, device_t, void *);
     79      1.1     skrll 
     80      1.1     skrll static struct pic_ops bcm2835_picops = {
     81      1.1     skrll 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
     82      1.1     skrll 	.pic_block_irqs = bcm2835_pic_block_irqs,
     83      1.1     skrll 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
     84      1.1     skrll 	.pic_establish_irq = bcm2835_pic_establish_irq,
     85      1.1     skrll 	.pic_source_name = bcm2835_pic_source_name,
     86      1.1     skrll };
     87      1.1     skrll 
     88      1.1     skrll struct pic_softc bcm2835_pic = {
     89      1.1     skrll 	.pic_ops = &bcm2835_picops,
     90      1.1     skrll 	.pic_maxsources = BCM2835_NIRQ,
     91      1.1     skrll 	.pic_name = "bcm2835 pic",
     92      1.1     skrll };
     93      1.1     skrll 
     94  1.2.2.2  jdolecek #if defined(BCM2836)
     95  1.2.2.2  jdolecek static struct pic_ops bcm2836mp_picops = {
     96  1.2.2.2  jdolecek 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
     97  1.2.2.2  jdolecek 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
     98  1.2.2.2  jdolecek 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
     99  1.2.2.2  jdolecek 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
    100  1.2.2.2  jdolecek 	.pic_source_name = bcm2836mp_pic_source_name,
    101  1.2.2.2  jdolecek #if defined(MULTIPROCESSOR)
    102  1.2.2.2  jdolecek 	.pic_cpu_init = bcm2836mp_cpu_init,
    103  1.2.2.2  jdolecek 	.pic_ipi_send = bcm2836mp_send_ipi,
    104  1.2.2.2  jdolecek #endif
    105  1.2.2.2  jdolecek };
    106  1.2.2.2  jdolecek 
    107  1.2.2.2  jdolecek struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
    108  1.2.2.2  jdolecek 	[0 ... BCM2836_NCPUS - 1] = {
    109  1.2.2.2  jdolecek 		.pic_ops = &bcm2836mp_picops,
    110  1.2.2.2  jdolecek 		.pic_maxsources = BCM2836_NIRQPERCPU,
    111  1.2.2.2  jdolecek 		.pic_name = "bcm2836 pic",
    112  1.2.2.2  jdolecek 	}
    113  1.2.2.2  jdolecek };
    114  1.2.2.2  jdolecek #endif
    115  1.2.2.2  jdolecek 
    116      1.1     skrll struct bcm2835icu_softc {
    117      1.1     skrll 	device_t		sc_dev;
    118      1.1     skrll 	bus_space_tag_t		sc_iot;
    119      1.1     skrll 	bus_space_handle_t	sc_ioh;
    120      1.1     skrll 	struct pic_softc	*sc_pic;
    121      1.1     skrll };
    122      1.1     skrll 
    123      1.1     skrll struct bcm2835icu_softc *bcmicu_sc;
    124  1.2.2.1       tls 
    125      1.1     skrll #define read_bcm2835reg(o)	\
    126      1.1     skrll 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
    127  1.2.2.1       tls 
    128      1.1     skrll #define write_bcm2835reg(o, v)	\
    129      1.1     skrll 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
    130      1.1     skrll 
    131      1.1     skrll 
    132      1.1     skrll #define bcm2835_barrier() \
    133      1.1     skrll 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
    134      1.1     skrll 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
    135  1.2.2.1       tls 
    136      1.1     skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
    137      1.1     skrll 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
    138      1.1     skrll 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
    139      1.2  jakllsch 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
    140      1.2  jakllsch 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
    141  1.2.2.2  jdolecek 	"dma0",		"dma1",		"dma2",		"dma3",
    142  1.2.2.2  jdolecek 	"dma4",		"dma5",		"dma6",		"dma7",
    143  1.2.2.2  jdolecek 	"dma8",		"dma9",		"dma10",	"dma11",
    144  1.2.2.2  jdolecek 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
    145      1.1     skrll 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    146      1.1     skrll 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    147      1.1     skrll 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    148      1.1     skrll 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    149      1.1     skrll 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    150      1.1     skrll 	"gpio[3]",	"i2c",		"spi",		"pcm",
    151  1.2.2.2  jdolecek 	"sdhost",	"uart",		"(unused 58)",	"(unused 59)",
    152      1.1     skrll 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    153      1.1     skrll 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    154      1.1     skrll 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    155      1.1     skrll };
    156      1.1     skrll 
    157  1.2.2.2  jdolecek #if defined(BCM2836)
    158  1.2.2.2  jdolecek static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
    159  1.2.2.2  jdolecek 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
    160  1.2.2.2  jdolecek 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
    161  1.2.2.2  jdolecek };
    162  1.2.2.2  jdolecek #endif
    163  1.2.2.2  jdolecek 
    164  1.2.2.2  jdolecek #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
    165  1.2.2.2  jdolecek 
    166      1.1     skrll #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    167      1.1     skrll #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    168      1.1     skrll #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    169      1.1     skrll #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    170      1.1     skrll #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    171      1.1     skrll 
    172      1.1     skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    173      1.1     skrll     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    174      1.1     skrll 
    175      1.1     skrll static int
    176      1.1     skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    177      1.1     skrll {
    178      1.1     skrll 	struct amba_attach_args *aaa = aux;
    179      1.1     skrll 
    180      1.1     skrll 	if (strcmp(aaa->aaa_name, "icu") != 0)
    181      1.1     skrll 		return 0;
    182      1.1     skrll 
    183      1.1     skrll 	return 1;
    184      1.1     skrll }
    185      1.1     skrll 
    186      1.1     skrll static void
    187      1.1     skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    188      1.1     skrll {
    189      1.1     skrll 	struct bcm2835icu_softc *sc = device_private(self);
    190      1.1     skrll 	struct amba_attach_args *aaa = aux;
    191      1.1     skrll 
    192      1.1     skrll 	sc->sc_dev = self;
    193      1.1     skrll 	sc->sc_iot = aaa->aaa_iot;
    194      1.1     skrll 	sc->sc_pic = &bcm2835_pic;
    195      1.1     skrll 
    196      1.1     skrll 	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
    197      1.1     skrll 	    &sc->sc_ioh)) {
    198      1.1     skrll 		aprint_error_dev(self, "unable to map device\n");
    199      1.1     skrll 		return;
    200      1.1     skrll 	}
    201      1.1     skrll 
    202      1.1     skrll 	bcmicu_sc = sc;
    203  1.2.2.2  jdolecek 
    204  1.2.2.2  jdolecek #if defined(BCM2836)
    205  1.2.2.2  jdolecek #if defined(MULTIPROCESSOR)
    206  1.2.2.2  jdolecek 	aprint_normal(": Multiprocessor");
    207  1.2.2.2  jdolecek 	bcm2836mp_intr_init(curcpu());
    208  1.2.2.2  jdolecek #else
    209  1.2.2.2  jdolecek 	pic_add(&bcm2836mp_pic[0], BCM2836_INT_BASECPUN(0));
    210  1.2.2.2  jdolecek #endif
    211  1.2.2.2  jdolecek #endif /* BCM2836 */
    212  1.2.2.2  jdolecek 	pic_add(sc->sc_pic, BCM2835_INT_BASE);
    213  1.2.2.2  jdolecek 
    214      1.1     skrll 	aprint_normal("\n");
    215      1.1     skrll }
    216      1.1     skrll 
    217      1.1     skrll void
    218      1.1     skrll bcm2835_irq_handler(void *frame)
    219      1.1     skrll {
    220      1.1     skrll 	struct cpu_info * const ci = curcpu();
    221      1.1     skrll 	const int oldipl = ci->ci_cpl;
    222  1.2.2.2  jdolecek 	const cpuid_t cpuid = ci->ci_cpuid;
    223      1.1     skrll 	const uint32_t oldipl_mask = __BIT(oldipl);
    224      1.1     skrll 	int ipl_mask = 0;
    225      1.1     skrll 
    226      1.1     skrll 	ci->ci_data.cpu_nintr++;
    227      1.1     skrll 
    228      1.1     skrll 	bcm2835_barrier();
    229  1.2.2.2  jdolecek 	if (cpuid == 0) {
    230  1.2.2.2  jdolecek 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    231  1.2.2.2  jdolecek 	}
    232  1.2.2.2  jdolecek #if defined(BCM2836)
    233  1.2.2.2  jdolecek 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
    234  1.2.2.2  jdolecek #endif
    235      1.1     skrll 
    236      1.1     skrll 	/*
    237      1.1     skrll 	 * Record the pending_ipls and deliver them if we can.
    238      1.1     skrll 	 */
    239      1.1     skrll 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    240      1.1     skrll 		pic_do_pending_ints(I32_bit, oldipl, frame);
    241      1.1     skrll }
    242      1.1     skrll 
    243      1.1     skrll static void
    244      1.1     skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    245      1.1     skrll     uint32_t irq_mask)
    246      1.1     skrll {
    247      1.1     skrll 
    248      1.1     skrll 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    249      1.1     skrll 	bcm2835_barrier();
    250      1.1     skrll }
    251      1.1     skrll 
    252      1.1     skrll static void
    253      1.1     skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    254      1.1     skrll     uint32_t irq_mask)
    255      1.1     skrll {
    256      1.1     skrll 
    257      1.1     skrll 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    258      1.1     skrll 	bcm2835_barrier();
    259      1.1     skrll }
    260      1.1     skrll 
    261      1.1     skrll /*
    262      1.1     skrll  * Called with interrupts disabled
    263      1.1     skrll  */
    264      1.1     skrll static int
    265      1.1     skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    266      1.1     skrll {
    267      1.1     skrll 	int ipl = 0;
    268      1.1     skrll 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    269      1.1     skrll 
    270      1.1     skrll 	bcm2835_barrier();
    271      1.1     skrll 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    272      1.1     skrll 	if (bpending == 0)
    273      1.1     skrll 		return 0;
    274      1.1     skrll 
    275      1.1     skrll 	armirq = bpending & BCM2835_INTBIT_ARM;
    276      1.1     skrll 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    277      1.1     skrll 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    278      1.1     skrll 
    279      1.1     skrll 	if (armirq) {
    280  1.2.2.2  jdolecek 		ipl |= pic_mark_pending_sources(pic,
    281  1.2.2.2  jdolecek 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
    282      1.1     skrll 	}
    283      1.1     skrll 
    284      1.1     skrll 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    285      1.1     skrll 		uint32_t pending1;
    286  1.2.2.1       tls 
    287      1.1     skrll 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    288  1.2.2.2  jdolecek 		ipl |= pic_mark_pending_sources(pic,
    289  1.2.2.2  jdolecek 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
    290      1.1     skrll 	}
    291      1.1     skrll 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    292      1.1     skrll 		uint32_t pending2;
    293  1.2.2.1       tls 
    294      1.1     skrll 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    295  1.2.2.2  jdolecek 		ipl |= pic_mark_pending_sources(pic,
    296  1.2.2.2  jdolecek 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
    297      1.1     skrll 	}
    298  1.2.2.1       tls 
    299      1.1     skrll 	return ipl;
    300      1.1     skrll }
    301      1.1     skrll 
    302      1.1     skrll static void
    303      1.1     skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    304      1.1     skrll {
    305      1.1     skrll 
    306      1.1     skrll 	/* Nothing really*/
    307      1.1     skrll 	KASSERT(is->is_irq < BCM2835_NIRQ);
    308      1.1     skrll 	KASSERT(is->is_type == IST_LEVEL);
    309      1.1     skrll }
    310      1.1     skrll 
    311      1.1     skrll static void
    312      1.1     skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    313      1.1     skrll {
    314      1.1     skrll 
    315      1.1     skrll 	strlcpy(buf, bcm2835_sources[irq], len);
    316      1.1     skrll }
    317  1.2.2.2  jdolecek 
    318  1.2.2.2  jdolecek 
    319  1.2.2.2  jdolecek #if defined(BCM2836)
    320  1.2.2.2  jdolecek 
    321  1.2.2.2  jdolecek #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    322  1.2.2.2  jdolecek #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,4)
    323  1.2.2.2  jdolecek 
    324  1.2.2.2  jdolecek #define	BCM2836MP_ALL_IRQS	\
    325  1.2.2.2  jdolecek     (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
    326  1.2.2.2  jdolecek 
    327  1.2.2.2  jdolecek static void
    328  1.2.2.2  jdolecek bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    329  1.2.2.2  jdolecek     uint32_t irq_mask)
    330  1.2.2.2  jdolecek {
    331  1.2.2.2  jdolecek 	struct cpu_info * const ci = curcpu();
    332  1.2.2.2  jdolecek 	const cpuid_t cpuid = ci->ci_cpuid;
    333  1.2.2.2  jdolecek 
    334  1.2.2.2  jdolecek 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    335  1.2.2.2  jdolecek 	KASSERT(irqbase == 0);
    336  1.2.2.2  jdolecek 
    337  1.2.2.2  jdolecek 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    338  1.2.2.2  jdolecek 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    339  1.2.2.2  jdolecek 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    340  1.2.2.2  jdolecek 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    341  1.2.2.2  jdolecek 		val |= mask;
    342  1.2.2.2  jdolecek 		bus_space_write_4(al_iot, al_ioh,
    343  1.2.2.2  jdolecek 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    344  1.2.2.2  jdolecek 		    val);
    345  1.2.2.2  jdolecek 		bus_space_barrier(al_iot, al_ioh,
    346  1.2.2.2  jdolecek 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    347  1.2.2.2  jdolecek 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    348  1.2.2.2  jdolecek 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    349  1.2.2.2  jdolecek 	}
    350  1.2.2.2  jdolecek 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    351  1.2.2.2  jdolecek 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    352  1.2.2.2  jdolecek 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    353  1.2.2.2  jdolecek 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    354  1.2.2.2  jdolecek 		val |= mask;
    355  1.2.2.2  jdolecek 		bus_space_write_4(al_iot, al_ioh,
    356  1.2.2.2  jdolecek 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    357  1.2.2.2  jdolecek 		    val);
    358  1.2.2.2  jdolecek 		bus_space_barrier(al_iot, al_ioh,
    359  1.2.2.2  jdolecek 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    360  1.2.2.2  jdolecek 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    361  1.2.2.2  jdolecek 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    362  1.2.2.2  jdolecek 	}
    363  1.2.2.2  jdolecek 
    364  1.2.2.2  jdolecek 	return;
    365  1.2.2.2  jdolecek }
    366  1.2.2.2  jdolecek 
    367  1.2.2.2  jdolecek static void
    368  1.2.2.2  jdolecek bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    369  1.2.2.2  jdolecek     uint32_t irq_mask)
    370  1.2.2.2  jdolecek {
    371  1.2.2.2  jdolecek 	struct cpu_info * const ci = curcpu();
    372  1.2.2.2  jdolecek 	const cpuid_t cpuid = ci->ci_cpuid;
    373  1.2.2.2  jdolecek 
    374  1.2.2.2  jdolecek 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    375  1.2.2.2  jdolecek 	KASSERT(irqbase == 0);
    376  1.2.2.2  jdolecek 
    377  1.2.2.2  jdolecek 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    378  1.2.2.2  jdolecek 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    379  1.2.2.2  jdolecek 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    380  1.2.2.2  jdolecek 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    381  1.2.2.2  jdolecek 		val &= ~mask;
    382  1.2.2.2  jdolecek 		bus_space_write_4(al_iot, al_ioh,
    383  1.2.2.2  jdolecek 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    384  1.2.2.2  jdolecek 		    val);
    385  1.2.2.2  jdolecek 	}
    386  1.2.2.2  jdolecek 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    387  1.2.2.2  jdolecek 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    388  1.2.2.2  jdolecek 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    389  1.2.2.2  jdolecek 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    390  1.2.2.2  jdolecek 		val &= ~mask;
    391  1.2.2.2  jdolecek 		bus_space_write_4(al_iot, al_ioh,
    392  1.2.2.2  jdolecek 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    393  1.2.2.2  jdolecek 		    val);
    394  1.2.2.2  jdolecek 	}
    395  1.2.2.2  jdolecek 
    396  1.2.2.2  jdolecek 	bcm2835_barrier();
    397  1.2.2.2  jdolecek 	return;
    398  1.2.2.2  jdolecek }
    399  1.2.2.2  jdolecek 
    400  1.2.2.2  jdolecek static int
    401  1.2.2.2  jdolecek bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    402  1.2.2.2  jdolecek {
    403  1.2.2.2  jdolecek 	struct cpu_info * const ci = curcpu();
    404  1.2.2.2  jdolecek 	const cpuid_t cpuid = ci->ci_cpuid;
    405  1.2.2.2  jdolecek 	uint32_t lpending;
    406  1.2.2.2  jdolecek 	int ipl = 0;
    407  1.2.2.2  jdolecek 
    408  1.2.2.2  jdolecek 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    409  1.2.2.2  jdolecek 
    410  1.2.2.2  jdolecek 	bcm2835_barrier();
    411  1.2.2.2  jdolecek 
    412  1.2.2.2  jdolecek 	lpending = bus_space_read_4(al_iot, al_ioh,
    413  1.2.2.2  jdolecek 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    414  1.2.2.2  jdolecek 
    415  1.2.2.2  jdolecek 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    416  1.2.2.2  jdolecek 	if (lpending & BCM2836MP_ALL_IRQS) {
    417  1.2.2.2  jdolecek 		ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
    418  1.2.2.2  jdolecek 		    lpending & BCM2836MP_ALL_IRQS);
    419  1.2.2.2  jdolecek 	}
    420  1.2.2.2  jdolecek 
    421  1.2.2.2  jdolecek 	return ipl;
    422  1.2.2.2  jdolecek }
    423  1.2.2.2  jdolecek 
    424  1.2.2.2  jdolecek static void
    425  1.2.2.2  jdolecek bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    426  1.2.2.2  jdolecek {
    427  1.2.2.2  jdolecek 	/* Nothing really*/
    428  1.2.2.2  jdolecek 	KASSERT(is->is_irq >= 0);
    429  1.2.2.2  jdolecek 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
    430  1.2.2.2  jdolecek }
    431  1.2.2.2  jdolecek 
    432  1.2.2.2  jdolecek static void
    433  1.2.2.2  jdolecek bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    434  1.2.2.2  jdolecek {
    435  1.2.2.2  jdolecek 
    436  1.2.2.2  jdolecek 	irq %= BCM2836_NIRQPERCPU;
    437  1.2.2.2  jdolecek 	strlcpy(buf, bcm2836mp_sources[irq], len);
    438  1.2.2.2  jdolecek }
    439  1.2.2.2  jdolecek 
    440  1.2.2.2  jdolecek 
    441  1.2.2.2  jdolecek #ifdef MULTIPROCESSOR
    442  1.2.2.2  jdolecek static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
    443  1.2.2.2  jdolecek {
    444  1.2.2.2  jdolecek 
    445  1.2.2.2  jdolecek 	/* Enable IRQ and not FIQ */
    446  1.2.2.2  jdolecek 	bus_space_write_4(al_iot, al_ioh,
    447  1.2.2.2  jdolecek 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_cpuid), 1);
    448  1.2.2.2  jdolecek }
    449  1.2.2.2  jdolecek 
    450  1.2.2.2  jdolecek 
    451  1.2.2.2  jdolecek static void
    452  1.2.2.2  jdolecek bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
    453  1.2.2.2  jdolecek {
    454  1.2.2.2  jdolecek 	KASSERT(pic != NULL);
    455  1.2.2.2  jdolecek 	KASSERT(pic != &bcm2835_pic);
    456  1.2.2.2  jdolecek 	KASSERT(pic->pic_cpus != NULL);
    457  1.2.2.2  jdolecek 
    458  1.2.2.2  jdolecek 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    459  1.2.2.2  jdolecek 
    460  1.2.2.2  jdolecek 	bus_space_write_4(al_iot, al_ioh,
    461  1.2.2.2  jdolecek 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
    462  1.2.2.2  jdolecek }
    463  1.2.2.2  jdolecek 
    464  1.2.2.2  jdolecek int
    465  1.2.2.2  jdolecek bcm2836mp_ipi_handler(void *priv)
    466  1.2.2.2  jdolecek {
    467  1.2.2.2  jdolecek 	const struct cpu_info *ci = curcpu();
    468  1.2.2.2  jdolecek 	const cpuid_t cpuid = ci->ci_cpuid;
    469  1.2.2.2  jdolecek 	uint32_t ipimask, bit;
    470  1.2.2.2  jdolecek 
    471  1.2.2.2  jdolecek 	ipimask = bus_space_read_4(al_iot, al_ioh,
    472  1.2.2.2  jdolecek 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
    473  1.2.2.2  jdolecek 	bus_space_write_4(al_iot, al_ioh, BCM2836_LOCAL_MAILBOX0_CLRN(cpuid),
    474  1.2.2.2  jdolecek 	    ipimask);
    475  1.2.2.2  jdolecek 
    476  1.2.2.2  jdolecek 	while ((bit = ffs(ipimask)) > 0) {
    477  1.2.2.2  jdolecek 		const u_int ipi = bit - 1;
    478  1.2.2.2  jdolecek 		switch (ipi) {
    479  1.2.2.2  jdolecek 		case IPI_AST:
    480  1.2.2.2  jdolecek 			pic_ipi_ast(priv);
    481  1.2.2.2  jdolecek 			break;
    482  1.2.2.2  jdolecek 		case IPI_NOP:
    483  1.2.2.2  jdolecek 			pic_ipi_nop(priv);
    484  1.2.2.2  jdolecek 			break;
    485  1.2.2.2  jdolecek #ifdef __HAVE_PREEMPTION
    486  1.2.2.2  jdolecek 		case IPI_KPREEMPT:
    487  1.2.2.2  jdolecek 			pic_ipi_kpreempt(priv);
    488  1.2.2.2  jdolecek 			break;
    489  1.2.2.2  jdolecek #endif
    490  1.2.2.2  jdolecek 		case IPI_XCALL:
    491  1.2.2.2  jdolecek 			pic_ipi_xcall(priv);
    492  1.2.2.2  jdolecek 			break;
    493  1.2.2.2  jdolecek 		case IPI_GENERIC:
    494  1.2.2.2  jdolecek 			pic_ipi_generic(priv);
    495  1.2.2.2  jdolecek 			break;
    496  1.2.2.2  jdolecek 		case IPI_SHOOTDOWN:
    497  1.2.2.2  jdolecek 			pic_ipi_shootdown(priv);
    498  1.2.2.2  jdolecek 			break;
    499  1.2.2.2  jdolecek #ifdef DDB
    500  1.2.2.2  jdolecek 		case IPI_DDB:
    501  1.2.2.2  jdolecek 			pic_ipi_ddb(priv);
    502  1.2.2.2  jdolecek 			break;
    503  1.2.2.2  jdolecek #endif
    504  1.2.2.2  jdolecek 		}
    505  1.2.2.2  jdolecek 		ipimask &= ~__BIT(ipi);
    506  1.2.2.2  jdolecek 	}
    507  1.2.2.2  jdolecek 
    508  1.2.2.2  jdolecek 	return 1;
    509  1.2.2.2  jdolecek }
    510  1.2.2.2  jdolecek 
    511  1.2.2.2  jdolecek void
    512  1.2.2.2  jdolecek bcm2836mp_intr_init(struct cpu_info *ci)
    513  1.2.2.2  jdolecek {
    514  1.2.2.2  jdolecek 	const cpuid_t cpuid = ci->ci_cpuid;
    515  1.2.2.2  jdolecek 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
    516  1.2.2.2  jdolecek 
    517  1.2.2.2  jdolecek 	pic->pic_cpus = ci->ci_kcpuset;
    518  1.2.2.2  jdolecek 	pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
    519  1.2.2.2  jdolecek 
    520  1.2.2.2  jdolecek 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
    521  1.2.2.2  jdolecek 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
    522  1.2.2.2  jdolecek 
    523  1.2.2.2  jdolecek 	/* clock interrupt will attach with gtmr */
    524  1.2.2.2  jdolecek 	if (cpuid == 0)
    525  1.2.2.2  jdolecek 		return;
    526  1.2.2.2  jdolecek 
    527  1.2.2.2  jdolecek 	intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
    528  1.2.2.2  jdolecek 	    IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
    529  1.2.2.2  jdolecek 
    530  1.2.2.2  jdolecek }
    531  1.2.2.2  jdolecek #endif
    532  1.2.2.2  jdolecek 
    533  1.2.2.2  jdolecek #endif
    534