1 /* 2 * Copyright 2015 Andrew Turner. 3 * Copyright 2016 Svatopluk Kraus 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_platform.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bus.h> 37 #include <sys/cpuset.h> 38 #include <sys/kernel.h> 39 #include <sys/lock.h> 40 #include <sys/module.h> 41 #include <sys/mutex.h> 42 #include <sys/proc.h> 43 #include <sys/rman.h> 44 #ifdef SMP 45 #include <sys/smp.h> 46 #endif 47 48 #include <machine/bus.h> 49 #include <machine/intr.h> 50 #include <machine/resource.h> 51 #ifdef SMP 52 #include <machine/smp.h> 53 #endif 54 55 #include <dev/ofw/ofw_bus_subr.h> 56 #include <dev/ofw/ofw_bus.h> 57 58 #include "pic_if.h" 59 60 #define BCM_LINTC_CONTROL_REG 0x00 61 #define BCM_LINTC_PRESCALER_REG 0x08 62 #define BCM_LINTC_GPU_ROUTING_REG 0x0c 63 #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10 64 #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14 65 #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4) 66 #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4) 67 #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4) 68 #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16) 69 #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16) 70 #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16) 71 #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16) 72 #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16) 73 #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16) 74 #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16) 75 #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16) 76 77 /* Prescaler Register */ 78 #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */ 79 80 /* GPU Interrupt Routing Register */ 81 #define BCM_LINTC_GIRR_IRQ_CORE(n) (n) 82 #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2) 83 84 /* PMU Interrupt Routing Register */ 85 #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n)) 86 #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4)) 87 88 /* Timer Config Register */ 89 #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n)) 90 #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4)) 91 92 /* MBOX Config Register */ 93 #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n)) 94 #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4)) 95 96 #define BCM_LINTC_CNTPSIRQ_IRQ 0 97 #define BCM_LINTC_CNTPNSIRQ_IRQ 1 98 #define BCM_LINTC_CNTHPIRQ_IRQ 2 99 #define BCM_LINTC_CNTVIRQ_IRQ 3 100 #define BCM_LINTC_MBOX0_IRQ 4 101 #define BCM_LINTC_MBOX1_IRQ 5 102 #define BCM_LINTC_MBOX2_IRQ 6 103 #define BCM_LINTC_MBOX3_IRQ 7 104 #define BCM_LINTC_GPU_IRQ 8 105 #define BCM_LINTC_PMU_IRQ 9 106 #define BCM_LINTC_AXI_IRQ 10 107 #define BCM_LINTC_LTIMER_IRQ 11 108 109 #define BCM_LINTC_NIRQS 12 110 111 #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ 112 #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ 113 #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ 114 #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ 115 116 #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ) 117 #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ) 118 #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ) 119 #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ) 120 #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ) 121 #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ) 122 #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ) 123 124 #define BCM_LINTC_UP_PENDING_MASK \ 125 (BCM_LINTC_TIMER0_IRQ_MASK | \ 126 BCM_LINTC_TIMER1_IRQ_MASK | \ 127 BCM_LINTC_TIMER2_IRQ_MASK | \ 128 BCM_LINTC_TIMER3_IRQ_MASK | \ 129 BCM_LINTC_GPU_IRQ_MASK | \ 130 BCM_LINTC_PMU_IRQ_MASK) 131 132 #define BCM_LINTC_SMP_PENDING_MASK \ 133 (BCM_LINTC_UP_PENDING_MASK | \ 134 BCM_LINTC_MBOX0_IRQ_MASK) 135 136 #ifdef SMP 137 #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK 138 #else 139 #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK 140 #endif 141 142 struct bcm_lintc_irqsrc { 143 struct intr_irqsrc bli_isrc; 144 u_int bli_irq; 145 union { 146 u_int bli_mask; /* for timers */ 147 u_int bli_value; /* for GPU */ 148 }; 149 }; 150 151 struct bcm_lintc_softc { 152 device_t bls_dev; 153 struct mtx bls_mtx; 154 struct resource * bls_mem; 155 bus_space_tag_t bls_bst; 156 bus_space_handle_t bls_bsh; 157 struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS]; 158 }; 159 160 static struct bcm_lintc_softc *bcm_lintc_sc; 161 162 #ifdef SMP 163 #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */ 164 CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS); 165 #endif 166 167 #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx) 168 #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx) 169 #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \ 170 device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN) 171 #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx) 172 173 #define bcm_lintc_read_4(sc, reg) \ 174 bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg)) 175 #define bcm_lintc_write_4(sc, reg, val) \ 176 bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val)) 177 178 static inline void 179 bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg, 180 uint32_t mask) 181 { 182 183 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask); 184 } 185 186 static inline void 187 bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg, 188 uint32_t mask) 189 { 190 191 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask); 192 } 193 194 static void 195 bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 196 { 197 cpuset_t *cpus; 198 uint32_t cpu; 199 200 cpus = &bli->bli_isrc.isrc_cpu; 201 202 BCM_LINTC_LOCK(sc); 203 for (cpu = 0; cpu < 4; cpu++) 204 if (CPU_ISSET(cpu, cpus)) 205 bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 206 bli->bli_mask); 207 BCM_LINTC_UNLOCK(sc); 208 } 209 210 static void 211 bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 212 { 213 cpuset_t *cpus; 214 uint32_t cpu; 215 216 cpus = &bli->bli_isrc.isrc_cpu; 217 218 BCM_LINTC_LOCK(sc); 219 for (cpu = 0; cpu < 4; cpu++) 220 if (CPU_ISSET(cpu, cpus)) 221 bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 222 bli->bli_mask); 223 BCM_LINTC_UNLOCK(sc); 224 } 225 226 static inline void 227 bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 228 { 229 230 /* It's accessed just and only by one core. */ 231 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0); 232 } 233 234 static inline void 235 bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 236 { 237 238 /* It's accessed just and only by one core. */ 239 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value); 240 } 241 242 static inline void 243 bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 244 { 245 cpuset_t *cpus; 246 uint32_t cpu, mask; 247 248 mask = 0; 249 cpus = &bli->bli_isrc.isrc_cpu; 250 251 BCM_LINTC_LOCK(sc); 252 for (cpu = 0; cpu < 4; cpu++) 253 if (CPU_ISSET(cpu, cpus)) 254 mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); 255 /* Write-clear register. */ 256 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask); 257 BCM_LINTC_UNLOCK(sc); 258 } 259 260 static inline void 261 bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 262 { 263 cpuset_t *cpus; 264 uint32_t cpu, mask; 265 266 mask = 0; 267 cpus = &bli->bli_isrc.isrc_cpu; 268 269 BCM_LINTC_LOCK(sc); 270 for (cpu = 0; cpu < 4; cpu++) 271 if (CPU_ISSET(cpu, cpus)) 272 mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); 273 /* Write-set register. */ 274 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask); 275 BCM_LINTC_UNLOCK(sc); 276 } 277 278 static void 279 bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 280 { 281 282 switch (bli->bli_irq) { 283 case BCM_LINTC_TIMER0_IRQ: 284 case BCM_LINTC_TIMER1_IRQ: 285 case BCM_LINTC_TIMER2_IRQ: 286 case BCM_LINTC_TIMER3_IRQ: 287 bcm_lintc_timer_mask(sc, bli); 288 return; 289 case BCM_LINTC_MBOX0_IRQ: 290 case BCM_LINTC_MBOX1_IRQ: 291 case BCM_LINTC_MBOX2_IRQ: 292 case BCM_LINTC_MBOX3_IRQ: 293 return; 294 case BCM_LINTC_GPU_IRQ: 295 bcm_lintc_gpu_mask(sc, bli); 296 return; 297 case BCM_LINTC_PMU_IRQ: 298 bcm_lintc_pmu_mask(sc, bli); 299 return; 300 default: 301 panic("%s: not implemented for irq %u", __func__, bli->bli_irq); 302 } 303 } 304 305 static void 306 bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 307 { 308 309 switch (bli->bli_irq) { 310 case BCM_LINTC_TIMER0_IRQ: 311 case BCM_LINTC_TIMER1_IRQ: 312 case BCM_LINTC_TIMER2_IRQ: 313 case BCM_LINTC_TIMER3_IRQ: 314 bcm_lintc_timer_unmask(sc, bli); 315 return; 316 case BCM_LINTC_MBOX0_IRQ: 317 case BCM_LINTC_MBOX1_IRQ: 318 case BCM_LINTC_MBOX2_IRQ: 319 case BCM_LINTC_MBOX3_IRQ: 320 return; 321 case BCM_LINTC_GPU_IRQ: 322 bcm_lintc_gpu_unmask(sc, bli); 323 return; 324 case BCM_LINTC_PMU_IRQ: 325 bcm_lintc_pmu_unmask(sc, bli); 326 return; 327 default: 328 panic("%s: not implemented for irq %u", __func__, bli->bli_irq); 329 } 330 } 331 332 #ifdef SMP 333 static inline void 334 bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi) 335 { 336 u_int cpu; 337 uint32_t mask; 338 339 mask = 1 << ipi; 340 for (cpu = 0; cpu < mp_ncpus; cpu++) 341 if (CPU_ISSET(cpu, &cpus)) 342 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu), 343 mask); 344 } 345 346 static inline void 347 bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu, 348 struct trapframe *tf) 349 { 350 u_int ipi; 351 uint32_t mask; 352 353 mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu)); 354 if (mask == 0) { 355 device_printf(sc->bls_dev, "Spurious ipi detected\n"); 356 return; 357 } 358 359 for (ipi = 0; mask != 0; mask >>= 1, ipi++) { 360 if ((mask & 0x01) == 0) 361 continue; 362 /* 363 * Clear an IPI before dispatching to not miss anyone 364 * and make sure that it's observed by everybody. 365 */ 366 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi); 367 #if defined(__aarch64__) 368 dsb(sy); 369 #else 370 dsb(); 371 #endif 372 intr_ipi_dispatch(ipi, tf); 373 } 374 } 375 #endif 376 377 static inline void 378 bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq, 379 struct trapframe *tf) 380 { 381 struct bcm_lintc_irqsrc *bli; 382 383 bli = &sc->bls_isrcs[irq]; 384 if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0) 385 device_printf(sc->bls_dev, "Stray irq %u detected\n", irq); 386 } 387 388 static int 389 bcm_lintc_intr(void *arg) 390 { 391 struct bcm_lintc_softc *sc; 392 u_int cpu; 393 uint32_t num, reg; 394 struct trapframe *tf; 395 396 sc = arg; 397 cpu = PCPU_GET(cpuid); 398 tf = curthread->td_intr_frame; 399 400 for (num = 0; ; num++) { 401 reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu)); 402 if ((reg & BCM_LINTC_PENDING_MASK) == 0) 403 break; 404 #ifdef SMP 405 if (reg & BCM_LINTC_MBOX0_IRQ_MASK) 406 bcm_lintc_ipi_dispatch(sc, cpu, tf); 407 #endif 408 if (reg & BCM_LINTC_TIMER0_IRQ_MASK) 409 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf); 410 if (reg & BCM_LINTC_TIMER1_IRQ_MASK) 411 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf); 412 if (reg & BCM_LINTC_TIMER2_IRQ_MASK) 413 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf); 414 if (reg & BCM_LINTC_TIMER3_IRQ_MASK) 415 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf); 416 if (reg & BCM_LINTC_GPU_IRQ_MASK) 417 bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf); 418 if (reg & BCM_LINTC_PMU_IRQ_MASK) 419 bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf); 420 421 arm_irq_memory_barrier(0); /* XXX */ 422 } 423 reg &= ~BCM_LINTC_PENDING_MASK; 424 if (reg != 0) 425 device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg); 426 else if (num == 0 && bootverbose) 427 device_printf(sc->bls_dev, "Spurious interrupt detected\n"); 428 429 return (FILTER_HANDLED); 430 } 431 432 static void 433 bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc) 434 { 435 436 bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc); 437 } 438 439 static void 440 bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc) 441 { 442 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 443 444 arm_irq_memory_barrier(bli->bli_irq); 445 bcm_lintc_unmask(device_get_softc(dev), bli); 446 } 447 448 static int 449 bcm_lintc_map_intr(device_t dev, struct intr_map_data *data, 450 struct intr_irqsrc **isrcp) 451 { 452 struct intr_map_data_fdt *daf; 453 struct bcm_lintc_softc *sc; 454 455 if (data->type != INTR_MAP_DATA_FDT) 456 return (ENOTSUP); 457 458 daf = (struct intr_map_data_fdt *)data; 459 if (daf->ncells > 2 || daf->cells[0] >= BCM_LINTC_NIRQS) 460 return (EINVAL); 461 462 /* TODO: handle IRQ type here */ 463 464 sc = device_get_softc(dev); 465 *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc; 466 return (0); 467 } 468 469 static void 470 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 471 { 472 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 473 474 if (bli->bli_irq == BCM_LINTC_GPU_IRQ) 475 bcm_lintc_gpu_mask(device_get_softc(dev), bli); 476 else { 477 /* 478 * Handler for PPI interrupt does not make sense much unless 479 * there is one bound ithread for each core for it. Thus the 480 * interrupt can be masked on current core only while ithread 481 * bounded to this core ensures unmasking on the same core. 482 */ 483 panic ("%s: handlers are not supported", __func__); 484 } 485 } 486 487 static void 488 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc) 489 { 490 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 491 492 if (bli->bli_irq == BCM_LINTC_GPU_IRQ) 493 bcm_lintc_gpu_unmask(device_get_softc(dev), bli); 494 else { 495 /* See comment in bcm_lintc_pre_ithread(). */ 496 panic ("%s: handlers are not supported", __func__); 497 } 498 } 499 500 static void 501 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc) 502 { 503 } 504 505 static int 506 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc, 507 struct resource *res, struct intr_map_data *data) 508 { 509 struct bcm_lintc_softc *sc; 510 511 if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) { 512 sc = device_get_softc(dev); 513 BCM_LINTC_LOCK(sc); 514 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 515 BCM_LINTC_UNLOCK(sc); 516 } 517 return (0); 518 } 519 520 #ifdef SMP 521 static void 522 bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq, 523 uint32_t reg, uint32_t mask) 524 { 525 526 if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu)) 527 bcm_lintc_rwreg_set(sc, reg, mask); 528 } 529 530 static void 531 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu) 532 { 533 struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc; 534 535 if (intr_isrc_init_on_cpu(isrc, cpu)) { 536 /* Write-set register. */ 537 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, 538 BCM_LINTC_PIRR_IRQ_EN_CORE(cpu)); 539 } 540 } 541 542 static void 543 bcm_lintc_init_secondary(device_t dev) 544 { 545 u_int cpu; 546 struct bcm_lintc_softc *sc; 547 548 cpu = PCPU_GET(cpuid); 549 sc = device_get_softc(dev); 550 551 BCM_LINTC_LOCK(sc); 552 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ, 553 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0)); 554 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ, 555 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1)); 556 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ, 557 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2)); 558 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ, 559 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3)); 560 bcm_lintc_init_pmu_on_ap(sc, cpu); 561 BCM_LINTC_UNLOCK(sc); 562 } 563 564 static void 565 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, 566 u_int ipi) 567 { 568 struct bcm_lintc_softc *sc = device_get_softc(dev); 569 570 KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc, 571 ("%s: bad ISRC %p argument", __func__, isrc)); 572 bcm_lintc_ipi_write(sc, cpus, ipi); 573 } 574 575 static int 576 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) 577 { 578 struct bcm_lintc_softc *sc = device_get_softc(dev); 579 580 KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi)); 581 582 *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc; 583 return (0); 584 } 585 #endif 586 587 static int 588 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc) 589 { 590 struct bcm_lintc_irqsrc *bisrcs; 591 struct intr_pic *pic; 592 int error; 593 u_int flags; 594 uint32_t irq; 595 const char *name; 596 intptr_t xref; 597 598 bisrcs = sc->bls_isrcs; 599 name = device_get_nameunit(sc->bls_dev); 600 for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) { 601 bisrcs[irq].bli_irq = irq; 602 switch (irq) { 603 case BCM_LINTC_TIMER0_IRQ: 604 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0); 605 flags = INTR_ISRCF_PPI; 606 break; 607 case BCM_LINTC_TIMER1_IRQ: 608 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1); 609 flags = INTR_ISRCF_PPI; 610 break; 611 case BCM_LINTC_TIMER2_IRQ: 612 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2); 613 flags = INTR_ISRCF_PPI; 614 break; 615 case BCM_LINTC_TIMER3_IRQ: 616 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3); 617 flags = INTR_ISRCF_PPI; 618 break; 619 case BCM_LINTC_MBOX0_IRQ: 620 case BCM_LINTC_MBOX1_IRQ: 621 case BCM_LINTC_MBOX2_IRQ: 622 case BCM_LINTC_MBOX3_IRQ: 623 bisrcs[irq].bli_value = 0; /* not used */ 624 flags = INTR_ISRCF_IPI; 625 break; 626 case BCM_LINTC_GPU_IRQ: 627 bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0); 628 flags = 0; 629 break; 630 case BCM_LINTC_PMU_IRQ: 631 bisrcs[irq].bli_value = 0; /* not used */ 632 flags = INTR_ISRCF_PPI; 633 break; 634 default: 635 bisrcs[irq].bli_value = 0; /* not used */ 636 flags = 0; 637 break; 638 } 639 640 error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev, 641 flags, "%s,%u", name, irq); 642 if (error != 0) 643 return (error); 644 } 645 646 xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev)); 647 pic = intr_pic_register(sc->bls_dev, xref); 648 if (pic == NULL) 649 return (ENXIO); 650 651 return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0)); 652 } 653 654 static int 655 bcm_lintc_probe(device_t dev) 656 { 657 658 if (!ofw_bus_status_okay(dev)) 659 return (ENXIO); 660 661 if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc")) 662 return (ENXIO); 663 if (!ofw_bus_has_prop(dev, "interrupt-controller")) 664 return (ENXIO); 665 device_set_desc(dev, "BCM2836 Interrupt Controller"); 666 return (BUS_PROBE_DEFAULT); 667 } 668 669 static int 670 bcm_lintc_attach(device_t dev) 671 { 672 struct bcm_lintc_softc *sc; 673 int cpu, rid; 674 675 sc = device_get_softc(dev); 676 677 sc->bls_dev = dev; 678 if (bcm_lintc_sc != NULL) 679 return (ENXIO); 680 681 rid = 0; 682 sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 683 RF_ACTIVE); 684 if (sc->bls_mem == NULL) { 685 device_printf(dev, "could not allocate memory resource\n"); 686 return (ENXIO); 687 } 688 689 sc->bls_bst = rman_get_bustag(sc->bls_mem); 690 sc->bls_bsh = rman_get_bushandle(sc->bls_mem); 691 692 bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0); 693 bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2); 694 695 /* Disable all timers on all cores. */ 696 for (cpu = 0; cpu < 4; cpu++) 697 bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0); 698 699 #ifdef SMP 700 /* Enable mailbox 0 on all cores used for IPI. */ 701 for (cpu = 0; cpu < 4; cpu++) 702 bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu), 703 BCM_LINTC_MCR_IRQ_EN_MBOX(0)); 704 #endif 705 706 if (bcm_lintc_pic_attach(sc) != 0) { 707 device_printf(dev, "could not attach PIC\n"); 708 return (ENXIO); 709 } 710 711 BCM_LINTC_LOCK_INIT(sc); 712 bcm_lintc_sc = sc; 713 return (0); 714 } 715 716 static device_method_t bcm_lintc_methods[] = { 717 DEVMETHOD(device_probe, bcm_lintc_probe), 718 DEVMETHOD(device_attach, bcm_lintc_attach), 719 720 DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr), 721 DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr), 722 DEVMETHOD(pic_map_intr, bcm_lintc_map_intr), 723 DEVMETHOD(pic_post_filter, bcm_lintc_post_filter), 724 DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread), 725 DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread), 726 DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr), 727 #ifdef SMP 728 DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary), 729 DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send), 730 DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup), 731 #endif 732 733 DEVMETHOD_END 734 }; 735 736 static driver_t bcm_lintc_driver = { 737 "lintc", 738 bcm_lintc_methods, 739 sizeof(struct bcm_lintc_softc), 740 }; 741 742 static devclass_t bcm_lintc_devclass; 743 744 EARLY_DRIVER_MODULE(lintc, simplebus, bcm_lintc_driver, bcm_lintc_devclass, 745 0, 0, BUS_PASS_INTERRUPT); 746