bcm2835_intr.c revision 1.1.2.2 1 1.1.2.2 jdc /* $NetBSD: bcm2835_intr.c,v 1.1.2.2 2012/08/09 06:36:49 jdc Exp $ */
2 1.1.2.2 jdc
3 1.1.2.2 jdc /*-
4 1.1.2.2 jdc * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 1.1.2.2 jdc * All rights reserved.
6 1.1.2.2 jdc *
7 1.1.2.2 jdc * This code is derived from software contributed to The NetBSD Foundation
8 1.1.2.2 jdc * by Nick Hudson
9 1.1.2.2 jdc *
10 1.1.2.2 jdc * Redistribution and use in source and binary forms, with or without
11 1.1.2.2 jdc * modification, are permitted provided that the following conditions
12 1.1.2.2 jdc * are met:
13 1.1.2.2 jdc * 1. Redistributions of source code must retain the above copyright
14 1.1.2.2 jdc * notice, this list of conditions and the following disclaimer.
15 1.1.2.2 jdc * 2. Redistributions in binary form must reproduce the above copyright
16 1.1.2.2 jdc * notice, this list of conditions and the following disclaimer in the
17 1.1.2.2 jdc * documentation and/or other materials provided with the distribution.
18 1.1.2.2 jdc *
19 1.1.2.2 jdc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1.2.2 jdc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1.2.2 jdc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1.2.2 jdc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1.2.2 jdc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1.2.2 jdc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1.2.2 jdc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1.2.2 jdc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1.2.2 jdc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1.2.2 jdc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1.2.2 jdc * POSSIBILITY OF SUCH DAMAGE.
30 1.1.2.2 jdc */
31 1.1.2.2 jdc
32 1.1.2.2 jdc #include <sys/cdefs.h>
33 1.1.2.2 jdc __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.1.2.2 2012/08/09 06:36:49 jdc Exp $");
34 1.1.2.2 jdc
35 1.1.2.2 jdc #define _INTR_PRIVATE
36 1.1.2.2 jdc
37 1.1.2.2 jdc #include <sys/param.h>
38 1.1.2.2 jdc #include <sys/proc.h>
39 1.1.2.2 jdc #include <sys/device.h>
40 1.1.2.2 jdc
41 1.1.2.2 jdc #include <machine/intr.h>
42 1.1.2.2 jdc #include <sys/bus.h>
43 1.1.2.2 jdc
44 1.1.2.2 jdc #include <arm/pic/picvar.h>
45 1.1.2.2 jdc
46 1.1.2.2 jdc #include <arm/broadcom/bcm_amba.h>
47 1.1.2.2 jdc #include <arm/broadcom/bcm2835reg.h>
48 1.1.2.2 jdc
49 1.1.2.2 jdc static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
50 1.1.2.2 jdc static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
51 1.1.2.2 jdc static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
52 1.1.2.2 jdc static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
53 1.1.2.2 jdc static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
54 1.1.2.2 jdc size_t);
55 1.1.2.2 jdc
56 1.1.2.2 jdc static int bcm2835_icu_match(device_t, cfdata_t, void *);
57 1.1.2.2 jdc static void bcm2835_icu_attach(device_t, device_t, void *);
58 1.1.2.2 jdc
59 1.1.2.2 jdc static struct pic_ops bcm2835_picops = {
60 1.1.2.2 jdc .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
61 1.1.2.2 jdc .pic_block_irqs = bcm2835_pic_block_irqs,
62 1.1.2.2 jdc .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
63 1.1.2.2 jdc .pic_establish_irq = bcm2835_pic_establish_irq,
64 1.1.2.2 jdc .pic_source_name = bcm2835_pic_source_name,
65 1.1.2.2 jdc };
66 1.1.2.2 jdc
67 1.1.2.2 jdc struct pic_softc bcm2835_pic = {
68 1.1.2.2 jdc .pic_ops = &bcm2835_picops,
69 1.1.2.2 jdc .pic_maxsources = BCM2835_NIRQ,
70 1.1.2.2 jdc .pic_name = "bcm2835 pic",
71 1.1.2.2 jdc };
72 1.1.2.2 jdc
73 1.1.2.2 jdc struct bcm2835icu_softc {
74 1.1.2.2 jdc device_t sc_dev;
75 1.1.2.2 jdc bus_space_tag_t sc_iot;
76 1.1.2.2 jdc bus_space_handle_t sc_ioh;
77 1.1.2.2 jdc struct pic_softc *sc_pic;
78 1.1.2.2 jdc };
79 1.1.2.2 jdc
80 1.1.2.2 jdc struct bcm2835icu_softc *bcmicu_sc;
81 1.1.2.2 jdc
82 1.1.2.2 jdc #define read_bcm2835reg(o) \
83 1.1.2.2 jdc bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
84 1.1.2.2 jdc
85 1.1.2.2 jdc #define write_bcm2835reg(o, v) \
86 1.1.2.2 jdc bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
87 1.1.2.2 jdc
88 1.1.2.2 jdc
89 1.1.2.2 jdc #define bcm2835_barrier() \
90 1.1.2.2 jdc bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
91 1.1.2.2 jdc BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
92 1.1.2.2 jdc
93 1.1.2.2 jdc static const char * const bcm2835_sources[BCM2835_NIRQ] = {
94 1.1.2.2 jdc "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
95 1.1.2.2 jdc "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
96 1.1.2.2 jdc "(unused 8)", "usb", "(unused 10)", "(unused 11)"
97 1.1.2.2 jdc "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)"
98 1.1.2.2 jdc "(unused 16)", "(unused 17)", "dma2", "dma3",
99 1.1.2.2 jdc "(unused 20)", "(unused 21)", "(unused 22)", "(unused 23)",
100 1.1.2.2 jdc "(unused 24)", "(unused 25)", "(unused 26)", "(unused 27)",
101 1.1.2.2 jdc "(unused 28)", "aux", "(unused 30)", "(unused 31)",
102 1.1.2.2 jdc "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
103 1.1.2.2 jdc "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
104 1.1.2.2 jdc "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
105 1.1.2.2 jdc "(unused 44)", "pwa0", "pwa1", "(unused 47)",
106 1.1.2.2 jdc "smi", "gpio[0]", "gpio[1]", "gpio[2]",
107 1.1.2.2 jdc "gpio[3]", "i2c", "spi", "pcm",
108 1.1.2.2 jdc "sdio", "uart", "(unused 58)", "(unused 59)",
109 1.1.2.2 jdc "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
110 1.1.2.2 jdc "Timer", "Mailbox", "Doorbell0", "Doorbell1",
111 1.1.2.2 jdc "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
112 1.1.2.2 jdc };
113 1.1.2.2 jdc
114 1.1.2.2 jdc #define BCM2835_INTBIT_PENDING1 __BIT(8)
115 1.1.2.2 jdc #define BCM2835_INTBIT_PENDING2 __BIT(9)
116 1.1.2.2 jdc #define BCM2835_INTBIT_ARM __BITS(0,7)
117 1.1.2.2 jdc #define BCM2835_INTBIT_GPU0 __BITS(10,14)
118 1.1.2.2 jdc #define BCM2835_INTBIT_GPU1 __BITS(15,20)
119 1.1.2.2 jdc
120 1.1.2.2 jdc CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
121 1.1.2.2 jdc bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
122 1.1.2.2 jdc
123 1.1.2.2 jdc static int
124 1.1.2.2 jdc bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
125 1.1.2.2 jdc {
126 1.1.2.2 jdc struct amba_attach_args *aaa = aux;
127 1.1.2.2 jdc
128 1.1.2.2 jdc if (strcmp(aaa->aaa_name, "icu") != 0)
129 1.1.2.2 jdc return 0;
130 1.1.2.2 jdc
131 1.1.2.2 jdc return 1;
132 1.1.2.2 jdc }
133 1.1.2.2 jdc
134 1.1.2.2 jdc static void
135 1.1.2.2 jdc bcm2835_icu_attach(device_t parent, device_t self, void *aux)
136 1.1.2.2 jdc {
137 1.1.2.2 jdc struct bcm2835icu_softc *sc = device_private(self);
138 1.1.2.2 jdc struct amba_attach_args *aaa = aux;
139 1.1.2.2 jdc
140 1.1.2.2 jdc sc->sc_dev = self;
141 1.1.2.2 jdc sc->sc_iot = aaa->aaa_iot;
142 1.1.2.2 jdc sc->sc_pic = &bcm2835_pic;
143 1.1.2.2 jdc
144 1.1.2.2 jdc if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
145 1.1.2.2 jdc &sc->sc_ioh)) {
146 1.1.2.2 jdc aprint_error_dev(self, "unable to map device\n");
147 1.1.2.2 jdc return;
148 1.1.2.2 jdc }
149 1.1.2.2 jdc
150 1.1.2.2 jdc bcmicu_sc = sc;
151 1.1.2.2 jdc pic_add(sc->sc_pic, 0);
152 1.1.2.2 jdc aprint_normal("\n");
153 1.1.2.2 jdc }
154 1.1.2.2 jdc
155 1.1.2.2 jdc void
156 1.1.2.2 jdc bcm2835_irq_handler(void *frame)
157 1.1.2.2 jdc {
158 1.1.2.2 jdc struct cpu_info * const ci = curcpu();
159 1.1.2.2 jdc const int oldipl = ci->ci_cpl;
160 1.1.2.2 jdc const uint32_t oldipl_mask = __BIT(oldipl);
161 1.1.2.2 jdc int ipl_mask = 0;
162 1.1.2.2 jdc
163 1.1.2.2 jdc ci->ci_data.cpu_nintr++;
164 1.1.2.2 jdc
165 1.1.2.2 jdc bcm2835_barrier();
166 1.1.2.2 jdc ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
167 1.1.2.2 jdc
168 1.1.2.2 jdc /*
169 1.1.2.2 jdc * Record the pending_ipls and deliver them if we can.
170 1.1.2.2 jdc */
171 1.1.2.2 jdc if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
172 1.1.2.2 jdc pic_do_pending_ints(I32_bit, oldipl, frame);
173 1.1.2.2 jdc }
174 1.1.2.2 jdc
175 1.1.2.2 jdc
176 1.1.2.2 jdc static void
177 1.1.2.2 jdc bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
178 1.1.2.2 jdc uint32_t irq_mask)
179 1.1.2.2 jdc {
180 1.1.2.2 jdc
181 1.1.2.2 jdc write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
182 1.1.2.2 jdc bcm2835_barrier();
183 1.1.2.2 jdc }
184 1.1.2.2 jdc
185 1.1.2.2 jdc static void
186 1.1.2.2 jdc bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
187 1.1.2.2 jdc uint32_t irq_mask)
188 1.1.2.2 jdc {
189 1.1.2.2 jdc
190 1.1.2.2 jdc write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
191 1.1.2.2 jdc bcm2835_barrier();
192 1.1.2.2 jdc }
193 1.1.2.2 jdc
194 1.1.2.2 jdc /*
195 1.1.2.2 jdc * Called with interrupts disabled
196 1.1.2.2 jdc */
197 1.1.2.2 jdc static int
198 1.1.2.2 jdc bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
199 1.1.2.2 jdc {
200 1.1.2.2 jdc int ipl = 0;
201 1.1.2.2 jdc uint32_t bpending, gpu0irq, gpu1irq, armirq;
202 1.1.2.2 jdc
203 1.1.2.2 jdc bcm2835_barrier();
204 1.1.2.2 jdc bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
205 1.1.2.2 jdc if (bpending == 0)
206 1.1.2.2 jdc return 0;
207 1.1.2.2 jdc
208 1.1.2.2 jdc armirq = bpending & BCM2835_INTBIT_ARM;
209 1.1.2.2 jdc gpu0irq = bpending & BCM2835_INTBIT_GPU0;
210 1.1.2.2 jdc gpu1irq = bpending & BCM2835_INTBIT_GPU1;
211 1.1.2.2 jdc
212 1.1.2.2 jdc if (armirq) {
213 1.1.2.2 jdc ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE,
214 1.1.2.2 jdc armirq);
215 1.1.2.2 jdc
216 1.1.2.2 jdc }
217 1.1.2.2 jdc
218 1.1.2.2 jdc if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
219 1.1.2.2 jdc uint32_t pending1;
220 1.1.2.2 jdc
221 1.1.2.2 jdc pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
222 1.1.2.2 jdc ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE,
223 1.1.2.2 jdc pending1);
224 1.1.2.2 jdc }
225 1.1.2.2 jdc if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
226 1.1.2.2 jdc uint32_t pending2;
227 1.1.2.2 jdc
228 1.1.2.2 jdc pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
229 1.1.2.2 jdc ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE,
230 1.1.2.2 jdc pending2);
231 1.1.2.2 jdc }
232 1.1.2.2 jdc
233 1.1.2.2 jdc return ipl;
234 1.1.2.2 jdc }
235 1.1.2.2 jdc
236 1.1.2.2 jdc static void
237 1.1.2.2 jdc bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
238 1.1.2.2 jdc {
239 1.1.2.2 jdc
240 1.1.2.2 jdc /* Nothing really*/
241 1.1.2.2 jdc KASSERT(is->is_irq < BCM2835_NIRQ);
242 1.1.2.2 jdc KASSERT(is->is_type == IST_LEVEL);
243 1.1.2.2 jdc }
244 1.1.2.2 jdc
245 1.1.2.2 jdc static void
246 1.1.2.2 jdc bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
247 1.1.2.2 jdc {
248 1.1.2.2 jdc
249 1.1.2.2 jdc strlcpy(buf, bcm2835_sources[irq], len);
250 1.1.2.2 jdc }
251