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