Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.38
      1  1.38   mlelstv /*	$NetBSD: bcm2835_intr.c,v 1.38 2021/03/08 14:22:42 mlelstv Exp $	*/
      2   1.1     skrll 
      3   1.1     skrll /*-
      4  1.25   thorpej  * Copyright (c) 2012, 2015, 2019 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.38   mlelstv __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.38 2021/03/08 14:22:42 mlelstv Exp $");
     34   1.1     skrll 
     35   1.1     skrll #define _INTR_PRIVATE
     36   1.1     skrll 
     37   1.5     skrll #include "opt_bcm283x.h"
     38   1.5     skrll 
     39   1.1     skrll #include <sys/param.h>
     40   1.5     skrll #include <sys/bus.h>
     41   1.5     skrll #include <sys/cpu.h>
     42   1.5     skrll #include <sys/device.h>
     43  1.19     skrll #include <sys/kernel.h>
     44  1.19     skrll #include <sys/kmem.h>
     45   1.1     skrll #include <sys/proc.h>
     46   1.1     skrll 
     47  1.15     skrll #include <dev/fdt/fdtvar.h>
     48  1.15     skrll 
     49   1.1     skrll #include <machine/intr.h>
     50   1.5     skrll 
     51   1.5     skrll #include <arm/locore.h>
     52   1.1     skrll 
     53   1.1     skrll #include <arm/pic/picvar.h>
     54   1.5     skrll #include <arm/cortex/gtmr_var.h>
     55   1.1     skrll 
     56  1.15     skrll #include <arm/broadcom/bcm2835_intr.h>
     57   1.1     skrll #include <arm/broadcom/bcm2835reg.h>
     58   1.5     skrll #include <arm/broadcom/bcm2835var.h>
     59   1.1     skrll 
     60  1.15     skrll #include <arm/fdt/arm_fdtvar.h>
     61  1.15     skrll 
     62  1.15     skrll static void bcm2835_irq_handler(void *);
     63  1.15     skrll static void bcm2836mp_intr_init(void *, struct cpu_info *);
     64  1.15     skrll 
     65   1.1     skrll static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     66   1.1     skrll static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     67   1.1     skrll static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     68   1.1     skrll static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     69   1.1     skrll static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     70   1.1     skrll     size_t);
     71   1.1     skrll 
     72   1.5     skrll static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     73   1.5     skrll static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     74   1.5     skrll static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
     75   1.5     skrll static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
     76   1.5     skrll static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
     77   1.5     skrll     size_t);
     78   1.5     skrll #ifdef MULTIPROCESSOR
     79   1.5     skrll int bcm2836mp_ipi_handler(void *);
     80   1.5     skrll static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
     81   1.5     skrll static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
     82   1.5     skrll #endif
     83  1.15     skrll 
     84  1.15     skrll static int bcm2835_icu_fdt_decode_irq(u_int *);
     85  1.15     skrll static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
     86  1.34  jmcneill     int (*)(void *), void *, const char *);
     87  1.15     skrll static void bcm2835_icu_fdt_disestablish(device_t, void *);
     88  1.15     skrll static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
     89  1.15     skrll 
     90  1.25   thorpej static int bcm2835_icu_intr(void *);
     91  1.25   thorpej 
     92  1.15     skrll static int bcm2836mp_icu_fdt_decode_irq(u_int *);
     93  1.15     skrll static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
     94  1.34  jmcneill     int (*)(void *), void *, const char *);
     95  1.15     skrll static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
     96  1.15     skrll static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
     97   1.5     skrll 
     98   1.1     skrll static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     99   1.1     skrll static void bcm2835_icu_attach(device_t, device_t, void *);
    100   1.1     skrll 
    101  1.28     skrll static int bcm2835_int_base;
    102  1.29     skrll static int bcm2836mp_int_base[BCM2836_NCPUS];
    103  1.29     skrll 
    104  1.29     skrll #define	BCM2835_INT_BASE		bcm2835_int_base
    105  1.29     skrll #define	BCM2836_INT_BASECPUN(n)		bcm2836mp_int_base[(n)]
    106  1.28     skrll 
    107  1.38   mlelstv #define BCM2836_INT_CNTPSIRQ_CPUN(n)	(BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTPSIRQ)
    108  1.38   mlelstv #define BCM2836_INT_CNTPNSIRQ_CPUN(n)	(BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTPNSIRQ)
    109  1.38   mlelstv #define BCM2836_INT_CNTVIRQ_CPUN(n)	(BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTVIRQ)
    110  1.38   mlelstv #define BCM2836_INT_CNTHPIRQ_CPUN(n)	(BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTHPIRQ)
    111  1.38   mlelstv #define BCM2836_INT_MAILBOX0_CPUN(n)	(BCM2836_INT_BASECPUN(n) + BCM2836_INT_MAILBOX0)
    112  1.38   mlelstv 
    113  1.38   mlelstv /* Periperal Interrupt sources */
    114  1.38   mlelstv #define	BCM2835_NIRQ			96
    115  1.38   mlelstv 
    116  1.38   mlelstv #define BCM2835_INT_GPU0BASE		(BCM2835_INT_BASE + 0)
    117  1.38   mlelstv #define BCM2835_INT_TIMER0		(BCM2835_INT_GPU0BASE + 0)
    118  1.38   mlelstv #define BCM2835_INT_TIMER1		(BCM2835_INT_GPU0BASE + 1)
    119  1.38   mlelstv #define BCM2835_INT_TIMER2		(BCM2835_INT_GPU0BASE + 2)
    120  1.38   mlelstv #define BCM2835_INT_TIMER3		(BCM2835_INT_GPU0BASE + 3)
    121  1.38   mlelstv #define BCM2835_INT_USB			(BCM2835_INT_GPU0BASE + 9)
    122  1.38   mlelstv #define BCM2835_INT_DMA0		(BCM2835_INT_GPU0BASE + 16)
    123  1.38   mlelstv #define BCM2835_INT_DMA2		(BCM2835_INT_GPU0BASE + 18)
    124  1.38   mlelstv #define BCM2835_INT_DMA3		(BCM2835_INT_GPU0BASE + 19)
    125  1.38   mlelstv #define BCM2835_INT_AUX			(BCM2835_INT_GPU0BASE + 29)
    126  1.38   mlelstv #define BCM2835_INT_ARM			(BCM2835_INT_GPU0BASE + 30)
    127  1.38   mlelstv 
    128  1.38   mlelstv #define BCM2835_INT_GPU1BASE		(BCM2835_INT_BASE + 32)
    129  1.38   mlelstv #define BCM2835_INT_GPIO0		(BCM2835_INT_GPU1BASE + 17)
    130  1.38   mlelstv #define BCM2835_INT_GPIO1		(BCM2835_INT_GPU1BASE + 18)
    131  1.38   mlelstv #define BCM2835_INT_GPIO2		(BCM2835_INT_GPU1BASE + 19)
    132  1.38   mlelstv #define BCM2835_INT_GPIO3		(BCM2835_INT_GPU1BASE + 20)
    133  1.38   mlelstv #define BCM2835_INT_BSC			(BCM2835_INT_GPU1BASE + 21)
    134  1.38   mlelstv #define BCM2835_INT_SPI0		(BCM2835_INT_GPU1BASE + 22)
    135  1.38   mlelstv #define BCM2835_INT_PCM			(BCM2835_INT_GPU1BASE + 23)
    136  1.38   mlelstv #define BCM2835_INT_SDHOST		(BCM2835_INT_GPU1BASE + 24)
    137  1.38   mlelstv #define BCM2835_INT_UART0		(BCM2835_INT_GPU1BASE + 25)
    138  1.38   mlelstv #define BCM2835_INT_EMMC		(BCM2835_INT_GPU1BASE + 30)
    139  1.38   mlelstv 
    140  1.38   mlelstv #define BCM2835_INT_BASICBASE		(BCM2835_INT_BASE + 64)
    141  1.38   mlelstv #define BCM2835_INT_ARMTIMER		(BCM2835_INT_BASICBASE + 0)
    142  1.38   mlelstv #define BCM2835_INT_ARMMAILBOX		(BCM2835_INT_BASICBASE + 1)
    143  1.38   mlelstv #define BCM2835_INT_ARMDOORBELL0	(BCM2835_INT_BASICBASE + 2)
    144  1.38   mlelstv #define BCM2835_INT_ARMDOORBELL1	(BCM2835_INT_BASICBASE + 3)
    145  1.38   mlelstv #define BCM2835_INT_GPU0HALTED		(BCM2835_INT_BASICBASE + 4)
    146  1.38   mlelstv #define BCM2835_INT_GPU1HALTED		(BCM2835_INT_BASICBASE + 5)
    147  1.38   mlelstv #define BCM2835_INT_ILLEGALTYPE0	(BCM2835_INT_BASICBASE + 6)
    148  1.38   mlelstv #define BCM2835_INT_ILLEGALTYPE1	(BCM2835_INT_BASICBASE + 7)
    149  1.38   mlelstv 
    150  1.15     skrll static void
    151  1.15     skrll bcm2835_set_priority(struct pic_softc *pic, int ipl)
    152  1.15     skrll {
    153  1.15     skrll }
    154  1.15     skrll 
    155   1.1     skrll static struct pic_ops bcm2835_picops = {
    156   1.1     skrll 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
    157   1.1     skrll 	.pic_block_irqs = bcm2835_pic_block_irqs,
    158   1.1     skrll 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
    159   1.1     skrll 	.pic_establish_irq = bcm2835_pic_establish_irq,
    160   1.1     skrll 	.pic_source_name = bcm2835_pic_source_name,
    161  1.15     skrll 	.pic_set_priority = bcm2835_set_priority,
    162   1.1     skrll };
    163   1.1     skrll 
    164  1.18     skrll static struct pic_softc bcm2835_pic = {
    165   1.1     skrll 	.pic_ops = &bcm2835_picops,
    166   1.1     skrll 	.pic_maxsources = BCM2835_NIRQ,
    167   1.1     skrll 	.pic_name = "bcm2835 pic",
    168   1.1     skrll };
    169   1.1     skrll 
    170   1.5     skrll static struct pic_ops bcm2836mp_picops = {
    171   1.5     skrll 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
    172   1.5     skrll 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
    173   1.5     skrll 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
    174   1.5     skrll 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
    175   1.5     skrll 	.pic_source_name = bcm2836mp_pic_source_name,
    176   1.8     skrll #if defined(MULTIPROCESSOR)
    177   1.5     skrll 	.pic_cpu_init = bcm2836mp_cpu_init,
    178   1.5     skrll 	.pic_ipi_send = bcm2836mp_send_ipi,
    179   1.5     skrll #endif
    180   1.5     skrll };
    181   1.5     skrll 
    182  1.18     skrll static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
    183  1.13     skrll 	[0 ... BCM2836_NCPUS - 1] = {
    184   1.8     skrll 		.pic_ops = &bcm2836mp_picops,
    185   1.8     skrll 		.pic_maxsources = BCM2836_NIRQPERCPU,
    186   1.8     skrll 		.pic_name = "bcm2836 pic",
    187  1.13     skrll 	}
    188   1.5     skrll };
    189  1.15     skrll 
    190  1.15     skrll static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
    191  1.15     skrll 	.establish = bcm2835_icu_fdt_establish,
    192  1.15     skrll 	.disestablish = bcm2835_icu_fdt_disestablish,
    193  1.15     skrll 	.intrstr = bcm2835_icu_fdt_intrstr
    194  1.15     skrll };
    195  1.15     skrll 
    196  1.15     skrll static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
    197  1.15     skrll 	.establish = bcm2836mp_icu_fdt_establish,
    198  1.15     skrll 	.disestablish = bcm2836mp_icu_fdt_disestablish,
    199  1.15     skrll 	.intrstr = bcm2836mp_icu_fdt_intrstr
    200  1.15     skrll };
    201   1.5     skrll 
    202  1.19     skrll struct bcm2836mp_interrupt {
    203  1.19     skrll 	bool bi_done;
    204  1.19     skrll 	TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
    205  1.19     skrll 	int bi_irq;
    206  1.19     skrll 	int bi_ipl;
    207  1.19     skrll 	int bi_flags;
    208  1.19     skrll 	int (*bi_func)(void *);
    209  1.19     skrll 	void *bi_arg;
    210  1.19     skrll 	void *bi_ihs[BCM2836_NCPUS];
    211  1.19     skrll };
    212  1.19     skrll 
    213  1.19     skrll static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
    214  1.19     skrll     TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
    215  1.19     skrll 
    216  1.25   thorpej struct bcm2835icu_irqhandler;
    217  1.25   thorpej struct bcm2835icu_irq;
    218  1.25   thorpej struct bcm2835icu_softc;
    219  1.25   thorpej 
    220  1.25   thorpej struct bcm2835icu_irqhandler {
    221  1.25   thorpej 	struct bcm2835icu_irq	*ih_irq;
    222  1.25   thorpej 	int			(*ih_fn)(void *);
    223  1.25   thorpej 	void			*ih_arg;
    224  1.25   thorpej 	TAILQ_ENTRY(bcm2835icu_irqhandler) ih_next;
    225  1.25   thorpej };
    226  1.25   thorpej 
    227  1.25   thorpej struct bcm2835icu_irq {
    228  1.25   thorpej 	struct bcm2835icu_softc	*intr_sc;
    229  1.25   thorpej 	void			*intr_ih;
    230  1.25   thorpej 	void			*intr_arg;
    231  1.25   thorpej 	int			intr_refcnt;
    232  1.25   thorpej 	int			intr_ipl;
    233  1.25   thorpej 	int			intr_irq;
    234  1.25   thorpej 	int			intr_mpsafe;
    235  1.25   thorpej 	TAILQ_HEAD(, bcm2835icu_irqhandler) intr_handlers;
    236  1.25   thorpej };
    237  1.25   thorpej 
    238   1.1     skrll struct bcm2835icu_softc {
    239   1.1     skrll 	device_t		sc_dev;
    240   1.1     skrll 	bus_space_tag_t		sc_iot;
    241   1.1     skrll 	bus_space_handle_t	sc_ioh;
    242  1.15     skrll 
    243  1.25   thorpej 	struct bcm2835icu_irq	*sc_irq[BCM2835_NIRQ];
    244  1.25   thorpej 
    245  1.15     skrll 	int sc_phandle;
    246   1.1     skrll };
    247   1.1     skrll 
    248  1.23     skrll static struct bcm2835icu_softc *bcml1icu_sc;
    249  1.23     skrll static struct bcm2835icu_softc *bcmicu_sc;
    250   1.3     skrll 
    251   1.1     skrll #define read_bcm2835reg(o)	\
    252   1.1     skrll 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
    253   1.3     skrll 
    254   1.1     skrll #define write_bcm2835reg(o, v)	\
    255   1.1     skrll 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
    256   1.1     skrll 
    257   1.1     skrll 
    258   1.1     skrll #define bcm2835_barrier() \
    259   1.1     skrll 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
    260   1.1     skrll 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
    261   1.3     skrll 
    262   1.1     skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
    263   1.1     skrll 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
    264   1.1     skrll 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
    265   1.2  jakllsch 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
    266   1.2  jakllsch 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
    267   1.4     skrll 	"dma0",		"dma1",		"dma2",		"dma3",
    268   1.4     skrll 	"dma4",		"dma5",		"dma6",		"dma7",
    269   1.4     skrll 	"dma8",		"dma9",		"dma10",	"dma11",
    270   1.4     skrll 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
    271   1.1     skrll 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    272   1.1     skrll 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    273   1.1     skrll 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    274   1.1     skrll 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    275   1.1     skrll 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    276   1.1     skrll 	"gpio[3]",	"i2c",		"spi",		"pcm",
    277  1.12  jmcneill 	"sdhost",	"uart",		"(unused 58)",	"(unused 59)",
    278   1.1     skrll 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    279   1.1     skrll 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    280   1.1     skrll 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    281   1.1     skrll };
    282   1.1     skrll 
    283   1.8     skrll static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
    284   1.5     skrll 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
    285   1.5     skrll 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
    286  1.17     skrll 	"gpu",		"pmu"
    287   1.5     skrll };
    288   1.5     skrll 
    289   1.5     skrll #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
    290   1.5     skrll 
    291   1.1     skrll #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    292   1.1     skrll #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    293   1.1     skrll #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    294   1.1     skrll #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    295   1.1     skrll #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    296   1.1     skrll 
    297   1.1     skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    298   1.1     skrll     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    299   1.1     skrll 
    300  1.35   thorpej static const struct device_compatible_entry compat_data[] = {
    301  1.35   thorpej 	{ .compat = "brcm,bcm2708-armctrl-ic",	.value = 0 },
    302  1.35   thorpej 	{ .compat = "brcm,bcm2709-armctrl-ic",	.value = 0 },
    303  1.35   thorpej 	{ .compat = "brcm,bcm2835-armctrl-ic",	.value = 0 },
    304  1.35   thorpej 	{ .compat = "brcm,bcm2836-armctrl-ic",	.value = 0 },
    305  1.35   thorpej 	{ .compat = "brcm,bcm2836-l1-intc",	.value = 1 },
    306  1.37   thorpej 	DEVICE_COMPAT_EOL
    307  1.35   thorpej };
    308  1.35   thorpej 
    309   1.1     skrll static int
    310   1.1     skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    311   1.1     skrll {
    312  1.15     skrll 	struct fdt_attach_args * const faa = aux;
    313   1.1     skrll 
    314  1.37   thorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
    315   1.1     skrll }
    316   1.1     skrll 
    317   1.1     skrll static void
    318   1.1     skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    319   1.1     skrll {
    320  1.15     skrll 	struct bcm2835icu_softc * const sc = device_private(self);
    321  1.15     skrll 	struct fdt_attach_args * const faa = aux;
    322  1.15     skrll 	struct fdtbus_interrupt_controller_func *ifuncs;
    323  1.35   thorpej 	const struct device_compatible_entry *dce;
    324  1.15     skrll 	const int phandle = faa->faa_phandle;
    325  1.15     skrll 	bus_addr_t addr;
    326  1.15     skrll 	bus_size_t size;
    327  1.15     skrll 	bus_space_handle_t ioh;
    328  1.15     skrll 	int error;
    329  1.15     skrll 
    330  1.15     skrll 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    331  1.15     skrll 		aprint_error(": couldn't get registers\n");
    332  1.15     skrll 		return;
    333  1.15     skrll 	}
    334   1.1     skrll 
    335   1.1     skrll 	sc->sc_dev = self;
    336  1.15     skrll 	sc->sc_iot = faa->faa_bst;
    337   1.1     skrll 
    338  1.15     skrll 	if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
    339  1.15     skrll 		aprint_error(": couldn't map device\n");
    340   1.1     skrll 		return;
    341   1.1     skrll 	}
    342   1.1     skrll 
    343  1.15     skrll 	sc->sc_ioh = ioh;
    344  1.15     skrll 	sc->sc_phandle = phandle;
    345   1.5     skrll 
    346  1.37   thorpej 	dce = of_compatible_lookup(faa->faa_phandle, compat_data);
    347  1.35   thorpej 	KASSERT(dce != NULL);
    348  1.35   thorpej 
    349  1.35   thorpej 	if (dce->value != 0) {
    350   1.8     skrll #if defined(MULTIPROCESSOR)
    351  1.15     skrll 		aprint_normal(": Multiprocessor");
    352   1.5     skrll #endif
    353  1.15     skrll 		bcml1icu_sc = sc;
    354   1.5     skrll 
    355  1.15     skrll 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    356  1.15     skrll 		    BCM2836_LOCAL_CONTROL, 0);
    357  1.15     skrll 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    358  1.15     skrll 		    BCM2836_LOCAL_PRESCALER, 0x80000000);
    359  1.15     skrll 
    360  1.15     skrll 		ifuncs = &bcm2836mpicu_fdt_funcs;
    361  1.15     skrll 
    362  1.15     skrll 		bcm2836mp_intr_init(self, curcpu());
    363  1.15     skrll 		arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
    364  1.15     skrll 	} else {
    365  1.15     skrll 		if (bcml1icu_sc == NULL)
    366  1.15     skrll 			arm_fdt_irq_set_handler(bcm2835_irq_handler);
    367  1.15     skrll 		bcmicu_sc = sc;
    368  1.15     skrll 		sc->sc_ioh = ioh;
    369  1.15     skrll 		sc->sc_phandle = phandle;
    370  1.28     skrll 		bcm2835_int_base = pic_add(&bcm2835_pic, PIC_IRQBASE_ALLOC);
    371  1.15     skrll 		ifuncs = &bcm2835icu_fdt_funcs;
    372  1.15     skrll 	}
    373  1.15     skrll 
    374  1.15     skrll 	error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
    375  1.15     skrll 	if (error != 0) {
    376  1.15     skrll 		aprint_error(": couldn't register with fdtbus: %d\n", error);
    377  1.15     skrll 		return;
    378  1.15     skrll 	}
    379   1.1     skrll 	aprint_normal("\n");
    380   1.1     skrll }
    381   1.1     skrll 
    382  1.15     skrll static void
    383   1.1     skrll bcm2835_irq_handler(void *frame)
    384   1.1     skrll {
    385   1.1     skrll 	struct cpu_info * const ci = curcpu();
    386   1.1     skrll 	const int oldipl = ci->ci_cpl;
    387  1.32     skrll 	const cpuid_t cpuid = ci->ci_core_id;
    388   1.1     skrll 	const uint32_t oldipl_mask = __BIT(oldipl);
    389   1.1     skrll 	int ipl_mask = 0;
    390   1.1     skrll 
    391  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    392  1.24     skrll 
    393   1.1     skrll 	ci->ci_data.cpu_nintr++;
    394   1.1     skrll 
    395   1.1     skrll 	bcm2835_barrier();
    396   1.8     skrll 	if (cpuid == 0) {
    397   1.8     skrll 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    398   1.8     skrll 	}
    399  1.15     skrll #if defined(SOC_BCM2836)
    400   1.8     skrll 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
    401   1.5     skrll #endif
    402   1.1     skrll 
    403   1.1     skrll 	/*
    404   1.1     skrll 	 * Record the pending_ipls and deliver them if we can.
    405   1.1     skrll 	 */
    406   1.1     skrll 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    407   1.1     skrll 		pic_do_pending_ints(I32_bit, oldipl, frame);
    408   1.1     skrll }
    409   1.1     skrll 
    410   1.1     skrll static void
    411   1.1     skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    412   1.1     skrll     uint32_t irq_mask)
    413   1.1     skrll {
    414   1.1     skrll 
    415   1.1     skrll 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    416   1.1     skrll 	bcm2835_barrier();
    417   1.1     skrll }
    418   1.1     skrll 
    419   1.1     skrll static void
    420   1.1     skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    421   1.1     skrll     uint32_t irq_mask)
    422   1.1     skrll {
    423   1.1     skrll 
    424   1.1     skrll 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    425   1.1     skrll 	bcm2835_barrier();
    426   1.1     skrll }
    427   1.1     skrll 
    428   1.1     skrll /*
    429   1.1     skrll  * Called with interrupts disabled
    430   1.1     skrll  */
    431   1.1     skrll static int
    432   1.1     skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    433   1.1     skrll {
    434   1.1     skrll 	int ipl = 0;
    435   1.1     skrll 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    436   1.1     skrll 
    437   1.1     skrll 	bcm2835_barrier();
    438   1.1     skrll 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    439   1.1     skrll 	if (bpending == 0)
    440   1.1     skrll 		return 0;
    441   1.1     skrll 
    442   1.1     skrll 	armirq = bpending & BCM2835_INTBIT_ARM;
    443   1.1     skrll 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    444   1.1     skrll 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    445   1.1     skrll 
    446   1.1     skrll 	if (armirq) {
    447   1.8     skrll 		ipl |= pic_mark_pending_sources(pic,
    448   1.8     skrll 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
    449   1.1     skrll 	}
    450   1.1     skrll 
    451   1.1     skrll 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    452   1.1     skrll 		uint32_t pending1;
    453   1.3     skrll 
    454   1.1     skrll 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    455   1.8     skrll 		ipl |= pic_mark_pending_sources(pic,
    456   1.8     skrll 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
    457   1.1     skrll 	}
    458   1.1     skrll 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    459   1.1     skrll 		uint32_t pending2;
    460   1.3     skrll 
    461   1.1     skrll 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    462   1.8     skrll 		ipl |= pic_mark_pending_sources(pic,
    463   1.8     skrll 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
    464   1.1     skrll 	}
    465   1.3     skrll 
    466   1.1     skrll 	return ipl;
    467   1.1     skrll }
    468   1.1     skrll 
    469   1.1     skrll static void
    470   1.1     skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    471   1.1     skrll {
    472   1.1     skrll 
    473   1.1     skrll 	/* Nothing really*/
    474   1.1     skrll 	KASSERT(is->is_irq < BCM2835_NIRQ);
    475   1.1     skrll 	KASSERT(is->is_type == IST_LEVEL);
    476   1.1     skrll }
    477   1.1     skrll 
    478   1.1     skrll static void
    479   1.1     skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    480   1.1     skrll {
    481   1.1     skrll 
    482   1.1     skrll 	strlcpy(buf, bcm2835_sources[irq], len);
    483   1.1     skrll }
    484   1.5     skrll 
    485  1.15     skrll static int
    486  1.15     skrll bcm2835_icu_fdt_decode_irq(u_int *specifier)
    487  1.15     skrll {
    488  1.15     skrll 	u_int base;
    489  1.15     skrll 
    490  1.15     skrll 	if (!specifier)
    491  1.15     skrll 		return -1;
    492  1.15     skrll 
    493  1.15     skrll 	/* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
    494  1.15     skrll 	/* 2nd cell is the irq relative to that bank */
    495  1.15     skrll 
    496  1.15     skrll 	const u_int bank = be32toh(specifier[0]);
    497  1.15     skrll 	switch (bank) {
    498  1.15     skrll 	case 0:
    499  1.15     skrll 		base = BCM2835_INT_BASICBASE;
    500  1.15     skrll 		break;
    501  1.15     skrll 	case 1:
    502  1.15     skrll 		base = BCM2835_INT_GPU0BASE;
    503  1.15     skrll 		break;
    504  1.15     skrll 	case 2:
    505  1.15     skrll 		base = BCM2835_INT_GPU1BASE;
    506  1.15     skrll 		break;
    507  1.15     skrll 	default:
    508  1.15     skrll 		return -1;
    509  1.15     skrll 	}
    510  1.15     skrll 	const u_int off = be32toh(specifier[1]);
    511  1.15     skrll 
    512  1.15     skrll 	return base + off;
    513  1.15     skrll }
    514  1.15     skrll 
    515  1.15     skrll static void *
    516  1.15     skrll bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    517  1.34  jmcneill     int (*func)(void *), void *arg, const char *xname)
    518  1.15     skrll {
    519  1.25   thorpej 	struct bcm2835icu_softc * const sc = device_private(dev);
    520  1.25   thorpej 	struct bcm2835icu_irq *firq;
    521  1.25   thorpej 	struct bcm2835icu_irqhandler *firqh;
    522  1.15     skrll 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    523  1.27   thorpej 	int irq, irqidx;
    524  1.15     skrll 
    525  1.15     skrll 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    526  1.15     skrll 	if (irq == -1)
    527  1.15     skrll 		return NULL;
    528  1.27   thorpej 	irqidx = irq - BCM2835_INT_BASE;
    529   1.5     skrll 
    530  1.27   thorpej 	KASSERT(irqidx < BCM2835_NIRQ);
    531  1.26   thorpej 
    532  1.27   thorpej 	firq = sc->sc_irq[irqidx];
    533  1.25   thorpej 	if (firq == NULL) {
    534  1.25   thorpej 		firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
    535  1.25   thorpej 		firq->intr_sc = sc;
    536  1.25   thorpej 		firq->intr_refcnt = 0;
    537  1.25   thorpej 		firq->intr_arg = arg;
    538  1.25   thorpej 		firq->intr_ipl = ipl;
    539  1.25   thorpej 		firq->intr_mpsafe = iflags;
    540  1.25   thorpej 		firq->intr_irq = irq;
    541  1.25   thorpej 		TAILQ_INIT(&firq->intr_handlers);
    542  1.25   thorpej 		if (arg == NULL) {
    543  1.34  jmcneill 			firq->intr_ih = intr_establish_xname(irq, ipl,
    544  1.34  jmcneill 			    IST_LEVEL | iflags, func, NULL, xname);
    545  1.25   thorpej 		} else {
    546  1.34  jmcneill 			firq->intr_ih = intr_establish_xname(irq, ipl,
    547  1.34  jmcneill 			    IST_LEVEL | iflags, bcm2835_icu_intr, firq, xname);
    548  1.25   thorpej 		}
    549  1.25   thorpej 		if (firq->intr_ih == NULL) {
    550  1.25   thorpej 			kmem_free(firq, sizeof(*firq));
    551  1.25   thorpej 			return NULL;
    552  1.25   thorpej 		}
    553  1.27   thorpej 		sc->sc_irq[irqidx] = firq;
    554  1.25   thorpej 	} else {
    555  1.25   thorpej 		if (firq->intr_arg == NULL || arg == NULL) {
    556  1.25   thorpej 			device_printf(dev,
    557  1.25   thorpej 			    "cannot share irq with NULL-arg handler\n");
    558  1.25   thorpej 			return NULL;
    559  1.25   thorpej 		}
    560  1.25   thorpej 		if (firq->intr_ipl != ipl) {
    561  1.25   thorpej 			device_printf(dev,
    562  1.25   thorpej 			    "cannot share irq with different ipl\n");
    563  1.25   thorpej 			return NULL;
    564  1.25   thorpej 		}
    565  1.25   thorpej 		if (firq->intr_mpsafe != iflags) {
    566  1.25   thorpej 			device_printf(dev,
    567  1.25   thorpej 			    "cannot share irq between mpsafe/non-mpsafe\n");
    568  1.25   thorpej 			return NULL;
    569  1.25   thorpej 		}
    570  1.25   thorpej 	}
    571  1.25   thorpej 
    572  1.25   thorpej 	firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
    573  1.25   thorpej 	firqh->ih_irq = firq;
    574  1.25   thorpej 	firqh->ih_fn = func;
    575  1.25   thorpej 	firqh->ih_arg = arg;
    576  1.26   thorpej 
    577  1.26   thorpej 	firq->intr_refcnt++;
    578  1.25   thorpej 	TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
    579  1.25   thorpej 
    580  1.26   thorpej 	/*
    581  1.26   thorpej 	 * XXX interrupt_distribute(9) assumes that any interrupt
    582  1.26   thorpej 	 * handle can be used as an input to the MD interrupt_distribute
    583  1.26   thorpej 	 * implementationm, so we are forced to return the handle
    584  1.26   thorpej 	 * we got back from intr_establish().  Upshot is that the
    585  1.26   thorpej 	 * input to bcm2835_icu_fdt_disestablish() is ambiguous for
    586  1.26   thorpej 	 * shared IRQs, rendering them un-disestablishable.
    587  1.26   thorpej 	 */
    588  1.26   thorpej 
    589  1.26   thorpej 	return firq->intr_ih;
    590  1.15     skrll }
    591  1.15     skrll 
    592  1.15     skrll static void
    593  1.15     skrll bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
    594  1.15     skrll {
    595  1.25   thorpej 	struct bcm2835icu_softc * const sc = device_private(dev);
    596  1.26   thorpej 	struct bcm2835icu_irqhandler *firqh;
    597  1.26   thorpej 	struct bcm2835icu_irq *firq;
    598  1.26   thorpej 	u_int n;
    599  1.25   thorpej 
    600  1.26   thorpej 	for (n = 0; n < BCM2835_NIRQ; n++) {
    601  1.26   thorpej 		firq = sc->sc_irq[n];
    602  1.26   thorpej 		if (firq == NULL || firq->intr_ih != ih)
    603  1.26   thorpej 			continue;
    604  1.26   thorpej 
    605  1.26   thorpej 		KASSERT(firq->intr_refcnt > 0);
    606  1.27   thorpej 		KASSERT(n == (firq->intr_irq - BCM2835_INT_BASE));
    607  1.26   thorpej 
    608  1.26   thorpej 		/* XXX see above */
    609  1.26   thorpej 		if (firq->intr_refcnt > 1)
    610  1.26   thorpej 			panic("%s: cannot disestablish shared irq", __func__);
    611  1.25   thorpej 
    612  1.26   thorpej 		intr_disestablish(firq->intr_ih);
    613  1.25   thorpej 
    614  1.26   thorpej 		firqh = TAILQ_FIRST(&firq->intr_handlers);
    615  1.26   thorpej 		TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
    616  1.26   thorpej 		kmem_free(firqh, sizeof(*firqh));
    617  1.25   thorpej 
    618  1.27   thorpej 		sc->sc_irq[n] = NULL;
    619  1.26   thorpej 		kmem_free(firq, sizeof(*firq));
    620  1.26   thorpej 
    621  1.26   thorpej 		return;
    622  1.26   thorpej 	}
    623  1.25   thorpej 
    624  1.26   thorpej 	panic("%s: interrupt not established", __func__);
    625  1.25   thorpej }
    626  1.25   thorpej 
    627  1.25   thorpej static int
    628  1.25   thorpej bcm2835_icu_intr(void *priv)
    629  1.25   thorpej {
    630  1.25   thorpej 	struct bcm2835icu_irq *firq = priv;
    631  1.25   thorpej 	struct bcm2835icu_irqhandler *firqh;
    632  1.25   thorpej 	int handled = 0;
    633  1.25   thorpej 
    634  1.25   thorpej 	TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
    635  1.25   thorpej 		handled |= firqh->ih_fn(firqh->ih_arg);
    636  1.25   thorpej 	}
    637  1.25   thorpej 
    638  1.25   thorpej 	return handled;
    639  1.15     skrll }
    640  1.15     skrll 
    641  1.15     skrll static bool
    642  1.15     skrll bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
    643  1.15     skrll {
    644  1.15     skrll 	int irq;
    645  1.15     skrll 
    646  1.15     skrll 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    647  1.15     skrll 	if (irq == -1)
    648  1.15     skrll 		return false;
    649  1.15     skrll 
    650  1.15     skrll 	snprintf(buf, buflen, "icu irq %d", irq);
    651  1.15     skrll 
    652  1.15     skrll 	return true;
    653  1.15     skrll }
    654   1.5     skrll 
    655   1.5     skrll #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    656  1.19     skrll #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,7)
    657  1.19     skrll #define	BCM2836MP_GPU_IRQ	__BIT(8)
    658  1.19     skrll #define	BCM2836MP_PMU_IRQ	__BIT(9)
    659  1.19     skrll #define	BCM2836MP_ALL_IRQS	(BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
    660   1.5     skrll 
    661   1.5     skrll static void
    662   1.5     skrll bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    663   1.5     skrll     uint32_t irq_mask)
    664   1.5     skrll {
    665  1.15     skrll 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    666  1.15     skrll 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    667  1.19     skrll 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    668   1.5     skrll 
    669  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    670   1.8     skrll 	KASSERT(irqbase == 0);
    671   1.5     skrll 
    672   1.5     skrll 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    673   1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    674  1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    675   1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    676   1.5     skrll 		val |= mask;
    677  1.15     skrll 		bus_space_write_4(iot, ioh,
    678   1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    679   1.5     skrll 		    val);
    680  1.15     skrll 		bus_space_barrier(iot, ioh,
    681   1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    682   1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    683   1.5     skrll 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    684  1.10     skrll 	}
    685  1.10     skrll 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    686   1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    687  1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    688   1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    689   1.5     skrll 		val |= mask;
    690  1.15     skrll 		bus_space_write_4(iot, ioh,
    691   1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    692   1.5     skrll 		    val);
    693  1.15     skrll 		bus_space_barrier(iot, ioh,
    694   1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    695   1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    696   1.5     skrll 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    697   1.5     skrll 	}
    698  1.19     skrll 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    699  1.19     skrll 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
    700  1.19     skrll 		    __BIT(cpuid));
    701  1.19     skrll 		bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
    702  1.19     skrll 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    703  1.19     skrll 	}
    704   1.5     skrll 
    705   1.5     skrll 	return;
    706   1.5     skrll }
    707   1.5     skrll 
    708   1.5     skrll static void
    709   1.5     skrll bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    710   1.5     skrll     uint32_t irq_mask)
    711   1.5     skrll {
    712  1.15     skrll 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    713  1.15     skrll 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    714  1.19     skrll 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    715   1.8     skrll 
    716  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    717   1.8     skrll 	KASSERT(irqbase == 0);
    718   1.5     skrll 
    719   1.5     skrll 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    720   1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    721  1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    722   1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    723   1.5     skrll 		val &= ~mask;
    724  1.15     skrll 		bus_space_write_4(iot, ioh,
    725   1.5     skrll 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    726   1.5     skrll 		    val);
    727  1.10     skrll 	}
    728  1.10     skrll 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    729   1.5     skrll 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    730  1.15     skrll 		uint32_t val = bus_space_read_4(iot, ioh,
    731   1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    732   1.5     skrll 		val &= ~mask;
    733  1.15     skrll 		bus_space_write_4(iot, ioh,
    734   1.5     skrll 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    735   1.5     skrll 		    val);
    736   1.5     skrll 	}
    737  1.19     skrll 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    738  1.19     skrll 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
    739  1.21     skrll 		    __BIT(cpuid));
    740  1.19     skrll 	}
    741   1.5     skrll 
    742   1.5     skrll 	bcm2835_barrier();
    743   1.5     skrll 	return;
    744   1.5     skrll }
    745   1.5     skrll 
    746   1.5     skrll static int
    747   1.5     skrll bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    748   1.5     skrll {
    749   1.8     skrll 	struct cpu_info * const ci = curcpu();
    750  1.32     skrll 	const cpuid_t cpuid = ci->ci_core_id;
    751   1.5     skrll 	uint32_t lpending;
    752   1.5     skrll 	int ipl = 0;
    753   1.5     skrll 
    754  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    755   1.8     skrll 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    756   1.8     skrll 
    757   1.5     skrll 	bcm2835_barrier();
    758   1.5     skrll 
    759  1.15     skrll 	lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    760   1.5     skrll 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    761   1.5     skrll 
    762   1.5     skrll 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    763  1.29     skrll 	const uint32_t allirqs = lpending & BCM2836MP_ALL_IRQS;
    764  1.29     skrll 	if (allirqs) {
    765  1.29     skrll 		ipl |= pic_mark_pending_sources(pic, 0, allirqs);
    766   1.5     skrll 	}
    767   1.5     skrll 
    768   1.5     skrll 	return ipl;
    769   1.5     skrll }
    770   1.5     skrll 
    771   1.5     skrll static void
    772   1.5     skrll bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    773   1.5     skrll {
    774   1.5     skrll 	/* Nothing really*/
    775   1.5     skrll 	KASSERT(is->is_irq >= 0);
    776   1.8     skrll 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
    777   1.8     skrll }
    778   1.8     skrll 
    779   1.8     skrll static void
    780   1.8     skrll bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    781   1.8     skrll {
    782   1.8     skrll 
    783   1.8     skrll 	irq %= BCM2836_NIRQPERCPU;
    784   1.8     skrll 	strlcpy(buf, bcm2836mp_sources[irq], len);
    785   1.8     skrll }
    786   1.5     skrll 
    787   1.5     skrll 
    788  1.15     skrll #if defined(MULTIPROCESSOR)
    789   1.8     skrll static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
    790   1.8     skrll {
    791  1.32     skrll 	const cpuid_t cpuid = ci->ci_core_id;
    792  1.24     skrll 
    793  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    794   1.8     skrll 
    795   1.8     skrll 	/* Enable IRQ and not FIQ */
    796  1.15     skrll 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    797  1.24     skrll 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid), 1);
    798   1.5     skrll }
    799   1.5     skrll 
    800   1.5     skrll static void
    801   1.8     skrll bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
    802   1.8     skrll {
    803  1.10     skrll 	KASSERT(pic != NULL);
    804  1.10     skrll 	KASSERT(pic != &bcm2835_pic);
    805  1.10     skrll 	KASSERT(pic->pic_cpus != NULL);
    806  1.10     skrll 
    807   1.8     skrll 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    808  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    809   1.8     skrll 
    810  1.15     skrll 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    811   1.9  jmcneill 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
    812   1.8     skrll }
    813   1.8     skrll 
    814   1.8     skrll int
    815   1.8     skrll bcm2836mp_ipi_handler(void *priv)
    816   1.8     skrll {
    817   1.8     skrll 	const struct cpu_info *ci = curcpu();
    818  1.32     skrll 	const cpuid_t cpuid = ci->ci_core_id;
    819   1.9  jmcneill 	uint32_t ipimask, bit;
    820   1.9  jmcneill 
    821  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    822  1.24     skrll 
    823  1.15     skrll 	ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    824   1.8     skrll 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
    825  1.15     skrll 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    826  1.15     skrll 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
    827   1.8     skrll 
    828   1.9  jmcneill 	while ((bit = ffs(ipimask)) > 0) {
    829   1.9  jmcneill 		const u_int ipi = bit - 1;
    830   1.9  jmcneill 		switch (ipi) {
    831   1.9  jmcneill 		case IPI_AST:
    832  1.11     skrll 			pic_ipi_ast(priv);
    833  1.11     skrll 			break;
    834   1.9  jmcneill 		case IPI_NOP:
    835  1.11     skrll 			pic_ipi_nop(priv);
    836  1.11     skrll 			break;
    837   1.9  jmcneill #ifdef __HAVE_PREEMPTION
    838   1.9  jmcneill 		case IPI_KPREEMPT:
    839  1.11     skrll 			pic_ipi_kpreempt(priv);
    840  1.11     skrll 			break;
    841   1.9  jmcneill #endif
    842   1.9  jmcneill 		case IPI_XCALL:
    843   1.9  jmcneill 			pic_ipi_xcall(priv);
    844   1.9  jmcneill 			break;
    845   1.9  jmcneill 		case IPI_GENERIC:
    846   1.9  jmcneill 			pic_ipi_generic(priv);
    847   1.9  jmcneill 			break;
    848   1.9  jmcneill 		case IPI_SHOOTDOWN:
    849   1.9  jmcneill 			pic_ipi_shootdown(priv);
    850   1.9  jmcneill 			break;
    851   1.8     skrll #ifdef DDB
    852   1.9  jmcneill 		case IPI_DDB:
    853   1.9  jmcneill 			pic_ipi_ddb(priv);
    854   1.9  jmcneill 			break;
    855   1.8     skrll #endif
    856   1.9  jmcneill 		}
    857   1.9  jmcneill 		ipimask &= ~__BIT(ipi);
    858   1.8     skrll 	}
    859   1.8     skrll 
    860   1.8     skrll 	return 1;
    861   1.8     skrll }
    862  1.15     skrll #endif
    863   1.8     skrll 
    864  1.15     skrll static void
    865  1.15     skrll bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
    866   1.5     skrll {
    867  1.32     skrll 	const cpuid_t cpuid = ci->ci_core_id;
    868   1.8     skrll 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
    869   1.8     skrll 
    870  1.24     skrll 	KASSERT(cpuid < BCM2836_NCPUS);
    871  1.24     skrll 
    872  1.15     skrll #if defined(MULTIPROCESSOR)
    873   1.8     skrll 	pic->pic_cpus = ci->ci_kcpuset;
    874  1.20       ryo 
    875  1.20       ryo 	/*
    876  1.20       ryo 	 * Append "#n" to avoid duplication of .pic_name[]
    877  1.20       ryo 	 * It should be a unique id for intr_get_source()
    878  1.20       ryo 	 */
    879  1.20       ryo 	char suffix[sizeof("#00000")];
    880  1.20       ryo 	snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
    881  1.20       ryo 	strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
    882  1.15     skrll #endif
    883  1.29     skrll 	bcm2836mp_int_base[cpuid] = pic_add(pic, PIC_IRQBASE_ALLOC);
    884   1.8     skrll 
    885  1.15     skrll #if defined(MULTIPROCESSOR)
    886  1.10     skrll 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
    887   1.8     skrll 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
    888   1.8     skrll 
    889  1.19     skrll 	struct bcm2836mp_interrupt *bip;
    890  1.19     skrll 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    891  1.19     skrll 		if (bip->bi_done)
    892  1.19     skrll 			continue;
    893  1.19     skrll 
    894  1.19     skrll 		const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
    895  1.19     skrll 		void *ih = intr_establish(irq, bip->bi_ipl,
    896  1.19     skrll 		    IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
    897  1.19     skrll 
    898  1.19     skrll 		bip->bi_ihs[cpuid] = ih;
    899  1.19     skrll 	}
    900  1.15     skrll #endif
    901   1.5     skrll }
    902   1.8     skrll 
    903  1.15     skrll static int
    904  1.15     skrll bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
    905  1.15     skrll {
    906  1.22     skrll 
    907  1.15     skrll 	if (!specifier)
    908  1.15     skrll 		return -1;
    909  1.19     skrll 	return be32toh(specifier[0]);
    910  1.15     skrll }
    911  1.15     skrll 
    912  1.15     skrll static void *
    913  1.15     skrll bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    914  1.34  jmcneill     int (*func)(void *), void *arg, const char *xname)
    915  1.15     skrll {
    916  1.15     skrll 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    917  1.19     skrll 	struct bcm2836mp_interrupt *bip;
    918  1.19     skrll 	void *ih;
    919  1.15     skrll 
    920  1.19     skrll 	int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    921  1.15     skrll 	if (irq == -1)
    922  1.15     skrll 		return NULL;
    923  1.15     skrll 
    924  1.19     skrll 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    925  1.19     skrll 		if (irq == bip->bi_irq)
    926  1.19     skrll 			return NULL;
    927  1.19     skrll 	}
    928  1.19     skrll 
    929  1.19     skrll 	bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
    930  1.19     skrll 	if (bip == NULL)
    931  1.19     skrll 		return NULL;
    932  1.19     skrll 
    933  1.19     skrll 	bip->bi_done = false;
    934  1.19     skrll 	bip->bi_irq = irq;
    935  1.19     skrll 	bip->bi_ipl = ipl;
    936  1.19     skrll 	bip->bi_flags = IST_LEVEL | iflags;
    937  1.19     skrll 	bip->bi_func = func;
    938  1.19     skrll 	bip->bi_arg = arg;
    939  1.19     skrll 
    940  1.19     skrll 	/*
    941  1.33  christos 	 * If we're not cold and the BPs have been started then we can
    942  1.33  christos 	 * register the interrupt for all CPUs now, e.g. PMU
    943  1.19     skrll 	 */
    944  1.19     skrll 	if (!cold) {
    945  1.19     skrll 		for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
    946  1.34  jmcneill 			ih = intr_establish_xname(
    947  1.34  jmcneill 			    BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
    948  1.34  jmcneill 			    IST_LEVEL | iflags, func, arg, xname);
    949  1.19     skrll 			if (!ih) {
    950  1.19     skrll 				kmem_free(bip, sizeof(*bip));
    951  1.19     skrll 				return NULL;
    952  1.19     skrll 			}
    953  1.19     skrll 			bip->bi_ihs[cpuid] = ih;
    954  1.19     skrll 
    955  1.19     skrll 		}
    956  1.19     skrll 		bip->bi_done = true;
    957  1.19     skrll 		ih = bip->bi_ihs[0];
    958  1.19     skrll 		goto done;
    959  1.19     skrll 	}
    960  1.19     skrll 
    961  1.19     skrll 	/*
    962  1.19     skrll 	 * Otherwise we can only establish the interrupt for the BP and
    963  1.19     skrll 	 * delay until bcm2836mp_intr_init is called for each AP, e.g.
    964  1.19     skrll 	 * gtmr
    965  1.19     skrll 	 */
    966  1.34  jmcneill 	ih = intr_establish_xname(BCM2836_INT_BASECPUN(0) + irq, ipl,
    967  1.34  jmcneill 	    IST_LEVEL | iflags, func, arg, xname);
    968  1.19     skrll 	if (!ih) {
    969  1.19     skrll 		kmem_free(bip, sizeof(*bip));
    970  1.19     skrll 		return NULL;
    971  1.19     skrll 	}
    972  1.19     skrll 
    973  1.19     skrll 	bip->bi_ihs[0] = ih;
    974  1.19     skrll 	for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
    975  1.19     skrll 		bip->bi_ihs[cpuid] = NULL;
    976  1.19     skrll 
    977  1.19     skrll done:
    978  1.19     skrll 	TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
    979  1.19     skrll 
    980  1.19     skrll 	/*
    981  1.19     skrll 	 * Return the intr_establish handle for cpu 0 for API compatibility.
    982  1.19     skrll 	 * Any cpu would do here as these sources don't support set_affinity
    983  1.19     skrll 	 * when the handle is used in interrupt_distribute(9)
    984  1.19     skrll 	 */
    985  1.19     skrll 	return ih;
    986  1.15     skrll }
    987  1.15     skrll 
    988  1.15     skrll static void
    989  1.15     skrll bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
    990  1.15     skrll {
    991  1.19     skrll 	struct bcm2836mp_interrupt *bip;
    992  1.19     skrll 
    993  1.19     skrll 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    994  1.19     skrll 		if (bip->bi_ihs[0] == ih)
    995  1.19     skrll 			break;
    996  1.19     skrll 	}
    997  1.19     skrll 
    998  1.19     skrll 	if (bip == NULL)
    999  1.19     skrll 		return;
   1000  1.19     skrll 
   1001  1.19     skrll 	for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
   1002  1.19     skrll 		intr_disestablish(bip->bi_ihs[cpuid]);
   1003  1.19     skrll 
   1004  1.19     skrll 	TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
   1005  1.19     skrll 
   1006  1.19     skrll 	kmem_free(bip, sizeof(*bip));
   1007  1.15     skrll }
   1008  1.15     skrll 
   1009  1.15     skrll static bool
   1010  1.15     skrll bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
   1011  1.15     skrll     size_t buflen)
   1012  1.15     skrll {
   1013  1.15     skrll 	int irq;
   1014  1.15     skrll 
   1015  1.15     skrll 	irq = bcm2836mp_icu_fdt_decode_irq(specifier);
   1016  1.15     skrll 	if (irq == -1)
   1017  1.15     skrll 		return false;
   1018  1.15     skrll 
   1019  1.15     skrll 	snprintf(buf, buflen, "local_intc irq %d", irq);
   1020  1.15     skrll 
   1021  1.15     skrll 	return true;
   1022  1.15     skrll }
   1023