2 * Copyright 2015 Andrew Turner.
3 * Copyright 2016 Svatopluk Kraus
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
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.
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.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include "opt_platform.h"
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/cpuset.h>
38 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
48 #include <machine/bus.h>
49 #include <machine/intr.h>
50 #include <machine/resource.h>
52 #include <machine/smp.h>
55 #include <dev/ofw/ofw_bus_subr.h>
56 #include <dev/ofw/ofw_bus.h>
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)
77 /* Prescaler Register */
78 #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */
80 /* GPU Interrupt Routing Register */
81 #define BCM_LINTC_GIRR_IRQ_CORE(n) (n)
82 #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2)
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))
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))
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))
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
109 #define BCM_LINTC_NIRQS 12
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
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)
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)
132 #define BCM_LINTC_SMP_PENDING_MASK \
133 (BCM_LINTC_UP_PENDING_MASK | \
134 BCM_LINTC_MBOX0_IRQ_MASK)
137 #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK
139 #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK
142 struct bcm_lintc_irqsrc {
143 struct intr_irqsrc bli_isrc;
146 u_int bli_mask; /* for timers */
147 u_int bli_value; /* for GPU */
151 struct bcm_lintc_softc {
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];
160 static struct bcm_lintc_softc *bcm_lintc_sc;
163 #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */
164 CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
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)
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))
179 bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
183 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
187 bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
191 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
195 bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
200 cpus = &bli->bli_isrc.isrc_cpu;
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),
207 BCM_LINTC_UNLOCK(sc);
211 bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
216 cpus = &bli->bli_isrc.isrc_cpu;
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),
223 BCM_LINTC_UNLOCK(sc);
227 bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
230 /* It's accessed just and only by one core. */
231 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
235 bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
238 /* It's accessed just and only by one core. */
239 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
243 bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
249 cpus = &bli->bli_isrc.isrc_cpu;
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);
261 bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
267 cpus = &bli->bli_isrc.isrc_cpu;
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);
279 bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
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);
289 case BCM_LINTC_MBOX0_IRQ:
290 case BCM_LINTC_MBOX1_IRQ:
291 case BCM_LINTC_MBOX2_IRQ:
292 case BCM_LINTC_MBOX3_IRQ:
294 case BCM_LINTC_GPU_IRQ:
295 bcm_lintc_gpu_mask(sc, bli);
297 case BCM_LINTC_PMU_IRQ:
298 bcm_lintc_pmu_mask(sc, bli);
301 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
306 bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
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);
316 case BCM_LINTC_MBOX0_IRQ:
317 case BCM_LINTC_MBOX1_IRQ:
318 case BCM_LINTC_MBOX2_IRQ:
319 case BCM_LINTC_MBOX3_IRQ:
321 case BCM_LINTC_GPU_IRQ:
322 bcm_lintc_gpu_unmask(sc, bli);
324 case BCM_LINTC_PMU_IRQ:
325 bcm_lintc_pmu_unmask(sc, bli);
328 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
334 bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int 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),
347 bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
348 struct trapframe *tf)
353 mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
355 device_printf(sc->bls_dev, "Spurious ipi detected\n");
359 for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
360 if ((mask & 0x01) == 0)
363 * Clear an IPI before dispatching to not miss anyone
364 * and make sure that it's observed by everybody.
366 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
367 #if defined(__aarch64__)
372 intr_ipi_dispatch(ipi, tf);
378 bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
379 struct trapframe *tf)
381 struct bcm_lintc_irqsrc *bli;
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);
389 bcm_lintc_intr(void *arg)
391 struct bcm_lintc_softc *sc;
394 struct trapframe *tf;
397 cpu = PCPU_GET(cpuid);
398 tf = curthread->td_intr_frame;
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)
405 if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
406 bcm_lintc_ipi_dispatch(sc, cpu, tf);
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);
421 arm_irq_memory_barrier(0); /* XXX */
423 reg &= ~BCM_LINTC_PENDING_MASK;
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");
429 return (FILTER_HANDLED);
433 bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
436 bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
440 bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
442 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
444 arm_irq_memory_barrier(bli->bli_irq);
445 bcm_lintc_unmask(device_get_softc(dev), bli);
449 bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
450 struct intr_irqsrc **isrcp)
452 struct intr_map_data_fdt *daf;
453 struct bcm_lintc_softc *sc;
455 if (data->type != INTR_MAP_DATA_FDT)
458 daf = (struct intr_map_data_fdt *)data;
459 if (daf->ncells > 2 || daf->cells[0] >= BCM_LINTC_NIRQS)
462 /* TODO: handle IRQ type here */
464 sc = device_get_softc(dev);
465 *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
470 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
472 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
474 if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
475 bcm_lintc_gpu_mask(device_get_softc(dev), bli);
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.
483 panic ("%s: handlers are not supported", __func__);
488 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
490 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
492 if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
493 bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
495 /* See comment in bcm_lintc_pre_ithread(). */
496 panic ("%s: handlers are not supported", __func__);
501 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
506 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
507 struct resource *res, struct intr_map_data *data)
509 struct bcm_lintc_softc *sc;
511 if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
512 sc = device_get_softc(dev);
514 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
515 BCM_LINTC_UNLOCK(sc);
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)
526 if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
527 bcm_lintc_rwreg_set(sc, reg, mask);
531 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
533 struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
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));
543 bcm_lintc_init_secondary(device_t dev)
546 struct bcm_lintc_softc *sc;
548 cpu = PCPU_GET(cpuid);
549 sc = device_get_softc(dev);
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);
565 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
568 struct bcm_lintc_softc *sc = device_get_softc(dev);
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);
576 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
578 struct bcm_lintc_softc *sc = device_get_softc(dev);
580 KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
582 *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
588 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
590 struct bcm_lintc_irqsrc *bisrcs;
591 struct intr_pic *pic;
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;
603 case BCM_LINTC_TIMER0_IRQ:
604 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
605 flags = INTR_ISRCF_PPI;
607 case BCM_LINTC_TIMER1_IRQ:
608 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
609 flags = INTR_ISRCF_PPI;
611 case BCM_LINTC_TIMER2_IRQ:
612 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
613 flags = INTR_ISRCF_PPI;
615 case BCM_LINTC_TIMER3_IRQ:
616 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
617 flags = INTR_ISRCF_PPI;
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;
626 case BCM_LINTC_GPU_IRQ:
627 bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
630 case BCM_LINTC_PMU_IRQ:
631 bisrcs[irq].bli_value = 0; /* not used */
632 flags = INTR_ISRCF_PPI;
635 bisrcs[irq].bli_value = 0; /* not used */
640 error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
641 flags, "%s,%u", name, irq);
646 xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
647 pic = intr_pic_register(sc->bls_dev, xref);
651 return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
655 bcm_lintc_probe(device_t dev)
658 if (!ofw_bus_status_okay(dev))
661 if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
663 device_set_desc(dev, "BCM2836 Interrupt Controller");
664 return (BUS_PROBE_DEFAULT);
668 bcm_lintc_attach(device_t dev)
670 struct bcm_lintc_softc *sc;
673 sc = device_get_softc(dev);
676 if (bcm_lintc_sc != NULL)
680 sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
682 if (sc->bls_mem == NULL) {
683 device_printf(dev, "could not allocate memory resource\n");
687 sc->bls_bst = rman_get_bustag(sc->bls_mem);
688 sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
690 bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
691 bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
693 /* Disable all timers on all cores. */
694 for (cpu = 0; cpu < 4; cpu++)
695 bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
698 /* Enable mailbox 0 on all cores used for IPI. */
699 for (cpu = 0; cpu < 4; cpu++)
700 bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
701 BCM_LINTC_MCR_IRQ_EN_MBOX(0));
704 if (bcm_lintc_pic_attach(sc) != 0) {
705 device_printf(dev, "could not attach PIC\n");
709 BCM_LINTC_LOCK_INIT(sc);
714 static device_method_t bcm_lintc_methods[] = {
715 DEVMETHOD(device_probe, bcm_lintc_probe),
716 DEVMETHOD(device_attach, bcm_lintc_attach),
718 DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr),
719 DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr),
720 DEVMETHOD(pic_map_intr, bcm_lintc_map_intr),
721 DEVMETHOD(pic_post_filter, bcm_lintc_post_filter),
722 DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread),
723 DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread),
724 DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr),
726 DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary),
727 DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send),
728 DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup),
734 static driver_t bcm_lintc_driver = {
737 sizeof(struct bcm_lintc_softc),
740 static devclass_t bcm_lintc_devclass;
742 EARLY_DRIVER_MODULE(lintc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
743 0, 0, BUS_PASS_INTERRUPT);