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