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