ic.c revision 238873
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: head/sys/arm/mv/ic.c 238873 2012-07-28 21:56:24Z hrs $");
33
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
50struct 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
58static struct resource_spec mv_ic_spec[] = {
59	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
60	{ -1, 0 }
61};
62
63static struct mv_ic_softc *mv_ic_sc = NULL;
64
65static int	mv_ic_probe(device_t);
66static int	mv_ic_attach(device_t);
67
68uint32_t	mv_ic_get_cause(void);
69uint32_t	mv_ic_get_mask(void);
70void		mv_ic_set_mask(uint32_t);
71uint32_t	mv_ic_get_cause_hi(void);
72uint32_t	mv_ic_get_mask_hi(void);
73void		mv_ic_set_mask_hi(uint32_t);
74uint32_t	mv_ic_get_cause_error(void);
75uint32_t	mv_ic_get_mask_error(void);
76void		mv_ic_set_mask_error(uint32_t);
77static void	arm_mask_irq_all(void);
78
79static int
80mv_ic_probe(device_t dev)
81{
82
83	if (!ofw_bus_is_compatible(dev, "mrvl,pic"))
84		return (ENXIO);
85
86	device_set_desc(dev, "Marvell Integrated Interrupt Controller");
87	return (0);
88}
89
90static int
91mv_ic_attach(device_t dev)
92{
93	struct mv_ic_softc *sc;
94	uint32_t dev_id, rev_id;
95	int error;
96
97	sc = (struct mv_ic_softc *)device_get_softc(dev);
98
99	if (mv_ic_sc != NULL)
100		return (ENXIO);
101	mv_ic_sc = sc;
102
103	soc_id(&dev_id, &rev_id);
104
105	sc->ic_high_regs = 0;
106	sc->ic_error_regs = 0;
107
108	if (dev_id == MV_DEV_88F6281 ||
109	    dev_id == MV_DEV_88F6282 ||
110	    dev_id == MV_DEV_MV78100 ||
111	    dev_id == MV_DEV_MV78100_Z0)
112		sc->ic_high_regs = 1;
113
114	if (dev_id == MV_DEV_MV78100 || dev_id == MV_DEV_MV78100_Z0)
115		sc->ic_error_regs = 1;
116
117	error = bus_alloc_resources(dev, mv_ic_spec, sc->ic_res);
118	if (error) {
119		device_printf(dev, "could not allocate resources\n");
120		return (ENXIO);
121	}
122
123	sc->ic_bst = rman_get_bustag(sc->ic_res[0]);
124	sc->ic_bsh = rman_get_bushandle(sc->ic_res[0]);
125
126	/* Mask all interrupts */
127	arm_mask_irq_all();
128
129	return (0);
130}
131
132static device_method_t mv_ic_methods[] = {
133	DEVMETHOD(device_probe,		mv_ic_probe),
134	DEVMETHOD(device_attach,	mv_ic_attach),
135	{ 0, 0 }
136};
137
138static driver_t mv_ic_driver = {
139	"ic",
140	mv_ic_methods,
141	sizeof(struct mv_ic_softc),
142};
143
144static devclass_t mv_ic_devclass;
145
146DRIVER_MODULE(ic, simplebus, mv_ic_driver, mv_ic_devclass, 0, 0);
147
148int
149arm_get_next_irq(int last)
150{
151	u_int filt, irq;
152	int next;
153
154	filt = ~((last >= 0) ? (2 << last) - 1 : 0);
155	irq = mv_ic_get_cause() & mv_ic_get_mask();
156	if (irq & filt) {
157		next = ffs(irq & filt) - 1;
158		goto out;
159	}
160	if (mv_ic_sc->ic_high_regs) {
161		filt = ~((last >= 32) ? (2 << (last - 32)) - 1 : 0);
162		irq = mv_ic_get_cause_hi() & mv_ic_get_mask_hi();
163		if (irq & filt) {
164			next = ffs(irq & filt) + 31;
165			goto out;
166		}
167	}
168	if (mv_ic_sc->ic_error_regs) {
169		filt = ~((last >= 64) ? (2 << (last - 64)) - 1 : 0);
170		irq = mv_ic_get_cause_error() & mv_ic_get_mask_error();
171		if (irq & filt) {
172			next = ffs(irq & filt) + 63;
173			goto out;
174		}
175	}
176	next = -1;
177
178 out:
179	CTR3(KTR_INTR, "%s: last=%d, next=%d", __func__, last, next);
180	return (next);
181}
182
183static void
184arm_mask_irq_all(void)
185{
186
187	mv_ic_set_mask(0);
188
189	if (mv_ic_sc->ic_high_regs)
190		mv_ic_set_mask_hi(0);
191
192	if (mv_ic_sc->ic_error_regs)
193		mv_ic_set_mask_error(0);
194}
195
196void
197arm_mask_irq(uintptr_t nb)
198{
199	uint32_t	mr;
200
201	if (nb < 32) {
202		mr = mv_ic_get_mask();
203		mr &= ~(1 << nb);
204		mv_ic_set_mask(mr);
205
206	} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
207		mr = mv_ic_get_mask_hi();
208		mr &= ~(1 << (nb - 32));
209		mv_ic_set_mask_hi(mr);
210
211	} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
212		mr = mv_ic_get_mask_error();
213		mr &= ~(1 << (nb - 64));
214		mv_ic_set_mask_error(mr);
215	}
216}
217
218void
219arm_unmask_irq(uintptr_t nb)
220{
221	uint32_t	mr;
222
223	if (nb < 32) {
224		mr = mv_ic_get_mask();
225		mr |= (1 << nb);
226		mv_ic_set_mask(mr);
227
228	} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
229		mr = mv_ic_get_mask_hi();
230		mr |= (1 << (nb - 32));
231		mv_ic_set_mask_hi(mr);
232
233	} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
234		mr = mv_ic_get_mask_error();
235		mr |= (1 << (nb - 64));
236		mv_ic_set_mask_error(mr);
237	}
238}
239
240void
241mv_ic_set_mask(uint32_t val)
242{
243
244	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
245	    IRQ_MASK, val);
246}
247
248uint32_t
249mv_ic_get_mask(void)
250{
251
252	return (bus_space_read_4(mv_ic_sc->ic_bst,
253	    mv_ic_sc->ic_bsh, IRQ_MASK));
254}
255
256uint32_t
257mv_ic_get_cause(void)
258{
259
260	return (bus_space_read_4(mv_ic_sc->ic_bst,
261	    mv_ic_sc->ic_bsh, IRQ_CAUSE));
262}
263
264void
265mv_ic_set_mask_hi(uint32_t val)
266{
267
268	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
269	    IRQ_MASK_HI, val);
270}
271
272uint32_t
273mv_ic_get_mask_hi(void)
274{
275
276	return (bus_space_read_4(mv_ic_sc->ic_bst,
277	    mv_ic_sc->ic_bsh, IRQ_MASK_HI));
278}
279
280uint32_t
281mv_ic_get_cause_hi(void)
282{
283
284	return (bus_space_read_4(mv_ic_sc->ic_bst,
285	    mv_ic_sc->ic_bsh, IRQ_CAUSE_HI));
286}
287
288void
289mv_ic_set_mask_error(uint32_t val)
290{
291
292	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
293	    IRQ_MASK_ERROR, val);
294}
295
296uint32_t
297mv_ic_get_mask_error(void)
298{
299
300	return (bus_space_read_4(mv_ic_sc->ic_bst,
301	    mv_ic_sc->ic_bsh, IRQ_MASK_ERROR));
302}
303
304uint32_t
305mv_ic_get_cause_error(void)
306{
307
308	return (bus_space_read_4(mv_ic_sc->ic_bst,
309	    mv_ic_sc->ic_bsh, IRQ_CAUSE_ERROR));
310}
311