aintc.c revision 266152
1239281Sgonzo/*-
2239281Sgonzo * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
3239281Sgonzo * All rights reserved.
4239281Sgonzo *
5239281Sgonzo * Based on OMAP3 INTC code by Ben Gray
6239281Sgonzo *
7239281Sgonzo * Redistribution and use in source and binary forms, with or without
8239281Sgonzo * modification, are permitted provided that the following conditions
9239281Sgonzo * are met:
10239281Sgonzo * 1. Redistributions of source code must retain the above copyright
11239281Sgonzo *    notice, this list of conditions and the following disclaimer.
12239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
13239281Sgonzo *    notice, this list of conditions and the following disclaimer in the
14239281Sgonzo *    documentation and/or other materials provided with the distribution.
15239281Sgonzo *
16239281Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17239281Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18239281Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19239281Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20239281Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21239281Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22239281Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23239281Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24239281Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25239281Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26239281Sgonzo * SUCH DAMAGE.
27239281Sgonzo */
28239281Sgonzo
29239281Sgonzo
30239281Sgonzo#include <sys/cdefs.h>
31239281Sgonzo__FBSDID("$FreeBSD: stable/10/sys/arm/ti/aintc.c 266152 2014-05-15 16:11:06Z ian $");
32239281Sgonzo
33239281Sgonzo#include <sys/param.h>
34239281Sgonzo#include <sys/systm.h>
35239281Sgonzo#include <sys/bus.h>
36239281Sgonzo#include <sys/kernel.h>
37239281Sgonzo#include <sys/ktr.h>
38239281Sgonzo#include <sys/module.h>
39239281Sgonzo#include <sys/rman.h>
40239281Sgonzo#include <machine/bus.h>
41239281Sgonzo#include <machine/intr.h>
42239281Sgonzo
43239281Sgonzo#include <dev/fdt/fdt_common.h>
44239281Sgonzo#include <dev/ofw/openfirm.h>
45239281Sgonzo#include <dev/ofw/ofw_bus.h>
46239281Sgonzo#include <dev/ofw/ofw_bus_subr.h>
47239281Sgonzo
48239281Sgonzo#define INTC_REVISION		0x00
49239281Sgonzo#define INTC_SYSCONFIG		0x10
50239281Sgonzo#define INTC_SYSSTATUS		0x14
51239281Sgonzo#define INTC_SIR_IRQ		0x40
52239281Sgonzo#define INTC_CONTROL		0x48
53239281Sgonzo#define INTC_THRESHOLD		0x68
54239281Sgonzo#define INTC_MIR_CLEAR(x)	(0x88 + ((x) * 0x20))
55239281Sgonzo#define INTC_MIR_SET(x)		(0x8C + ((x) * 0x20))
56239281Sgonzo#define INTC_ISR_SET(x)		(0x90 + ((x) * 0x20))
57239281Sgonzo#define INTC_ISR_CLEAR(x)	(0x94 + ((x) * 0x20))
58239281Sgonzo
59239281Sgonzostruct ti_aintc_softc {
60239281Sgonzo	device_t		sc_dev;
61239281Sgonzo	struct resource *	aintc_res[3];
62239281Sgonzo	bus_space_tag_t		aintc_bst;
63239281Sgonzo	bus_space_handle_t	aintc_bsh;
64239281Sgonzo	uint8_t			ver;
65239281Sgonzo};
66239281Sgonzo
67239281Sgonzostatic struct resource_spec ti_aintc_spec[] = {
68239281Sgonzo	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
69239281Sgonzo	{ -1, 0 }
70239281Sgonzo};
71239281Sgonzo
72239281Sgonzo
73239281Sgonzostatic struct ti_aintc_softc *ti_aintc_sc = NULL;
74239281Sgonzo
75239281Sgonzo#define	aintc_read_4(reg)		\
76239281Sgonzo    bus_space_read_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg)
77239281Sgonzo#define	aintc_write_4(reg, val)		\
78239281Sgonzo    bus_space_write_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg, val)
79239281Sgonzo
80239281Sgonzo
81239281Sgonzostatic int
82239281Sgonzoti_aintc_probe(device_t dev)
83239281Sgonzo{
84266152Sian	if (!ofw_bus_status_okay(dev))
85266152Sian		return (ENXIO);
86266152Sian
87266152Sian
88239281Sgonzo	if (!ofw_bus_is_compatible(dev, "ti,aintc"))
89239281Sgonzo		return (ENXIO);
90239281Sgonzo	device_set_desc(dev, "TI AINTC Interrupt Controller");
91239281Sgonzo	return (BUS_PROBE_DEFAULT);
92239281Sgonzo}
93239281Sgonzo
94239281Sgonzostatic int
95239281Sgonzoti_aintc_attach(device_t dev)
96239281Sgonzo{
97239281Sgonzo	struct		ti_aintc_softc *sc = device_get_softc(dev);
98239281Sgonzo	uint32_t x;
99239281Sgonzo
100239281Sgonzo	sc->sc_dev = dev;
101239281Sgonzo
102239281Sgonzo	if (ti_aintc_sc)
103239281Sgonzo		return (ENXIO);
104239281Sgonzo
105239281Sgonzo	if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) {
106239281Sgonzo		device_printf(dev, "could not allocate resources\n");
107239281Sgonzo		return (ENXIO);
108239281Sgonzo	}
109239281Sgonzo
110239281Sgonzo	sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]);
111239281Sgonzo	sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]);
112239281Sgonzo
113239281Sgonzo	ti_aintc_sc = sc;
114239281Sgonzo
115239281Sgonzo	x = aintc_read_4(INTC_REVISION);
116239281Sgonzo	device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF);
117239281Sgonzo
118239281Sgonzo	/* SoftReset */
119239281Sgonzo	aintc_write_4(INTC_SYSCONFIG, 2);
120239281Sgonzo
121239281Sgonzo	/* Wait for reset to complete */
122239281Sgonzo	while(!(aintc_read_4(INTC_SYSSTATUS) & 1));
123239281Sgonzo
124239281Sgonzo	/*Set Priority Threshold */
125239281Sgonzo	aintc_write_4(INTC_THRESHOLD, 0xFF);
126239281Sgonzo
127239281Sgonzo	return (0);
128239281Sgonzo}
129239281Sgonzo
130239281Sgonzostatic device_method_t ti_aintc_methods[] = {
131239281Sgonzo	DEVMETHOD(device_probe,		ti_aintc_probe),
132239281Sgonzo	DEVMETHOD(device_attach,	ti_aintc_attach),
133239281Sgonzo	{ 0, 0 }
134239281Sgonzo};
135239281Sgonzo
136239281Sgonzostatic driver_t ti_aintc_driver = {
137239281Sgonzo	"aintc",
138239281Sgonzo	ti_aintc_methods,
139239281Sgonzo	sizeof(struct ti_aintc_softc),
140239281Sgonzo};
141239281Sgonzo
142239281Sgonzostatic devclass_t ti_aintc_devclass;
143239281Sgonzo
144239281SgonzoDRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass, 0, 0);
145239281Sgonzo
146239281Sgonzoint
147239281Sgonzoarm_get_next_irq(int last_irq)
148239281Sgonzo{
149239281Sgonzo	uint32_t active_irq;
150239281Sgonzo
151239281Sgonzo	if (last_irq != -1) {
152239281Sgonzo		aintc_write_4(INTC_ISR_CLEAR(last_irq >> 5),
153239281Sgonzo			1UL << (last_irq & 0x1F));
154239281Sgonzo		aintc_write_4(INTC_CONTROL,1);
155239281Sgonzo	}
156239281Sgonzo
157239281Sgonzo	/* Get the next active interrupt */
158239281Sgonzo	active_irq = aintc_read_4(INTC_SIR_IRQ);
159239281Sgonzo
160239281Sgonzo	/* Check for spurious interrupt */
161239281Sgonzo	if ((active_irq & 0xffffff80)) {
162239281Sgonzo		device_printf(ti_aintc_sc->sc_dev,
163239281Sgonzo			"Spurious interrupt detected (0x%08x)\n", active_irq);
164249181Sgonzo		aintc_write_4(INTC_SIR_IRQ, 0);
165239281Sgonzo		return -1;
166239281Sgonzo	}
167239281Sgonzo
168239281Sgonzo	if (active_irq != last_irq)
169239281Sgonzo		return active_irq;
170239281Sgonzo	else
171239281Sgonzo		return -1;
172239281Sgonzo}
173239281Sgonzo
174239281Sgonzovoid
175239281Sgonzoarm_mask_irq(uintptr_t nb)
176239281Sgonzo{
177239281Sgonzo	aintc_write_4(INTC_MIR_SET(nb >> 5), (1UL << (nb & 0x1F)));
178239281Sgonzo}
179239281Sgonzo
180239281Sgonzovoid
181239281Sgonzoarm_unmask_irq(uintptr_t nb)
182239281Sgonzo{
183239281Sgonzo	aintc_write_4(INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F)));
184239281Sgonzo}
185