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