xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2836.c (revision 120b6fc9b2c98550c520adf4d70230f81fb0f7cb)
14e46a66eSAndrew Turner /*
24e46a66eSAndrew Turner  * Copyright 2015 Andrew Turner.
3*120b6fc9SSvatopluk 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>
304e46a66eSAndrew Turner __FBSDID("$FreeBSD$");
314e46a66eSAndrew Turner 
32*120b6fc9SSvatopluk Kraus #include "opt_platform.h"
33*120b6fc9SSvatopluk Kraus 
344e46a66eSAndrew Turner #include <sys/param.h>
354e46a66eSAndrew Turner #include <sys/systm.h>
364e46a66eSAndrew Turner #include <sys/bus.h>
37*120b6fc9SSvatopluk Kraus #include <sys/cpuset.h>
384e46a66eSAndrew Turner #include <sys/kernel.h>
394e46a66eSAndrew Turner #include <sys/module.h>
40*120b6fc9SSvatopluk Kraus #include <sys/proc.h>
414e46a66eSAndrew Turner #include <sys/rman.h>
42*120b6fc9SSvatopluk Kraus #ifdef SMP
43*120b6fc9SSvatopluk Kraus #include <sys/smp.h>
44*120b6fc9SSvatopluk Kraus #endif
454e46a66eSAndrew Turner 
464e46a66eSAndrew Turner #include <machine/bus.h>
47*120b6fc9SSvatopluk Kraus #include <machine/intr.h>
484e46a66eSAndrew Turner #include <machine/resource.h>
49*120b6fc9SSvatopluk Kraus #ifdef SMP
50*120b6fc9SSvatopluk Kraus #include <machine/smp.h>
51*120b6fc9SSvatopluk Kraus #endif
524e46a66eSAndrew Turner 
534e46a66eSAndrew Turner #include <dev/ofw/ofw_bus_subr.h>
544e46a66eSAndrew Turner #include <dev/ofw/ofw_bus.h>
554e46a66eSAndrew Turner 
56*120b6fc9SSvatopluk Kraus #ifdef ARM_INTRNG
57*120b6fc9SSvatopluk Kraus #include "pic_if.h"
58*120b6fc9SSvatopluk Kraus #else
594e46a66eSAndrew Turner #include <arm/broadcom/bcm2835/bcm2836.h>
604e46a66eSAndrew Turner 
614e46a66eSAndrew Turner #define	ARM_LOCAL_BASE	0x40000000
624e46a66eSAndrew Turner #define	ARM_LOCAL_SIZE	0x00001000
634e46a66eSAndrew Turner 
644e46a66eSAndrew Turner #define	ARM_LOCAL_CONTROL		0x00
654e46a66eSAndrew Turner #define	ARM_LOCAL_PRESCALER		0x08
664e46a66eSAndrew Turner #define	 PRESCALER_19_2			0x80000000 /* 19.2 MHz */
674e46a66eSAndrew Turner #define	ARM_LOCAL_INT_TIMER(n)		(0x40 + (n) * 4)
684e46a66eSAndrew Turner #define	ARM_LOCAL_INT_MAILBOX(n)	(0x50 + (n) * 4)
694e46a66eSAndrew Turner #define	ARM_LOCAL_INT_PENDING(n)	(0x60 + (n) * 4)
703084b64cSSvatopluk Kraus #define	 INT_PENDING_MASK		0x011f
71962940ceSLuiz Otavio O Souza #define	MAILBOX0_IRQ			4
72962940ceSLuiz Otavio O Souza #define	MAILBOX0_IRQEN			(1 << 0)
73*120b6fc9SSvatopluk Kraus #endif
744e46a66eSAndrew Turner 
75*120b6fc9SSvatopluk Kraus #ifdef ARM_INTRNG
76*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CONTROL_REG		0x00
77*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PRESCALER_REG		0x08
78*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GPU_ROUTING_REG	0x0c
79*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_ROUTING_SET_REG	0x10
80*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_ROUTING_CLR_REG	0x14
81*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER_CFG_REG(n)	(0x40 + (n) * 4)
82*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX_CFG_REG(n)	(0x50 + (n) * 4)
83*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PENDING_REG(n)	(0x60 + (n) * 4)
84*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_SET_REG(n)	(0x80 + (n) * 16)
85*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX1_SET_REG(n)	(0x84 + (n) * 16)
86*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX2_SET_REG(n)	(0x88 + (n) * 16)
87*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX3_SET_REG(n)	(0x8C + (n) * 16)
88*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_CLR_REG(n)	(0xC0 + (n) * 16)
89*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX1_CLR_REG(n)	(0xC4 + (n) * 16)
90*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX2_CLR_REG(n)	(0xC8 + (n) * 16)
91*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX3_CLR_REG(n)	(0xCC + (n) * 16)
92*120b6fc9SSvatopluk Kraus 
93*120b6fc9SSvatopluk Kraus /* Prescaler Register */
94*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PSR_19_2		0x80000000	/* 19.2 MHz */
95*120b6fc9SSvatopluk Kraus 
96*120b6fc9SSvatopluk Kraus /* GPU Interrupt Routing Register */
97*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GIRR_IRQ_CORE(n)	(n)
98*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GIRR_FIQ_CORE(n)	((n) << 2)
99*120b6fc9SSvatopluk Kraus 
100*120b6fc9SSvatopluk Kraus /* PMU Interrupt Routing Register */
101*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PIRR_IRQ_EN_CORE(n)	(1 << (n))
102*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PIRR_FIQ_EN_CORE(n)	(1 << ((n) + 4))
103*120b6fc9SSvatopluk Kraus 
104*120b6fc9SSvatopluk Kraus /* Timer Config Register */
105*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TCR_IRQ_EN_TIMER(n)	(1 << (n))
106*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TCR_FIQ_EN_TIMER(n)	(1 << ((n) + 4))
107*120b6fc9SSvatopluk Kraus 
108*120b6fc9SSvatopluk Kraus /* MBOX Config Register */
109*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MCR_IRQ_EN_MBOX(n)	(1 << (n))
110*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MCR_FIQ_EN_MBOX(n)	(1 << ((n) + 4))
111*120b6fc9SSvatopluk Kraus 
112*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTPSIRQ_IRQ		0
113*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTPNSIRQ_IRQ		1
114*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTHPIRQ_IRQ		2
115*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTVIRQ_IRQ		3
116*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_IRQ		4
117*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX1_IRQ		5
118*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX2_IRQ		6
119*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX3_IRQ		7
120*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GPU_IRQ		8
121*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_IRQ		9
122*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_AXI_IRQ		10
123*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LTIMER_IRQ		11
124*120b6fc9SSvatopluk Kraus 
125*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_NIRQS			12
126*120b6fc9SSvatopluk Kraus 
127*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER0_IRQ		BCM_LINTC_CNTPSIRQ_IRQ
128*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER1_IRQ		BCM_LINTC_CNTPNSIRQ_IRQ
129*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER2_IRQ		BCM_LINTC_CNTHPIRQ_IRQ
130*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER3_IRQ		BCM_LINTC_CNTVIRQ_IRQ
131*120b6fc9SSvatopluk Kraus 
132*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER0_IRQ_MASK	(1 << BCM_LINTC_TIMER0_IRQ)
133*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER1_IRQ_MASK	(1 << BCM_LINTC_TIMER1_IRQ)
134*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER2_IRQ_MASK	(1 << BCM_LINTC_TIMER2_IRQ)
135*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER3_IRQ_MASK	(1 << BCM_LINTC_TIMER3_IRQ)
136*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_IRQ_MASK	(1 << BCM_LINTC_MBOX0_IRQ)
137*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GPU_IRQ_MASK		(1 << BCM_LINTC_GPU_IRQ)
138*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_IRQ_MASK		(1 << BCM_LINTC_PMU_IRQ)
139*120b6fc9SSvatopluk Kraus 
140*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_UP_PENDING_MASK	\
141*120b6fc9SSvatopluk Kraus     (BCM_LINTC_TIMER0_IRQ_MASK |	\
142*120b6fc9SSvatopluk Kraus      BCM_LINTC_TIMER1_IRQ_MASK |	\
143*120b6fc9SSvatopluk Kraus      BCM_LINTC_TIMER2_IRQ_MASK |	\
144*120b6fc9SSvatopluk Kraus      BCM_LINTC_TIMER3_IRQ_MASK |	\
145*120b6fc9SSvatopluk Kraus      BCM_LINTC_GPU_IRQ_MASK |		\
146*120b6fc9SSvatopluk Kraus      BCM_LINTC_PMU_IRQ_MASK)
147*120b6fc9SSvatopluk Kraus 
148*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_SMP_PENDING_MASK	\
149*120b6fc9SSvatopluk Kraus     (BCM_LINTC_UP_PENDING_MASK |	\
150*120b6fc9SSvatopluk Kraus      BCM_LINTC_MBOX0_IRQ_MASK)
151*120b6fc9SSvatopluk Kraus 
152*120b6fc9SSvatopluk Kraus #ifdef SMP
153*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK		BCM_LINTC_SMP_PENDING_MASK
154*120b6fc9SSvatopluk Kraus #else
155*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK		BCM_LINTC_UP_PENDING_MASK
156*120b6fc9SSvatopluk Kraus #endif
157*120b6fc9SSvatopluk Kraus 
158*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc {
159*120b6fc9SSvatopluk Kraus 	struct intr_irqsrc	bli_isrc;
160*120b6fc9SSvatopluk Kraus 	u_int			bli_irq;
161*120b6fc9SSvatopluk Kraus 	union {
162*120b6fc9SSvatopluk Kraus 		u_int		bli_mask;	/* for timers */
163*120b6fc9SSvatopluk Kraus 		u_int		bli_value;	/* for GPU */
164*120b6fc9SSvatopluk Kraus 	};
165*120b6fc9SSvatopluk Kraus };
166*120b6fc9SSvatopluk Kraus 
167*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc {
168*120b6fc9SSvatopluk Kraus 	device_t		bls_dev;
169*120b6fc9SSvatopluk Kraus 	struct mtx		bls_mtx;
170*120b6fc9SSvatopluk Kraus 	struct resource *	bls_mem;
171*120b6fc9SSvatopluk Kraus 	bus_space_tag_t		bls_bst;
172*120b6fc9SSvatopluk Kraus 	bus_space_handle_t	bls_bsh;
173*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc	bls_isrcs[BCM_LINTC_NIRQS];
174*120b6fc9SSvatopluk Kraus };
175*120b6fc9SSvatopluk Kraus 
176*120b6fc9SSvatopluk Kraus static struct bcm_lintc_softc *bcm_lintc_sc;
177*120b6fc9SSvatopluk Kraus 
178*120b6fc9SSvatopluk Kraus #ifdef SMP
179*120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIPIS		32	/* only mailbox 0 is used for IPI */
180*120b6fc9SSvatopluk Kraus CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
181*120b6fc9SSvatopluk Kraus #endif
182*120b6fc9SSvatopluk Kraus 
183*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LOCK(sc)		mtx_lock_spin(&(sc)->bls_mtx)
184*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_UNLOCK(sc)		mtx_unlock_spin(&(sc)->bls_mtx)
185*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LOCK_INIT(sc)		mtx_init(&(sc)->bls_mtx,	\
186*120b6fc9SSvatopluk Kraus     device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
187*120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->bls_mtx)
188*120b6fc9SSvatopluk Kraus 
189*120b6fc9SSvatopluk Kraus #define	bcm_lintc_read_4(sc, reg)		\
190*120b6fc9SSvatopluk Kraus     bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
191*120b6fc9SSvatopluk Kraus #define	bcm_lintc_write_4(sc, reg, val)		\
192*120b6fc9SSvatopluk Kraus     bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
193*120b6fc9SSvatopluk Kraus 
194*120b6fc9SSvatopluk Kraus static inline void
195*120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
196*120b6fc9SSvatopluk Kraus     uint32_t mask)
197*120b6fc9SSvatopluk Kraus {
198*120b6fc9SSvatopluk Kraus 
199*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
200*120b6fc9SSvatopluk Kraus }
201*120b6fc9SSvatopluk Kraus 
202*120b6fc9SSvatopluk Kraus static inline void
203*120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
204*120b6fc9SSvatopluk Kraus     uint32_t mask)
205*120b6fc9SSvatopluk Kraus {
206*120b6fc9SSvatopluk Kraus 
207*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
208*120b6fc9SSvatopluk Kraus }
209*120b6fc9SSvatopluk Kraus 
210*120b6fc9SSvatopluk Kraus static void
211*120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
212*120b6fc9SSvatopluk Kraus {
213*120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
214*120b6fc9SSvatopluk Kraus 	uint32_t cpu;
215*120b6fc9SSvatopluk Kraus 
216*120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
217*120b6fc9SSvatopluk Kraus 
218*120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
219*120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
220*120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
221*120b6fc9SSvatopluk Kraus 			bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
222*120b6fc9SSvatopluk Kraus 			    bli->bli_mask);
223*120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
224*120b6fc9SSvatopluk Kraus }
225*120b6fc9SSvatopluk Kraus 
226*120b6fc9SSvatopluk Kraus static void
227*120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
228*120b6fc9SSvatopluk Kraus {
229*120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
230*120b6fc9SSvatopluk Kraus 	uint32_t cpu;
231*120b6fc9SSvatopluk Kraus 
232*120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
233*120b6fc9SSvatopluk Kraus 
234*120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
235*120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
236*120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
237*120b6fc9SSvatopluk Kraus 			bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
238*120b6fc9SSvatopluk Kraus 			    bli->bli_mask);
239*120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
240*120b6fc9SSvatopluk Kraus }
241*120b6fc9SSvatopluk Kraus 
242*120b6fc9SSvatopluk Kraus static inline void
243*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
244*120b6fc9SSvatopluk Kraus {
245*120b6fc9SSvatopluk Kraus 
246*120b6fc9SSvatopluk Kraus 	/* It's accessed just and only by one core. */
247*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
248*120b6fc9SSvatopluk Kraus }
249*120b6fc9SSvatopluk Kraus 
250*120b6fc9SSvatopluk Kraus static inline void
251*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
252*120b6fc9SSvatopluk Kraus {
253*120b6fc9SSvatopluk Kraus 
254*120b6fc9SSvatopluk Kraus 	/* It's accessed just and only by one core. */
255*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
256*120b6fc9SSvatopluk Kraus }
257*120b6fc9SSvatopluk Kraus 
258*120b6fc9SSvatopluk Kraus static inline void
259*120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
260*120b6fc9SSvatopluk Kraus {
261*120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
262*120b6fc9SSvatopluk Kraus 	uint32_t cpu, mask;
263*120b6fc9SSvatopluk Kraus 
264*120b6fc9SSvatopluk Kraus 	mask = 0;
265*120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
266*120b6fc9SSvatopluk Kraus 
267*120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
268*120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
269*120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
270*120b6fc9SSvatopluk Kraus 			mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
271*120b6fc9SSvatopluk Kraus 	/* Write-clear register. */
272*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
273*120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
274*120b6fc9SSvatopluk Kraus }
275*120b6fc9SSvatopluk Kraus 
276*120b6fc9SSvatopluk Kraus static inline void
277*120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
278*120b6fc9SSvatopluk Kraus {
279*120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
280*120b6fc9SSvatopluk Kraus 	uint32_t cpu, mask;
281*120b6fc9SSvatopluk Kraus 
282*120b6fc9SSvatopluk Kraus 	mask = 0;
283*120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
284*120b6fc9SSvatopluk Kraus 
285*120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
286*120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
287*120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
288*120b6fc9SSvatopluk Kraus 			mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
289*120b6fc9SSvatopluk Kraus 	/* Write-set register. */
290*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
291*120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
292*120b6fc9SSvatopluk Kraus }
293*120b6fc9SSvatopluk Kraus 
294*120b6fc9SSvatopluk Kraus static void
295*120b6fc9SSvatopluk Kraus bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
296*120b6fc9SSvatopluk Kraus {
297*120b6fc9SSvatopluk Kraus 
298*120b6fc9SSvatopluk Kraus 	switch (bli->bli_irq) {
299*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER0_IRQ:
300*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER1_IRQ:
301*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER2_IRQ:
302*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER3_IRQ:
303*120b6fc9SSvatopluk Kraus 		bcm_lintc_timer_mask(sc, bli);
304*120b6fc9SSvatopluk Kraus 		return;
305*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX0_IRQ:
306*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX1_IRQ:
307*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX2_IRQ:
308*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX3_IRQ:
309*120b6fc9SSvatopluk Kraus 		return;
310*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_GPU_IRQ:
311*120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_mask(sc, bli);
312*120b6fc9SSvatopluk Kraus 		return;
313*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_PMU_IRQ:
314*120b6fc9SSvatopluk Kraus 		bcm_lintc_pmu_mask(sc, bli);
315*120b6fc9SSvatopluk Kraus 		return;
316*120b6fc9SSvatopluk Kraus 	default:
317*120b6fc9SSvatopluk Kraus 		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
318*120b6fc9SSvatopluk Kraus 	}
319*120b6fc9SSvatopluk Kraus }
320*120b6fc9SSvatopluk Kraus 
321*120b6fc9SSvatopluk Kraus static void
322*120b6fc9SSvatopluk Kraus bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
323*120b6fc9SSvatopluk Kraus {
324*120b6fc9SSvatopluk Kraus 
325*120b6fc9SSvatopluk Kraus 	switch (bli->bli_irq) {
326*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER0_IRQ:
327*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER1_IRQ:
328*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER2_IRQ:
329*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER3_IRQ:
330*120b6fc9SSvatopluk Kraus 		bcm_lintc_timer_unmask(sc, bli);
331*120b6fc9SSvatopluk Kraus 		return;
332*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX0_IRQ:
333*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX1_IRQ:
334*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX2_IRQ:
335*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX3_IRQ:
336*120b6fc9SSvatopluk Kraus 		return;
337*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_GPU_IRQ:
338*120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_unmask(sc, bli);
339*120b6fc9SSvatopluk Kraus 		return;
340*120b6fc9SSvatopluk Kraus 	case BCM_LINTC_PMU_IRQ:
341*120b6fc9SSvatopluk Kraus 		bcm_lintc_pmu_unmask(sc, bli);
342*120b6fc9SSvatopluk Kraus 		return;
343*120b6fc9SSvatopluk Kraus 	default:
344*120b6fc9SSvatopluk Kraus 		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
345*120b6fc9SSvatopluk Kraus 	}
346*120b6fc9SSvatopluk Kraus }
347*120b6fc9SSvatopluk Kraus 
348*120b6fc9SSvatopluk Kraus #ifdef SMP
349*120b6fc9SSvatopluk Kraus static inline void
350*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
351*120b6fc9SSvatopluk Kraus {
352*120b6fc9SSvatopluk Kraus 	u_int cpu;
353*120b6fc9SSvatopluk Kraus 	uint32_t mask;
354*120b6fc9SSvatopluk Kraus 
355*120b6fc9SSvatopluk Kraus 	mask = 1 << ipi;
356*120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < mp_ncpus; cpu++)
357*120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, &cpus))
358*120b6fc9SSvatopluk Kraus 			bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
359*120b6fc9SSvatopluk Kraus 			    mask);
360*120b6fc9SSvatopluk Kraus }
361*120b6fc9SSvatopluk Kraus 
362*120b6fc9SSvatopluk Kraus static inline void
363*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
364*120b6fc9SSvatopluk Kraus     struct trapframe *tf)
365*120b6fc9SSvatopluk Kraus {
366*120b6fc9SSvatopluk Kraus 	u_int ipi;
367*120b6fc9SSvatopluk Kraus 	uint32_t mask;
368*120b6fc9SSvatopluk Kraus 
369*120b6fc9SSvatopluk Kraus 	mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
370*120b6fc9SSvatopluk Kraus 	if (mask == 0) {
371*120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Spurious ipi detected\n");
372*120b6fc9SSvatopluk Kraus 		return;
373*120b6fc9SSvatopluk Kraus 	}
374*120b6fc9SSvatopluk Kraus 
375*120b6fc9SSvatopluk Kraus 	for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
376*120b6fc9SSvatopluk Kraus 		if ((mask & 0x01) == 0)
377*120b6fc9SSvatopluk Kraus 			continue;
378*120b6fc9SSvatopluk Kraus 		/*
379*120b6fc9SSvatopluk Kraus 		 * Clear an IPI before dispatching to not miss anyone
380*120b6fc9SSvatopluk Kraus 		 * and make sure that it's observed by everybody.
381*120b6fc9SSvatopluk Kraus 		 */
382*120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
383*120b6fc9SSvatopluk Kraus 		dsb();
384*120b6fc9SSvatopluk Kraus 		intr_ipi_dispatch(ipi, tf);
385*120b6fc9SSvatopluk Kraus 	}
386*120b6fc9SSvatopluk Kraus }
387*120b6fc9SSvatopluk Kraus #endif
388*120b6fc9SSvatopluk Kraus 
389*120b6fc9SSvatopluk Kraus static inline void
390*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
391*120b6fc9SSvatopluk Kraus     struct trapframe *tf)
392*120b6fc9SSvatopluk Kraus {
393*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli;
394*120b6fc9SSvatopluk Kraus 
395*120b6fc9SSvatopluk Kraus 	bli = &sc->bls_isrcs[irq];
396*120b6fc9SSvatopluk Kraus 	if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
397*120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
398*120b6fc9SSvatopluk Kraus }
399*120b6fc9SSvatopluk Kraus 
400*120b6fc9SSvatopluk Kraus static int
401*120b6fc9SSvatopluk Kraus bcm_lintc_intr(void *arg)
402*120b6fc9SSvatopluk Kraus {
403*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
404*120b6fc9SSvatopluk Kraus 	u_int cpu;
405*120b6fc9SSvatopluk Kraus 	uint32_t num, reg;
406*120b6fc9SSvatopluk Kraus 	struct trapframe *tf;
407*120b6fc9SSvatopluk Kraus 
408*120b6fc9SSvatopluk Kraus 	sc = arg;
409*120b6fc9SSvatopluk Kraus 	cpu = PCPU_GET(cpuid);
410*120b6fc9SSvatopluk Kraus 	tf = curthread->td_intr_frame;
411*120b6fc9SSvatopluk Kraus 
412*120b6fc9SSvatopluk Kraus 	for (num = 0; ; num++) {
413*120b6fc9SSvatopluk Kraus 		reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
414*120b6fc9SSvatopluk Kraus 		if ((reg & BCM_LINTC_PENDING_MASK) == 0)
415*120b6fc9SSvatopluk Kraus 			break;
416*120b6fc9SSvatopluk Kraus #ifdef SMP
417*120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
418*120b6fc9SSvatopluk Kraus 			bcm_lintc_ipi_dispatch(sc, cpu, tf);
419*120b6fc9SSvatopluk Kraus #endif
420*120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
421*120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
422*120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
423*120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
424*120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
425*120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
426*120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
427*120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
428*120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_GPU_IRQ_MASK)
429*120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
430*120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_PMU_IRQ_MASK)
431*120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
432*120b6fc9SSvatopluk Kraus 
433*120b6fc9SSvatopluk Kraus 		arm_irq_memory_barrier(0); /* XXX */
434*120b6fc9SSvatopluk Kraus 	}
435*120b6fc9SSvatopluk Kraus 	reg &= ~BCM_LINTC_PENDING_MASK;
436*120b6fc9SSvatopluk Kraus 	if (reg != 0)
437*120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
438*120b6fc9SSvatopluk Kraus 	else if (num == 0)
439*120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Spurious interrupt detected\n");
440*120b6fc9SSvatopluk Kraus 
441*120b6fc9SSvatopluk Kraus 	return (FILTER_HANDLED);
442*120b6fc9SSvatopluk Kraus }
443*120b6fc9SSvatopluk Kraus 
444*120b6fc9SSvatopluk Kraus static void
445*120b6fc9SSvatopluk Kraus bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
446*120b6fc9SSvatopluk Kraus {
447*120b6fc9SSvatopluk Kraus 
448*120b6fc9SSvatopluk Kraus 	bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
449*120b6fc9SSvatopluk Kraus }
450*120b6fc9SSvatopluk Kraus 
451*120b6fc9SSvatopluk Kraus static void
452*120b6fc9SSvatopluk Kraus bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
453*120b6fc9SSvatopluk Kraus {
454*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
455*120b6fc9SSvatopluk Kraus 
456*120b6fc9SSvatopluk Kraus 	arm_irq_memory_barrier(bli->bli_irq);
457*120b6fc9SSvatopluk Kraus 	bcm_lintc_unmask(device_get_softc(dev), bli);
458*120b6fc9SSvatopluk Kraus }
459*120b6fc9SSvatopluk Kraus 
460*120b6fc9SSvatopluk Kraus static int
461*120b6fc9SSvatopluk Kraus bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
462*120b6fc9SSvatopluk Kraus     struct intr_irqsrc **isrcp)
463*120b6fc9SSvatopluk Kraus {
464*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
465*120b6fc9SSvatopluk Kraus 
466*120b6fc9SSvatopluk Kraus 	if (data->type != INTR_MAP_DATA_FDT)
467*120b6fc9SSvatopluk Kraus 		return (ENOTSUP);
468*120b6fc9SSvatopluk Kraus 	if (data->fdt.ncells != 1 || data->fdt.cells[0] >= BCM_LINTC_NIRQS)
469*120b6fc9SSvatopluk Kraus 		return (EINVAL);
470*120b6fc9SSvatopluk Kraus 
471*120b6fc9SSvatopluk Kraus 	sc = device_get_softc(dev);
472*120b6fc9SSvatopluk Kraus 	*isrcp = &sc->bls_isrcs[data->fdt.cells[0]].bli_isrc;
473*120b6fc9SSvatopluk Kraus 	return (0);
474*120b6fc9SSvatopluk Kraus }
475*120b6fc9SSvatopluk Kraus 
476*120b6fc9SSvatopluk Kraus static void
477*120b6fc9SSvatopluk Kraus bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
478*120b6fc9SSvatopluk Kraus {
479*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
480*120b6fc9SSvatopluk Kraus 
481*120b6fc9SSvatopluk Kraus 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
482*120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_mask(device_get_softc(dev), bli);
483*120b6fc9SSvatopluk Kraus 	else {
484*120b6fc9SSvatopluk Kraus 		/*
485*120b6fc9SSvatopluk Kraus 		 * Handler for PPI interrupt does not make sense much unless
486*120b6fc9SSvatopluk Kraus 		 * there is one bound ithread for each core for it. Thus the
487*120b6fc9SSvatopluk Kraus 		 * interrupt can be masked on current core only while ithread
488*120b6fc9SSvatopluk Kraus 		 * bounded to this core ensures unmasking on the same core.
489*120b6fc9SSvatopluk Kraus 		 */
490*120b6fc9SSvatopluk Kraus 		panic ("%s: handlers are not supported", __func__);
491*120b6fc9SSvatopluk Kraus 	}
492*120b6fc9SSvatopluk Kraus }
493*120b6fc9SSvatopluk Kraus 
494*120b6fc9SSvatopluk Kraus static void
495*120b6fc9SSvatopluk Kraus bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
496*120b6fc9SSvatopluk Kraus {
497*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
498*120b6fc9SSvatopluk Kraus 
499*120b6fc9SSvatopluk Kraus 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
500*120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
501*120b6fc9SSvatopluk Kraus 	else {
502*120b6fc9SSvatopluk Kraus 		/* See comment in bcm_lintc_pre_ithread(). */
503*120b6fc9SSvatopluk Kraus 		panic ("%s: handlers are not supported", __func__);
504*120b6fc9SSvatopluk Kraus 	}
505*120b6fc9SSvatopluk Kraus }
506*120b6fc9SSvatopluk Kraus 
507*120b6fc9SSvatopluk Kraus static void
508*120b6fc9SSvatopluk Kraus bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
509*120b6fc9SSvatopluk Kraus {
510*120b6fc9SSvatopluk Kraus }
511*120b6fc9SSvatopluk Kraus 
512*120b6fc9SSvatopluk Kraus static int
513*120b6fc9SSvatopluk Kraus bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
514*120b6fc9SSvatopluk Kraus     struct resource *res, struct intr_map_data *data)
515*120b6fc9SSvatopluk Kraus {
516*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
517*120b6fc9SSvatopluk Kraus 
518*120b6fc9SSvatopluk Kraus 	if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
519*120b6fc9SSvatopluk Kraus 		sc = device_get_softc(dev);
520*120b6fc9SSvatopluk Kraus 		BCM_LINTC_LOCK(sc);
521*120b6fc9SSvatopluk Kraus 		CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
522*120b6fc9SSvatopluk Kraus 		BCM_LINTC_UNLOCK(sc);
523*120b6fc9SSvatopluk Kraus 	}
524*120b6fc9SSvatopluk Kraus 	return (0);
525*120b6fc9SSvatopluk Kraus }
526*120b6fc9SSvatopluk Kraus 
527*120b6fc9SSvatopluk Kraus #ifdef SMP
528*120b6fc9SSvatopluk Kraus static bool
529*120b6fc9SSvatopluk Kraus bcm_lint_init_on_ap(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli,
530*120b6fc9SSvatopluk Kraus     u_int cpu)
531*120b6fc9SSvatopluk Kraus {
532*120b6fc9SSvatopluk Kraus 	struct intr_irqsrc *isrc;
533*120b6fc9SSvatopluk Kraus 
534*120b6fc9SSvatopluk Kraus 	isrc = &bli->bli_isrc;
535*120b6fc9SSvatopluk Kraus 
536*120b6fc9SSvatopluk Kraus 	KASSERT(isrc->isrc_flags & INTR_ISRCF_PPI,
537*120b6fc9SSvatopluk Kraus 	    ("%s: irq %d is not PPI", __func__, bli->bli_irq));
538*120b6fc9SSvatopluk Kraus 
539*120b6fc9SSvatopluk Kraus 	if (isrc->isrc_handlers == 0)
540*120b6fc9SSvatopluk Kraus 		return (false);
541*120b6fc9SSvatopluk Kraus 	if (isrc->isrc_flags & INTR_ISRCF_BOUND)
542*120b6fc9SSvatopluk Kraus 		return (CPU_ISSET(cpu, &isrc->isrc_cpu));
543*120b6fc9SSvatopluk Kraus 
544*120b6fc9SSvatopluk Kraus 	CPU_SET(cpu, &isrc->isrc_cpu);
545*120b6fc9SSvatopluk Kraus 	return (true);
546*120b6fc9SSvatopluk Kraus }
547*120b6fc9SSvatopluk Kraus 
548*120b6fc9SSvatopluk Kraus static void
549*120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
550*120b6fc9SSvatopluk Kraus     uint32_t reg, uint32_t mask)
551*120b6fc9SSvatopluk Kraus {
552*120b6fc9SSvatopluk Kraus 
553*120b6fc9SSvatopluk Kraus 	if (bcm_lint_init_on_ap(sc, &sc->bls_isrcs[irq], cpu))
554*120b6fc9SSvatopluk Kraus 		bcm_lintc_rwreg_set(sc, reg, mask);
555*120b6fc9SSvatopluk Kraus }
556*120b6fc9SSvatopluk Kraus 
557*120b6fc9SSvatopluk Kraus static void
558*120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
559*120b6fc9SSvatopluk Kraus {
560*120b6fc9SSvatopluk Kraus 
561*120b6fc9SSvatopluk Kraus 	if (bcm_lint_init_on_ap(sc, &sc->bls_isrcs[BCM_LINTC_PMU_IRQ], cpu)) {
562*120b6fc9SSvatopluk Kraus 		/* Write-set register. */
563*120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
564*120b6fc9SSvatopluk Kraus 		    BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
565*120b6fc9SSvatopluk Kraus 	}
566*120b6fc9SSvatopluk Kraus }
567*120b6fc9SSvatopluk Kraus 
568*120b6fc9SSvatopluk Kraus static void
569*120b6fc9SSvatopluk Kraus bcm_lintc_init_secondary(device_t dev)
570*120b6fc9SSvatopluk Kraus {
571*120b6fc9SSvatopluk Kraus 	u_int cpu;
572*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
573*120b6fc9SSvatopluk Kraus 
574*120b6fc9SSvatopluk Kraus 	cpu = PCPU_GET(cpuid);
575*120b6fc9SSvatopluk Kraus 	sc = device_get_softc(dev);
576*120b6fc9SSvatopluk Kraus 
577*120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
578*120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
579*120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
580*120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
581*120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
582*120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
583*120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
584*120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
585*120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
586*120b6fc9SSvatopluk Kraus 	bcm_lintc_init_pmu_on_ap(sc, cpu);
587*120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
588*120b6fc9SSvatopluk Kraus }
589*120b6fc9SSvatopluk Kraus 
590*120b6fc9SSvatopluk Kraus static void
591*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
592*120b6fc9SSvatopluk Kraus     u_int ipi)
593*120b6fc9SSvatopluk Kraus {
594*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc = device_get_softc(dev);
595*120b6fc9SSvatopluk Kraus 
596*120b6fc9SSvatopluk Kraus 	KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
597*120b6fc9SSvatopluk Kraus 	    ("%s: bad ISRC %p argument", __func__, isrc));
598*120b6fc9SSvatopluk Kraus 	bcm_lintc_ipi_write(sc, cpus, ipi);
599*120b6fc9SSvatopluk Kraus }
600*120b6fc9SSvatopluk Kraus 
601*120b6fc9SSvatopluk Kraus static int
602*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
603*120b6fc9SSvatopluk Kraus {
604*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc = device_get_softc(dev);
605*120b6fc9SSvatopluk Kraus 
606*120b6fc9SSvatopluk Kraus 	KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
607*120b6fc9SSvatopluk Kraus 
608*120b6fc9SSvatopluk Kraus 	*isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
609*120b6fc9SSvatopluk Kraus 	return (0);
610*120b6fc9SSvatopluk Kraus }
611*120b6fc9SSvatopluk Kraus #endif
612*120b6fc9SSvatopluk Kraus 
613*120b6fc9SSvatopluk Kraus static int
614*120b6fc9SSvatopluk Kraus bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
615*120b6fc9SSvatopluk Kraus {
616*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bisrcs;
617*120b6fc9SSvatopluk Kraus 	int error;
618*120b6fc9SSvatopluk Kraus 	u_int flags;
619*120b6fc9SSvatopluk Kraus 	uint32_t irq;
620*120b6fc9SSvatopluk Kraus 	const char *name;
621*120b6fc9SSvatopluk Kraus 	intptr_t xref;
622*120b6fc9SSvatopluk Kraus 
623*120b6fc9SSvatopluk Kraus 	bisrcs = sc->bls_isrcs;
624*120b6fc9SSvatopluk Kraus 	name = device_get_nameunit(sc->bls_dev);
625*120b6fc9SSvatopluk Kraus 	for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
626*120b6fc9SSvatopluk Kraus 		bisrcs[irq].bli_irq = irq;
627*120b6fc9SSvatopluk Kraus 		switch (irq) {
628*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER0_IRQ:
629*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
630*120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
631*120b6fc9SSvatopluk Kraus 			break;
632*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER1_IRQ:
633*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
634*120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
635*120b6fc9SSvatopluk Kraus 			break;
636*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER2_IRQ:
637*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
638*120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
639*120b6fc9SSvatopluk Kraus 			break;
640*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER3_IRQ:
641*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
642*120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
643*120b6fc9SSvatopluk Kraus 			break;
644*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX0_IRQ:
645*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX1_IRQ:
646*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX2_IRQ:
647*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX3_IRQ:
648*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = 0;	/* not used */
649*120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_IPI;
650*120b6fc9SSvatopluk Kraus 			break;
651*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_GPU_IRQ:
652*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
653*120b6fc9SSvatopluk Kraus 			flags = 0;
654*120b6fc9SSvatopluk Kraus 			break;
655*120b6fc9SSvatopluk Kraus 		case BCM_LINTC_PMU_IRQ:
656*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = 0;	/* not used */
657*120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
658*120b6fc9SSvatopluk Kraus 			break;
659*120b6fc9SSvatopluk Kraus 		default:
660*120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = 0;	/* not used */
661*120b6fc9SSvatopluk Kraus 			flags = 0;
662*120b6fc9SSvatopluk Kraus 			break;
663*120b6fc9SSvatopluk Kraus 		}
664*120b6fc9SSvatopluk Kraus 
665*120b6fc9SSvatopluk Kraus 		error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
666*120b6fc9SSvatopluk Kraus 		    flags, "%s,%u", name, irq);
667*120b6fc9SSvatopluk Kraus 		if (error != 0)
668*120b6fc9SSvatopluk Kraus 			return (error);
669*120b6fc9SSvatopluk Kraus 	}
670*120b6fc9SSvatopluk Kraus 
671*120b6fc9SSvatopluk Kraus 	xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
672*120b6fc9SSvatopluk Kraus 	error = intr_pic_register(sc->bls_dev, xref);
673*120b6fc9SSvatopluk Kraus 	if (error != 0)
674*120b6fc9SSvatopluk Kraus 		return (error);
675*120b6fc9SSvatopluk Kraus 
676*120b6fc9SSvatopluk Kraus 	return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
677*120b6fc9SSvatopluk Kraus }
678*120b6fc9SSvatopluk Kraus 
679*120b6fc9SSvatopluk Kraus static int
680*120b6fc9SSvatopluk Kraus bcm_lintc_probe(device_t dev)
681*120b6fc9SSvatopluk Kraus {
682*120b6fc9SSvatopluk Kraus 
683*120b6fc9SSvatopluk Kraus 	if (!ofw_bus_status_okay(dev))
684*120b6fc9SSvatopluk Kraus 		return (ENXIO);
685*120b6fc9SSvatopluk Kraus 
686*120b6fc9SSvatopluk Kraus 	if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
687*120b6fc9SSvatopluk Kraus 		return (ENXIO);
688*120b6fc9SSvatopluk Kraus 	device_set_desc(dev, "BCM2836 Interrupt Controller");
689*120b6fc9SSvatopluk Kraus 	return (BUS_PROBE_DEFAULT);
690*120b6fc9SSvatopluk Kraus }
691*120b6fc9SSvatopluk Kraus 
692*120b6fc9SSvatopluk Kraus static int
693*120b6fc9SSvatopluk Kraus bcm_lintc_attach(device_t dev)
694*120b6fc9SSvatopluk Kraus {
695*120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
696*120b6fc9SSvatopluk Kraus 	int cpu, rid;
697*120b6fc9SSvatopluk Kraus 
698*120b6fc9SSvatopluk Kraus 	sc = device_get_softc(dev);
699*120b6fc9SSvatopluk Kraus 
700*120b6fc9SSvatopluk Kraus 	sc->bls_dev = dev;
701*120b6fc9SSvatopluk Kraus 	if (bcm_lintc_sc != NULL)
702*120b6fc9SSvatopluk Kraus 		return (ENXIO);
703*120b6fc9SSvatopluk Kraus 
704*120b6fc9SSvatopluk Kraus 	rid = 0;
705*120b6fc9SSvatopluk Kraus 	sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
706*120b6fc9SSvatopluk Kraus 	    RF_ACTIVE);
707*120b6fc9SSvatopluk Kraus 	if (sc->bls_mem == NULL) {
708*120b6fc9SSvatopluk Kraus 		device_printf(dev, "could not allocate memory resource\n");
709*120b6fc9SSvatopluk Kraus 		return (ENXIO);
710*120b6fc9SSvatopluk Kraus 	}
711*120b6fc9SSvatopluk Kraus 
712*120b6fc9SSvatopluk Kraus 	sc->bls_bst = rman_get_bustag(sc->bls_mem);
713*120b6fc9SSvatopluk Kraus 	sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
714*120b6fc9SSvatopluk Kraus 
715*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
716*120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
717*120b6fc9SSvatopluk Kraus 
718*120b6fc9SSvatopluk Kraus 	/* Disable all timers on all cores. */
719*120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
720*120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
721*120b6fc9SSvatopluk Kraus 
722*120b6fc9SSvatopluk Kraus #ifdef SMP
723*120b6fc9SSvatopluk Kraus 	/* Enable mailbox 0 on all cores used for IPI. */
724*120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
725*120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
726*120b6fc9SSvatopluk Kraus 		    BCM_LINTC_MCR_IRQ_EN_MBOX(0));
727*120b6fc9SSvatopluk Kraus #endif
728*120b6fc9SSvatopluk Kraus 
729*120b6fc9SSvatopluk Kraus 	if (bcm_lintc_pic_attach(sc) != 0) {
730*120b6fc9SSvatopluk Kraus 		device_printf(dev, "could not attach PIC\n");
731*120b6fc9SSvatopluk Kraus 		return (ENXIO);
732*120b6fc9SSvatopluk Kraus 	}
733*120b6fc9SSvatopluk Kraus 
734*120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK_INIT(sc);
735*120b6fc9SSvatopluk Kraus 	bcm_lintc_sc = sc;
736*120b6fc9SSvatopluk Kraus 	return (0);
737*120b6fc9SSvatopluk Kraus }
738*120b6fc9SSvatopluk Kraus 
739*120b6fc9SSvatopluk Kraus static device_method_t bcm_lintc_methods[] = {
740*120b6fc9SSvatopluk Kraus 	DEVMETHOD(device_probe,		bcm_lintc_probe),
741*120b6fc9SSvatopluk Kraus 	DEVMETHOD(device_attach,	bcm_lintc_attach),
742*120b6fc9SSvatopluk Kraus 
743*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_disable_intr,	bcm_lintc_disable_intr),
744*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_enable_intr,	bcm_lintc_enable_intr),
745*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_map_intr,		bcm_lintc_map_intr),
746*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_post_filter,	bcm_lintc_post_filter),
747*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_post_ithread,	bcm_lintc_post_ithread),
748*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_pre_ithread,	bcm_lintc_pre_ithread),
749*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_setup_intr,	bcm_lintc_setup_intr),
750*120b6fc9SSvatopluk Kraus #ifdef SMP
751*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_init_secondary,	bcm_lintc_init_secondary),
752*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_ipi_send,		bcm_lintc_ipi_send),
753*120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_ipi_setup,	bcm_lintc_ipi_setup),
754*120b6fc9SSvatopluk Kraus #endif
755*120b6fc9SSvatopluk Kraus 
756*120b6fc9SSvatopluk Kraus 	DEVMETHOD_END
757*120b6fc9SSvatopluk Kraus };
758*120b6fc9SSvatopluk Kraus 
759*120b6fc9SSvatopluk Kraus static driver_t bcm_lintc_driver = {
760*120b6fc9SSvatopluk Kraus 	"local_intc",
761*120b6fc9SSvatopluk Kraus 	bcm_lintc_methods,
762*120b6fc9SSvatopluk Kraus 	sizeof(struct bcm_lintc_softc),
763*120b6fc9SSvatopluk Kraus };
764*120b6fc9SSvatopluk Kraus 
765*120b6fc9SSvatopluk Kraus static devclass_t bcm_lintc_devclass;
766*120b6fc9SSvatopluk Kraus 
767*120b6fc9SSvatopluk Kraus EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
768*120b6fc9SSvatopluk Kraus     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
769*120b6fc9SSvatopluk Kraus #else
7704e46a66eSAndrew Turner /*
7714e46a66eSAndrew Turner  * A driver for features of the bcm2836.
7724e46a66eSAndrew Turner  */
7734e46a66eSAndrew Turner 
7744e46a66eSAndrew Turner struct bcm2836_softc {
7754e46a66eSAndrew Turner 	device_t	 sc_dev;
7764e46a66eSAndrew Turner 	struct resource *sc_mem;
7774e46a66eSAndrew Turner };
7784e46a66eSAndrew Turner 
7794e46a66eSAndrew Turner static device_identify_t bcm2836_identify;
7804e46a66eSAndrew Turner static device_probe_t bcm2836_probe;
7814e46a66eSAndrew Turner static device_attach_t bcm2836_attach;
7824e46a66eSAndrew Turner 
7834e46a66eSAndrew Turner struct bcm2836_softc *softc;
7844e46a66eSAndrew Turner 
7854e46a66eSAndrew Turner static void
7864e46a66eSAndrew Turner bcm2836_identify(driver_t *driver, device_t parent)
7874e46a66eSAndrew Turner {
7884e46a66eSAndrew Turner 
7894e46a66eSAndrew Turner 	if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL)
7904e46a66eSAndrew Turner 		device_printf(parent, "add child failed\n");
7914e46a66eSAndrew Turner }
7924e46a66eSAndrew Turner 
7934e46a66eSAndrew Turner static int
7944e46a66eSAndrew Turner bcm2836_probe(device_t dev)
7954e46a66eSAndrew Turner {
7964e46a66eSAndrew Turner 
7974e46a66eSAndrew Turner 	if (softc != NULL)
7984e46a66eSAndrew Turner 		return (ENXIO);
7994e46a66eSAndrew Turner 
8004e46a66eSAndrew Turner 	device_set_desc(dev, "Broadcom bcm2836");
8014e46a66eSAndrew Turner 
8024e46a66eSAndrew Turner 	return (BUS_PROBE_DEFAULT);
8034e46a66eSAndrew Turner }
8044e46a66eSAndrew Turner 
8054e46a66eSAndrew Turner static int
8064e46a66eSAndrew Turner bcm2836_attach(device_t dev)
8074e46a66eSAndrew Turner {
8084e46a66eSAndrew Turner 	int i, rid;
8094e46a66eSAndrew Turner 
8104e46a66eSAndrew Turner 	softc = device_get_softc(dev);
8114e46a66eSAndrew Turner 	softc->sc_dev = dev;
8124e46a66eSAndrew Turner 
8134e46a66eSAndrew Turner 	rid = 0;
8144e46a66eSAndrew Turner 	softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
8154e46a66eSAndrew Turner 	    ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE,
8164e46a66eSAndrew Turner 	    RF_ACTIVE);
8174e46a66eSAndrew Turner 	if (softc->sc_mem == NULL) {
8184e46a66eSAndrew Turner 		device_printf(dev, "could not allocate memory resource\n");
8194e46a66eSAndrew Turner 		return (ENXIO);
8204e46a66eSAndrew Turner 	}
8214e46a66eSAndrew Turner 
8224e46a66eSAndrew Turner 	bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0);
8234e46a66eSAndrew Turner 	bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2);
8244e46a66eSAndrew Turner 
8254e46a66eSAndrew Turner 	for (i = 0; i < 4; i++)
8264e46a66eSAndrew Turner 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0);
8274e46a66eSAndrew Turner 
8284e46a66eSAndrew Turner 	for (i = 0; i < 4; i++)
8294e46a66eSAndrew Turner 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1);
8304e46a66eSAndrew Turner 
8314e46a66eSAndrew Turner 	return (0);
8324e46a66eSAndrew Turner }
8334e46a66eSAndrew Turner 
8344e46a66eSAndrew Turner int
8354e46a66eSAndrew Turner bcm2836_get_next_irq(int last_irq)
8364e46a66eSAndrew Turner {
8374e46a66eSAndrew Turner 	uint32_t reg;
8384e46a66eSAndrew Turner 	int cpu;
8394e46a66eSAndrew Turner 	int irq;
8404e46a66eSAndrew Turner 
8414e46a66eSAndrew Turner 	cpu = PCPU_GET(cpuid);
8424e46a66eSAndrew Turner 
8434e46a66eSAndrew Turner 	reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu));
8444e46a66eSAndrew Turner 	reg &= INT_PENDING_MASK;
8454e46a66eSAndrew Turner 	if (reg == 0)
8464e46a66eSAndrew Turner 		return (-1);
8474e46a66eSAndrew Turner 
8484e46a66eSAndrew Turner 	irq = ffs(reg) - 1;
8494e46a66eSAndrew Turner 
8504e46a66eSAndrew Turner 	return (irq);
8514e46a66eSAndrew Turner }
8524e46a66eSAndrew Turner 
8534e46a66eSAndrew Turner void
8544e46a66eSAndrew Turner bcm2836_mask_irq(uintptr_t irq)
8554e46a66eSAndrew Turner {
8564e46a66eSAndrew Turner 	uint32_t reg;
857962940ceSLuiz Otavio O Souza #ifdef SMP
858962940ceSLuiz Otavio O Souza 	int cpu;
859962940ceSLuiz Otavio O Souza #endif
8604e46a66eSAndrew Turner 	int i;
8614e46a66eSAndrew Turner 
862962940ceSLuiz Otavio O Souza 	if (irq < MAILBOX0_IRQ) {
8634e46a66eSAndrew Turner 		for (i = 0; i < 4; i++) {
864962940ceSLuiz Otavio O Souza 			reg = bus_read_4(softc->sc_mem,
865962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i));
8664e46a66eSAndrew Turner 			reg &= ~(1 << irq);
867962940ceSLuiz Otavio O Souza 			bus_write_4(softc->sc_mem,
868962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i), reg);
869962940ceSLuiz Otavio O Souza 		}
870962940ceSLuiz Otavio O Souza #ifdef SMP
871962940ceSLuiz Otavio O Souza 	} else if (irq == MAILBOX0_IRQ) {
872962940ceSLuiz Otavio O Souza 		/* Mailbox 0 for IPI */
873962940ceSLuiz Otavio O Souza 		cpu = PCPU_GET(cpuid);
874962940ceSLuiz Otavio O Souza 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
875962940ceSLuiz Otavio O Souza 		reg &= ~MAILBOX0_IRQEN;
876962940ceSLuiz Otavio O Souza 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
877962940ceSLuiz Otavio O Souza #endif
8784e46a66eSAndrew Turner 	}
8794e46a66eSAndrew Turner }
8804e46a66eSAndrew Turner 
8814e46a66eSAndrew Turner void
8824e46a66eSAndrew Turner bcm2836_unmask_irq(uintptr_t irq)
8834e46a66eSAndrew Turner {
8844e46a66eSAndrew Turner 	uint32_t reg;
885962940ceSLuiz Otavio O Souza #ifdef SMP
886962940ceSLuiz Otavio O Souza 	int cpu;
887962940ceSLuiz Otavio O Souza #endif
8884e46a66eSAndrew Turner 	int i;
8894e46a66eSAndrew Turner 
890962940ceSLuiz Otavio O Souza 	if (irq < MAILBOX0_IRQ) {
8914e46a66eSAndrew Turner 		for (i = 0; i < 4; i++) {
892962940ceSLuiz Otavio O Souza 			reg = bus_read_4(softc->sc_mem,
893962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i));
8944e46a66eSAndrew Turner 			reg |= (1 << irq);
895962940ceSLuiz Otavio O Souza 			bus_write_4(softc->sc_mem,
896962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i), reg);
897962940ceSLuiz Otavio O Souza 		}
898962940ceSLuiz Otavio O Souza #ifdef SMP
899962940ceSLuiz Otavio O Souza 	} else if (irq == MAILBOX0_IRQ) {
900962940ceSLuiz Otavio O Souza 		/* Mailbox 0 for IPI */
901962940ceSLuiz Otavio O Souza 		cpu = PCPU_GET(cpuid);
902962940ceSLuiz Otavio O Souza 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
903962940ceSLuiz Otavio O Souza 		reg |= MAILBOX0_IRQEN;
904962940ceSLuiz Otavio O Souza 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
905962940ceSLuiz Otavio O Souza #endif
9064e46a66eSAndrew Turner 	}
9074e46a66eSAndrew Turner }
9084e46a66eSAndrew Turner 
9094e46a66eSAndrew Turner static device_method_t bcm2836_methods[] = {
9104e46a66eSAndrew Turner 	/* Device interface */
9114e46a66eSAndrew Turner 	DEVMETHOD(device_identify,	bcm2836_identify),
9124e46a66eSAndrew Turner 	DEVMETHOD(device_probe,		bcm2836_probe),
9134e46a66eSAndrew Turner 	DEVMETHOD(device_attach,	bcm2836_attach),
9144e46a66eSAndrew Turner 
9154e46a66eSAndrew Turner 	DEVMETHOD_END
9164e46a66eSAndrew Turner };
9174e46a66eSAndrew Turner 
9184e46a66eSAndrew Turner static devclass_t bcm2836_devclass;
9194e46a66eSAndrew Turner 
9204e46a66eSAndrew Turner static driver_t bcm2836_driver = {
9214e46a66eSAndrew Turner 	"bcm2836",
9224e46a66eSAndrew Turner 	bcm2836_methods,
9234e46a66eSAndrew Turner 	sizeof(struct bcm2836_softc),
9244e46a66eSAndrew Turner };
9254e46a66eSAndrew Turner 
9264e46a66eSAndrew Turner EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
9274e46a66eSAndrew Turner     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
928*120b6fc9SSvatopluk Kraus #endif
929