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