bcm2835_intr.c revision 1.3.12.3 1 1.3.12.3 martin /* $NetBSD: bcm2835_intr.c,v 1.3.12.3 2015/07/30 09:37:37 martin Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.3.12.3 martin * 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.3.12.3 martin __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.3.12.3 2015/07/30 09:37:37 martin Exp $");
34 1.1 skrll
35 1.1 skrll #define _INTR_PRIVATE
36 1.1 skrll
37 1.3.12.2 snj #include "opt_bcm283x.h"
38 1.3.12.2 snj
39 1.1 skrll #include <sys/param.h>
40 1.3.12.2 snj #include <sys/bus.h>
41 1.3.12.2 snj #include <sys/cpu.h>
42 1.1 skrll #include <sys/device.h>
43 1.3.12.2 snj #include <sys/proc.h>
44 1.1 skrll
45 1.1 skrll #include <machine/intr.h>
46 1.3.12.2 snj
47 1.3.12.2 snj #include <arm/locore.h>
48 1.1 skrll
49 1.1 skrll #include <arm/pic/picvar.h>
50 1.3.12.2 snj #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.3.12.2 snj #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.3.12.2 snj #if defined(BCM2836)
64 1.3.12.2 snj static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
65 1.3.12.2 snj static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
66 1.3.12.2 snj static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
67 1.3.12.2 snj static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
68 1.3.12.2 snj static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
69 1.3.12.2 snj size_t);
70 1.3.12.2 snj #ifdef MULTIPROCESSOR
71 1.3.12.2 snj int bcm2836mp_ipi_handler(void *);
72 1.3.12.2 snj static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
73 1.3.12.2 snj static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
74 1.3.12.2 snj #endif
75 1.3.12.2 snj #endif
76 1.3.12.2 snj
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.3.12.2 snj #if defined(BCM2836)
95 1.3.12.2 snj static struct pic_ops bcm2836mp_picops = {
96 1.3.12.2 snj .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
97 1.3.12.2 snj .pic_block_irqs = bcm2836mp_pic_block_irqs,
98 1.3.12.2 snj .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
99 1.3.12.2 snj .pic_establish_irq = bcm2836mp_pic_establish_irq,
100 1.3.12.2 snj .pic_source_name = bcm2836mp_pic_source_name,
101 1.3.12.3 martin #if defined(MULTIPROCESSOR)
102 1.3.12.2 snj .pic_cpu_init = bcm2836mp_cpu_init,
103 1.3.12.2 snj .pic_ipi_send = bcm2836mp_send_ipi,
104 1.3.12.2 snj #endif
105 1.3.12.2 snj };
106 1.3.12.2 snj
107 1.3.12.3 martin struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
108 1.3.12.3 martin [0] = {
109 1.3.12.3 martin .pic_ops = &bcm2836mp_picops,
110 1.3.12.3 martin .pic_maxsources = BCM2836_NIRQPERCPU,
111 1.3.12.3 martin .pic_name = "bcm2836 pic",
112 1.3.12.3 martin },
113 1.3.12.3 martin [1] = {
114 1.3.12.3 martin .pic_ops = &bcm2836mp_picops,
115 1.3.12.3 martin .pic_maxsources = BCM2836_NIRQPERCPU,
116 1.3.12.3 martin .pic_name = "bcm2836 pic",
117 1.3.12.3 martin },
118 1.3.12.3 martin [2] = {
119 1.3.12.3 martin .pic_ops = &bcm2836mp_picops,
120 1.3.12.3 martin .pic_maxsources = BCM2836_NIRQPERCPU,
121 1.3.12.3 martin .pic_name = "bcm2836 pic",
122 1.3.12.3 martin },
123 1.3.12.3 martin [3] = {
124 1.3.12.3 martin .pic_ops = &bcm2836mp_picops,
125 1.3.12.3 martin .pic_maxsources = BCM2836_NIRQPERCPU,
126 1.3.12.3 martin .pic_name = "bcm2836 pic",
127 1.3.12.3 martin },
128 1.3.12.2 snj };
129 1.3.12.2 snj #endif
130 1.3.12.2 snj
131 1.1 skrll struct bcm2835icu_softc {
132 1.1 skrll device_t sc_dev;
133 1.1 skrll bus_space_tag_t sc_iot;
134 1.1 skrll bus_space_handle_t sc_ioh;
135 1.1 skrll struct pic_softc *sc_pic;
136 1.1 skrll };
137 1.1 skrll
138 1.1 skrll struct bcm2835icu_softc *bcmicu_sc;
139 1.3 skrll
140 1.1 skrll #define read_bcm2835reg(o) \
141 1.1 skrll bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
142 1.3 skrll
143 1.1 skrll #define write_bcm2835reg(o, v) \
144 1.1 skrll bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
145 1.1 skrll
146 1.1 skrll
147 1.1 skrll #define bcm2835_barrier() \
148 1.1 skrll bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
149 1.1 skrll BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
150 1.3 skrll
151 1.1 skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
152 1.1 skrll "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
153 1.1 skrll "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
154 1.2 jakllsch "(unused 8)", "usb", "(unused 10)", "(unused 11)",
155 1.2 jakllsch "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
156 1.3.12.1 martin "dma0", "dma1", "dma2", "dma3",
157 1.3.12.1 martin "dma4", "dma5", "dma6", "dma7",
158 1.3.12.1 martin "dma8", "dma9", "dma10", "dma11",
159 1.3.12.1 martin "dma12", "aux", "(unused 30)", "(unused 31)",
160 1.1 skrll "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
161 1.1 skrll "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
162 1.1 skrll "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
163 1.1 skrll "(unused 44)", "pwa0", "pwa1", "(unused 47)",
164 1.1 skrll "smi", "gpio[0]", "gpio[1]", "gpio[2]",
165 1.1 skrll "gpio[3]", "i2c", "spi", "pcm",
166 1.1 skrll "sdio", "uart", "(unused 58)", "(unused 59)",
167 1.1 skrll "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
168 1.1 skrll "Timer", "Mailbox", "Doorbell0", "Doorbell1",
169 1.1 skrll "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
170 1.1 skrll };
171 1.1 skrll
172 1.3.12.2 snj #if defined(BCM2836)
173 1.3.12.3 martin static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
174 1.3.12.2 snj "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
175 1.3.12.2 snj "mailbox0", "mailbox1", "mailbox2", "mailbox3",
176 1.3.12.2 snj };
177 1.3.12.2 snj #endif
178 1.3.12.2 snj
179 1.3.12.2 snj #define BCM2836_INTBIT_GPUPENDING __BIT(8)
180 1.3.12.2 snj
181 1.1 skrll #define BCM2835_INTBIT_PENDING1 __BIT(8)
182 1.1 skrll #define BCM2835_INTBIT_PENDING2 __BIT(9)
183 1.1 skrll #define BCM2835_INTBIT_ARM __BITS(0,7)
184 1.1 skrll #define BCM2835_INTBIT_GPU0 __BITS(10,14)
185 1.1 skrll #define BCM2835_INTBIT_GPU1 __BITS(15,20)
186 1.1 skrll
187 1.1 skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
188 1.1 skrll bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
189 1.1 skrll
190 1.1 skrll static int
191 1.1 skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
192 1.1 skrll {
193 1.1 skrll struct amba_attach_args *aaa = aux;
194 1.1 skrll
195 1.1 skrll if (strcmp(aaa->aaa_name, "icu") != 0)
196 1.1 skrll return 0;
197 1.1 skrll
198 1.1 skrll return 1;
199 1.1 skrll }
200 1.1 skrll
201 1.1 skrll static void
202 1.1 skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
203 1.1 skrll {
204 1.1 skrll struct bcm2835icu_softc *sc = device_private(self);
205 1.1 skrll struct amba_attach_args *aaa = aux;
206 1.1 skrll
207 1.1 skrll sc->sc_dev = self;
208 1.1 skrll sc->sc_iot = aaa->aaa_iot;
209 1.1 skrll sc->sc_pic = &bcm2835_pic;
210 1.1 skrll
211 1.1 skrll if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
212 1.1 skrll &sc->sc_ioh)) {
213 1.1 skrll aprint_error_dev(self, "unable to map device\n");
214 1.1 skrll return;
215 1.1 skrll }
216 1.1 skrll
217 1.1 skrll bcmicu_sc = sc;
218 1.3.12.2 snj
219 1.3.12.2 snj #if defined(BCM2836)
220 1.3.12.3 martin #if defined(MULTIPROCESSOR)
221 1.3.12.2 snj aprint_normal(": Multiprocessor");
222 1.3.12.2 snj #endif
223 1.3.12.3 martin
224 1.3.12.3 martin bcm2836mp_intr_init(curcpu());
225 1.3.12.2 snj #endif
226 1.3.12.3 martin pic_add(sc->sc_pic, BCM2835_INT_BASE);
227 1.3.12.2 snj
228 1.1 skrll aprint_normal("\n");
229 1.1 skrll }
230 1.1 skrll
231 1.1 skrll void
232 1.1 skrll bcm2835_irq_handler(void *frame)
233 1.1 skrll {
234 1.1 skrll struct cpu_info * const ci = curcpu();
235 1.1 skrll const int oldipl = ci->ci_cpl;
236 1.3.12.3 martin const cpuid_t cpuid = ci->ci_cpuid;
237 1.1 skrll const uint32_t oldipl_mask = __BIT(oldipl);
238 1.1 skrll int ipl_mask = 0;
239 1.1 skrll
240 1.1 skrll ci->ci_data.cpu_nintr++;
241 1.1 skrll
242 1.1 skrll bcm2835_barrier();
243 1.3.12.3 martin if (cpuid == 0) {
244 1.3.12.3 martin ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
245 1.3.12.3 martin }
246 1.3.12.2 snj #if defined(BCM2836)
247 1.3.12.3 martin ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
248 1.3.12.2 snj #endif
249 1.1 skrll
250 1.1 skrll /*
251 1.1 skrll * Record the pending_ipls and deliver them if we can.
252 1.1 skrll */
253 1.1 skrll if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
254 1.1 skrll pic_do_pending_ints(I32_bit, oldipl, frame);
255 1.1 skrll }
256 1.1 skrll
257 1.1 skrll static void
258 1.1 skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
259 1.1 skrll uint32_t irq_mask)
260 1.1 skrll {
261 1.1 skrll
262 1.1 skrll write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
263 1.1 skrll bcm2835_barrier();
264 1.1 skrll }
265 1.1 skrll
266 1.1 skrll static void
267 1.1 skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
268 1.1 skrll uint32_t irq_mask)
269 1.1 skrll {
270 1.1 skrll
271 1.1 skrll write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
272 1.1 skrll bcm2835_barrier();
273 1.1 skrll }
274 1.1 skrll
275 1.1 skrll /*
276 1.1 skrll * Called with interrupts disabled
277 1.1 skrll */
278 1.1 skrll static int
279 1.1 skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
280 1.1 skrll {
281 1.1 skrll int ipl = 0;
282 1.1 skrll uint32_t bpending, gpu0irq, gpu1irq, armirq;
283 1.1 skrll
284 1.1 skrll bcm2835_barrier();
285 1.1 skrll bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
286 1.1 skrll if (bpending == 0)
287 1.1 skrll return 0;
288 1.1 skrll
289 1.1 skrll armirq = bpending & BCM2835_INTBIT_ARM;
290 1.1 skrll gpu0irq = bpending & BCM2835_INTBIT_GPU0;
291 1.1 skrll gpu1irq = bpending & BCM2835_INTBIT_GPU1;
292 1.1 skrll
293 1.1 skrll if (armirq) {
294 1.3.12.3 martin ipl |= pic_mark_pending_sources(pic,
295 1.3.12.3 martin BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
296 1.3 skrll
297 1.1 skrll }
298 1.1 skrll
299 1.1 skrll if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
300 1.1 skrll uint32_t pending1;
301 1.3 skrll
302 1.1 skrll pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
303 1.3.12.3 martin ipl |= pic_mark_pending_sources(pic,
304 1.3.12.3 martin BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
305 1.1 skrll }
306 1.1 skrll if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
307 1.1 skrll uint32_t pending2;
308 1.3 skrll
309 1.1 skrll pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
310 1.3.12.3 martin ipl |= pic_mark_pending_sources(pic,
311 1.3.12.3 martin BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
312 1.1 skrll }
313 1.3 skrll
314 1.1 skrll return ipl;
315 1.1 skrll }
316 1.1 skrll
317 1.1 skrll static void
318 1.1 skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
319 1.1 skrll {
320 1.1 skrll
321 1.1 skrll /* Nothing really*/
322 1.1 skrll KASSERT(is->is_irq < BCM2835_NIRQ);
323 1.1 skrll KASSERT(is->is_type == IST_LEVEL);
324 1.1 skrll }
325 1.1 skrll
326 1.1 skrll static void
327 1.1 skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
328 1.1 skrll {
329 1.1 skrll
330 1.1 skrll strlcpy(buf, bcm2835_sources[irq], len);
331 1.1 skrll }
332 1.3.12.2 snj
333 1.3.12.2 snj
334 1.3.12.2 snj #if defined(BCM2836)
335 1.3.12.2 snj
336 1.3.12.2 snj #define BCM2836MP_TIMER_IRQS __BITS(3,0)
337 1.3.12.2 snj #define BCM2836MP_MAILBOX_IRQS __BITS(4,4)
338 1.3.12.2 snj
339 1.3.12.2 snj #define BCM2836MP_ALL_IRQS \
340 1.3.12.3 martin (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
341 1.3.12.2 snj
342 1.3.12.2 snj static void
343 1.3.12.2 snj bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
344 1.3.12.2 snj uint32_t irq_mask)
345 1.3.12.2 snj {
346 1.3.12.3 martin struct cpu_info * const ci = curcpu();
347 1.3.12.3 martin const cpuid_t cpuid = ci->ci_cpuid;
348 1.3.12.2 snj
349 1.3.12.3 martin KASSERT(pic == &bcm2836mp_pic[cpuid]);
350 1.3.12.3 martin KASSERT(irqbase == 0);
351 1.3.12.2 snj
352 1.3.12.2 snj if (irq_mask & BCM2836MP_TIMER_IRQS) {
353 1.3.12.2 snj uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
354 1.3.12.2 snj uint32_t val = bus_space_read_4(al_iot, al_ioh,
355 1.3.12.2 snj BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
356 1.3.12.2 snj val |= mask;
357 1.3.12.2 snj bus_space_write_4(al_iot, al_ioh,
358 1.3.12.2 snj BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
359 1.3.12.2 snj val);
360 1.3.12.2 snj bus_space_barrier(al_iot, al_ioh,
361 1.3.12.2 snj BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
362 1.3.12.2 snj BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
363 1.3.12.2 snj BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
364 1.3.12.3 martin }
365 1.3.12.3 martin if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
366 1.3.12.2 snj uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
367 1.3.12.2 snj uint32_t val = bus_space_read_4(al_iot, al_ioh,
368 1.3.12.2 snj BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
369 1.3.12.2 snj val |= mask;
370 1.3.12.2 snj bus_space_write_4(al_iot, al_ioh,
371 1.3.12.2 snj BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
372 1.3.12.2 snj val);
373 1.3.12.2 snj bus_space_barrier(al_iot, al_ioh,
374 1.3.12.2 snj BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
375 1.3.12.2 snj BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
376 1.3.12.2 snj BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
377 1.3.12.2 snj }
378 1.3.12.2 snj
379 1.3.12.2 snj return;
380 1.3.12.2 snj }
381 1.3.12.2 snj
382 1.3.12.2 snj static void
383 1.3.12.2 snj bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
384 1.3.12.2 snj uint32_t irq_mask)
385 1.3.12.2 snj {
386 1.3.12.3 martin struct cpu_info * const ci = curcpu();
387 1.3.12.3 martin const cpuid_t cpuid = ci->ci_cpuid;
388 1.3.12.3 martin
389 1.3.12.3 martin KASSERT(pic == &bcm2836mp_pic[cpuid]);
390 1.3.12.3 martin KASSERT(irqbase == 0);
391 1.3.12.2 snj
392 1.3.12.2 snj if (irq_mask & BCM2836MP_TIMER_IRQS) {
393 1.3.12.2 snj uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
394 1.3.12.2 snj uint32_t val = bus_space_read_4(al_iot, al_ioh,
395 1.3.12.2 snj BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
396 1.3.12.2 snj val &= ~mask;
397 1.3.12.2 snj bus_space_write_4(al_iot, al_ioh,
398 1.3.12.2 snj BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
399 1.3.12.2 snj val);
400 1.3.12.3 martin }
401 1.3.12.3 martin if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
402 1.3.12.2 snj uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
403 1.3.12.2 snj uint32_t val = bus_space_read_4(al_iot, al_ioh,
404 1.3.12.2 snj BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
405 1.3.12.2 snj val &= ~mask;
406 1.3.12.2 snj bus_space_write_4(al_iot, al_ioh,
407 1.3.12.2 snj BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
408 1.3.12.2 snj val);
409 1.3.12.2 snj }
410 1.3.12.2 snj
411 1.3.12.2 snj bcm2835_barrier();
412 1.3.12.2 snj return;
413 1.3.12.2 snj }
414 1.3.12.2 snj
415 1.3.12.2 snj static int
416 1.3.12.2 snj bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
417 1.3.12.2 snj {
418 1.3.12.3 martin struct cpu_info * const ci = curcpu();
419 1.3.12.3 martin const cpuid_t cpuid = ci->ci_cpuid;
420 1.3.12.2 snj uint32_t lpending;
421 1.3.12.2 snj int ipl = 0;
422 1.3.12.2 snj
423 1.3.12.3 martin KASSERT(pic == &bcm2836mp_pic[cpuid]);
424 1.3.12.3 martin
425 1.3.12.2 snj bcm2835_barrier();
426 1.3.12.2 snj
427 1.3.12.2 snj lpending = bus_space_read_4(al_iot, al_ioh,
428 1.3.12.2 snj BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
429 1.3.12.2 snj
430 1.3.12.2 snj lpending &= ~BCM2836_INTBIT_GPUPENDING;
431 1.3.12.2 snj if (lpending & BCM2836MP_ALL_IRQS) {
432 1.3.12.2 snj ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
433 1.3.12.2 snj lpending & BCM2836MP_ALL_IRQS);
434 1.3.12.2 snj }
435 1.3.12.2 snj
436 1.3.12.2 snj return ipl;
437 1.3.12.2 snj }
438 1.3.12.2 snj
439 1.3.12.2 snj static void
440 1.3.12.2 snj bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
441 1.3.12.2 snj {
442 1.3.12.2 snj /* Nothing really*/
443 1.3.12.2 snj KASSERT(is->is_irq >= 0);
444 1.3.12.3 martin KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
445 1.3.12.2 snj }
446 1.3.12.2 snj
447 1.3.12.2 snj static void
448 1.3.12.2 snj bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
449 1.3.12.2 snj {
450 1.3.12.3 martin
451 1.3.12.3 martin irq %= BCM2836_NIRQPERCPU;
452 1.3.12.2 snj strlcpy(buf, bcm2836mp_sources[irq], len);
453 1.3.12.2 snj }
454 1.3.12.3 martin
455 1.3.12.3 martin
456 1.3.12.3 martin #ifdef MULTIPROCESSOR
457 1.3.12.3 martin static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
458 1.3.12.3 martin {
459 1.3.12.3 martin
460 1.3.12.3 martin /* Enable IRQ and not FIQ */
461 1.3.12.3 martin bus_space_write_4(al_iot, al_ioh,
462 1.3.12.3 martin BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_cpuid), 1);
463 1.3.12.3 martin }
464 1.3.12.3 martin
465 1.3.12.3 martin
466 1.3.12.3 martin static void
467 1.3.12.3 martin bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
468 1.3.12.3 martin {
469 1.3.12.3 martin KASSERT(pic != NULL);
470 1.3.12.3 martin KASSERT(pic != &bcm2835_pic);
471 1.3.12.3 martin KASSERT(pic->pic_cpus != NULL);
472 1.3.12.3 martin
473 1.3.12.3 martin const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
474 1.3.12.3 martin
475 1.3.12.3 martin bus_space_write_4(al_iot, al_ioh,
476 1.3.12.3 martin BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
477 1.3.12.3 martin }
478 1.3.12.3 martin
479 1.3.12.3 martin int
480 1.3.12.3 martin bcm2836mp_ipi_handler(void *priv)
481 1.3.12.3 martin {
482 1.3.12.3 martin const struct cpu_info *ci = curcpu();
483 1.3.12.3 martin const cpuid_t cpuid = ci->ci_cpuid;
484 1.3.12.3 martin uint32_t ipimask, bit;
485 1.3.12.3 martin
486 1.3.12.3 martin ipimask = bus_space_read_4(al_iot, al_ioh,
487 1.3.12.3 martin BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
488 1.3.12.3 martin bus_space_write_4(al_iot, al_ioh, BCM2836_LOCAL_MAILBOX0_CLRN(cpuid),
489 1.3.12.3 martin ipimask);
490 1.3.12.3 martin
491 1.3.12.3 martin while ((bit = ffs(ipimask)) > 0) {
492 1.3.12.3 martin const u_int ipi = bit - 1;
493 1.3.12.3 martin switch (ipi) {
494 1.3.12.3 martin case IPI_AST:
495 1.3.12.3 martin case IPI_NOP:
496 1.3.12.3 martin #ifdef __HAVE_PREEMPTION
497 1.3.12.3 martin case IPI_KPREEMPT:
498 1.3.12.3 martin #endif
499 1.3.12.3 martin pic_ipi_nop(priv);
500 1.3.12.3 martin break;
501 1.3.12.3 martin case IPI_XCALL:
502 1.3.12.3 martin pic_ipi_xcall(priv);
503 1.3.12.3 martin break;
504 1.3.12.3 martin case IPI_GENERIC:
505 1.3.12.3 martin pic_ipi_generic(priv);
506 1.3.12.3 martin break;
507 1.3.12.3 martin case IPI_SHOOTDOWN:
508 1.3.12.3 martin pic_ipi_shootdown(priv);
509 1.3.12.3 martin break;
510 1.3.12.3 martin #ifdef DDB
511 1.3.12.3 martin case IPI_DDB:
512 1.3.12.3 martin pic_ipi_ddb(priv);
513 1.3.12.3 martin break;
514 1.3.12.3 martin #endif
515 1.3.12.3 martin }
516 1.3.12.3 martin ipimask &= ~__BIT(ipi);
517 1.3.12.3 martin }
518 1.3.12.3 martin
519 1.3.12.3 martin return 1;
520 1.3.12.3 martin }
521 1.3.12.3 martin
522 1.3.12.3 martin void
523 1.3.12.3 martin bcm2836mp_intr_init(struct cpu_info *ci)
524 1.3.12.3 martin {
525 1.3.12.3 martin const cpuid_t cpuid = ci->ci_cpuid;
526 1.3.12.3 martin struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
527 1.3.12.3 martin
528 1.3.12.3 martin pic->pic_cpus = ci->ci_kcpuset;
529 1.3.12.3 martin pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
530 1.3.12.3 martin
531 1.3.12.3 martin intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
532 1.3.12.3 martin IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
533 1.3.12.3 martin
534 1.3.12.3 martin /* clock interrupt will attach with gtmr */
535 1.3.12.3 martin if (cpuid == 0)
536 1.3.12.3 martin return;
537 1.3.12.3 martin
538 1.3.12.3 martin intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
539 1.3.12.3 martin IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
540 1.3.12.3 martin
541 1.3.12.3 martin }
542 1.3.12.3 martin #endif
543 1.3.12.3 martin
544 1.3.12.2 snj #endif
545