]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2836.c
MFV r362143:
[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/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);