aintc.c revision 266152
1/*-
2 * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
3 * All rights reserved.
4 *
5 * Based on OMAP3 INTC code by Ben Gray
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/10/sys/arm/ti/aintc.c 266152 2014-05-15 16:11:06Z ian $");
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/bus.h>
36#include <sys/kernel.h>
37#include <sys/ktr.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/fdt/fdt_common.h>
44#include <dev/ofw/openfirm.h>
45#include <dev/ofw/ofw_bus.h>
46#include <dev/ofw/ofw_bus_subr.h>
47
48#define INTC_REVISION		0x00
49#define INTC_SYSCONFIG		0x10
50#define INTC_SYSSTATUS		0x14
51#define INTC_SIR_IRQ		0x40
52#define INTC_CONTROL		0x48
53#define INTC_THRESHOLD		0x68
54#define INTC_MIR_CLEAR(x)	(0x88 + ((x) * 0x20))
55#define INTC_MIR_SET(x)		(0x8C + ((x) * 0x20))
56#define INTC_ISR_SET(x)		(0x90 + ((x) * 0x20))
57#define INTC_ISR_CLEAR(x)	(0x94 + ((x) * 0x20))
58
59struct ti_aintc_softc {
60	device_t		sc_dev;
61	struct resource *	aintc_res[3];
62	bus_space_tag_t		aintc_bst;
63	bus_space_handle_t	aintc_bsh;
64	uint8_t			ver;
65};
66
67static struct resource_spec ti_aintc_spec[] = {
68	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
69	{ -1, 0 }
70};
71
72
73static struct ti_aintc_softc *ti_aintc_sc = NULL;
74
75#define	aintc_read_4(reg)		\
76    bus_space_read_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg)
77#define	aintc_write_4(reg, val)		\
78    bus_space_write_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg, val)
79
80
81static int
82ti_aintc_probe(device_t dev)
83{
84	if (!ofw_bus_status_okay(dev))
85		return (ENXIO);
86
87
88	if (!ofw_bus_is_compatible(dev, "ti,aintc"))
89		return (ENXIO);
90	device_set_desc(dev, "TI AINTC Interrupt Controller");
91	return (BUS_PROBE_DEFAULT);
92}
93
94static int
95ti_aintc_attach(device_t dev)
96{
97	struct		ti_aintc_softc *sc = device_get_softc(dev);
98	uint32_t x;
99
100	sc->sc_dev = dev;
101
102	if (ti_aintc_sc)
103		return (ENXIO);
104
105	if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) {
106		device_printf(dev, "could not allocate resources\n");
107		return (ENXIO);
108	}
109
110	sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]);
111	sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]);
112
113	ti_aintc_sc = sc;
114
115	x = aintc_read_4(INTC_REVISION);
116	device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF);
117
118	/* SoftReset */
119	aintc_write_4(INTC_SYSCONFIG, 2);
120
121	/* Wait for reset to complete */
122	while(!(aintc_read_4(INTC_SYSSTATUS) & 1));
123
124	/*Set Priority Threshold */
125	aintc_write_4(INTC_THRESHOLD, 0xFF);
126
127	return (0);
128}
129
130static device_method_t ti_aintc_methods[] = {
131	DEVMETHOD(device_probe,		ti_aintc_probe),
132	DEVMETHOD(device_attach,	ti_aintc_attach),
133	{ 0, 0 }
134};
135
136static driver_t ti_aintc_driver = {
137	"aintc",
138	ti_aintc_methods,
139	sizeof(struct ti_aintc_softc),
140};
141
142static devclass_t ti_aintc_devclass;
143
144DRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass, 0, 0);
145
146int
147arm_get_next_irq(int last_irq)
148{
149	uint32_t active_irq;
150
151	if (last_irq != -1) {
152		aintc_write_4(INTC_ISR_CLEAR(last_irq >> 5),
153			1UL << (last_irq & 0x1F));
154		aintc_write_4(INTC_CONTROL,1);
155	}
156
157	/* Get the next active interrupt */
158	active_irq = aintc_read_4(INTC_SIR_IRQ);
159
160	/* Check for spurious interrupt */
161	if ((active_irq & 0xffffff80)) {
162		device_printf(ti_aintc_sc->sc_dev,
163			"Spurious interrupt detected (0x%08x)\n", active_irq);
164		aintc_write_4(INTC_SIR_IRQ, 0);
165		return -1;
166	}
167
168	if (active_irq != last_irq)
169		return active_irq;
170	else
171		return -1;
172}
173
174void
175arm_mask_irq(uintptr_t nb)
176{
177	aintc_write_4(INTC_MIR_SET(nb >> 5), (1UL << (nb & 0x1F)));
178}
179
180void
181arm_unmask_irq(uintptr_t nb)
182{
183	aintc_write_4(INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F)));
184}
185