Index: head/sys/arm/broadcom/bcm2835/bcm2835_intr.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_intr.c (revision 297579) +++ head/sys/arm/broadcom/bcm2835/bcm2835_intr.c (revision 297580) @@ -1,249 +1,537 @@ /*- * Copyright (c) 2012 Damjan Marion * All rights reserved. * * Based on OMAP3 INTC code by Ben Gray * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #ifdef SOC_BCM2836 #include #endif +#ifdef ARM_INTRNG +#include "pic_if.h" +#endif + #define INTC_PENDING_BASIC 0x00 #define INTC_PENDING_BANK1 0x04 #define INTC_PENDING_BANK2 0x08 #define INTC_FIQ_CONTROL 0x0C #define INTC_ENABLE_BANK1 0x10 #define INTC_ENABLE_BANK2 0x14 #define INTC_ENABLE_BASIC 0x18 #define INTC_DISABLE_BANK1 0x1C #define INTC_DISABLE_BANK2 0x20 #define INTC_DISABLE_BASIC 0x24 +#define INTC_PENDING_BASIC_ARM 0x0000FF +#define INTC_PENDING_BASIC_GPU1_PEND 0x000100 +#define INTC_PENDING_BASIC_GPU2_PEND 0x000200 +#define INTC_PENDING_BASIC_GPU1_7 0x000400 +#define INTC_PENDING_BASIC_GPU1_9 0x000800 +#define INTC_PENDING_BASIC_GPU1_10 0x001000 +#define INTC_PENDING_BASIC_GPU1_18 0x002000 +#define INTC_PENDING_BASIC_GPU1_19 0x004000 +#define INTC_PENDING_BASIC_GPU2_21 0x008000 +#define INTC_PENDING_BASIC_GPU2_22 0x010000 +#define INTC_PENDING_BASIC_GPU2_23 0x020000 +#define INTC_PENDING_BASIC_GPU2_24 0x040000 +#define INTC_PENDING_BASIC_GPU2_25 0x080000 +#define INTC_PENDING_BASIC_GPU2_30 0x100000 +#define INTC_PENDING_BASIC_MASK 0x1FFFFF + +#define INTC_PENDING_BASIC_GPU1_MASK (INTC_PENDING_BASIC_GPU1_7 | \ + INTC_PENDING_BASIC_GPU1_9 | \ + INTC_PENDING_BASIC_GPU1_10 | \ + INTC_PENDING_BASIC_GPU1_18 | \ + INTC_PENDING_BASIC_GPU1_19) + +#define INTC_PENDING_BASIC_GPU2_MASK (INTC_PENDING_BASIC_GPU2_21 | \ + INTC_PENDING_BASIC_GPU2_22 | \ + INTC_PENDING_BASIC_GPU2_23 | \ + INTC_PENDING_BASIC_GPU2_24 | \ + INTC_PENDING_BASIC_GPU2_25 | \ + INTC_PENDING_BASIC_GPU2_30) + +#define INTC_PENDING_BANK1_MASK (~((1 << 7) | (1 << 9) | (1 << 10) | \ + (1 << 18) | (1 << 19))) +#define INTC_PENDING_BANK2_MASK (~((1 << 21) | (1 << 22) | (1 << 23) | \ + (1 << 24) | (1 << 25) | (1 << 30))) + #define BANK1_START 8 #define BANK1_END (BANK1_START + 32 - 1) #define BANK2_START (BANK1_START + 32) #define BANK2_END (BANK2_START + 32 - 1) +#ifndef ARM_INTRNG #define BANK3_START (BANK2_START + 32) #define BANK3_END (BANK3_START + 32 - 1) +#endif #define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START)) #define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END)) #define IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END)) +#ifndef ARM_INTRNG #define ID_IRQ_BCM2836(n) (((n) >= BANK3_START) && ((n) <= BANK3_END)) +#endif #define IRQ_BANK1(n) ((n) - BANK1_START) #define IRQ_BANK2(n) ((n) - BANK2_START) #ifdef DEBUG #define dprintf(fmt, args...) printf(fmt, ##args) #else #define dprintf(fmt, args...) #endif +#ifdef ARM_INTRNG +#define BCM_INTC_NIRQS 72 /* 8 + 32 + 32 */ + +struct bcm_intc_irqsrc { + struct intr_irqsrc bii_isrc; + u_int bii_irq; + uint16_t bii_disable_reg; + uint16_t bii_enable_reg; + uint32_t bii_mask; +}; +#endif + struct bcm_intc_softc { device_t sc_dev; struct resource * intc_res; bus_space_tag_t intc_bst; bus_space_handle_t intc_bsh; +#ifdef ARM_INTRNG + struct resource * intc_irq_res; + void * intc_irq_hdl; + struct bcm_intc_irqsrc intc_isrcs[BCM_INTC_NIRQS]; +#endif }; static struct bcm_intc_softc *bcm_intc_sc = NULL; #define intc_read_4(_sc, reg) \ bus_space_read_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg)) #define intc_write_4(_sc, reg, val) \ bus_space_write_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg), (val)) +#ifdef ARM_INTRNG +static inline void +bcm_intc_isrc_mask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) +{ + + intc_write_4(sc, bii->bii_disable_reg, bii->bii_mask); +} + +static inline void +bcm_intc_isrc_unmask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) +{ + + intc_write_4(sc, bii->bii_enable_reg, bii->bii_mask); +} + +static inline int +bcm2835_intc_active_intr(struct bcm_intc_softc *sc) +{ + uint32_t pending, pending_gpu; + + pending = intc_read_4(sc, INTC_PENDING_BASIC) & INTC_PENDING_BASIC_MASK; + if (pending == 0) + return (-1); + if (pending & INTC_PENDING_BASIC_ARM) + return (ffs(pending) - 1); + if (pending & INTC_PENDING_BASIC_GPU1_MASK) { + if (pending & INTC_PENDING_BASIC_GPU1_7) + return (BANK1_START + 7); + if (pending & INTC_PENDING_BASIC_GPU1_9) + return (BANK1_START + 9); + if (pending & INTC_PENDING_BASIC_GPU1_10) + return (BANK1_START + 10); + if (pending & INTC_PENDING_BASIC_GPU1_18) + return (BANK1_START + 18); + if (pending & INTC_PENDING_BASIC_GPU1_19) + return (BANK1_START + 19); + } + if (pending & INTC_PENDING_BASIC_GPU2_MASK) { + if (pending & INTC_PENDING_BASIC_GPU2_21) + return (BANK2_START + 21); + if (pending & INTC_PENDING_BASIC_GPU2_22) + return (BANK2_START + 22); + if (pending & INTC_PENDING_BASIC_GPU2_23) + return (BANK2_START + 23); + if (pending & INTC_PENDING_BASIC_GPU2_24) + return (BANK2_START + 24); + if (pending & INTC_PENDING_BASIC_GPU2_25) + return (BANK2_START + 25); + if (pending & INTC_PENDING_BASIC_GPU2_30) + return (BANK2_START + 30); + } + if (pending & INTC_PENDING_BASIC_GPU1_PEND) { + pending_gpu = intc_read_4(sc, INTC_PENDING_BANK1); + pending_gpu &= INTC_PENDING_BANK1_MASK; + if (pending_gpu != 0) + return (BANK1_START + ffs(pending_gpu) - 1); + } + if (pending & INTC_PENDING_BASIC_GPU2_PEND) { + pending_gpu = intc_read_4(sc, INTC_PENDING_BANK2); + pending_gpu &= INTC_PENDING_BANK2_MASK; + if (pending_gpu != 0) + return (BANK2_START + ffs(pending_gpu) - 1); + } + return (-1); /* It shouldn't end here, but it's hardware. */ +} + static int +bcm2835_intc_intr(void *arg) +{ + int irq, num; + struct bcm_intc_softc *sc = arg; + + for (num = 0; ; num++) { + irq = bcm2835_intc_active_intr(sc); + if (irq == -1) + break; + if (intr_isrc_dispatch(&sc->intc_isrcs[irq].bii_isrc, + curthread->td_intr_frame) != 0) { + bcm_intc_isrc_mask(sc, &sc->intc_isrcs[irq]); + device_printf(sc->sc_dev, "Stray irq %u disabled\n", + irq); + } + arm_irq_memory_barrier(0); /* XXX */ + } + if (num == 0) + device_printf(sc->sc_dev, "Spurious interrupt detected\n"); + + return (FILTER_HANDLED); +} + +static void +bcm_intc_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct bcm_intc_irqsrc *bii = (struct bcm_intc_irqsrc *)isrc; + + arm_irq_memory_barrier(bii->bii_irq); + bcm_intc_isrc_unmask(device_get_softc(dev), bii); +} + +static void +bcm_intc_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + + bcm_intc_isrc_mask(device_get_softc(dev), + (struct bcm_intc_irqsrc *)isrc); +} + +static int +bcm_intc_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ + u_int irq; + struct bcm_intc_softc *sc; + + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + if (data->fdt.ncells == 1) + irq = data->fdt.cells[0]; + else if (data->fdt.ncells == 2) + irq = data->fdt.cells[0] * 32 + data->fdt.cells[1]; + else + return (EINVAL); + + if (irq >= BCM_INTC_NIRQS) + return (EINVAL); + + sc = device_get_softc(dev); + *isrcp = &sc->intc_isrcs[irq].bii_isrc; + return (0); +} + +static void +bcm_intc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + bcm_intc_disable_intr(dev, isrc); +} + +static void +bcm_intc_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + bcm_intc_enable_intr(dev, isrc); +} + +static void +bcm_intc_post_filter(device_t dev, struct intr_irqsrc *isrc) +{ +} + +static int +bcm_intc_pic_register(struct bcm_intc_softc *sc, intptr_t xref) +{ + struct bcm_intc_irqsrc *bii; + int error; + uint32_t irq; + const char *name; + + name = device_get_nameunit(sc->sc_dev); + for (irq = 0; irq < BCM_INTC_NIRQS; irq++) { + bii = &sc->intc_isrcs[irq]; + bii->bii_irq = irq; + if (IS_IRQ_BASIC(irq)) { + bii->bii_disable_reg = INTC_DISABLE_BASIC; + bii->bii_enable_reg = INTC_ENABLE_BASIC; + bii->bii_mask = 1 << irq; + } else if (IS_IRQ_BANK1(irq)) { + bii->bii_disable_reg = INTC_DISABLE_BANK1; + bii->bii_enable_reg = INTC_ENABLE_BANK1; + bii->bii_mask = 1 << IRQ_BANK1(irq); + } else if (IS_IRQ_BANK2(irq)) { + bii->bii_disable_reg = INTC_DISABLE_BANK2; + bii->bii_enable_reg = INTC_ENABLE_BANK2; + bii->bii_mask = 1 << IRQ_BANK2(irq); + } else + return (ENXIO); + + error = intr_isrc_register(&bii->bii_isrc, sc->sc_dev, 0, + "%s,%u", name, irq); + if (error != 0) + return (error); + } + return (intr_pic_register(sc->sc_dev, xref)); +} +#endif + +static int bcm_intc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-armctrl-ic")) return (ENXIO); device_set_desc(dev, "BCM2835 Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static int bcm_intc_attach(device_t dev) { struct bcm_intc_softc *sc = device_get_softc(dev); int rid = 0; - +#ifdef ARM_INTRNG + intptr_t xref; +#endif sc->sc_dev = dev; if (bcm_intc_sc) return (ENXIO); sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->intc_res == NULL) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } +#ifdef ARM_INTRNG + xref = OF_xref_from_node(ofw_bus_get_node(dev)); + if (bcm_intc_pic_register(sc, xref) != 0) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->intc_res); + device_printf(dev, "could not register PIC\n"); + return (ENXIO); + } + + rid = 0; + sc->intc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (sc->intc_irq_res == NULL) { + if (intr_pic_claim_root(dev, xref, bcm2835_intc_intr, sc, 0) != 0) { + /* XXX clean up */ + device_printf(dev, "could not set PIC as a root\n"); + return (ENXIO); + } + } else { + if (bus_setup_intr(dev, sc->intc_irq_res, INTR_TYPE_CLK, + bcm2835_intc_intr, NULL, sc, &sc->intc_irq_hdl)) { + /* XXX clean up */ + device_printf(dev, "could not setup irq handler\n"); + return (ENXIO); + } + } +#endif sc->intc_bst = rman_get_bustag(sc->intc_res); sc->intc_bsh = rman_get_bushandle(sc->intc_res); bcm_intc_sc = sc; return (0); } static device_method_t bcm_intc_methods[] = { DEVMETHOD(device_probe, bcm_intc_probe), DEVMETHOD(device_attach, bcm_intc_attach), + +#ifdef ARM_INTRNG + DEVMETHOD(pic_disable_intr, bcm_intc_disable_intr), + DEVMETHOD(pic_enable_intr, bcm_intc_enable_intr), + DEVMETHOD(pic_map_intr, bcm_intc_map_intr), + DEVMETHOD(pic_post_filter, bcm_intc_post_filter), + DEVMETHOD(pic_post_ithread, bcm_intc_post_ithread), + DEVMETHOD(pic_pre_ithread, bcm_intc_pre_ithread), +#endif + { 0, 0 } }; static driver_t bcm_intc_driver = { "intc", bcm_intc_methods, sizeof(struct bcm_intc_softc), }; static devclass_t bcm_intc_devclass; DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 0, 0); +#ifndef ARM_INTRNG int arm_get_next_irq(int last_irq) { struct bcm_intc_softc *sc = bcm_intc_sc; uint32_t pending; int32_t irq = last_irq + 1; #ifdef SOC_BCM2836 int ret; #endif /* Sanity check */ if (irq < 0) irq = 0; #ifdef SOC_BCM2836 if ((ret = bcm2836_get_next_irq(irq)) < 0) return (-1); if (ret != BCM2836_GPU_IRQ) return (ret + BANK3_START); #endif /* TODO: should we mask last_irq? */ if (irq < BANK1_START) { pending = intc_read_4(sc, INTC_PENDING_BASIC); if ((pending & 0xFF) == 0) { irq = BANK1_START; /* skip to next bank */ } else do { if (pending & (1 << irq)) return irq; irq++; } while (irq < BANK1_START); } if (irq < BANK2_START) { pending = intc_read_4(sc, INTC_PENDING_BANK1); if (pending == 0) { irq = BANK2_START; /* skip to next bank */ } else do { if (pending & (1 << IRQ_BANK1(irq))) return irq; irq++; } while (irq < BANK2_START); } if (irq < BANK3_START) { pending = intc_read_4(sc, INTC_PENDING_BANK2); if (pending != 0) do { if (pending & (1 << IRQ_BANK2(irq))) return irq; irq++; } while (irq < BANK3_START); } return (-1); } void arm_mask_irq(uintptr_t nb) { struct bcm_intc_softc *sc = bcm_intc_sc; dprintf("%s: %d\n", __func__, nb); if (IS_IRQ_BASIC(nb)) intc_write_4(sc, INTC_DISABLE_BASIC, (1 << nb)); else if (IS_IRQ_BANK1(nb)) intc_write_4(sc, INTC_DISABLE_BANK1, (1 << IRQ_BANK1(nb))); else if (IS_IRQ_BANK2(nb)) intc_write_4(sc, INTC_DISABLE_BANK2, (1 << IRQ_BANK2(nb))); #ifdef SOC_BCM2836 else if (ID_IRQ_BCM2836(nb)) bcm2836_mask_irq(nb - BANK3_START); #endif else printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); } void arm_unmask_irq(uintptr_t nb) { struct bcm_intc_softc *sc = bcm_intc_sc; dprintf("%s: %d\n", __func__, nb); if (IS_IRQ_BASIC(nb)) intc_write_4(sc, INTC_ENABLE_BASIC, (1 << nb)); else if (IS_IRQ_BANK1(nb)) intc_write_4(sc, INTC_ENABLE_BANK1, (1 << IRQ_BANK1(nb))); else if (IS_IRQ_BANK2(nb)) intc_write_4(sc, INTC_ENABLE_BANK2, (1 << IRQ_BANK2(nb))); #ifdef SOC_BCM2836 else if (ID_IRQ_BCM2836(nb)) bcm2836_unmask_irq(nb - BANK3_START); #endif else printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); } #ifdef SMP void intr_pic_init_secondary(void) { } +#endif #endif Index: head/sys/arm/conf/RPI-B =================================================================== --- head/sys/arm/conf/RPI-B (revision 297579) +++ head/sys/arm/conf/RPI-B (revision 297580) @@ -1,111 +1,113 @@ # # RPI-B -- Custom configuration for the Raspberry Pi # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ ident RPI-B include "std.armv6" include "../broadcom/bcm2835/std.rpi" include "../broadcom/bcm2835/std.bcm2835" +options ARM_INTRNG + options HZ=100 options SCHED_4BSD # 4BSD scheduler options PLATFORM # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER #options VERBOSE_SYSINIT # Enable verbose sysinit messages options KDB # Enable kernel debugger support # For minimum debugger support (stable branch) use: #options KDB_TRACE # Print a stack trace for a panic # For full debugger support use this instead: options DDB # Enable the kernel debugger options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS #options WITNESS # Enable checks to detect deadlocks and cycles #options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options DIAGNOSTIC # NFS root from boopt/dhcp #options BOOTP #options BOOTP_NFSROOT #options BOOTP_COMPAT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=ue0 #options ROOTDEVNAME=\"ufs:mmcsd0s2\" device bpf device loop device ether device uart device pty device snp device pl011 # Comment following lines for boot console on serial port device vt device kbdmux device ukbd device sdhci device mmc device mmcsd device gpio device gpioled # I2C device iic device iicbus device bcm2835_bsc device md device random # Entropy device # USB support device usb options USB_DEBUG device dwcotg # DWC OTG controller # USB storage support device scbus device da device umass # USB ethernet support device smcphy device mii device smsc # SPI device spibus device bcm2835_spi device vchiq device sound # Flattened Device Tree options FDT # Configure using FDT/DTB data # Note: DTB is normally loaded and modified by RPi boot loader, then # handed to kernel via U-Boot and ubldr. #options FDT_DTB_STATIC #makeoptions FDT_DTS_FILE=rpi.dts makeoptions MODULES_EXTRA=dtb/rpi