14e46a66eSAndrew Turner /*
24e46a66eSAndrew Turner * Copyright 2015 Andrew Turner.
3120b6fc9SSvatopluk Kraus * Copyright 2016 Svatopluk Kraus
44e46a66eSAndrew Turner * All rights reserved.
54e46a66eSAndrew Turner *
64e46a66eSAndrew Turner * Redistribution and use in source and binary forms, with or without
74e46a66eSAndrew Turner * modification, are permitted provided that the following conditions are
84e46a66eSAndrew Turner * met:
94e46a66eSAndrew Turner *
104e46a66eSAndrew Turner * 1. Redistributions of source code must retain the above copyright
114e46a66eSAndrew Turner * notice, this list of conditions and the following disclaimer.
124e46a66eSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
134e46a66eSAndrew Turner * notice, this list of conditions and the following disclaimer in the
144e46a66eSAndrew Turner * documentation and/or other materials provided with the distribution.
154e46a66eSAndrew Turner *
164e46a66eSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
174e46a66eSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184e46a66eSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
194e46a66eSAndrew Turner * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
204e46a66eSAndrew Turner * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214e46a66eSAndrew Turner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224e46a66eSAndrew Turner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
234e46a66eSAndrew Turner * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
244e46a66eSAndrew Turner * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
254e46a66eSAndrew Turner * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
264e46a66eSAndrew Turner * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274e46a66eSAndrew Turner */
284e46a66eSAndrew Turner
294e46a66eSAndrew Turner #include <sys/cdefs.h>
30120b6fc9SSvatopluk Kraus #include "opt_platform.h"
31120b6fc9SSvatopluk Kraus
324e46a66eSAndrew Turner #include <sys/param.h>
334e46a66eSAndrew Turner #include <sys/systm.h>
344e46a66eSAndrew Turner #include <sys/bus.h>
35120b6fc9SSvatopluk Kraus #include <sys/cpuset.h>
364e46a66eSAndrew Turner #include <sys/kernel.h>
37e2e050c8SConrad Meyer #include <sys/lock.h>
384e46a66eSAndrew Turner #include <sys/module.h>
39e2e050c8SConrad Meyer #include <sys/mutex.h>
40120b6fc9SSvatopluk Kraus #include <sys/proc.h>
414e46a66eSAndrew Turner #include <sys/rman.h>
42120b6fc9SSvatopluk Kraus #ifdef SMP
43120b6fc9SSvatopluk Kraus #include <sys/smp.h>
44120b6fc9SSvatopluk Kraus #endif
454e46a66eSAndrew Turner
464e46a66eSAndrew Turner #include <machine/bus.h>
47120b6fc9SSvatopluk Kraus #include <machine/intr.h>
484e46a66eSAndrew Turner #include <machine/resource.h>
49120b6fc9SSvatopluk Kraus #ifdef SMP
50120b6fc9SSvatopluk Kraus #include <machine/smp.h>
51120b6fc9SSvatopluk Kraus #endif
524e46a66eSAndrew Turner
534e46a66eSAndrew Turner #include <dev/ofw/ofw_bus_subr.h>
544e46a66eSAndrew Turner #include <dev/ofw/ofw_bus.h>
554e46a66eSAndrew Turner
56120b6fc9SSvatopluk Kraus #include "pic_if.h"
574e46a66eSAndrew Turner
58120b6fc9SSvatopluk Kraus #define BCM_LINTC_CONTROL_REG 0x00
59120b6fc9SSvatopluk Kraus #define BCM_LINTC_PRESCALER_REG 0x08
60120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_ROUTING_REG 0x0c
61120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10
62120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14
63120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4)
64120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4)
65120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4)
66120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16)
67120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16)
68120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16)
69120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16)
70120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16)
71120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16)
72120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16)
73120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16)
74120b6fc9SSvatopluk Kraus
75120b6fc9SSvatopluk Kraus /* Prescaler Register */
76120b6fc9SSvatopluk Kraus #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */
77120b6fc9SSvatopluk Kraus
78120b6fc9SSvatopluk Kraus /* GPU Interrupt Routing Register */
79120b6fc9SSvatopluk Kraus #define BCM_LINTC_GIRR_IRQ_CORE(n) (n)
80120b6fc9SSvatopluk Kraus #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2)
81120b6fc9SSvatopluk Kraus
82120b6fc9SSvatopluk Kraus /* PMU Interrupt Routing Register */
83120b6fc9SSvatopluk Kraus #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n))
84120b6fc9SSvatopluk Kraus #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4))
85120b6fc9SSvatopluk Kraus
86120b6fc9SSvatopluk Kraus /* Timer Config Register */
87120b6fc9SSvatopluk Kraus #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n))
88120b6fc9SSvatopluk Kraus #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4))
89120b6fc9SSvatopluk Kraus
90120b6fc9SSvatopluk Kraus /* MBOX Config Register */
91120b6fc9SSvatopluk Kraus #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n))
92120b6fc9SSvatopluk Kraus #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4))
93120b6fc9SSvatopluk Kraus
94120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTPSIRQ_IRQ 0
95120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTPNSIRQ_IRQ 1
96120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTHPIRQ_IRQ 2
97120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTVIRQ_IRQ 3
98120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_IRQ 4
99120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_IRQ 5
100120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_IRQ 6
101120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_IRQ 7
102120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_IRQ 8
103120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_IRQ 9
104120b6fc9SSvatopluk Kraus #define BCM_LINTC_AXI_IRQ 10
105120b6fc9SSvatopluk Kraus #define BCM_LINTC_LTIMER_IRQ 11
106120b6fc9SSvatopluk Kraus
107120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIRQS 12
108120b6fc9SSvatopluk Kraus
109120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ
110120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ
111120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ
112120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ
113120b6fc9SSvatopluk Kraus
114120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ)
115120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ)
116120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ)
117120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ)
118120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ)
119120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ)
120120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ)
121120b6fc9SSvatopluk Kraus
122120b6fc9SSvatopluk Kraus #define BCM_LINTC_UP_PENDING_MASK \
123120b6fc9SSvatopluk Kraus (BCM_LINTC_TIMER0_IRQ_MASK | \
124120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER1_IRQ_MASK | \
125120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER2_IRQ_MASK | \
126120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER3_IRQ_MASK | \
127120b6fc9SSvatopluk Kraus BCM_LINTC_GPU_IRQ_MASK | \
128120b6fc9SSvatopluk Kraus BCM_LINTC_PMU_IRQ_MASK)
129120b6fc9SSvatopluk Kraus
130120b6fc9SSvatopluk Kraus #define BCM_LINTC_SMP_PENDING_MASK \
131120b6fc9SSvatopluk Kraus (BCM_LINTC_UP_PENDING_MASK | \
132120b6fc9SSvatopluk Kraus BCM_LINTC_MBOX0_IRQ_MASK)
133120b6fc9SSvatopluk Kraus
134120b6fc9SSvatopluk Kraus #ifdef SMP
135120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK
136120b6fc9SSvatopluk Kraus #else
137120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK
138120b6fc9SSvatopluk Kraus #endif
139120b6fc9SSvatopluk Kraus
140120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc {
141120b6fc9SSvatopluk Kraus struct intr_irqsrc bli_isrc;
142120b6fc9SSvatopluk Kraus u_int bli_irq;
143120b6fc9SSvatopluk Kraus union {
144120b6fc9SSvatopluk Kraus u_int bli_mask; /* for timers */
145120b6fc9SSvatopluk Kraus u_int bli_value; /* for GPU */
146120b6fc9SSvatopluk Kraus };
147120b6fc9SSvatopluk Kraus };
148120b6fc9SSvatopluk Kraus
149120b6fc9SSvatopluk Kraus struct bcm_lintc_softc {
150120b6fc9SSvatopluk Kraus device_t bls_dev;
151120b6fc9SSvatopluk Kraus struct mtx bls_mtx;
152120b6fc9SSvatopluk Kraus struct resource * bls_mem;
153120b6fc9SSvatopluk Kraus bus_space_tag_t bls_bst;
154120b6fc9SSvatopluk Kraus bus_space_handle_t bls_bsh;
155120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS];
156120b6fc9SSvatopluk Kraus };
157120b6fc9SSvatopluk Kraus
158120b6fc9SSvatopluk Kraus static struct bcm_lintc_softc *bcm_lintc_sc;
159120b6fc9SSvatopluk Kraus
160120b6fc9SSvatopluk Kraus #ifdef SMP
161120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */
162120b6fc9SSvatopluk Kraus CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
163120b6fc9SSvatopluk Kraus #endif
164120b6fc9SSvatopluk Kraus
165120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx)
166120b6fc9SSvatopluk Kraus #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx)
167120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \
168120b6fc9SSvatopluk Kraus device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
169120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx)
170120b6fc9SSvatopluk Kraus
171120b6fc9SSvatopluk Kraus #define bcm_lintc_read_4(sc, reg) \
172120b6fc9SSvatopluk Kraus bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
173120b6fc9SSvatopluk Kraus #define bcm_lintc_write_4(sc, reg, val) \
174120b6fc9SSvatopluk Kraus bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
175120b6fc9SSvatopluk Kraus
176120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_rwreg_clr(struct bcm_lintc_softc * sc,uint32_t reg,uint32_t mask)177120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
178120b6fc9SSvatopluk Kraus uint32_t mask)
179120b6fc9SSvatopluk Kraus {
180120b6fc9SSvatopluk Kraus
181120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
182120b6fc9SSvatopluk Kraus }
183120b6fc9SSvatopluk Kraus
184120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_rwreg_set(struct bcm_lintc_softc * sc,uint32_t reg,uint32_t mask)185120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
186120b6fc9SSvatopluk Kraus uint32_t mask)
187120b6fc9SSvatopluk Kraus {
188120b6fc9SSvatopluk Kraus
189120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
190120b6fc9SSvatopluk Kraus }
191120b6fc9SSvatopluk Kraus
192120b6fc9SSvatopluk Kraus static void
bcm_lintc_timer_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)193120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
194120b6fc9SSvatopluk Kraus {
195120b6fc9SSvatopluk Kraus cpuset_t *cpus;
196120b6fc9SSvatopluk Kraus uint32_t cpu;
197120b6fc9SSvatopluk Kraus
198120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu;
199120b6fc9SSvatopluk Kraus
200120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc);
201120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++)
202120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus))
203120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
204120b6fc9SSvatopluk Kraus bli->bli_mask);
205120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc);
206120b6fc9SSvatopluk Kraus }
207120b6fc9SSvatopluk Kraus
208120b6fc9SSvatopluk Kraus static void
bcm_lintc_timer_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)209120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
210120b6fc9SSvatopluk Kraus {
211120b6fc9SSvatopluk Kraus cpuset_t *cpus;
212120b6fc9SSvatopluk Kraus uint32_t cpu;
213120b6fc9SSvatopluk Kraus
214120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu;
215120b6fc9SSvatopluk Kraus
216120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc);
217120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++)
218120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus))
219120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
220120b6fc9SSvatopluk Kraus bli->bli_mask);
221120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc);
222120b6fc9SSvatopluk Kraus }
223120b6fc9SSvatopluk Kraus
224120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_gpu_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)225120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
226120b6fc9SSvatopluk Kraus {
227120b6fc9SSvatopluk Kraus
228120b6fc9SSvatopluk Kraus /* It's accessed just and only by one core. */
229120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
230120b6fc9SSvatopluk Kraus }
231120b6fc9SSvatopluk Kraus
232120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_gpu_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)233120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
234120b6fc9SSvatopluk Kraus {
235120b6fc9SSvatopluk Kraus
236120b6fc9SSvatopluk Kraus /* It's accessed just and only by one core. */
237120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
238120b6fc9SSvatopluk Kraus }
239120b6fc9SSvatopluk Kraus
240120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_pmu_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)241120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
242120b6fc9SSvatopluk Kraus {
243120b6fc9SSvatopluk Kraus cpuset_t *cpus;
244120b6fc9SSvatopluk Kraus uint32_t cpu, mask;
245120b6fc9SSvatopluk Kraus
246120b6fc9SSvatopluk Kraus mask = 0;
247120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu;
248120b6fc9SSvatopluk Kraus
249120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc);
250120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++)
251120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus))
252120b6fc9SSvatopluk Kraus mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
253120b6fc9SSvatopluk Kraus /* Write-clear register. */
254120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
255120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc);
256120b6fc9SSvatopluk Kraus }
257120b6fc9SSvatopluk Kraus
258120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_pmu_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)259120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
260120b6fc9SSvatopluk Kraus {
261120b6fc9SSvatopluk Kraus cpuset_t *cpus;
262120b6fc9SSvatopluk Kraus uint32_t cpu, mask;
263120b6fc9SSvatopluk Kraus
264120b6fc9SSvatopluk Kraus mask = 0;
265120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu;
266120b6fc9SSvatopluk Kraus
267120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc);
268120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++)
269120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus))
270120b6fc9SSvatopluk Kraus mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
271120b6fc9SSvatopluk Kraus /* Write-set register. */
272120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
273120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc);
274120b6fc9SSvatopluk Kraus }
275120b6fc9SSvatopluk Kraus
276120b6fc9SSvatopluk Kraus static void
bcm_lintc_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)277120b6fc9SSvatopluk Kraus bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
278120b6fc9SSvatopluk Kraus {
279120b6fc9SSvatopluk Kraus
280120b6fc9SSvatopluk Kraus switch (bli->bli_irq) {
281120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ:
282120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ:
283120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ:
284120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ:
285120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(sc, bli);
286120b6fc9SSvatopluk Kraus return;
287120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ:
288120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ:
289120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ:
290120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ:
291120b6fc9SSvatopluk Kraus return;
292120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ:
293120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(sc, bli);
294120b6fc9SSvatopluk Kraus return;
295120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ:
296120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(sc, bli);
297120b6fc9SSvatopluk Kraus return;
298120b6fc9SSvatopluk Kraus default:
299120b6fc9SSvatopluk Kraus panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
300120b6fc9SSvatopluk Kraus }
301120b6fc9SSvatopluk Kraus }
302120b6fc9SSvatopluk Kraus
303120b6fc9SSvatopluk Kraus static void
bcm_lintc_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)304120b6fc9SSvatopluk Kraus bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
305120b6fc9SSvatopluk Kraus {
306120b6fc9SSvatopluk Kraus
307120b6fc9SSvatopluk Kraus switch (bli->bli_irq) {
308120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ:
309120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ:
310120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ:
311120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ:
312120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(sc, bli);
313120b6fc9SSvatopluk Kraus return;
314120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ:
315120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ:
316120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ:
317120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ:
318120b6fc9SSvatopluk Kraus return;
319120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ:
320120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(sc, bli);
321120b6fc9SSvatopluk Kraus return;
322120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ:
323120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(sc, bli);
324120b6fc9SSvatopluk Kraus return;
325120b6fc9SSvatopluk Kraus default:
326120b6fc9SSvatopluk Kraus panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
327120b6fc9SSvatopluk Kraus }
328120b6fc9SSvatopluk Kraus }
329120b6fc9SSvatopluk Kraus
330120b6fc9SSvatopluk Kraus #ifdef SMP
331120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_ipi_write(struct bcm_lintc_softc * sc,cpuset_t cpus,u_int ipi)332120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
333120b6fc9SSvatopluk Kraus {
334120b6fc9SSvatopluk Kraus u_int cpu;
335120b6fc9SSvatopluk Kraus uint32_t mask;
336120b6fc9SSvatopluk Kraus
337120b6fc9SSvatopluk Kraus mask = 1 << ipi;
338120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < mp_ncpus; cpu++)
339120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, &cpus))
340120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
341120b6fc9SSvatopluk Kraus mask);
342120b6fc9SSvatopluk Kraus }
343120b6fc9SSvatopluk Kraus
344120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_ipi_dispatch(struct bcm_lintc_softc * sc,u_int cpu,struct trapframe * tf)345120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
346120b6fc9SSvatopluk Kraus struct trapframe *tf)
347120b6fc9SSvatopluk Kraus {
348120b6fc9SSvatopluk Kraus u_int ipi;
349120b6fc9SSvatopluk Kraus uint32_t mask;
350120b6fc9SSvatopluk Kraus
351120b6fc9SSvatopluk Kraus mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
352120b6fc9SSvatopluk Kraus if (mask == 0) {
353120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Spurious ipi detected\n");
354120b6fc9SSvatopluk Kraus return;
355120b6fc9SSvatopluk Kraus }
356120b6fc9SSvatopluk Kraus
357120b6fc9SSvatopluk Kraus for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
358120b6fc9SSvatopluk Kraus if ((mask & 0x01) == 0)
359120b6fc9SSvatopluk Kraus continue;
360120b6fc9SSvatopluk Kraus /*
361120b6fc9SSvatopluk Kraus * Clear an IPI before dispatching to not miss anyone
362120b6fc9SSvatopluk Kraus * and make sure that it's observed by everybody.
363120b6fc9SSvatopluk Kraus */
364120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
3650f04f5deSOleksandr Tymoshenko #if defined(__aarch64__)
3660f04f5deSOleksandr Tymoshenko dsb(sy);
3670f04f5deSOleksandr Tymoshenko #else
368120b6fc9SSvatopluk Kraus dsb();
3690f04f5deSOleksandr Tymoshenko #endif
370d7e3b05bSElliott Mitchell intr_ipi_dispatch(ipi);
371120b6fc9SSvatopluk Kraus }
372120b6fc9SSvatopluk Kraus }
373120b6fc9SSvatopluk Kraus #endif
374120b6fc9SSvatopluk Kraus
375120b6fc9SSvatopluk Kraus static inline void
bcm_lintc_irq_dispatch(struct bcm_lintc_softc * sc,u_int irq,struct trapframe * tf)376120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
377120b6fc9SSvatopluk Kraus struct trapframe *tf)
378120b6fc9SSvatopluk Kraus {
379120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli;
380120b6fc9SSvatopluk Kraus
381120b6fc9SSvatopluk Kraus bli = &sc->bls_isrcs[irq];
382120b6fc9SSvatopluk Kraus if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
383120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
384120b6fc9SSvatopluk Kraus }
385120b6fc9SSvatopluk Kraus
386120b6fc9SSvatopluk Kraus static int
bcm_lintc_intr(void * arg)387120b6fc9SSvatopluk Kraus bcm_lintc_intr(void *arg)
388120b6fc9SSvatopluk Kraus {
389120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc;
390120b6fc9SSvatopluk Kraus u_int cpu;
391120b6fc9SSvatopluk Kraus uint32_t num, reg;
392120b6fc9SSvatopluk Kraus struct trapframe *tf;
393120b6fc9SSvatopluk Kraus
394120b6fc9SSvatopluk Kraus sc = arg;
395120b6fc9SSvatopluk Kraus cpu = PCPU_GET(cpuid);
396120b6fc9SSvatopluk Kraus tf = curthread->td_intr_frame;
397120b6fc9SSvatopluk Kraus
398120b6fc9SSvatopluk Kraus for (num = 0; ; num++) {
399120b6fc9SSvatopluk Kraus reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
400120b6fc9SSvatopluk Kraus if ((reg & BCM_LINTC_PENDING_MASK) == 0)
401120b6fc9SSvatopluk Kraus break;
402120b6fc9SSvatopluk Kraus #ifdef SMP
403120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
404120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(sc, cpu, tf);
405120b6fc9SSvatopluk Kraus #endif
406120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
407120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
408120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
409120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
410120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
411120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
412120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
413120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
414120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_GPU_IRQ_MASK)
415120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
416120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_PMU_IRQ_MASK)
417120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
418120b6fc9SSvatopluk Kraus
419120b6fc9SSvatopluk Kraus arm_irq_memory_barrier(0); /* XXX */
420120b6fc9SSvatopluk Kraus }
421120b6fc9SSvatopluk Kraus reg &= ~BCM_LINTC_PENDING_MASK;
422120b6fc9SSvatopluk Kraus if (reg != 0)
423120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
4249e655cd5SIan Lepore else if (num == 0 && bootverbose)
425120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Spurious interrupt detected\n");
426120b6fc9SSvatopluk Kraus
427120b6fc9SSvatopluk Kraus return (FILTER_HANDLED);
428120b6fc9SSvatopluk Kraus }
429120b6fc9SSvatopluk Kraus
430120b6fc9SSvatopluk Kraus static void
bcm_lintc_disable_intr(device_t dev,struct intr_irqsrc * isrc)431120b6fc9SSvatopluk Kraus bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
432120b6fc9SSvatopluk Kraus {
433120b6fc9SSvatopluk Kraus
434120b6fc9SSvatopluk Kraus bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
435120b6fc9SSvatopluk Kraus }
436120b6fc9SSvatopluk Kraus
437120b6fc9SSvatopluk Kraus static void
bcm_lintc_enable_intr(device_t dev,struct intr_irqsrc * isrc)438120b6fc9SSvatopluk Kraus bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
439120b6fc9SSvatopluk Kraus {
440120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
441120b6fc9SSvatopluk Kraus
442120b6fc9SSvatopluk Kraus arm_irq_memory_barrier(bli->bli_irq);
443120b6fc9SSvatopluk Kraus bcm_lintc_unmask(device_get_softc(dev), bli);
444120b6fc9SSvatopluk Kraus }
445120b6fc9SSvatopluk Kraus
446120b6fc9SSvatopluk Kraus static int
bcm_lintc_map_intr(device_t dev,struct intr_map_data * data,struct intr_irqsrc ** isrcp)447120b6fc9SSvatopluk Kraus bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
448120b6fc9SSvatopluk Kraus struct intr_irqsrc **isrcp)
449120b6fc9SSvatopluk Kraus {
450cd642c88SSvatopluk Kraus struct intr_map_data_fdt *daf;
451120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc;
452120b6fc9SSvatopluk Kraus
453120b6fc9SSvatopluk Kraus if (data->type != INTR_MAP_DATA_FDT)
454120b6fc9SSvatopluk Kraus return (ENOTSUP);
455cd642c88SSvatopluk Kraus
456cd642c88SSvatopluk Kraus daf = (struct intr_map_data_fdt *)data;
4575ebc699aSOleksandr Tymoshenko if (daf->ncells > 2 || daf->cells[0] >= BCM_LINTC_NIRQS)
458120b6fc9SSvatopluk Kraus return (EINVAL);
459120b6fc9SSvatopluk Kraus
4605ebc699aSOleksandr Tymoshenko /* TODO: handle IRQ type here */
4615ebc699aSOleksandr Tymoshenko
462120b6fc9SSvatopluk Kraus sc = device_get_softc(dev);
463cd642c88SSvatopluk Kraus *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
464120b6fc9SSvatopluk Kraus return (0);
465120b6fc9SSvatopluk Kraus }
466120b6fc9SSvatopluk Kraus
467120b6fc9SSvatopluk Kraus static void
bcm_lintc_pre_ithread(device_t dev,struct intr_irqsrc * isrc)468120b6fc9SSvatopluk Kraus bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
469120b6fc9SSvatopluk Kraus {
470120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
471120b6fc9SSvatopluk Kraus
472120b6fc9SSvatopluk Kraus if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
473120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(device_get_softc(dev), bli);
474120b6fc9SSvatopluk Kraus else {
475120b6fc9SSvatopluk Kraus /*
476120b6fc9SSvatopluk Kraus * Handler for PPI interrupt does not make sense much unless
477120b6fc9SSvatopluk Kraus * there is one bound ithread for each core for it. Thus the
478120b6fc9SSvatopluk Kraus * interrupt can be masked on current core only while ithread
479120b6fc9SSvatopluk Kraus * bounded to this core ensures unmasking on the same core.
480120b6fc9SSvatopluk Kraus */
481120b6fc9SSvatopluk Kraus panic ("%s: handlers are not supported", __func__);
482120b6fc9SSvatopluk Kraus }
483120b6fc9SSvatopluk Kraus }
484120b6fc9SSvatopluk Kraus
485120b6fc9SSvatopluk Kraus static void
bcm_lintc_post_ithread(device_t dev,struct intr_irqsrc * isrc)486120b6fc9SSvatopluk Kraus bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
487120b6fc9SSvatopluk Kraus {
488120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
489120b6fc9SSvatopluk Kraus
490120b6fc9SSvatopluk Kraus if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
491120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
492120b6fc9SSvatopluk Kraus else {
493120b6fc9SSvatopluk Kraus /* See comment in bcm_lintc_pre_ithread(). */
494120b6fc9SSvatopluk Kraus panic ("%s: handlers are not supported", __func__);
495120b6fc9SSvatopluk Kraus }
496120b6fc9SSvatopluk Kraus }
497120b6fc9SSvatopluk Kraus
498120b6fc9SSvatopluk Kraus static void
bcm_lintc_post_filter(device_t dev,struct intr_irqsrc * isrc)499120b6fc9SSvatopluk Kraus bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
500120b6fc9SSvatopluk Kraus {
501120b6fc9SSvatopluk Kraus }
502120b6fc9SSvatopluk Kraus
503120b6fc9SSvatopluk Kraus static int
bcm_lintc_setup_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)504120b6fc9SSvatopluk Kraus bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
505120b6fc9SSvatopluk Kraus struct resource *res, struct intr_map_data *data)
506120b6fc9SSvatopluk Kraus {
507120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc;
508120b6fc9SSvatopluk Kraus
509120b6fc9SSvatopluk Kraus if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
510120b6fc9SSvatopluk Kraus sc = device_get_softc(dev);
511120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc);
512120b6fc9SSvatopluk Kraus CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
513120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc);
514120b6fc9SSvatopluk Kraus }
515120b6fc9SSvatopluk Kraus return (0);
516120b6fc9SSvatopluk Kraus }
517120b6fc9SSvatopluk Kraus
518120b6fc9SSvatopluk Kraus #ifdef SMP
519120b6fc9SSvatopluk Kraus static void
bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc * sc,u_int cpu,u_int irq,uint32_t reg,uint32_t mask)520120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
521120b6fc9SSvatopluk Kraus uint32_t reg, uint32_t mask)
522120b6fc9SSvatopluk Kraus {
523120b6fc9SSvatopluk Kraus
5245b613c19SSvatopluk Kraus if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
525120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(sc, reg, mask);
526120b6fc9SSvatopluk Kraus }
527120b6fc9SSvatopluk Kraus
528120b6fc9SSvatopluk Kraus static void
bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc * sc,u_int cpu)529120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
530120b6fc9SSvatopluk Kraus {
5315b613c19SSvatopluk Kraus struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
532120b6fc9SSvatopluk Kraus
5335b613c19SSvatopluk Kraus if (intr_isrc_init_on_cpu(isrc, cpu)) {
534120b6fc9SSvatopluk Kraus /* Write-set register. */
535120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
536120b6fc9SSvatopluk Kraus BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
537120b6fc9SSvatopluk Kraus }
538120b6fc9SSvatopluk Kraus }
539120b6fc9SSvatopluk Kraus
540120b6fc9SSvatopluk Kraus static void
bcm_lintc_init_secondary(device_t dev,uint32_t rootnum)541*4b01a7faSKyle Evans bcm_lintc_init_secondary(device_t dev, uint32_t rootnum)
542120b6fc9SSvatopluk Kraus {
543120b6fc9SSvatopluk Kraus u_int cpu;
544120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc;
545120b6fc9SSvatopluk Kraus
546120b6fc9SSvatopluk Kraus cpu = PCPU_GET(cpuid);
547120b6fc9SSvatopluk Kraus sc = device_get_softc(dev);
548120b6fc9SSvatopluk Kraus
549120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc);
550120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
551120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
552120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
553120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
554120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
555120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
556120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
557120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
558120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(sc, cpu);
559120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc);
560120b6fc9SSvatopluk Kraus }
561120b6fc9SSvatopluk Kraus
562120b6fc9SSvatopluk Kraus static void
bcm_lintc_ipi_send(device_t dev,struct intr_irqsrc * isrc,cpuset_t cpus,u_int ipi)563120b6fc9SSvatopluk Kraus bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
564120b6fc9SSvatopluk Kraus u_int ipi)
565120b6fc9SSvatopluk Kraus {
566120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc = device_get_softc(dev);
567120b6fc9SSvatopluk Kraus
568120b6fc9SSvatopluk Kraus KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
569120b6fc9SSvatopluk Kraus ("%s: bad ISRC %p argument", __func__, isrc));
570120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(sc, cpus, ipi);
571120b6fc9SSvatopluk Kraus }
572120b6fc9SSvatopluk Kraus
573120b6fc9SSvatopluk Kraus static int
bcm_lintc_ipi_setup(device_t dev,u_int ipi,struct intr_irqsrc ** isrcp)574120b6fc9SSvatopluk Kraus bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
575120b6fc9SSvatopluk Kraus {
576120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc = device_get_softc(dev);
577120b6fc9SSvatopluk Kraus
578120b6fc9SSvatopluk Kraus KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
579120b6fc9SSvatopluk Kraus
580120b6fc9SSvatopluk Kraus *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
581120b6fc9SSvatopluk Kraus return (0);
582120b6fc9SSvatopluk Kraus }
583120b6fc9SSvatopluk Kraus #endif
584120b6fc9SSvatopluk Kraus
585120b6fc9SSvatopluk Kraus static int
bcm_lintc_pic_attach(struct bcm_lintc_softc * sc)586120b6fc9SSvatopluk Kraus bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
587120b6fc9SSvatopluk Kraus {
588120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bisrcs;
5899346e913SAndrew Turner struct intr_pic *pic;
590120b6fc9SSvatopluk Kraus int error;
591120b6fc9SSvatopluk Kraus u_int flags;
592120b6fc9SSvatopluk Kraus uint32_t irq;
593120b6fc9SSvatopluk Kraus const char *name;
594120b6fc9SSvatopluk Kraus intptr_t xref;
595120b6fc9SSvatopluk Kraus
596120b6fc9SSvatopluk Kraus bisrcs = sc->bls_isrcs;
597120b6fc9SSvatopluk Kraus name = device_get_nameunit(sc->bls_dev);
598120b6fc9SSvatopluk Kraus for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
599120b6fc9SSvatopluk Kraus bisrcs[irq].bli_irq = irq;
600120b6fc9SSvatopluk Kraus switch (irq) {
601120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ:
602120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
603120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI;
604120b6fc9SSvatopluk Kraus break;
605120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ:
606120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
607120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI;
608120b6fc9SSvatopluk Kraus break;
609120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ:
610120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
611120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI;
612120b6fc9SSvatopluk Kraus break;
613120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ:
614120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
615120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI;
616120b6fc9SSvatopluk Kraus break;
617120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ:
618120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ:
619120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ:
620120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ:
621120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */
622120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_IPI;
623120b6fc9SSvatopluk Kraus break;
624120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ:
625120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
626120b6fc9SSvatopluk Kraus flags = 0;
627120b6fc9SSvatopluk Kraus break;
628120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ:
629120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */
630120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI;
631120b6fc9SSvatopluk Kraus break;
632120b6fc9SSvatopluk Kraus default:
633120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */
634120b6fc9SSvatopluk Kraus flags = 0;
635120b6fc9SSvatopluk Kraus break;
636120b6fc9SSvatopluk Kraus }
637120b6fc9SSvatopluk Kraus
638120b6fc9SSvatopluk Kraus error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
639120b6fc9SSvatopluk Kraus flags, "%s,%u", name, irq);
640120b6fc9SSvatopluk Kraus if (error != 0)
641120b6fc9SSvatopluk Kraus return (error);
642120b6fc9SSvatopluk Kraus }
643120b6fc9SSvatopluk Kraus
644120b6fc9SSvatopluk Kraus xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
6459346e913SAndrew Turner pic = intr_pic_register(sc->bls_dev, xref);
6469346e913SAndrew Turner if (pic == NULL)
6479346e913SAndrew Turner return (ENXIO);
648120b6fc9SSvatopluk Kraus
64985918bebSAyrton Munoz error = intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc,
65085918bebSAyrton Munoz INTR_ROOT_IRQ);
651103d39efSJessica Clarke if (error != 0)
652103d39efSJessica Clarke return (error);
653103d39efSJessica Clarke
654103d39efSJessica Clarke #ifdef SMP
655103d39efSJessica Clarke error = intr_ipi_pic_register(sc->bls_dev, 0);
656103d39efSJessica Clarke if (error != 0)
657103d39efSJessica Clarke return (error);
658103d39efSJessica Clarke #endif
659103d39efSJessica Clarke
660103d39efSJessica Clarke return (0);
661120b6fc9SSvatopluk Kraus }
662120b6fc9SSvatopluk Kraus
663120b6fc9SSvatopluk Kraus static int
bcm_lintc_probe(device_t dev)664120b6fc9SSvatopluk Kraus bcm_lintc_probe(device_t dev)
665120b6fc9SSvatopluk Kraus {
666120b6fc9SSvatopluk Kraus
667120b6fc9SSvatopluk Kraus if (!ofw_bus_status_okay(dev))
668120b6fc9SSvatopluk Kraus return (ENXIO);
669120b6fc9SSvatopluk Kraus
670120b6fc9SSvatopluk Kraus if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
671120b6fc9SSvatopluk Kraus return (ENXIO);
67263f34d01SKyle Evans if (!ofw_bus_has_prop(dev, "interrupt-controller"))
67363f34d01SKyle Evans return (ENXIO);
674120b6fc9SSvatopluk Kraus device_set_desc(dev, "BCM2836 Interrupt Controller");
675120b6fc9SSvatopluk Kraus return (BUS_PROBE_DEFAULT);
676120b6fc9SSvatopluk Kraus }
677120b6fc9SSvatopluk Kraus
678120b6fc9SSvatopluk Kraus static int
bcm_lintc_attach(device_t dev)679120b6fc9SSvatopluk Kraus bcm_lintc_attach(device_t dev)
680120b6fc9SSvatopluk Kraus {
681120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc;
682120b6fc9SSvatopluk Kraus int cpu, rid;
683120b6fc9SSvatopluk Kraus
684120b6fc9SSvatopluk Kraus sc = device_get_softc(dev);
685120b6fc9SSvatopluk Kraus
686120b6fc9SSvatopluk Kraus sc->bls_dev = dev;
687120b6fc9SSvatopluk Kraus if (bcm_lintc_sc != NULL)
688120b6fc9SSvatopluk Kraus return (ENXIO);
689120b6fc9SSvatopluk Kraus
690120b6fc9SSvatopluk Kraus rid = 0;
691120b6fc9SSvatopluk Kraus sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
692120b6fc9SSvatopluk Kraus RF_ACTIVE);
693120b6fc9SSvatopluk Kraus if (sc->bls_mem == NULL) {
694120b6fc9SSvatopluk Kraus device_printf(dev, "could not allocate memory resource\n");
695120b6fc9SSvatopluk Kraus return (ENXIO);
696120b6fc9SSvatopluk Kraus }
697120b6fc9SSvatopluk Kraus
698120b6fc9SSvatopluk Kraus sc->bls_bst = rman_get_bustag(sc->bls_mem);
699120b6fc9SSvatopluk Kraus sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
700120b6fc9SSvatopluk Kraus
701120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
702120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
703120b6fc9SSvatopluk Kraus
704120b6fc9SSvatopluk Kraus /* Disable all timers on all cores. */
705120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++)
706120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
707120b6fc9SSvatopluk Kraus
708120b6fc9SSvatopluk Kraus #ifdef SMP
709120b6fc9SSvatopluk Kraus /* Enable mailbox 0 on all cores used for IPI. */
710120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++)
711120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
712120b6fc9SSvatopluk Kraus BCM_LINTC_MCR_IRQ_EN_MBOX(0));
713120b6fc9SSvatopluk Kraus #endif
714120b6fc9SSvatopluk Kraus
715120b6fc9SSvatopluk Kraus if (bcm_lintc_pic_attach(sc) != 0) {
716120b6fc9SSvatopluk Kraus device_printf(dev, "could not attach PIC\n");
717120b6fc9SSvatopluk Kraus return (ENXIO);
718120b6fc9SSvatopluk Kraus }
719120b6fc9SSvatopluk Kraus
720120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK_INIT(sc);
721120b6fc9SSvatopluk Kraus bcm_lintc_sc = sc;
722120b6fc9SSvatopluk Kraus return (0);
723120b6fc9SSvatopluk Kraus }
724120b6fc9SSvatopluk Kraus
725120b6fc9SSvatopluk Kraus static device_method_t bcm_lintc_methods[] = {
726120b6fc9SSvatopluk Kraus DEVMETHOD(device_probe, bcm_lintc_probe),
727120b6fc9SSvatopluk Kraus DEVMETHOD(device_attach, bcm_lintc_attach),
728120b6fc9SSvatopluk Kraus
729120b6fc9SSvatopluk Kraus DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr),
730120b6fc9SSvatopluk Kraus DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr),
731120b6fc9SSvatopluk Kraus DEVMETHOD(pic_map_intr, bcm_lintc_map_intr),
732120b6fc9SSvatopluk Kraus DEVMETHOD(pic_post_filter, bcm_lintc_post_filter),
733120b6fc9SSvatopluk Kraus DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread),
734120b6fc9SSvatopluk Kraus DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread),
735120b6fc9SSvatopluk Kraus DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr),
736120b6fc9SSvatopluk Kraus #ifdef SMP
737120b6fc9SSvatopluk Kraus DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary),
738120b6fc9SSvatopluk Kraus DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send),
739120b6fc9SSvatopluk Kraus DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup),
740120b6fc9SSvatopluk Kraus #endif
741120b6fc9SSvatopluk Kraus
742120b6fc9SSvatopluk Kraus DEVMETHOD_END
743120b6fc9SSvatopluk Kraus };
744120b6fc9SSvatopluk Kraus
745120b6fc9SSvatopluk Kraus static driver_t bcm_lintc_driver = {
7469e655cd5SIan Lepore "lintc",
747120b6fc9SSvatopluk Kraus bcm_lintc_methods,
748120b6fc9SSvatopluk Kraus sizeof(struct bcm_lintc_softc),
749120b6fc9SSvatopluk Kraus };
750120b6fc9SSvatopluk Kraus
75182d4dc06SJohn Baldwin EARLY_DRIVER_MODULE(lintc, simplebus, bcm_lintc_driver, 0, 0,
75282d4dc06SJohn Baldwin BUS_PASS_INTERRUPT);
753