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