ic.c revision 209131
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 209131 2010-06-13 13:28:53Z raj $");
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
49struct 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
57static struct resource_spec mv_ic_spec[] = {
58	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
59	{ -1, 0 }
60};
61
62static struct mv_ic_softc *mv_ic_sc = NULL;
63
64static int	mv_ic_probe(device_t);
65static int	mv_ic_attach(device_t);
66
67uint32_t	mv_ic_get_cause(void);
68uint32_t	mv_ic_get_mask(void);
69void		mv_ic_set_mask(uint32_t);
70uint32_t	mv_ic_get_cause_hi(void);
71uint32_t	mv_ic_get_mask_hi(void);
72void		mv_ic_set_mask_hi(uint32_t);
73uint32_t	mv_ic_get_cause_error(void);
74uint32_t	mv_ic_get_mask_error(void);
75void		mv_ic_set_mask_error(uint32_t);
76static void	arm_mask_irq_all(void);
77
78static int
79mv_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
89static int
90mv_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
129static 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
135static driver_t mv_ic_driver = {
136	"ic",
137	mv_ic_methods,
138	sizeof(struct mv_ic_softc),
139};
140
141static devclass_t mv_ic_devclass;
142
143DRIVER_MODULE(ic, simplebus, mv_ic_driver, mv_ic_devclass, 0, 0);
144
145int
146arm_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
169static void
170arm_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
182void
183arm_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
204void
205arm_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
226void
227mv_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
234uint32_t
235mv_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
242uint32_t
243mv_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
250void
251mv_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
258uint32_t
259mv_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
266uint32_t
267mv_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
274void
275mv_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
282uint32_t
283mv_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
290uint32_t
291mv_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