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>
39 #include <sys/module.h>
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48 #include <machine/resource.h>
50 #include <machine/smp.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54 #include <dev/ofw/ofw_bus.h>
59 #include <arm/broadcom/bcm2835/bcm2836.h>
61 #define ARM_LOCAL_BASE 0x40000000
62 #define ARM_LOCAL_SIZE 0x00001000
64 #define ARM_LOCAL_CONTROL 0x00
65 #define ARM_LOCAL_PRESCALER 0x08
66 #define PRESCALER_19_2 0x80000000 /* 19.2 MHz */
67 #define ARM_LOCAL_INT_TIMER(n) (0x40 + (n) * 4)
68 #define ARM_LOCAL_INT_MAILBOX(n) (0x50 + (n) * 4)
69 #define ARM_LOCAL_INT_PENDING(n) (0x60 + (n) * 4)
70 #define INT_PENDING_MASK 0x011f
71 #define MAILBOX0_IRQ 4
72 #define MAILBOX0_IRQEN (1 << 0)
76 #define BCM_LINTC_CONTROL_REG 0x00
77 #define BCM_LINTC_PRESCALER_REG 0x08
78 #define BCM_LINTC_GPU_ROUTING_REG 0x0c
79 #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10
80 #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14
81 #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4)
82 #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4)
83 #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4)
84 #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16)
85 #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16)
86 #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16)
87 #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16)
88 #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16)
89 #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16)
90 #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16)
91 #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16)
93 /* Prescaler Register */
94 #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */
96 /* GPU Interrupt Routing Register */
97 #define BCM_LINTC_GIRR_IRQ_CORE(n) (n)
98 #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2)
100 /* PMU Interrupt Routing Register */
101 #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n))
102 #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4))
104 /* Timer Config Register */
105 #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n))
106 #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4))
108 /* MBOX Config Register */
109 #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n))
110 #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4))
112 #define BCM_LINTC_CNTPSIRQ_IRQ 0
113 #define BCM_LINTC_CNTPNSIRQ_IRQ 1
114 #define BCM_LINTC_CNTHPIRQ_IRQ 2
115 #define BCM_LINTC_CNTVIRQ_IRQ 3
116 #define BCM_LINTC_MBOX0_IRQ 4
117 #define BCM_LINTC_MBOX1_IRQ 5
118 #define BCM_LINTC_MBOX2_IRQ 6
119 #define BCM_LINTC_MBOX3_IRQ 7
120 #define BCM_LINTC_GPU_IRQ 8
121 #define BCM_LINTC_PMU_IRQ 9
122 #define BCM_LINTC_AXI_IRQ 10
123 #define BCM_LINTC_LTIMER_IRQ 11
125 #define BCM_LINTC_NIRQS 12
127 #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ
128 #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ
129 #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ
130 #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ
132 #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ)
133 #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ)
134 #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ)
135 #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ)
136 #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ)
137 #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ)
138 #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ)
140 #define BCM_LINTC_UP_PENDING_MASK \
141 (BCM_LINTC_TIMER0_IRQ_MASK | \
142 BCM_LINTC_TIMER1_IRQ_MASK | \
143 BCM_LINTC_TIMER2_IRQ_MASK | \
144 BCM_LINTC_TIMER3_IRQ_MASK | \
145 BCM_LINTC_GPU_IRQ_MASK | \
146 BCM_LINTC_PMU_IRQ_MASK)
148 #define BCM_LINTC_SMP_PENDING_MASK \
149 (BCM_LINTC_UP_PENDING_MASK | \
150 BCM_LINTC_MBOX0_IRQ_MASK)
153 #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK
155 #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK
158 struct bcm_lintc_irqsrc {
159 struct intr_irqsrc bli_isrc;
162 u_int bli_mask; /* for timers */
163 u_int bli_value; /* for GPU */
167 struct bcm_lintc_softc {
170 struct resource * bls_mem;
171 bus_space_tag_t bls_bst;
172 bus_space_handle_t bls_bsh;
173 struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS];
176 static struct bcm_lintc_softc *bcm_lintc_sc;
179 #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */
180 CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
183 #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx)
184 #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx)
185 #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \
186 device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
187 #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx)
189 #define bcm_lintc_read_4(sc, reg) \
190 bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
191 #define bcm_lintc_write_4(sc, reg, val) \
192 bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
195 bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
199 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
203 bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
207 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
211 bcm_lintc_timer_mask(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_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
223 BCM_LINTC_UNLOCK(sc);
227 bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
232 cpus = &bli->bli_isrc.isrc_cpu;
235 for (cpu = 0; cpu < 4; cpu++)
236 if (CPU_ISSET(cpu, cpus))
237 bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
239 BCM_LINTC_UNLOCK(sc);
243 bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
246 /* It's accessed just and only by one core. */
247 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
251 bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
254 /* It's accessed just and only by one core. */
255 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
259 bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
265 cpus = &bli->bli_isrc.isrc_cpu;
268 for (cpu = 0; cpu < 4; cpu++)
269 if (CPU_ISSET(cpu, cpus))
270 mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
271 /* Write-clear register. */
272 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
273 BCM_LINTC_UNLOCK(sc);
277 bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
283 cpus = &bli->bli_isrc.isrc_cpu;
286 for (cpu = 0; cpu < 4; cpu++)
287 if (CPU_ISSET(cpu, cpus))
288 mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
289 /* Write-set register. */
290 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
291 BCM_LINTC_UNLOCK(sc);
295 bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
298 switch (bli->bli_irq) {
299 case BCM_LINTC_TIMER0_IRQ:
300 case BCM_LINTC_TIMER1_IRQ:
301 case BCM_LINTC_TIMER2_IRQ:
302 case BCM_LINTC_TIMER3_IRQ:
303 bcm_lintc_timer_mask(sc, bli);
305 case BCM_LINTC_MBOX0_IRQ:
306 case BCM_LINTC_MBOX1_IRQ:
307 case BCM_LINTC_MBOX2_IRQ:
308 case BCM_LINTC_MBOX3_IRQ:
310 case BCM_LINTC_GPU_IRQ:
311 bcm_lintc_gpu_mask(sc, bli);
313 case BCM_LINTC_PMU_IRQ:
314 bcm_lintc_pmu_mask(sc, bli);
317 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
322 bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
325 switch (bli->bli_irq) {
326 case BCM_LINTC_TIMER0_IRQ:
327 case BCM_LINTC_TIMER1_IRQ:
328 case BCM_LINTC_TIMER2_IRQ:
329 case BCM_LINTC_TIMER3_IRQ:
330 bcm_lintc_timer_unmask(sc, bli);
332 case BCM_LINTC_MBOX0_IRQ:
333 case BCM_LINTC_MBOX1_IRQ:
334 case BCM_LINTC_MBOX2_IRQ:
335 case BCM_LINTC_MBOX3_IRQ:
337 case BCM_LINTC_GPU_IRQ:
338 bcm_lintc_gpu_unmask(sc, bli);
340 case BCM_LINTC_PMU_IRQ:
341 bcm_lintc_pmu_unmask(sc, bli);
344 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
350 bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
356 for (cpu = 0; cpu < mp_ncpus; cpu++)
357 if (CPU_ISSET(cpu, &cpus))
358 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
363 bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
364 struct trapframe *tf)
369 mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
371 device_printf(sc->bls_dev, "Spurious ipi detected\n");
375 for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
376 if ((mask & 0x01) == 0)
379 * Clear an IPI before dispatching to not miss anyone
380 * and make sure that it's observed by everybody.
382 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
384 intr_ipi_dispatch(ipi, tf);
390 bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
391 struct trapframe *tf)
393 struct bcm_lintc_irqsrc *bli;
395 bli = &sc->bls_isrcs[irq];
396 if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
397 device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
401 bcm_lintc_intr(void *arg)
403 struct bcm_lintc_softc *sc;
406 struct trapframe *tf;
409 cpu = PCPU_GET(cpuid);
410 tf = curthread->td_intr_frame;
412 for (num = 0; ; num++) {
413 reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
414 if ((reg & BCM_LINTC_PENDING_MASK) == 0)
417 if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
418 bcm_lintc_ipi_dispatch(sc, cpu, tf);
420 if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
421 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
422 if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
423 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
424 if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
425 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
426 if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
427 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
428 if (reg & BCM_LINTC_GPU_IRQ_MASK)
429 bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
430 if (reg & BCM_LINTC_PMU_IRQ_MASK)
431 bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
433 arm_irq_memory_barrier(0); /* XXX */
435 reg &= ~BCM_LINTC_PENDING_MASK;
437 device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
439 device_printf(sc->bls_dev, "Spurious interrupt detected\n");
441 return (FILTER_HANDLED);
445 bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
448 bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
452 bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
454 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
456 arm_irq_memory_barrier(bli->bli_irq);
457 bcm_lintc_unmask(device_get_softc(dev), bli);
461 bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
462 struct intr_irqsrc **isrcp)
464 struct intr_map_data_fdt *daf;
465 struct bcm_lintc_softc *sc;
467 if (data->type != INTR_MAP_DATA_FDT)
470 daf = (struct intr_map_data_fdt *)data;
471 if (daf->ncells != 1 || daf->cells[0] >= BCM_LINTC_NIRQS)
474 sc = device_get_softc(dev);
475 *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
480 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
482 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
484 if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
485 bcm_lintc_gpu_mask(device_get_softc(dev), bli);
488 * Handler for PPI interrupt does not make sense much unless
489 * there is one bound ithread for each core for it. Thus the
490 * interrupt can be masked on current core only while ithread
491 * bounded to this core ensures unmasking on the same core.
493 panic ("%s: handlers are not supported", __func__);
498 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
500 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
502 if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
503 bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
505 /* See comment in bcm_lintc_pre_ithread(). */
506 panic ("%s: handlers are not supported", __func__);
511 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
516 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
517 struct resource *res, struct intr_map_data *data)
519 struct bcm_lintc_softc *sc;
521 if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
522 sc = device_get_softc(dev);
524 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
525 BCM_LINTC_UNLOCK(sc);
532 bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
533 uint32_t reg, uint32_t mask)
536 if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
537 bcm_lintc_rwreg_set(sc, reg, mask);
541 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
543 struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
545 if (intr_isrc_init_on_cpu(isrc, cpu)) {
546 /* Write-set register. */
547 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
548 BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
553 bcm_lintc_init_secondary(device_t dev)
556 struct bcm_lintc_softc *sc;
558 cpu = PCPU_GET(cpuid);
559 sc = device_get_softc(dev);
562 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
563 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
564 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
565 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
566 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
567 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
568 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
569 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
570 bcm_lintc_init_pmu_on_ap(sc, cpu);
571 BCM_LINTC_UNLOCK(sc);
575 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
578 struct bcm_lintc_softc *sc = device_get_softc(dev);
580 KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
581 ("%s: bad ISRC %p argument", __func__, isrc));
582 bcm_lintc_ipi_write(sc, cpus, ipi);
586 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
588 struct bcm_lintc_softc *sc = device_get_softc(dev);
590 KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
592 *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
598 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
600 struct bcm_lintc_irqsrc *bisrcs;
601 struct intr_pic *pic;
608 bisrcs = sc->bls_isrcs;
609 name = device_get_nameunit(sc->bls_dev);
610 for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
611 bisrcs[irq].bli_irq = irq;
613 case BCM_LINTC_TIMER0_IRQ:
614 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
615 flags = INTR_ISRCF_PPI;
617 case BCM_LINTC_TIMER1_IRQ:
618 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
619 flags = INTR_ISRCF_PPI;
621 case BCM_LINTC_TIMER2_IRQ:
622 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
623 flags = INTR_ISRCF_PPI;
625 case BCM_LINTC_TIMER3_IRQ:
626 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
627 flags = INTR_ISRCF_PPI;
629 case BCM_LINTC_MBOX0_IRQ:
630 case BCM_LINTC_MBOX1_IRQ:
631 case BCM_LINTC_MBOX2_IRQ:
632 case BCM_LINTC_MBOX3_IRQ:
633 bisrcs[irq].bli_value = 0; /* not used */
634 flags = INTR_ISRCF_IPI;
636 case BCM_LINTC_GPU_IRQ:
637 bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
640 case BCM_LINTC_PMU_IRQ:
641 bisrcs[irq].bli_value = 0; /* not used */
642 flags = INTR_ISRCF_PPI;
645 bisrcs[irq].bli_value = 0; /* not used */
650 error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
651 flags, "%s,%u", name, irq);
656 xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
657 pic = intr_pic_register(sc->bls_dev, xref);
661 return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
665 bcm_lintc_probe(device_t dev)
668 if (!ofw_bus_status_okay(dev))
671 if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
673 device_set_desc(dev, "BCM2836 Interrupt Controller");
674 return (BUS_PROBE_DEFAULT);
678 bcm_lintc_attach(device_t dev)
680 struct bcm_lintc_softc *sc;
683 sc = device_get_softc(dev);
686 if (bcm_lintc_sc != NULL)
690 sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
692 if (sc->bls_mem == NULL) {
693 device_printf(dev, "could not allocate memory resource\n");
697 sc->bls_bst = rman_get_bustag(sc->bls_mem);
698 sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
700 bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
701 bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
703 /* Disable all timers on all cores. */
704 for (cpu = 0; cpu < 4; cpu++)
705 bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
708 /* Enable mailbox 0 on all cores used for IPI. */
709 for (cpu = 0; cpu < 4; cpu++)
710 bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
711 BCM_LINTC_MCR_IRQ_EN_MBOX(0));
714 if (bcm_lintc_pic_attach(sc) != 0) {
715 device_printf(dev, "could not attach PIC\n");
719 BCM_LINTC_LOCK_INIT(sc);
724 static device_method_t bcm_lintc_methods[] = {
725 DEVMETHOD(device_probe, bcm_lintc_probe),
726 DEVMETHOD(device_attach, bcm_lintc_attach),
728 DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr),
729 DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr),
730 DEVMETHOD(pic_map_intr, bcm_lintc_map_intr),
731 DEVMETHOD(pic_post_filter, bcm_lintc_post_filter),
732 DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread),
733 DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread),
734 DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr),
736 DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary),
737 DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send),
738 DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup),
744 static driver_t bcm_lintc_driver = {
747 sizeof(struct bcm_lintc_softc),
750 static devclass_t bcm_lintc_devclass;
752 EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
753 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
756 * A driver for features of the bcm2836.
759 struct bcm2836_softc {
761 struct resource *sc_mem;
764 static device_identify_t bcm2836_identify;
765 static device_probe_t bcm2836_probe;
766 static device_attach_t bcm2836_attach;
768 struct bcm2836_softc *softc;
771 bcm2836_identify(driver_t *driver, device_t parent)
774 if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL)
775 device_printf(parent, "add child failed\n");
779 bcm2836_probe(device_t dev)
785 device_set_desc(dev, "Broadcom bcm2836");
787 return (BUS_PROBE_DEFAULT);
791 bcm2836_attach(device_t dev)
795 softc = device_get_softc(dev);
799 softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
800 ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE,
802 if (softc->sc_mem == NULL) {
803 device_printf(dev, "could not allocate memory resource\n");
807 bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0);
808 bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2);
810 for (i = 0; i < 4; i++)
811 bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0);
813 for (i = 0; i < 4; i++)
814 bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1);
820 bcm2836_get_next_irq(int last_irq)
826 cpu = PCPU_GET(cpuid);
828 reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu));
829 reg &= INT_PENDING_MASK;
839 bcm2836_mask_irq(uintptr_t irq)
847 if (irq < MAILBOX0_IRQ) {
848 for (i = 0; i < 4; i++) {
849 reg = bus_read_4(softc->sc_mem,
850 ARM_LOCAL_INT_TIMER(i));
852 bus_write_4(softc->sc_mem,
853 ARM_LOCAL_INT_TIMER(i), reg);
856 } else if (irq == MAILBOX0_IRQ) {
857 /* Mailbox 0 for IPI */
858 cpu = PCPU_GET(cpuid);
859 reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
860 reg &= ~MAILBOX0_IRQEN;
861 bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
867 bcm2836_unmask_irq(uintptr_t irq)
875 if (irq < MAILBOX0_IRQ) {
876 for (i = 0; i < 4; i++) {
877 reg = bus_read_4(softc->sc_mem,
878 ARM_LOCAL_INT_TIMER(i));
880 bus_write_4(softc->sc_mem,
881 ARM_LOCAL_INT_TIMER(i), reg);
884 } else if (irq == MAILBOX0_IRQ) {
885 /* Mailbox 0 for IPI */
886 cpu = PCPU_GET(cpuid);
887 reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
888 reg |= MAILBOX0_IRQEN;
889 bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
894 static device_method_t bcm2836_methods[] = {
895 /* Device interface */
896 DEVMETHOD(device_identify, bcm2836_identify),
897 DEVMETHOD(device_probe, bcm2836_probe),
898 DEVMETHOD(device_attach, bcm2836_attach),
903 static devclass_t bcm2836_devclass;
905 static driver_t bcm2836_driver = {
908 sizeof(struct bcm2836_softc),
911 EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
912 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);