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