xref: /freebsd/sys/arm/mv/ic.c (revision 8fc257994d0ce2396196d7a06d50d20c8015f4b7)
1 /*-
2  * Copyright (c) 2006 Benno Rice.
3  * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
4  * All rights reserved.
5  *
6  * Adapted and extended to Marvell SoCs by Semihalf.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_icu.c, rev 1
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/rman.h>
40 #include <machine/bus.h>
41 #include <machine/intr.h>
42 
43 #include <dev/ofw/ofw_bus.h>
44 #include <dev/ofw/ofw_bus_subr.h>
45 
46 #include <arm/mv/mvreg.h>
47 #include <arm/mv/mvvar.h>
48 
49 struct mv_ic_softc {
50 	struct resource	*	ic_res[1];
51 	bus_space_tag_t		ic_bst;
52 	bus_space_handle_t	ic_bsh;
53 	int			ic_high_regs;
54 	int			ic_error_regs;
55 };
56 
57 static struct resource_spec mv_ic_spec[] = {
58 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
59 	{ -1, 0 }
60 };
61 
62 static struct mv_ic_softc *mv_ic_sc = NULL;
63 
64 static int	mv_ic_probe(device_t);
65 static int	mv_ic_attach(device_t);
66 
67 uint32_t	mv_ic_get_cause(void);
68 uint32_t	mv_ic_get_mask(void);
69 void		mv_ic_set_mask(uint32_t);
70 uint32_t	mv_ic_get_cause_hi(void);
71 uint32_t	mv_ic_get_mask_hi(void);
72 void		mv_ic_set_mask_hi(uint32_t);
73 uint32_t	mv_ic_get_cause_error(void);
74 uint32_t	mv_ic_get_mask_error(void);
75 void		mv_ic_set_mask_error(uint32_t);
76 static void	arm_mask_irq_all(void);
77 
78 static int
79 mv_ic_probe(device_t dev)
80 {
81 
82 	if (!ofw_bus_is_compatible(dev, "mrvl,pic"))
83 		return (ENXIO);
84 
85 	device_set_desc(dev, "Marvell Integrated Interrupt Controller");
86 	return (0);
87 }
88 
89 static int
90 mv_ic_attach(device_t dev)
91 {
92 	struct mv_ic_softc *sc;
93 	uint32_t dev_id, rev_id;
94 	int error;
95 
96 	sc = (struct mv_ic_softc *)device_get_softc(dev);
97 
98 	if (mv_ic_sc != NULL)
99 		return (ENXIO);
100 	mv_ic_sc = sc;
101 
102 	soc_id(&dev_id, &rev_id);
103 
104 	sc->ic_high_regs = 0;
105 	sc->ic_error_regs = 0;
106 
107 	if (dev_id == MV_DEV_88F6281 || dev_id == MV_DEV_MV78100 ||
108 	    dev_id == MV_DEV_MV78100_Z0)
109 		sc->ic_high_regs = 1;
110 
111 	if (dev_id == MV_DEV_MV78100 || dev_id == MV_DEV_MV78100_Z0)
112 		sc->ic_error_regs = 1;
113 
114 	error = bus_alloc_resources(dev, mv_ic_spec, sc->ic_res);
115 	if (error) {
116 		device_printf(dev, "could not allocate resources\n");
117 		return (ENXIO);
118 	}
119 
120 	sc->ic_bst = rman_get_bustag(sc->ic_res[0]);
121 	sc->ic_bsh = rman_get_bushandle(sc->ic_res[0]);
122 
123 	/* Mask all interrupts */
124 	arm_mask_irq_all();
125 
126 	return (0);
127 }
128 
129 static device_method_t mv_ic_methods[] = {
130 	DEVMETHOD(device_probe,		mv_ic_probe),
131 	DEVMETHOD(device_attach,	mv_ic_attach),
132 	{ 0, 0 }
133 };
134 
135 static driver_t mv_ic_driver = {
136 	"ic",
137 	mv_ic_methods,
138 	sizeof(struct mv_ic_softc),
139 };
140 
141 static devclass_t mv_ic_devclass;
142 
143 DRIVER_MODULE(ic, simplebus, mv_ic_driver, mv_ic_devclass, 0, 0);
144 
145 int
146 arm_get_next_irq(int last __unused)
147 {
148 	int irq;
149 
150 	irq = mv_ic_get_cause() & mv_ic_get_mask();
151 	if (irq)
152 		return (ffs(irq) - 1);
153 
154 	if (mv_ic_sc->ic_high_regs) {
155 		irq = mv_ic_get_cause_hi() & mv_ic_get_mask_hi();
156 		if (irq)
157 			return (ffs(irq) + 31);
158 	}
159 
160 	if (mv_ic_sc->ic_error_regs) {
161 		irq = mv_ic_get_cause_error() & mv_ic_get_mask_error();
162 		if (irq)
163 			return (ffs(irq) + 63);
164 	}
165 
166 	return (-1);
167 }
168 
169 static void
170 arm_mask_irq_all(void)
171 {
172 
173 	mv_ic_set_mask(0);
174 
175 	if (mv_ic_sc->ic_high_regs)
176 		mv_ic_set_mask_hi(0);
177 
178 	if (mv_ic_sc->ic_error_regs)
179 		mv_ic_set_mask_error(0);
180 }
181 
182 void
183 arm_mask_irq(uintptr_t nb)
184 {
185 	uint32_t	mr;
186 
187 	if (nb < 32) {
188 		mr = mv_ic_get_mask();
189 		mr &= ~(1 << nb);
190 		mv_ic_set_mask(mr);
191 
192 	} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
193 		mr = mv_ic_get_mask_hi();
194 		mr &= ~(1 << (nb - 32));
195 		mv_ic_set_mask_hi(mr);
196 
197 	} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
198 		mr = mv_ic_get_mask_error();
199 		mr &= ~(1 << (nb - 64));
200 		mv_ic_set_mask_error(mr);
201 	}
202 }
203 
204 void
205 arm_unmask_irq(uintptr_t nb)
206 {
207 	uint32_t	mr;
208 
209 	if (nb < 32) {
210 		mr = mv_ic_get_mask();
211 		mr |= (1 << nb);
212 		mv_ic_set_mask(mr);
213 
214 	} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
215 		mr = mv_ic_get_mask_hi();
216 		mr |= (1 << (nb - 32));
217 		mv_ic_set_mask_hi(mr);
218 
219 	} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
220 		mr = mv_ic_get_mask_error();
221 		mr |= (1 << (nb - 64));
222 		mv_ic_set_mask_error(mr);
223 	}
224 }
225 
226 void
227 mv_ic_set_mask(uint32_t val)
228 {
229 
230 	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
231 	    IRQ_MASK, val);
232 }
233 
234 uint32_t
235 mv_ic_get_mask(void)
236 {
237 
238 	return (bus_space_read_4(mv_ic_sc->ic_bst,
239 	    mv_ic_sc->ic_bsh, IRQ_MASK));
240 }
241 
242 uint32_t
243 mv_ic_get_cause(void)
244 {
245 
246 	return (bus_space_read_4(mv_ic_sc->ic_bst,
247 	    mv_ic_sc->ic_bsh, IRQ_CAUSE));
248 }
249 
250 void
251 mv_ic_set_mask_hi(uint32_t val)
252 {
253 
254 	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
255 	    IRQ_MASK_HI, val);
256 }
257 
258 uint32_t
259 mv_ic_get_mask_hi(void)
260 {
261 
262 	return (bus_space_read_4(mv_ic_sc->ic_bst,
263 	    mv_ic_sc->ic_bsh, IRQ_MASK_HI));
264 }
265 
266 uint32_t
267 mv_ic_get_cause_hi(void)
268 {
269 
270 	return (bus_space_read_4(mv_ic_sc->ic_bst,
271 	    mv_ic_sc->ic_bsh, IRQ_CAUSE_HI));
272 }
273 
274 void
275 mv_ic_set_mask_error(uint32_t val)
276 {
277 
278 	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
279 	    IRQ_MASK_ERROR, val);
280 }
281 
282 uint32_t
283 mv_ic_get_mask_error(void)
284 {
285 
286 	return (bus_space_read_4(mv_ic_sc->ic_bst,
287 	    mv_ic_sc->ic_bsh, IRQ_MASK_ERROR));
288 }
289 
290 uint32_t
291 mv_ic_get_cause_error(void)
292 {
293 
294 	return (bus_space_read_4(mv_ic_sc->ic_bst,
295 	    mv_ic_sc->ic_bsh, IRQ_CAUSE_ERROR));
296 }
297