bcm2835_intr.c revision 1.2.2.2 1 1.2.2.2 jdolecek /* $NetBSD: bcm2835_intr.c,v 1.2.2.2 2017/12/03 11:35:52 jdolecek Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.2.2.2 jdolecek * Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
5 1.1 skrll * All rights reserved.
6 1.1 skrll *
7 1.1 skrll * This code is derived from software contributed to The NetBSD Foundation
8 1.1 skrll * by Nick Hudson
9 1.1 skrll *
10 1.1 skrll * Redistribution and use in source and binary forms, with or without
11 1.1 skrll * modification, are permitted provided that the following conditions
12 1.1 skrll * are met:
13 1.1 skrll * 1. Redistributions of source code must retain the above copyright
14 1.1 skrll * notice, this list of conditions and the following disclaimer.
15 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 skrll * notice, this list of conditions and the following disclaimer in the
17 1.1 skrll * documentation and/or other materials provided with the distribution.
18 1.1 skrll *
19 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 skrll * POSSIBILITY OF SUCH DAMAGE.
30 1.1 skrll */
31 1.1 skrll
32 1.1 skrll #include <sys/cdefs.h>
33 1.2.2.2 jdolecek __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.2.2.2 2017/12/03 11:35:52 jdolecek Exp $");
34 1.1 skrll
35 1.1 skrll #define _INTR_PRIVATE
36 1.1 skrll
37 1.2.2.2 jdolecek #include "opt_bcm283x.h"
38 1.2.2.2 jdolecek
39 1.1 skrll #include <sys/param.h>
40 1.2.2.2 jdolecek #include <sys/bus.h>
41 1.2.2.2 jdolecek #include <sys/cpu.h>
42 1.1 skrll #include <sys/device.h>
43 1.2.2.2 jdolecek #include <sys/proc.h>
44 1.1 skrll
45 1.1 skrll #include <machine/intr.h>
46 1.2.2.2 jdolecek
47 1.2.2.2 jdolecek #include <arm/locore.h>
48 1.1 skrll
49 1.1 skrll #include <arm/pic/picvar.h>
50 1.2.2.2 jdolecek #include <arm/cortex/gtmr_var.h>
51 1.1 skrll
52 1.1 skrll #include <arm/broadcom/bcm_amba.h>
53 1.1 skrll #include <arm/broadcom/bcm2835reg.h>
54 1.2.2.2 jdolecek #include <arm/broadcom/bcm2835var.h>
55 1.1 skrll
56 1.1 skrll static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
57 1.1 skrll static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
58 1.1 skrll static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
59 1.1 skrll static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
60 1.1 skrll static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
61 1.1 skrll size_t);
62 1.1 skrll
63 1.2.2.2 jdolecek #if defined(BCM2836)
64 1.2.2.2 jdolecek static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
65 1.2.2.2 jdolecek static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
66 1.2.2.2 jdolecek static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
67 1.2.2.2 jdolecek static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
68 1.2.2.2 jdolecek static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
69 1.2.2.2 jdolecek size_t);
70 1.2.2.2 jdolecek #ifdef MULTIPROCESSOR
71 1.2.2.2 jdolecek int bcm2836mp_ipi_handler(void *);
72 1.2.2.2 jdolecek static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
73 1.2.2.2 jdolecek static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
74 1.2.2.2 jdolecek #endif
75 1.2.2.2 jdolecek #endif
76 1.2.2.2 jdolecek
77 1.1 skrll static int bcm2835_icu_match(device_t, cfdata_t, void *);
78 1.1 skrll static void bcm2835_icu_attach(device_t, device_t, void *);
79 1.1 skrll
80 1.1 skrll static struct pic_ops bcm2835_picops = {
81 1.1 skrll .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
82 1.1 skrll .pic_block_irqs = bcm2835_pic_block_irqs,
83 1.1 skrll .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
84 1.1 skrll .pic_establish_irq = bcm2835_pic_establish_irq,
85 1.1 skrll .pic_source_name = bcm2835_pic_source_name,
86 1.1 skrll };
87 1.1 skrll
88 1.1 skrll struct pic_softc bcm2835_pic = {
89 1.1 skrll .pic_ops = &bcm2835_picops,
90 1.1 skrll .pic_maxsources = BCM2835_NIRQ,
91 1.1 skrll .pic_name = "bcm2835 pic",
92 1.1 skrll };
93 1.1 skrll
94 1.2.2.2 jdolecek #if defined(BCM2836)
95 1.2.2.2 jdolecek static struct pic_ops bcm2836mp_picops = {
96 1.2.2.2 jdolecek .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
97 1.2.2.2 jdolecek .pic_block_irqs = bcm2836mp_pic_block_irqs,
98 1.2.2.2 jdolecek .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
99 1.2.2.2 jdolecek .pic_establish_irq = bcm2836mp_pic_establish_irq,
100 1.2.2.2 jdolecek .pic_source_name = bcm2836mp_pic_source_name,
101 1.2.2.2 jdolecek #if defined(MULTIPROCESSOR)
102 1.2.2.2 jdolecek .pic_cpu_init = bcm2836mp_cpu_init,
103 1.2.2.2 jdolecek .pic_ipi_send = bcm2836mp_send_ipi,
104 1.2.2.2 jdolecek #endif
105 1.2.2.2 jdolecek };
106 1.2.2.2 jdolecek
107 1.2.2.2 jdolecek struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
108 1.2.2.2 jdolecek [0 ... BCM2836_NCPUS - 1] = {
109 1.2.2.2 jdolecek .pic_ops = &bcm2836mp_picops,
110 1.2.2.2 jdolecek .pic_maxsources = BCM2836_NIRQPERCPU,
111 1.2.2.2 jdolecek .pic_name = "bcm2836 pic",
112 1.2.2.2 jdolecek }
113 1.2.2.2 jdolecek };
114 1.2.2.2 jdolecek #endif
115 1.2.2.2 jdolecek
116 1.1 skrll struct bcm2835icu_softc {
117 1.1 skrll device_t sc_dev;
118 1.1 skrll bus_space_tag_t sc_iot;
119 1.1 skrll bus_space_handle_t sc_ioh;
120 1.1 skrll struct pic_softc *sc_pic;
121 1.1 skrll };
122 1.1 skrll
123 1.1 skrll struct bcm2835icu_softc *bcmicu_sc;
124 1.2.2.1 tls
125 1.1 skrll #define read_bcm2835reg(o) \
126 1.1 skrll bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
127 1.2.2.1 tls
128 1.1 skrll #define write_bcm2835reg(o, v) \
129 1.1 skrll bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
130 1.1 skrll
131 1.1 skrll
132 1.1 skrll #define bcm2835_barrier() \
133 1.1 skrll bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
134 1.1 skrll BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
135 1.2.2.1 tls
136 1.1 skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
137 1.1 skrll "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
138 1.1 skrll "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
139 1.2 jakllsch "(unused 8)", "usb", "(unused 10)", "(unused 11)",
140 1.2 jakllsch "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
141 1.2.2.2 jdolecek "dma0", "dma1", "dma2", "dma3",
142 1.2.2.2 jdolecek "dma4", "dma5", "dma6", "dma7",
143 1.2.2.2 jdolecek "dma8", "dma9", "dma10", "dma11",
144 1.2.2.2 jdolecek "dma12", "aux", "(unused 30)", "(unused 31)",
145 1.1 skrll "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
146 1.1 skrll "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
147 1.1 skrll "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
148 1.1 skrll "(unused 44)", "pwa0", "pwa1", "(unused 47)",
149 1.1 skrll "smi", "gpio[0]", "gpio[1]", "gpio[2]",
150 1.1 skrll "gpio[3]", "i2c", "spi", "pcm",
151 1.2.2.2 jdolecek "sdhost", "uart", "(unused 58)", "(unused 59)",
152 1.1 skrll "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
153 1.1 skrll "Timer", "Mailbox", "Doorbell0", "Doorbell1",
154 1.1 skrll "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
155 1.1 skrll };
156 1.1 skrll
157 1.2.2.2 jdolecek #if defined(BCM2836)
158 1.2.2.2 jdolecek static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
159 1.2.2.2 jdolecek "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
160 1.2.2.2 jdolecek "mailbox0", "mailbox1", "mailbox2", "mailbox3",
161 1.2.2.2 jdolecek };
162 1.2.2.2 jdolecek #endif
163 1.2.2.2 jdolecek
164 1.2.2.2 jdolecek #define BCM2836_INTBIT_GPUPENDING __BIT(8)
165 1.2.2.2 jdolecek
166 1.1 skrll #define BCM2835_INTBIT_PENDING1 __BIT(8)
167 1.1 skrll #define BCM2835_INTBIT_PENDING2 __BIT(9)
168 1.1 skrll #define BCM2835_INTBIT_ARM __BITS(0,7)
169 1.1 skrll #define BCM2835_INTBIT_GPU0 __BITS(10,14)
170 1.1 skrll #define BCM2835_INTBIT_GPU1 __BITS(15,20)
171 1.1 skrll
172 1.1 skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
173 1.1 skrll bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
174 1.1 skrll
175 1.1 skrll static int
176 1.1 skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
177 1.1 skrll {
178 1.1 skrll struct amba_attach_args *aaa = aux;
179 1.1 skrll
180 1.1 skrll if (strcmp(aaa->aaa_name, "icu") != 0)
181 1.1 skrll return 0;
182 1.1 skrll
183 1.1 skrll return 1;
184 1.1 skrll }
185 1.1 skrll
186 1.1 skrll static void
187 1.1 skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
188 1.1 skrll {
189 1.1 skrll struct bcm2835icu_softc *sc = device_private(self);
190 1.1 skrll struct amba_attach_args *aaa = aux;
191 1.1 skrll
192 1.1 skrll sc->sc_dev = self;
193 1.1 skrll sc->sc_iot = aaa->aaa_iot;
194 1.1 skrll sc->sc_pic = &bcm2835_pic;
195 1.1 skrll
196 1.1 skrll if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
197 1.1 skrll &sc->sc_ioh)) {
198 1.1 skrll aprint_error_dev(self, "unable to map device\n");
199 1.1 skrll return;
200 1.1 skrll }
201 1.1 skrll
202 1.1 skrll bcmicu_sc = sc;
203 1.2.2.2 jdolecek
204 1.2.2.2 jdolecek #if defined(BCM2836)
205 1.2.2.2 jdolecek #if defined(MULTIPROCESSOR)
206 1.2.2.2 jdolecek aprint_normal(": Multiprocessor");
207 1.2.2.2 jdolecek bcm2836mp_intr_init(curcpu());
208 1.2.2.2 jdolecek #else
209 1.2.2.2 jdolecek pic_add(&bcm2836mp_pic[0], BCM2836_INT_BASECPUN(0));
210 1.2.2.2 jdolecek #endif
211 1.2.2.2 jdolecek #endif /* BCM2836 */
212 1.2.2.2 jdolecek pic_add(sc->sc_pic, BCM2835_INT_BASE);
213 1.2.2.2 jdolecek
214 1.1 skrll aprint_normal("\n");
215 1.1 skrll }
216 1.1 skrll
217 1.1 skrll void
218 1.1 skrll bcm2835_irq_handler(void *frame)
219 1.1 skrll {
220 1.1 skrll struct cpu_info * const ci = curcpu();
221 1.1 skrll const int oldipl = ci->ci_cpl;
222 1.2.2.2 jdolecek const cpuid_t cpuid = ci->ci_cpuid;
223 1.1 skrll const uint32_t oldipl_mask = __BIT(oldipl);
224 1.1 skrll int ipl_mask = 0;
225 1.1 skrll
226 1.1 skrll ci->ci_data.cpu_nintr++;
227 1.1 skrll
228 1.1 skrll bcm2835_barrier();
229 1.2.2.2 jdolecek if (cpuid == 0) {
230 1.2.2.2 jdolecek ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
231 1.2.2.2 jdolecek }
232 1.2.2.2 jdolecek #if defined(BCM2836)
233 1.2.2.2 jdolecek ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
234 1.2.2.2 jdolecek #endif
235 1.1 skrll
236 1.1 skrll /*
237 1.1 skrll * Record the pending_ipls and deliver them if we can.
238 1.1 skrll */
239 1.1 skrll if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
240 1.1 skrll pic_do_pending_ints(I32_bit, oldipl, frame);
241 1.1 skrll }
242 1.1 skrll
243 1.1 skrll static void
244 1.1 skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
245 1.1 skrll uint32_t irq_mask)
246 1.1 skrll {
247 1.1 skrll
248 1.1 skrll write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
249 1.1 skrll bcm2835_barrier();
250 1.1 skrll }
251 1.1 skrll
252 1.1 skrll static void
253 1.1 skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
254 1.1 skrll uint32_t irq_mask)
255 1.1 skrll {
256 1.1 skrll
257 1.1 skrll write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
258 1.1 skrll bcm2835_barrier();
259 1.1 skrll }
260 1.1 skrll
261 1.1 skrll /*
262 1.1 skrll * Called with interrupts disabled
263 1.1 skrll */
264 1.1 skrll static int
265 1.1 skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
266 1.1 skrll {
267 1.1 skrll int ipl = 0;
268 1.1 skrll uint32_t bpending, gpu0irq, gpu1irq, armirq;
269 1.1 skrll
270 1.1 skrll bcm2835_barrier();
271 1.1 skrll bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
272 1.1 skrll if (bpending == 0)
273 1.1 skrll return 0;
274 1.1 skrll
275 1.1 skrll armirq = bpending & BCM2835_INTBIT_ARM;
276 1.1 skrll gpu0irq = bpending & BCM2835_INTBIT_GPU0;
277 1.1 skrll gpu1irq = bpending & BCM2835_INTBIT_GPU1;
278 1.1 skrll
279 1.1 skrll if (armirq) {
280 1.2.2.2 jdolecek ipl |= pic_mark_pending_sources(pic,
281 1.2.2.2 jdolecek BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
282 1.1 skrll }
283 1.1 skrll
284 1.1 skrll if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
285 1.1 skrll uint32_t pending1;
286 1.2.2.1 tls
287 1.1 skrll pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
288 1.2.2.2 jdolecek ipl |= pic_mark_pending_sources(pic,
289 1.2.2.2 jdolecek BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
290 1.1 skrll }
291 1.1 skrll if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
292 1.1 skrll uint32_t pending2;
293 1.2.2.1 tls
294 1.1 skrll pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
295 1.2.2.2 jdolecek ipl |= pic_mark_pending_sources(pic,
296 1.2.2.2 jdolecek BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
297 1.1 skrll }
298 1.2.2.1 tls
299 1.1 skrll return ipl;
300 1.1 skrll }
301 1.1 skrll
302 1.1 skrll static void
303 1.1 skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
304 1.1 skrll {
305 1.1 skrll
306 1.1 skrll /* Nothing really*/
307 1.1 skrll KASSERT(is->is_irq < BCM2835_NIRQ);
308 1.1 skrll KASSERT(is->is_type == IST_LEVEL);
309 1.1 skrll }
310 1.1 skrll
311 1.1 skrll static void
312 1.1 skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
313 1.1 skrll {
314 1.1 skrll
315 1.1 skrll strlcpy(buf, bcm2835_sources[irq], len);
316 1.1 skrll }
317 1.2.2.2 jdolecek
318 1.2.2.2 jdolecek
319 1.2.2.2 jdolecek #if defined(BCM2836)
320 1.2.2.2 jdolecek
321 1.2.2.2 jdolecek #define BCM2836MP_TIMER_IRQS __BITS(3,0)
322 1.2.2.2 jdolecek #define BCM2836MP_MAILBOX_IRQS __BITS(4,4)
323 1.2.2.2 jdolecek
324 1.2.2.2 jdolecek #define BCM2836MP_ALL_IRQS \
325 1.2.2.2 jdolecek (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
326 1.2.2.2 jdolecek
327 1.2.2.2 jdolecek static void
328 1.2.2.2 jdolecek bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
329 1.2.2.2 jdolecek uint32_t irq_mask)
330 1.2.2.2 jdolecek {
331 1.2.2.2 jdolecek struct cpu_info * const ci = curcpu();
332 1.2.2.2 jdolecek const cpuid_t cpuid = ci->ci_cpuid;
333 1.2.2.2 jdolecek
334 1.2.2.2 jdolecek KASSERT(pic == &bcm2836mp_pic[cpuid]);
335 1.2.2.2 jdolecek KASSERT(irqbase == 0);
336 1.2.2.2 jdolecek
337 1.2.2.2 jdolecek if (irq_mask & BCM2836MP_TIMER_IRQS) {
338 1.2.2.2 jdolecek uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
339 1.2.2.2 jdolecek uint32_t val = bus_space_read_4(al_iot, al_ioh,
340 1.2.2.2 jdolecek BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
341 1.2.2.2 jdolecek val |= mask;
342 1.2.2.2 jdolecek bus_space_write_4(al_iot, al_ioh,
343 1.2.2.2 jdolecek BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
344 1.2.2.2 jdolecek val);
345 1.2.2.2 jdolecek bus_space_barrier(al_iot, al_ioh,
346 1.2.2.2 jdolecek BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
347 1.2.2.2 jdolecek BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
348 1.2.2.2 jdolecek BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
349 1.2.2.2 jdolecek }
350 1.2.2.2 jdolecek if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
351 1.2.2.2 jdolecek uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
352 1.2.2.2 jdolecek uint32_t val = bus_space_read_4(al_iot, al_ioh,
353 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
354 1.2.2.2 jdolecek val |= mask;
355 1.2.2.2 jdolecek bus_space_write_4(al_iot, al_ioh,
356 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
357 1.2.2.2 jdolecek val);
358 1.2.2.2 jdolecek bus_space_barrier(al_iot, al_ioh,
359 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
360 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
361 1.2.2.2 jdolecek BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
362 1.2.2.2 jdolecek }
363 1.2.2.2 jdolecek
364 1.2.2.2 jdolecek return;
365 1.2.2.2 jdolecek }
366 1.2.2.2 jdolecek
367 1.2.2.2 jdolecek static void
368 1.2.2.2 jdolecek bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
369 1.2.2.2 jdolecek uint32_t irq_mask)
370 1.2.2.2 jdolecek {
371 1.2.2.2 jdolecek struct cpu_info * const ci = curcpu();
372 1.2.2.2 jdolecek const cpuid_t cpuid = ci->ci_cpuid;
373 1.2.2.2 jdolecek
374 1.2.2.2 jdolecek KASSERT(pic == &bcm2836mp_pic[cpuid]);
375 1.2.2.2 jdolecek KASSERT(irqbase == 0);
376 1.2.2.2 jdolecek
377 1.2.2.2 jdolecek if (irq_mask & BCM2836MP_TIMER_IRQS) {
378 1.2.2.2 jdolecek uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
379 1.2.2.2 jdolecek uint32_t val = bus_space_read_4(al_iot, al_ioh,
380 1.2.2.2 jdolecek BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
381 1.2.2.2 jdolecek val &= ~mask;
382 1.2.2.2 jdolecek bus_space_write_4(al_iot, al_ioh,
383 1.2.2.2 jdolecek BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
384 1.2.2.2 jdolecek val);
385 1.2.2.2 jdolecek }
386 1.2.2.2 jdolecek if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
387 1.2.2.2 jdolecek uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
388 1.2.2.2 jdolecek uint32_t val = bus_space_read_4(al_iot, al_ioh,
389 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
390 1.2.2.2 jdolecek val &= ~mask;
391 1.2.2.2 jdolecek bus_space_write_4(al_iot, al_ioh,
392 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
393 1.2.2.2 jdolecek val);
394 1.2.2.2 jdolecek }
395 1.2.2.2 jdolecek
396 1.2.2.2 jdolecek bcm2835_barrier();
397 1.2.2.2 jdolecek return;
398 1.2.2.2 jdolecek }
399 1.2.2.2 jdolecek
400 1.2.2.2 jdolecek static int
401 1.2.2.2 jdolecek bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
402 1.2.2.2 jdolecek {
403 1.2.2.2 jdolecek struct cpu_info * const ci = curcpu();
404 1.2.2.2 jdolecek const cpuid_t cpuid = ci->ci_cpuid;
405 1.2.2.2 jdolecek uint32_t lpending;
406 1.2.2.2 jdolecek int ipl = 0;
407 1.2.2.2 jdolecek
408 1.2.2.2 jdolecek KASSERT(pic == &bcm2836mp_pic[cpuid]);
409 1.2.2.2 jdolecek
410 1.2.2.2 jdolecek bcm2835_barrier();
411 1.2.2.2 jdolecek
412 1.2.2.2 jdolecek lpending = bus_space_read_4(al_iot, al_ioh,
413 1.2.2.2 jdolecek BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
414 1.2.2.2 jdolecek
415 1.2.2.2 jdolecek lpending &= ~BCM2836_INTBIT_GPUPENDING;
416 1.2.2.2 jdolecek if (lpending & BCM2836MP_ALL_IRQS) {
417 1.2.2.2 jdolecek ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
418 1.2.2.2 jdolecek lpending & BCM2836MP_ALL_IRQS);
419 1.2.2.2 jdolecek }
420 1.2.2.2 jdolecek
421 1.2.2.2 jdolecek return ipl;
422 1.2.2.2 jdolecek }
423 1.2.2.2 jdolecek
424 1.2.2.2 jdolecek static void
425 1.2.2.2 jdolecek bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
426 1.2.2.2 jdolecek {
427 1.2.2.2 jdolecek /* Nothing really*/
428 1.2.2.2 jdolecek KASSERT(is->is_irq >= 0);
429 1.2.2.2 jdolecek KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
430 1.2.2.2 jdolecek }
431 1.2.2.2 jdolecek
432 1.2.2.2 jdolecek static void
433 1.2.2.2 jdolecek bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
434 1.2.2.2 jdolecek {
435 1.2.2.2 jdolecek
436 1.2.2.2 jdolecek irq %= BCM2836_NIRQPERCPU;
437 1.2.2.2 jdolecek strlcpy(buf, bcm2836mp_sources[irq], len);
438 1.2.2.2 jdolecek }
439 1.2.2.2 jdolecek
440 1.2.2.2 jdolecek
441 1.2.2.2 jdolecek #ifdef MULTIPROCESSOR
442 1.2.2.2 jdolecek static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
443 1.2.2.2 jdolecek {
444 1.2.2.2 jdolecek
445 1.2.2.2 jdolecek /* Enable IRQ and not FIQ */
446 1.2.2.2 jdolecek bus_space_write_4(al_iot, al_ioh,
447 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_cpuid), 1);
448 1.2.2.2 jdolecek }
449 1.2.2.2 jdolecek
450 1.2.2.2 jdolecek
451 1.2.2.2 jdolecek static void
452 1.2.2.2 jdolecek bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
453 1.2.2.2 jdolecek {
454 1.2.2.2 jdolecek KASSERT(pic != NULL);
455 1.2.2.2 jdolecek KASSERT(pic != &bcm2835_pic);
456 1.2.2.2 jdolecek KASSERT(pic->pic_cpus != NULL);
457 1.2.2.2 jdolecek
458 1.2.2.2 jdolecek const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
459 1.2.2.2 jdolecek
460 1.2.2.2 jdolecek bus_space_write_4(al_iot, al_ioh,
461 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
462 1.2.2.2 jdolecek }
463 1.2.2.2 jdolecek
464 1.2.2.2 jdolecek int
465 1.2.2.2 jdolecek bcm2836mp_ipi_handler(void *priv)
466 1.2.2.2 jdolecek {
467 1.2.2.2 jdolecek const struct cpu_info *ci = curcpu();
468 1.2.2.2 jdolecek const cpuid_t cpuid = ci->ci_cpuid;
469 1.2.2.2 jdolecek uint32_t ipimask, bit;
470 1.2.2.2 jdolecek
471 1.2.2.2 jdolecek ipimask = bus_space_read_4(al_iot, al_ioh,
472 1.2.2.2 jdolecek BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
473 1.2.2.2 jdolecek bus_space_write_4(al_iot, al_ioh, BCM2836_LOCAL_MAILBOX0_CLRN(cpuid),
474 1.2.2.2 jdolecek ipimask);
475 1.2.2.2 jdolecek
476 1.2.2.2 jdolecek while ((bit = ffs(ipimask)) > 0) {
477 1.2.2.2 jdolecek const u_int ipi = bit - 1;
478 1.2.2.2 jdolecek switch (ipi) {
479 1.2.2.2 jdolecek case IPI_AST:
480 1.2.2.2 jdolecek pic_ipi_ast(priv);
481 1.2.2.2 jdolecek break;
482 1.2.2.2 jdolecek case IPI_NOP:
483 1.2.2.2 jdolecek pic_ipi_nop(priv);
484 1.2.2.2 jdolecek break;
485 1.2.2.2 jdolecek #ifdef __HAVE_PREEMPTION
486 1.2.2.2 jdolecek case IPI_KPREEMPT:
487 1.2.2.2 jdolecek pic_ipi_kpreempt(priv);
488 1.2.2.2 jdolecek break;
489 1.2.2.2 jdolecek #endif
490 1.2.2.2 jdolecek case IPI_XCALL:
491 1.2.2.2 jdolecek pic_ipi_xcall(priv);
492 1.2.2.2 jdolecek break;
493 1.2.2.2 jdolecek case IPI_GENERIC:
494 1.2.2.2 jdolecek pic_ipi_generic(priv);
495 1.2.2.2 jdolecek break;
496 1.2.2.2 jdolecek case IPI_SHOOTDOWN:
497 1.2.2.2 jdolecek pic_ipi_shootdown(priv);
498 1.2.2.2 jdolecek break;
499 1.2.2.2 jdolecek #ifdef DDB
500 1.2.2.2 jdolecek case IPI_DDB:
501 1.2.2.2 jdolecek pic_ipi_ddb(priv);
502 1.2.2.2 jdolecek break;
503 1.2.2.2 jdolecek #endif
504 1.2.2.2 jdolecek }
505 1.2.2.2 jdolecek ipimask &= ~__BIT(ipi);
506 1.2.2.2 jdolecek }
507 1.2.2.2 jdolecek
508 1.2.2.2 jdolecek return 1;
509 1.2.2.2 jdolecek }
510 1.2.2.2 jdolecek
511 1.2.2.2 jdolecek void
512 1.2.2.2 jdolecek bcm2836mp_intr_init(struct cpu_info *ci)
513 1.2.2.2 jdolecek {
514 1.2.2.2 jdolecek const cpuid_t cpuid = ci->ci_cpuid;
515 1.2.2.2 jdolecek struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
516 1.2.2.2 jdolecek
517 1.2.2.2 jdolecek pic->pic_cpus = ci->ci_kcpuset;
518 1.2.2.2 jdolecek pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
519 1.2.2.2 jdolecek
520 1.2.2.2 jdolecek intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
521 1.2.2.2 jdolecek IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
522 1.2.2.2 jdolecek
523 1.2.2.2 jdolecek /* clock interrupt will attach with gtmr */
524 1.2.2.2 jdolecek if (cpuid == 0)
525 1.2.2.2 jdolecek return;
526 1.2.2.2 jdolecek
527 1.2.2.2 jdolecek intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
528 1.2.2.2 jdolecek IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
529 1.2.2.2 jdolecek
530 1.2.2.2 jdolecek }
531 1.2.2.2 jdolecek #endif
532 1.2.2.2 jdolecek
533 1.2.2.2 jdolecek #endif
534