]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2836.c
Return the struct intr_pic pointer from intr_pic_register. This will be
[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 #ifdef INTRNG
57 #include "pic_if.h"
58 #else
59 #include <arm/broadcom/bcm2835/bcm2836.h>
60
61 #define ARM_LOCAL_BASE  0x40000000
62 #define ARM_LOCAL_SIZE  0x00001000
63
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)
73 #endif
74
75 #ifdef INTRNG
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)
92
93 /* Prescaler Register */
94 #define BCM_LINTC_PSR_19_2              0x80000000      /* 19.2 MHz */
95
96 /* GPU Interrupt Routing Register */
97 #define BCM_LINTC_GIRR_IRQ_CORE(n)      (n)
98 #define BCM_LINTC_GIRR_FIQ_CORE(n)      ((n) << 2)
99
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))
103
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))
107
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))
111
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
124
125 #define BCM_LINTC_NIRQS                 12
126
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
131
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)
139
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)
147
148 #define BCM_LINTC_SMP_PENDING_MASK      \
149     (BCM_LINTC_UP_PENDING_MASK |        \
150      BCM_LINTC_MBOX0_IRQ_MASK)
151
152 #ifdef SMP
153 #define BCM_LINTC_PENDING_MASK          BCM_LINTC_SMP_PENDING_MASK
154 #else
155 #define BCM_LINTC_PENDING_MASK          BCM_LINTC_UP_PENDING_MASK
156 #endif
157
158 struct bcm_lintc_irqsrc {
159         struct intr_irqsrc      bli_isrc;
160         u_int                   bli_irq;
161         union {
162                 u_int           bli_mask;       /* for timers */
163                 u_int           bli_value;      /* for GPU */
164         };
165 };
166
167 struct bcm_lintc_softc {
168         device_t                bls_dev;
169         struct mtx              bls_mtx;
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];
174 };
175
176 static struct bcm_lintc_softc *bcm_lintc_sc;
177
178 #ifdef SMP
179 #define BCM_LINTC_NIPIS         32      /* only mailbox 0 is used for IPI */
180 CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
181 #endif
182
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)
188
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))
193
194 static inline void
195 bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
196     uint32_t mask)
197 {
198
199         bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
200 }
201
202 static inline void
203 bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
204     uint32_t mask)
205 {
206
207         bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
208 }
209
210 static void
211 bcm_lintc_timer_mask(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_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
222                             bli->bli_mask);
223         BCM_LINTC_UNLOCK(sc);
224 }
225
226 static void
227 bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
228 {
229         cpuset_t *cpus;
230         uint32_t cpu;
231
232         cpus = &bli->bli_isrc.isrc_cpu;
233
234         BCM_LINTC_LOCK(sc);
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),
238                             bli->bli_mask);
239         BCM_LINTC_UNLOCK(sc);
240 }
241
242 static inline void
243 bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
244 {
245
246         /* It's accessed just and only by one core. */
247         bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
248 }
249
250 static inline void
251 bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
252 {
253
254         /* It's accessed just and only by one core. */
255         bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
256 }
257
258 static inline void
259 bcm_lintc_pmu_mask(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-clear register. */
272         bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
273         BCM_LINTC_UNLOCK(sc);
274 }
275
276 static inline void
277 bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
278 {
279         cpuset_t *cpus;
280         uint32_t cpu, mask;
281
282         mask = 0;
283         cpus = &bli->bli_isrc.isrc_cpu;
284
285         BCM_LINTC_LOCK(sc);
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);
292 }
293
294 static void
295 bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
296 {
297
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);
304                 return;
305         case BCM_LINTC_MBOX0_IRQ:
306         case BCM_LINTC_MBOX1_IRQ:
307         case BCM_LINTC_MBOX2_IRQ:
308         case BCM_LINTC_MBOX3_IRQ:
309                 return;
310         case BCM_LINTC_GPU_IRQ:
311                 bcm_lintc_gpu_mask(sc, bli);
312                 return;
313         case BCM_LINTC_PMU_IRQ:
314                 bcm_lintc_pmu_mask(sc, bli);
315                 return;
316         default:
317                 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
318         }
319 }
320
321 static void
322 bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
323 {
324
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);
331                 return;
332         case BCM_LINTC_MBOX0_IRQ:
333         case BCM_LINTC_MBOX1_IRQ:
334         case BCM_LINTC_MBOX2_IRQ:
335         case BCM_LINTC_MBOX3_IRQ:
336                 return;
337         case BCM_LINTC_GPU_IRQ:
338                 bcm_lintc_gpu_unmask(sc, bli);
339                 return;
340         case BCM_LINTC_PMU_IRQ:
341                 bcm_lintc_pmu_unmask(sc, bli);
342                 return;
343         default:
344                 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
345         }
346 }
347
348 #ifdef SMP
349 static inline void
350 bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
351 {
352         u_int cpu;
353         uint32_t mask;
354
355         mask = 1 << 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),
359                             mask);
360 }
361
362 static inline void
363 bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
364     struct trapframe *tf)
365 {
366         u_int ipi;
367         uint32_t mask;
368
369         mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
370         if (mask == 0) {
371                 device_printf(sc->bls_dev, "Spurious ipi detected\n");
372                 return;
373         }
374
375         for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
376                 if ((mask & 0x01) == 0)
377                         continue;
378                 /*
379                  * Clear an IPI before dispatching to not miss anyone
380                  * and make sure that it's observed by everybody.
381                  */
382                 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
383                 dsb();
384                 intr_ipi_dispatch(ipi, tf);
385         }
386 }
387 #endif
388
389 static inline void
390 bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
391     struct trapframe *tf)
392 {
393         struct bcm_lintc_irqsrc *bli;
394
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);
398 }
399
400 static int
401 bcm_lintc_intr(void *arg)
402 {
403         struct bcm_lintc_softc *sc;
404         u_int cpu;
405         uint32_t num, reg;
406         struct trapframe *tf;
407
408         sc = arg;
409         cpu = PCPU_GET(cpuid);
410         tf = curthread->td_intr_frame;
411
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)
415                         break;
416 #ifdef SMP
417                 if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
418                         bcm_lintc_ipi_dispatch(sc, cpu, tf);
419 #endif
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);
432
433                 arm_irq_memory_barrier(0); /* XXX */
434         }
435         reg &= ~BCM_LINTC_PENDING_MASK;
436         if (reg != 0)
437                 device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
438         else if (num == 0)
439                 device_printf(sc->bls_dev, "Spurious interrupt detected\n");
440
441         return (FILTER_HANDLED);
442 }
443
444 static void
445 bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
446 {
447
448         bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
449 }
450
451 static void
452 bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
453 {
454         struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
455
456         arm_irq_memory_barrier(bli->bli_irq);
457         bcm_lintc_unmask(device_get_softc(dev), bli);
458 }
459
460 static int
461 bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
462     struct intr_irqsrc **isrcp)
463 {
464         struct intr_map_data_fdt *daf;
465         struct bcm_lintc_softc *sc;
466
467         if (data->type != INTR_MAP_DATA_FDT)
468                 return (ENOTSUP);
469
470         daf = (struct intr_map_data_fdt *)data;
471         if (daf->ncells != 1 || daf->cells[0] >= BCM_LINTC_NIRQS)
472                 return (EINVAL);
473
474         sc = device_get_softc(dev);
475         *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
476         return (0);
477 }
478
479 static void
480 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
481 {
482         struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
483
484         if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
485                 bcm_lintc_gpu_mask(device_get_softc(dev), bli);
486         else {
487                 /*
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.
492                  */
493                 panic ("%s: handlers are not supported", __func__);
494         }
495 }
496
497 static void
498 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
499 {
500         struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
501
502         if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
503                 bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
504         else {
505                 /* See comment in bcm_lintc_pre_ithread(). */
506                 panic ("%s: handlers are not supported", __func__);
507         }
508 }
509
510 static void
511 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
512 {
513 }
514
515 static int
516 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
517     struct resource *res, struct intr_map_data *data)
518 {
519         struct bcm_lintc_softc *sc;
520
521         if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
522                 sc = device_get_softc(dev);
523                 BCM_LINTC_LOCK(sc);
524                 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
525                 BCM_LINTC_UNLOCK(sc);
526         }
527         return (0);
528 }
529
530 #ifdef SMP
531 static void
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)
534 {
535
536         if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
537                 bcm_lintc_rwreg_set(sc, reg, mask);
538 }
539
540 static void
541 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
542 {
543         struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
544
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));
549         }
550 }
551
552 static void
553 bcm_lintc_init_secondary(device_t dev)
554 {
555         u_int cpu;
556         struct bcm_lintc_softc *sc;
557
558         cpu = PCPU_GET(cpuid);
559         sc = device_get_softc(dev);
560
561         BCM_LINTC_LOCK(sc);
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);
572 }
573
574 static void
575 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
576     u_int ipi)
577 {
578         struct bcm_lintc_softc *sc = device_get_softc(dev);
579
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);
583 }
584
585 static int
586 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
587 {
588         struct bcm_lintc_softc *sc = device_get_softc(dev);
589
590         KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
591
592         *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
593         return (0);
594 }
595 #endif
596
597 static int
598 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
599 {
600         struct bcm_lintc_irqsrc *bisrcs;
601         struct intr_pic *pic;
602         int error;
603         u_int flags;
604         uint32_t irq;
605         const char *name;
606         intptr_t xref;
607
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;
612                 switch (irq) {
613                 case BCM_LINTC_TIMER0_IRQ:
614                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
615                         flags = INTR_ISRCF_PPI;
616                         break;
617                 case BCM_LINTC_TIMER1_IRQ:
618                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
619                         flags = INTR_ISRCF_PPI;
620                         break;
621                 case BCM_LINTC_TIMER2_IRQ:
622                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
623                         flags = INTR_ISRCF_PPI;
624                         break;
625                 case BCM_LINTC_TIMER3_IRQ:
626                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
627                         flags = INTR_ISRCF_PPI;
628                         break;
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;
635                         break;
636                 case BCM_LINTC_GPU_IRQ:
637                         bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
638                         flags = 0;
639                         break;
640                 case BCM_LINTC_PMU_IRQ:
641                         bisrcs[irq].bli_value = 0;      /* not used */
642                         flags = INTR_ISRCF_PPI;
643                         break;
644                 default:
645                         bisrcs[irq].bli_value = 0;      /* not used */
646                         flags = 0;
647                         break;
648                 }
649
650                 error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
651                     flags, "%s,%u", name, irq);
652                 if (error != 0)
653                         return (error);
654         }
655
656         xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
657         pic = intr_pic_register(sc->bls_dev, xref);
658         if (pic == NULL)
659                 return (ENXIO);
660
661         return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
662 }
663
664 static int
665 bcm_lintc_probe(device_t dev)
666 {
667
668         if (!ofw_bus_status_okay(dev))
669                 return (ENXIO);
670
671         if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
672                 return (ENXIO);
673         device_set_desc(dev, "BCM2836 Interrupt Controller");
674         return (BUS_PROBE_DEFAULT);
675 }
676
677 static int
678 bcm_lintc_attach(device_t dev)
679 {
680         struct bcm_lintc_softc *sc;
681         int cpu, rid;
682
683         sc = device_get_softc(dev);
684
685         sc->bls_dev = dev;
686         if (bcm_lintc_sc != NULL)
687                 return (ENXIO);
688
689         rid = 0;
690         sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
691             RF_ACTIVE);
692         if (sc->bls_mem == NULL) {
693                 device_printf(dev, "could not allocate memory resource\n");
694                 return (ENXIO);
695         }
696
697         sc->bls_bst = rman_get_bustag(sc->bls_mem);
698         sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
699
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);
702
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);
706
707 #ifdef SMP
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));
712 #endif
713
714         if (bcm_lintc_pic_attach(sc) != 0) {
715                 device_printf(dev, "could not attach PIC\n");
716                 return (ENXIO);
717         }
718
719         BCM_LINTC_LOCK_INIT(sc);
720         bcm_lintc_sc = sc;
721         return (0);
722 }
723
724 static device_method_t bcm_lintc_methods[] = {
725         DEVMETHOD(device_probe,         bcm_lintc_probe),
726         DEVMETHOD(device_attach,        bcm_lintc_attach),
727
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),
735 #ifdef SMP
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),
739 #endif
740
741         DEVMETHOD_END
742 };
743
744 static driver_t bcm_lintc_driver = {
745         "local_intc",
746         bcm_lintc_methods,
747         sizeof(struct bcm_lintc_softc),
748 };
749
750 static devclass_t bcm_lintc_devclass;
751
752 EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
753     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
754 #else
755 /*
756  * A driver for features of the bcm2836.
757  */
758
759 struct bcm2836_softc {
760         device_t         sc_dev;
761         struct resource *sc_mem;
762 };
763
764 static device_identify_t bcm2836_identify;
765 static device_probe_t bcm2836_probe;
766 static device_attach_t bcm2836_attach;
767
768 struct bcm2836_softc *softc;
769
770 static void
771 bcm2836_identify(driver_t *driver, device_t parent)
772 {
773
774         if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL)
775                 device_printf(parent, "add child failed\n");
776 }
777
778 static int
779 bcm2836_probe(device_t dev)
780 {
781
782         if (softc != NULL)
783                 return (ENXIO);
784
785         device_set_desc(dev, "Broadcom bcm2836");
786
787         return (BUS_PROBE_DEFAULT);
788 }
789
790 static int
791 bcm2836_attach(device_t dev)
792 {
793         int i, rid;
794
795         softc = device_get_softc(dev);
796         softc->sc_dev = dev;
797
798         rid = 0;
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,
801             RF_ACTIVE);
802         if (softc->sc_mem == NULL) {
803                 device_printf(dev, "could not allocate memory resource\n");
804                 return (ENXIO);
805         }
806
807         bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0);
808         bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2);
809
810         for (i = 0; i < 4; i++)
811                 bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0);
812
813         for (i = 0; i < 4; i++)
814                 bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1);
815
816         return (0);
817 }
818
819 int
820 bcm2836_get_next_irq(int last_irq)
821 {
822         uint32_t reg;
823         int cpu;
824         int irq;
825
826         cpu = PCPU_GET(cpuid);
827
828         reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu));
829         reg &= INT_PENDING_MASK;
830         if (reg == 0)
831                 return (-1);
832
833         irq = ffs(reg) - 1;
834
835         return (irq);
836 }
837
838 void
839 bcm2836_mask_irq(uintptr_t irq)
840 {
841         uint32_t reg;
842 #ifdef SMP
843         int cpu;
844 #endif
845         int i;
846
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));
851                         reg &= ~(1 << irq);
852                         bus_write_4(softc->sc_mem,
853                             ARM_LOCAL_INT_TIMER(i), reg);
854                 }
855 #ifdef SMP
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);
862 #endif
863         }
864 }
865
866 void
867 bcm2836_unmask_irq(uintptr_t irq)
868 {
869         uint32_t reg;
870 #ifdef SMP
871         int cpu;
872 #endif
873         int i;
874
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));
879                         reg |= (1 << irq);
880                         bus_write_4(softc->sc_mem,
881                             ARM_LOCAL_INT_TIMER(i), reg);
882                 }
883 #ifdef SMP
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);
890 #endif
891         }
892 }
893
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),
899
900         DEVMETHOD_END
901 };
902
903 static devclass_t bcm2836_devclass;
904
905 static driver_t bcm2836_driver = {
906         "bcm2836",
907         bcm2836_methods,
908         sizeof(struct bcm2836_softc),
909 };
910
911 EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
912     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
913 #endif