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