Index: head/sys/arm/conf/BEAGLEBONE =================================================================== --- head/sys/arm/conf/BEAGLEBONE +++ head/sys/arm/conf/BEAGLEBONE @@ -28,6 +28,8 @@ makeoptions MODULES_EXTRA="dtb/am335x am335x_dmtpps" +options ARM_INTRNG + options HZ=100 options SCHED_4BSD # 4BSD scheduler options PLATFORM Index: head/sys/arm/ti/aintc.c =================================================================== --- head/sys/arm/ti/aintc.c +++ head/sys/arm/ti/aintc.c @@ -30,12 +30,15 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include #include #include #include #include #include +#include #include #include #include @@ -45,6 +48,10 @@ #include #include +#ifdef ARM_INTRNG +#include "pic_if.h" +#endif + #define INTC_REVISION 0x00 #define INTC_SYSCONFIG 0x10 #define INTC_SYSSTATUS 0x14 @@ -56,12 +63,27 @@ #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 @@ {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 @@ 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 @@ /*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 @@ 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_irq_memory_barrier(nb); aintc_write_4(sc, INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F))); } +#endif