summaryrefslogtreecommitdiffstats
path: root/sys/arm/ti/aintc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arm/ti/aintc.c')
-rw-r--r--sys/arm/ti/aintc.c178
1 files changed, 177 insertions, 1 deletions
diff --git a/sys/arm/ti/aintc.c b/sys/arm/ti/aintc.c
index 19f4544..9a0a313 100644
--- a/sys/arm/ti/aintc.c
+++ b/sys/arm/ti/aintc.c
@@ -30,12 +30,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/module.h>
+#include <sys/proc.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -45,6 +48,10 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#ifdef ARM_INTRNG
+#include "pic_if.h"
+#endif
+
#define INTC_REVISION 0x00
#define INTC_SYSCONFIG 0x10
#define INTC_SYSSTATUS 0x14
@@ -56,12 +63,27 @@ __FBSDID("$FreeBSD$");
#define INTC_ISR_SET(x) (0x90 + ((x) * 0x20))
#define INTC_ISR_CLEAR(x) (0x94 + ((x) * 0x20))
+#define INTC_SIR_SPURIOUS_MASK 0xffffff80
+#define INTS_SIR_ACTIVE_MASK 0x7f
+
+#define INTC_NIRQS 128
+
+#ifdef ARM_INTRNG
+struct ti_aintc_irqsrc {
+ struct intr_irqsrc tai_isrc;
+ u_int tai_irq;
+};
+#endif
+
struct ti_aintc_softc {
device_t sc_dev;
struct resource * aintc_res[3];
bus_space_tag_t aintc_bst;
bus_space_handle_t aintc_bsh;
uint8_t ver;
+#ifdef ARM_INTRNG
+ struct ti_aintc_irqsrc aintc_isrcs[INTC_NIRQS];
+#endif
};
static struct resource_spec ti_aintc_spec[] = {
@@ -83,6 +105,141 @@ static struct ofw_compat_data compat_data[] = {
{NULL, 0},
};
+#ifdef ARM_INTRNG
+static inline void
+ti_aintc_irq_eoi(struct ti_aintc_softc *sc)
+{
+
+ aintc_write_4(sc, INTC_CONTROL, 1);
+}
+
+static inline void
+ti_aintc_irq_mask(struct ti_aintc_softc *sc, u_int irq)
+{
+
+ aintc_write_4(sc, INTC_MIR_SET(irq >> 5), (1UL << (irq & 0x1F)));
+}
+
+static inline void
+ti_aintc_irq_unmask(struct ti_aintc_softc *sc, u_int irq)
+{
+
+ aintc_write_4(sc, INTC_MIR_CLEAR(irq >> 5), (1UL << (irq & 0x1F)));
+}
+
+static int
+ti_aintc_intr(void *arg)
+{
+ uint32_t irq;
+ struct ti_aintc_softc *sc = arg;
+
+ /* Get active interrupt */
+ irq = aintc_read_4(sc, INTC_SIR_IRQ);
+ if ((irq & INTC_SIR_SPURIOUS_MASK) != 0) {
+ device_printf(sc->sc_dev,
+ "Spurious interrupt detected (0x%08x)\n", irq);
+ ti_aintc_irq_eoi(sc);
+ return (FILTER_HANDLED);
+ }
+
+ /* Only level-sensitive interrupts detection is supported. */
+ irq &= INTS_SIR_ACTIVE_MASK;
+ if (intr_isrc_dispatch(&sc->aintc_isrcs[irq].tai_isrc,
+ curthread->td_intr_frame) != 0) {
+ ti_aintc_irq_mask(sc, irq);
+ ti_aintc_irq_eoi(sc);
+ device_printf(sc->sc_dev, "Stray irq %u disabled\n", irq);
+ }
+
+ arm_irq_memory_barrier(irq); /* XXX */
+ return (FILTER_HANDLED);
+}
+
+static void
+ti_aintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
+ struct ti_aintc_softc *sc = device_get_softc(dev);
+
+ arm_irq_memory_barrier(irq);
+ ti_aintc_irq_unmask(sc, irq);
+}
+
+static void
+ti_aintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
+ struct ti_aintc_softc *sc = device_get_softc(dev);
+
+ ti_aintc_irq_mask(sc, irq);
+}
+
+static int
+ti_aintc_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct ti_aintc_softc *sc;
+
+ if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells != 1 ||
+ data->fdt.cells[0] >= INTC_NIRQS)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ *isrcp = &sc->aintc_isrcs[data->fdt.cells[0]].tai_isrc;
+ return (0);
+}
+
+static void
+ti_aintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
+ struct ti_aintc_softc *sc = device_get_softc(dev);
+
+ ti_aintc_irq_mask(sc, irq);
+ ti_aintc_irq_eoi(sc);
+}
+
+static void
+ti_aintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ ti_aintc_enable_intr(dev, isrc);
+}
+
+static void
+ti_aintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ ti_aintc_irq_eoi(device_get_softc(dev));
+}
+
+static int
+ti_aintc_pic_attach(struct ti_aintc_softc *sc)
+{
+ int error;
+ uint32_t irq;
+ const char *name;
+ intptr_t xref;
+
+ name = device_get_nameunit(sc->sc_dev);
+ for (irq = 0; irq < INTC_NIRQS; irq++) {
+ sc->aintc_isrcs[irq].tai_irq = irq;
+
+ error = intr_isrc_register(&sc->aintc_isrcs[irq].tai_isrc,
+ sc->sc_dev, 0, "%s,%u", name, irq);
+ if (error != 0)
+ return (error);
+ }
+
+ xref = OF_xref_from_node(ofw_bus_get_node(sc->sc_dev));
+ error = intr_pic_register(sc->sc_dev, xref);
+ if (error != 0)
+ return (error);
+
+ return (intr_pic_claim_root(sc->sc_dev, xref, ti_aintc_intr, sc, 0));
+}
+
+#else
static void
aintc_post_filter(void *arg)
{
@@ -90,6 +247,7 @@ aintc_post_filter(void *arg)
arm_irq_memory_barrier(0);
aintc_write_4(ti_aintc_sc, INTC_CONTROL, 1); /* EOI */
}
+#endif
static int
ti_aintc_probe(device_t dev)
@@ -137,14 +295,30 @@ ti_aintc_attach(device_t dev)
/*Set Priority Threshold */
aintc_write_4(sc, INTC_THRESHOLD, 0xFF);
+#ifndef ARM_INTRNG
arm_post_filter = aintc_post_filter;
-
+#else
+ if (ti_aintc_pic_attach(sc) != 0) {
+ device_printf(dev, "could not attach PIC\n");
+ return (ENXIO);
+ }
+#endif
return (0);
}
static device_method_t ti_aintc_methods[] = {
DEVMETHOD(device_probe, ti_aintc_probe),
DEVMETHOD(device_attach, ti_aintc_attach),
+
+#ifdef ARM_INTRNG
+ DEVMETHOD(pic_disable_intr, ti_aintc_disable_intr),
+ DEVMETHOD(pic_enable_intr, ti_aintc_enable_intr),
+ DEVMETHOD(pic_map_intr, ti_aintc_map_intr),
+ DEVMETHOD(pic_post_filter, ti_aintc_post_filter),
+ DEVMETHOD(pic_post_ithread, ti_aintc_post_ithread),
+ DEVMETHOD(pic_pre_ithread, ti_aintc_pre_ithread),
+#endif
+
{ 0, 0 }
};
@@ -160,6 +334,7 @@ EARLY_DRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass,
0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
SIMPLEBUS_PNP_INFO(compat_data);
+#ifndef ARM_INTRNG
int
arm_get_next_irq(int last_irq)
{
@@ -200,3 +375,4 @@ arm_unmask_irq(uintptr_t nb)
arm_irq_memory_barrier(nb);
aintc_write_4(sc, INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F)));
}
+#endif
OpenPOWER on IntegriCloud