bcm2835_intr.c revision 1.1.2.4 1 1.1.2.4 riz /* $NetBSD: bcm2835_intr.c,v 1.1.2.4 2013/02/13 01:36:14 riz 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.4 riz __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.1.2.4 2013/02/13 01:36:14 riz 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.4 riz
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.4 riz
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 #define bcm2835_barrier() \
89 1.1.2.2 jdc bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
90 1.1.2.2 jdc BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
91 1.1.2.4 riz
92 1.1.2.2 jdc static const char * const bcm2835_sources[BCM2835_NIRQ] = {
93 1.1.2.2 jdc "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
94 1.1.2.2 jdc "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
95 1.1.2.3 riz "(unused 8)", "usb", "(unused 10)", "(unused 11)",
96 1.1.2.3 riz "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
97 1.1.2.2 jdc "(unused 16)", "(unused 17)", "dma2", "dma3",
98 1.1.2.2 jdc "(unused 20)", "(unused 21)", "(unused 22)", "(unused 23)",
99 1.1.2.2 jdc "(unused 24)", "(unused 25)", "(unused 26)", "(unused 27)",
100 1.1.2.2 jdc "(unused 28)", "aux", "(unused 30)", "(unused 31)",
101 1.1.2.2 jdc "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
102 1.1.2.2 jdc "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
103 1.1.2.2 jdc "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
104 1.1.2.2 jdc "(unused 44)", "pwa0", "pwa1", "(unused 47)",
105 1.1.2.2 jdc "smi", "gpio[0]", "gpio[1]", "gpio[2]",
106 1.1.2.2 jdc "gpio[3]", "i2c", "spi", "pcm",
107 1.1.2.2 jdc "sdio", "uart", "(unused 58)", "(unused 59)",
108 1.1.2.2 jdc "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
109 1.1.2.2 jdc "Timer", "Mailbox", "Doorbell0", "Doorbell1",
110 1.1.2.2 jdc "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
111 1.1.2.2 jdc };
112 1.1.2.2 jdc
113 1.1.2.2 jdc #define BCM2835_INTBIT_PENDING1 __BIT(8)
114 1.1.2.2 jdc #define BCM2835_INTBIT_PENDING2 __BIT(9)
115 1.1.2.2 jdc #define BCM2835_INTBIT_ARM __BITS(0,7)
116 1.1.2.2 jdc #define BCM2835_INTBIT_GPU0 __BITS(10,14)
117 1.1.2.2 jdc #define BCM2835_INTBIT_GPU1 __BITS(15,20)
118 1.1.2.2 jdc
119 1.1.2.2 jdc CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
120 1.1.2.2 jdc bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
121 1.1.2.2 jdc
122 1.1.2.2 jdc static int
123 1.1.2.2 jdc bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
124 1.1.2.2 jdc {
125 1.1.2.2 jdc struct amba_attach_args *aaa = aux;
126 1.1.2.2 jdc
127 1.1.2.2 jdc if (strcmp(aaa->aaa_name, "icu") != 0)
128 1.1.2.2 jdc return 0;
129 1.1.2.2 jdc
130 1.1.2.2 jdc return 1;
131 1.1.2.2 jdc }
132 1.1.2.2 jdc
133 1.1.2.2 jdc static void
134 1.1.2.2 jdc bcm2835_icu_attach(device_t parent, device_t self, void *aux)
135 1.1.2.2 jdc {
136 1.1.2.2 jdc struct bcm2835icu_softc *sc = device_private(self);
137 1.1.2.2 jdc struct amba_attach_args *aaa = aux;
138 1.1.2.2 jdc
139 1.1.2.2 jdc sc->sc_dev = self;
140 1.1.2.2 jdc sc->sc_iot = aaa->aaa_iot;
141 1.1.2.2 jdc sc->sc_pic = &bcm2835_pic;
142 1.1.2.2 jdc
143 1.1.2.2 jdc if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
144 1.1.2.2 jdc &sc->sc_ioh)) {
145 1.1.2.2 jdc aprint_error_dev(self, "unable to map device\n");
146 1.1.2.2 jdc return;
147 1.1.2.2 jdc }
148 1.1.2.2 jdc
149 1.1.2.2 jdc bcmicu_sc = sc;
150 1.1.2.2 jdc pic_add(sc->sc_pic, 0);
151 1.1.2.2 jdc aprint_normal("\n");
152 1.1.2.2 jdc }
153 1.1.2.2 jdc
154 1.1.2.2 jdc void
155 1.1.2.2 jdc bcm2835_irq_handler(void *frame)
156 1.1.2.2 jdc {
157 1.1.2.2 jdc struct cpu_info * const ci = curcpu();
158 1.1.2.2 jdc const int oldipl = ci->ci_cpl;
159 1.1.2.2 jdc const uint32_t oldipl_mask = __BIT(oldipl);
160 1.1.2.2 jdc int ipl_mask = 0;
161 1.1.2.2 jdc
162 1.1.2.2 jdc ci->ci_data.cpu_nintr++;
163 1.1.2.2 jdc
164 1.1.2.2 jdc bcm2835_barrier();
165 1.1.2.2 jdc ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
166 1.1.2.2 jdc
167 1.1.2.2 jdc /*
168 1.1.2.2 jdc * Record the pending_ipls and deliver them if we can.
169 1.1.2.2 jdc */
170 1.1.2.2 jdc if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
171 1.1.2.2 jdc pic_do_pending_ints(I32_bit, oldipl, frame);
172 1.1.2.2 jdc }
173 1.1.2.2 jdc
174 1.1.2.2 jdc
175 1.1.2.2 jdc static void
176 1.1.2.2 jdc bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
177 1.1.2.2 jdc uint32_t irq_mask)
178 1.1.2.2 jdc {
179 1.1.2.2 jdc
180 1.1.2.2 jdc write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
181 1.1.2.2 jdc bcm2835_barrier();
182 1.1.2.2 jdc }
183 1.1.2.2 jdc
184 1.1.2.2 jdc static void
185 1.1.2.2 jdc bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
186 1.1.2.2 jdc uint32_t irq_mask)
187 1.1.2.2 jdc {
188 1.1.2.2 jdc
189 1.1.2.2 jdc write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
190 1.1.2.2 jdc bcm2835_barrier();
191 1.1.2.2 jdc }
192 1.1.2.2 jdc
193 1.1.2.2 jdc /*
194 1.1.2.2 jdc * Called with interrupts disabled
195 1.1.2.2 jdc */
196 1.1.2.2 jdc static int
197 1.1.2.2 jdc bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
198 1.1.2.2 jdc {
199 1.1.2.2 jdc int ipl = 0;
200 1.1.2.2 jdc uint32_t bpending, gpu0irq, gpu1irq, armirq;
201 1.1.2.2 jdc
202 1.1.2.2 jdc bcm2835_barrier();
203 1.1.2.2 jdc bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
204 1.1.2.2 jdc if (bpending == 0)
205 1.1.2.2 jdc return 0;
206 1.1.2.2 jdc
207 1.1.2.2 jdc armirq = bpending & BCM2835_INTBIT_ARM;
208 1.1.2.2 jdc gpu0irq = bpending & BCM2835_INTBIT_GPU0;
209 1.1.2.2 jdc gpu1irq = bpending & BCM2835_INTBIT_GPU1;
210 1.1.2.2 jdc
211 1.1.2.2 jdc if (armirq) {
212 1.1.2.2 jdc ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE,
213 1.1.2.2 jdc armirq);
214 1.1.2.4 riz
215 1.1.2.2 jdc }
216 1.1.2.2 jdc
217 1.1.2.2 jdc if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
218 1.1.2.2 jdc uint32_t pending1;
219 1.1.2.4 riz
220 1.1.2.2 jdc pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
221 1.1.2.2 jdc ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE,
222 1.1.2.2 jdc pending1);
223 1.1.2.2 jdc }
224 1.1.2.2 jdc if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
225 1.1.2.2 jdc uint32_t pending2;
226 1.1.2.4 riz
227 1.1.2.2 jdc pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
228 1.1.2.2 jdc ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE,
229 1.1.2.2 jdc pending2);
230 1.1.2.2 jdc }
231 1.1.2.4 riz
232 1.1.2.2 jdc return ipl;
233 1.1.2.2 jdc }
234 1.1.2.2 jdc
235 1.1.2.2 jdc static void
236 1.1.2.2 jdc bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
237 1.1.2.2 jdc {
238 1.1.2.2 jdc
239 1.1.2.2 jdc /* Nothing really*/
240 1.1.2.2 jdc KASSERT(is->is_irq < BCM2835_NIRQ);
241 1.1.2.2 jdc KASSERT(is->is_type == IST_LEVEL);
242 1.1.2.2 jdc }
243 1.1.2.2 jdc
244 1.1.2.2 jdc static void
245 1.1.2.2 jdc bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
246 1.1.2.2 jdc {
247 1.1.2.2 jdc
248 1.1.2.2 jdc strlcpy(buf, bcm2835_sources[irq], len);
249 1.1.2.2 jdc }
250