Index: head/sys/arm/allwinner/a10_common.c =================================================================== --- head/sys/arm/allwinner/a10_common.c (revision 308443) +++ head/sys/arm/allwinner/a10_common.c (nonexistent) @@ -1,68 +0,0 @@ -/*- - * Copyright (c) 2012 Ganbold Tsagaankhuu - * All rights reserved. - * - * 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 -#include -#include -#include - -#include -#include - -#include -#include - -#ifndef INTRNG - -static int -fdt_aintc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, - int *pol) -{ - int offset; - - if (fdt_is_compatible(node, "allwinner,sun4i-a10-ic")) - offset = 0; - else if (fdt_is_compatible(node, "arm,gic")) - offset = 32; - else - return (ENXIO); - - *interrupt = fdt32_to_cpu(intr[0]) + offset; - *trig = INTR_TRIGGER_CONFORM; - *pol = INTR_POLARITY_CONFORM; - - return (0); -} - -fdt_pic_decode_t fdt_pic_table[] = { - &fdt_aintc_decode_ic, - NULL -}; - -#endif /* INTRNG */ Property changes on: head/sys/arm/allwinner/a10_common.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/arm/allwinner/a10/a10_intc.c =================================================================== --- head/sys/arm/allwinner/a10/a10_intc.c (revision 308443) +++ head/sys/arm/allwinner/a10/a10_intc.c (revision 308444) @@ -1,435 +1,391 @@ /*- * Copyright (c) 2012 Ganbold Tsagaankhuu * Copyright (c) 2016 Emmanuel Vadot * All rights reserved. * * 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 -#ifdef INTRNG #include -#endif #include #include #include #include #include #include -#ifdef INTRNG #include "pic_if.h" -#endif /** * Interrupt controller registers * */ #define SW_INT_VECTOR_REG 0x00 #define SW_INT_BASE_ADR_REG 0x04 #define SW_INT_PROTECTION_REG 0x08 #define SW_INT_NMI_CTRL_REG 0x0c #define SW_INT_IRQ_PENDING_REG0 0x10 #define SW_INT_IRQ_PENDING_REG1 0x14 #define SW_INT_IRQ_PENDING_REG2 0x18 #define SW_INT_FIQ_PENDING_REG0 0x20 #define SW_INT_FIQ_PENDING_REG1 0x24 #define SW_INT_FIQ_PENDING_REG2 0x28 #define SW_INT_SELECT_REG0 0x30 #define SW_INT_SELECT_REG1 0x34 #define SW_INT_SELECT_REG2 0x38 #define SW_INT_ENABLE_REG0 0x40 #define SW_INT_ENABLE_REG1 0x44 #define SW_INT_ENABLE_REG2 0x48 #define SW_INT_MASK_REG0 0x50 #define SW_INT_MASK_REG1 0x54 #define SW_INT_MASK_REG2 0x58 #define SW_INT_IRQNO_ENMI 0 #define A10_INTR_MAX_NIRQS 81 #define SW_INT_IRQ_PENDING_REG(_b) (0x10 + ((_b) * 4)) #define SW_INT_FIQ_PENDING_REG(_b) (0x20 + ((_b) * 4)) #define SW_INT_SELECT_REG(_b) (0x30 + ((_b) * 4)) #define SW_INT_ENABLE_REG(_b) (0x40 + ((_b) * 4)) #define SW_INT_MASK_REG(_b) (0x50 + ((_b) * 4)) -#ifdef INTRNG struct a10_intr_irqsrc { struct intr_irqsrc isrc; u_int irq; }; -#endif struct a10_aintc_softc { device_t sc_dev; struct resource * aintc_res; bus_space_tag_t aintc_bst; bus_space_handle_t aintc_bsh; struct mtx mtx; -#ifdef INTRNG struct a10_intr_irqsrc isrcs[A10_INTR_MAX_NIRQS]; -#endif }; #define aintc_read_4(sc, reg) \ bus_space_read_4(sc->aintc_bst, sc->aintc_bsh, reg) #define aintc_write_4(sc, reg, val) \ bus_space_write_4(sc->aintc_bst, sc->aintc_bsh, reg, val) static __inline void a10_intr_eoi(struct a10_aintc_softc *sc, u_int irq) { if (irq != SW_INT_IRQNO_ENMI) return; mtx_lock_spin(&sc->mtx); aintc_write_4(sc, SW_INT_IRQ_PENDING_REG(0), (1 << SW_INT_IRQNO_ENMI)); mtx_unlock_spin(&sc->mtx); } static void a10_intr_unmask(struct a10_aintc_softc *sc, u_int irq) { uint32_t bit, block, value; bit = (irq % 32); block = (irq / 32); mtx_lock_spin(&sc->mtx); value = aintc_read_4(sc, SW_INT_ENABLE_REG(block)); value |= (1 << bit); aintc_write_4(sc, SW_INT_ENABLE_REG(block), value); value = aintc_read_4(sc, SW_INT_MASK_REG(block)); value &= ~(1 << bit); aintc_write_4(sc, SW_INT_MASK_REG(block), value); mtx_unlock_spin(&sc->mtx); } static void a10_intr_mask(struct a10_aintc_softc *sc, u_int irq) { uint32_t bit, block, value; bit = (irq % 32); block = (irq / 32); mtx_lock_spin(&sc->mtx); value = aintc_read_4(sc, SW_INT_ENABLE_REG(block)); value &= ~(1 << bit); aintc_write_4(sc, SW_INT_ENABLE_REG(block), value); value = aintc_read_4(sc, SW_INT_MASK_REG(block)); value |= (1 << bit); aintc_write_4(sc, SW_INT_MASK_REG(block), value); mtx_unlock_spin(&sc->mtx); } static int a10_pending_irq(struct a10_aintc_softc *sc) { uint32_t value; int i, b; for (i = 0; i < 3; i++) { value = aintc_read_4(sc, SW_INT_IRQ_PENDING_REG(i)); if (value == 0) continue; for (b = 0; b < 32; b++) if (value & (1 << b)) { return (i * 32 + b); } } return (-1); } -#ifndef INTRNG - -static struct a10_aintc_softc *a10_aintc_sc = NULL; - -int -arm_get_next_irq(int last_irq) -{ - return (a10_pending_irq(a10_aintc_sc)); -} - -void -arm_mask_irq(uintptr_t irq) -{ - a10_intr_mask(a10_aintc_sc, irq); -} - -void -arm_unmask_irq(uintptr_t irq) -{ - a10_intr_unmask(a10_aintc_sc, irq); - a10_intr_eoi(a10_aintc_sc, irq); -} - -#else /* INTRNG */ - static int a10_intr(void *arg) { struct a10_aintc_softc *sc = arg; u_int irq; irq = a10_pending_irq(sc); if (irq == -1 || irq > A10_INTR_MAX_NIRQS) { device_printf(sc->sc_dev, "Spurious interrupt %d\n", irq); return (FILTER_HANDLED); } while (irq != -1) { if (irq > A10_INTR_MAX_NIRQS) { device_printf(sc->sc_dev, "Spurious interrupt %d\n", irq); return (FILTER_HANDLED); } if (intr_isrc_dispatch(&sc->isrcs[irq].isrc, curthread->td_intr_frame) != 0) { a10_intr_mask(sc, irq); a10_intr_eoi(sc, irq); device_printf(sc->sc_dev, "Stray interrupt %d disabled\n", irq); } arm_irq_memory_barrier(irq); irq = a10_pending_irq(sc); } return (FILTER_HANDLED); } static int a10_intr_pic_attach(struct a10_aintc_softc *sc) { struct intr_pic *pic; int error; uint32_t irq; const char *name; intptr_t xref; name = device_get_nameunit(sc->sc_dev); for (irq = 0; irq < A10_INTR_MAX_NIRQS; irq++) { sc->isrcs[irq].irq = irq; error = intr_isrc_register(&sc->isrcs[irq].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)); pic = intr_pic_register(sc->sc_dev, xref); if (pic == NULL) return (ENXIO); return (intr_pic_claim_root(sc->sc_dev, xref, a10_intr, sc, 0)); } static void a10_intr_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct a10_aintc_softc *sc; u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; sc = device_get_softc(dev); arm_irq_memory_barrier(irq); a10_intr_unmask(sc, irq); } static void a10_intr_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct a10_aintc_softc *sc; u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; sc = device_get_softc(dev); a10_intr_mask(sc, irq); } static int a10_intr_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { struct intr_map_data_fdt *daf; struct a10_aintc_softc *sc; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); daf = (struct intr_map_data_fdt *)data; if (daf->ncells != 1 || daf->cells[0] >= A10_INTR_MAX_NIRQS) return (EINVAL); sc = device_get_softc(dev); *isrcp = &sc->isrcs[daf->cells[0]].isrc; return (0); } static void a10_intr_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct a10_aintc_softc *sc = device_get_softc(dev); u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; a10_intr_mask(sc, irq); a10_intr_eoi(sc, irq); } static void a10_intr_post_ithread(device_t dev, struct intr_irqsrc *isrc) { a10_intr_enable_intr(dev, isrc); } static void a10_intr_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct a10_aintc_softc *sc = device_get_softc(dev); u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; a10_intr_eoi(sc, irq); } -#endif /* INTRNG */ - static int a10_aintc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-ic")) return (ENXIO); device_set_desc(dev, "A10 AINTC Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static int a10_aintc_attach(device_t dev) { struct a10_aintc_softc *sc = device_get_softc(dev); int rid = 0; int i; sc->sc_dev = dev; -#ifndef INTRNG - if (a10_aintc_sc) - goto error; - - a10_aintc_sc = sc; -#endif - sc->aintc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->aintc_res) { device_printf(dev, "could not allocate resource\n"); goto error; } sc->aintc_bst = rman_get_bustag(sc->aintc_res); sc->aintc_bsh = rman_get_bushandle(sc->aintc_res); mtx_init(&sc->mtx, "A10 AINTC lock", "", MTX_SPIN); /* Disable & clear all interrupts */ for (i = 0; i < 3; i++) { aintc_write_4(sc, SW_INT_ENABLE_REG(i), 0); aintc_write_4(sc, SW_INT_MASK_REG(i), 0xffffffff); } /* enable protection mode*/ aintc_write_4(sc, SW_INT_PROTECTION_REG, 0x01); /* config the external interrupt source type*/ aintc_write_4(sc, SW_INT_NMI_CTRL_REG, 0x00); -#ifdef INTRNG if (a10_intr_pic_attach(sc) != 0) { device_printf(dev, "could not attach PIC\n"); return (ENXIO); } -#endif return (0); error: bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->aintc_res); return (ENXIO); } static device_method_t a10_aintc_methods[] = { DEVMETHOD(device_probe, a10_aintc_probe), DEVMETHOD(device_attach, a10_aintc_attach), -#ifdef INTRNG + /* Interrupt controller interface */ DEVMETHOD(pic_disable_intr, a10_intr_disable_intr), DEVMETHOD(pic_enable_intr, a10_intr_enable_intr), DEVMETHOD(pic_map_intr, a10_intr_map_intr), DEVMETHOD(pic_post_filter, a10_intr_post_filter), DEVMETHOD(pic_post_ithread, a10_intr_post_ithread), DEVMETHOD(pic_pre_ithread, a10_intr_pre_ithread), -#endif + { 0, 0 } }; static driver_t a10_aintc_driver = { "aintc", a10_aintc_methods, sizeof(struct a10_aintc_softc), }; static devclass_t a10_aintc_devclass; EARLY_DRIVER_MODULE(aintc, simplebus, a10_aintc_driver, a10_aintc_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_FIRST); Index: head/sys/arm/allwinner/files.allwinner =================================================================== --- head/sys/arm/allwinner/files.allwinner (revision 308443) +++ head/sys/arm/allwinner/files.allwinner (revision 308444) @@ -1,59 +1,58 @@ # $FreeBSD$ kern/kern_clocksource.c standard arm/allwinner/a10_ahci.c optional ahci arm/allwinner/a10_codec.c optional sound -arm/allwinner/a10_common.c standard arm/allwinner/a10_dmac.c standard arm/allwinner/a31_dmac.c standard arm/allwinner/a10_ehci.c optional ehci arm/allwinner/aw_usbphy.c optional ehci arm/allwinner/a10_gpio.c optional gpio arm/allwinner/a10_mmc.c optional mmc arm/allwinner/a10_sramc.c standard arm/allwinner/aw_nmi.c optional intrng arm/allwinner/aw_if_dwc.c optional dwc arm/allwinner/aw_rsb.c optional rsb | p2wi arm/allwinner/aw_rtc.c standard arm/allwinner/aw_ts.c standard arm/allwinner/aw_wdog.c standard arm/allwinner/aw_machdep.c standard arm/allwinner/aw_mp.c optional smp arm/allwinner/axp209.c optional axp209 arm/allwinner/axp81x.c optional axp81x arm/allwinner/if_awg.c optional awg arm/allwinner/if_emac.c optional emac arm/allwinner/sunxi_dma_if.m standard dev/iicbus/twsi/a10_twsi.c optional twsi dev/usb/controller/generic_ohci.c optional ohci dev/usb/controller/generic_usb_if.m optional ohci arm/allwinner/aw_sid.c standard arm/allwinner/aw_thermal.c standard dev/iicbus/sy8106a.c optional sy8106a arm/allwinner/aw_cir.c optional aw_cir evdev #arm/allwinner/console.c standard arm/allwinner/a10_fb.c optional vt arm/allwinner/a10_hdmi.c optional hdmi arm/allwinner/a10_hdmiaudio.c optional hdmi sound arm/arm/hdmi_if.m optional hdmi arm/allwinner/aw_reset.c standard arm/allwinner/aw_ccu.c standard arm/allwinner/clk/aw_ahbclk.c standard arm/allwinner/clk/aw_apbclk.c standard arm/allwinner/clk/aw_axiclk.c standard arm/allwinner/clk/aw_codecclk.c standard arm/allwinner/clk/aw_cpuclk.c standard arm/allwinner/clk/aw_cpusclk.c standard arm/allwinner/clk/aw_debeclk.c standard arm/allwinner/clk/aw_gate.c standard arm/allwinner/clk/aw_gmacclk.c standard arm/allwinner/clk/aw_hdmiclk.c standard arm/allwinner/clk/aw_lcdclk.c standard arm/allwinner/clk/aw_modclk.c standard arm/allwinner/clk/aw_mmcclk.c standard arm/allwinner/clk/aw_oscclk.c standard arm/allwinner/clk/aw_pll.c standard arm/allwinner/clk/aw_thsclk.c standard arm/allwinner/clk/aw_usbclk.c standard Index: head/sys/arm/broadcom/bcm2835/bcm2835_common.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_common.c (revision 308443) +++ head/sys/arm/broadcom/bcm2835/bcm2835_common.c (nonexistent) @@ -1,78 +0,0 @@ -/*- - * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD. - * All rights reserved. - * - * Developed by Semihalf. - * - * 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. - * 3. Neither the name of MARVELL nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY 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 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#ifndef INTRNG -static int -fdt_intc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, - int *pol) -{ - - if (fdt_is_compatible(node, "broadcom,bcm2835-armctrl-ic") || - fdt_is_compatible(node, "brcm,bcm2836-armctrl-ic")) { - *interrupt = fdt32_to_cpu(intr[0]); - *trig = INTR_TRIGGER_CONFORM; - *pol = INTR_POLARITY_CONFORM; - return (0); - } -#ifdef SOC_BCM2836 - if (fdt_is_compatible(node, "brcm,bcm2836-l1-intc")) { - *interrupt = fdt32_to_cpu(intr[0]) + 72; - *trig = INTR_TRIGGER_CONFORM; - *pol = INTR_POLARITY_CONFORM; - return (0); - } -#endif - return (ENXIO); -} - - -fdt_pic_decode_t fdt_pic_table[] = { - &fdt_intc_decode_ic, - NULL -}; -#endif /* INTRNG */ Property changes on: head/sys/arm/broadcom/bcm2835/bcm2835_common.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/arm/broadcom/bcm2835/bcm2836.h =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2836.h (revision 308443) +++ head/sys/arm/broadcom/bcm2835/bcm2836.h (nonexistent) @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Andrew Turner. - * All rights reserved. - * - * 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. - * - * $FreeBSD$ - */ - -#ifndef _BCM2815_BCM2836_H -#define _BCM2815_BCM2836_H - -#ifndef INTRNG -#define BCM2836_GPU_IRQ 8 - -int bcm2836_get_next_irq(int); -void bcm2836_mask_irq(uintptr_t); -void bcm2836_unmask_irq(uintptr_t); -#endif -#endif Property changes on: head/sys/arm/broadcom/bcm2835/bcm2836.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/sys/arm/broadcom/bcm2835/bcm2835_gpio.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_gpio.c (revision 308443) +++ head/sys/arm/broadcom/bcm2835/bcm2835_gpio.c (revision 308444) @@ -1,1508 +1,1230 @@ /*- * Copyright (c) 2012 Oleksandr Tymoshenko * Copyright (c) 2012-2015 Luiz Otavio O Souza * All rights reserved. * * 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 #include #include #include #include "gpio_if.h" -#ifdef INTRNG #include "pic_if.h" -#endif #ifdef DEBUG #define dprintf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define dprintf(fmt, args...) #endif #define BCM_GPIO_IRQS 4 #define BCM_GPIO_PINS 54 #define BCM_GPIO_PINS_PER_BANK 32 -#ifdef INTRNG #define BCM_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_INTR_LEVEL_LOW | \ GPIO_INTR_LEVEL_HIGH | GPIO_INTR_EDGE_RISING | \ GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH) -#else -#define BCM_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ - GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN) -#endif static struct resource_spec bcm_gpio_res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, /* bank 0 interrupt */ { SYS_RES_IRQ, 1, RF_ACTIVE }, /* bank 1 interrupt */ { -1, 0, 0 } }; struct bcm_gpio_sysctl { struct bcm_gpio_softc *sc; uint32_t pin; }; -#ifdef INTRNG struct bcm_gpio_irqsrc { struct intr_irqsrc bgi_isrc; uint32_t bgi_irq; uint32_t bgi_mode; uint32_t bgi_mask; }; -#endif struct bcm_gpio_softc { device_t sc_dev; device_t sc_busdev; struct mtx sc_mtx; struct resource * sc_res[BCM_GPIO_IRQS + 1]; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; void * sc_intrhand[BCM_GPIO_IRQS]; int sc_gpio_npins; int sc_ro_npins; int sc_ro_pins[BCM_GPIO_PINS]; struct gpio_pin sc_gpio_pins[BCM_GPIO_PINS]; -#ifndef INTRNG - struct intr_event * sc_events[BCM_GPIO_PINS]; -#endif struct bcm_gpio_sysctl sc_sysctl[BCM_GPIO_PINS]; -#ifdef INTRNG struct bcm_gpio_irqsrc sc_isrcs[BCM_GPIO_PINS]; -#else - enum intr_trigger sc_irq_trigger[BCM_GPIO_PINS]; - enum intr_polarity sc_irq_polarity[BCM_GPIO_PINS]; -#endif }; enum bcm_gpio_pud { BCM_GPIO_NONE, BCM_GPIO_PULLDOWN, BCM_GPIO_PULLUP, }; #define BCM_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) #define BCM_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) #define BCM_GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define BCM_GPIO_WRITE(_sc, _off, _val) \ bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, _off, _val) #define BCM_GPIO_READ(_sc, _off) \ bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, _off) #define BCM_GPIO_CLEAR_BITS(_sc, _off, _bits) \ BCM_GPIO_WRITE(_sc, _off, BCM_GPIO_READ(_sc, _off) & ~(_bits)) #define BCM_GPIO_SET_BITS(_sc, _off, _bits) \ BCM_GPIO_WRITE(_sc, _off, BCM_GPIO_READ(_sc, _off) | _bits) #define BCM_GPIO_BANK(a) (a / BCM_GPIO_PINS_PER_BANK) #define BCM_GPIO_MASK(a) (1U << (a % BCM_GPIO_PINS_PER_BANK)) #define BCM_GPIO_GPFSEL(_bank) (0x00 + _bank * 4) /* Function Select */ #define BCM_GPIO_GPSET(_bank) (0x1c + _bank * 4) /* Pin Out Set */ #define BCM_GPIO_GPCLR(_bank) (0x28 + _bank * 4) /* Pin Out Clear */ #define BCM_GPIO_GPLEV(_bank) (0x34 + _bank * 4) /* Pin Level */ #define BCM_GPIO_GPEDS(_bank) (0x40 + _bank * 4) /* Event Status */ #define BCM_GPIO_GPREN(_bank) (0x4c + _bank * 4) /* Rising Edge irq */ #define BCM_GPIO_GPFEN(_bank) (0x58 + _bank * 4) /* Falling Edge irq */ #define BCM_GPIO_GPHEN(_bank) (0x64 + _bank * 4) /* High Level irq */ #define BCM_GPIO_GPLEN(_bank) (0x70 + _bank * 4) /* Low Level irq */ #define BCM_GPIO_GPAREN(_bank) (0x7c + _bank * 4) /* Async Rising Edge */ #define BCM_GPIO_GPAFEN(_bank) (0x88 + _bank * 4) /* Async Falling Egde */ #define BCM_GPIO_GPPUD(_bank) (0x94) /* Pin Pull up/down */ #define BCM_GPIO_GPPUDCLK(_bank) (0x98 + _bank * 4) /* Pin Pull up clock */ static struct ofw_compat_data compat_data[] = { {"broadcom,bcm2835-gpio", 1}, {"brcm,bcm2835-gpio", 1}, {NULL, 0} }; static struct bcm_gpio_softc *bcm_gpio_sc = NULL; -#ifdef INTRNG static int bcm_gpio_intr_bank0(void *arg); static int bcm_gpio_intr_bank1(void *arg); static int bcm_gpio_pic_attach(struct bcm_gpio_softc *sc); static int bcm_gpio_pic_detach(struct bcm_gpio_softc *sc); -#endif static int bcm_gpio_pin_is_ro(struct bcm_gpio_softc *sc, int pin) { int i; for (i = 0; i < sc->sc_ro_npins; i++) if (pin == sc->sc_ro_pins[i]) return (1); return (0); } static uint32_t bcm_gpio_get_function(struct bcm_gpio_softc *sc, uint32_t pin) { uint32_t bank, func, offset; /* Five banks, 10 pins per bank, 3 bits per pin. */ bank = pin / 10; offset = (pin - bank * 10) * 3; BCM_GPIO_LOCK(sc); func = (BCM_GPIO_READ(sc, BCM_GPIO_GPFSEL(bank)) >> offset) & 7; BCM_GPIO_UNLOCK(sc); return (func); } static void bcm_gpio_func_str(uint32_t nfunc, char *buf, int bufsize) { switch (nfunc) { case BCM_GPIO_INPUT: strncpy(buf, "input", bufsize); break; case BCM_GPIO_OUTPUT: strncpy(buf, "output", bufsize); break; case BCM_GPIO_ALT0: strncpy(buf, "alt0", bufsize); break; case BCM_GPIO_ALT1: strncpy(buf, "alt1", bufsize); break; case BCM_GPIO_ALT2: strncpy(buf, "alt2", bufsize); break; case BCM_GPIO_ALT3: strncpy(buf, "alt3", bufsize); break; case BCM_GPIO_ALT4: strncpy(buf, "alt4", bufsize); break; case BCM_GPIO_ALT5: strncpy(buf, "alt5", bufsize); break; default: strncpy(buf, "invalid", bufsize); } } static int bcm_gpio_str_func(char *func, uint32_t *nfunc) { if (strcasecmp(func, "input") == 0) *nfunc = BCM_GPIO_INPUT; else if (strcasecmp(func, "output") == 0) *nfunc = BCM_GPIO_OUTPUT; else if (strcasecmp(func, "alt0") == 0) *nfunc = BCM_GPIO_ALT0; else if (strcasecmp(func, "alt1") == 0) *nfunc = BCM_GPIO_ALT1; else if (strcasecmp(func, "alt2") == 0) *nfunc = BCM_GPIO_ALT2; else if (strcasecmp(func, "alt3") == 0) *nfunc = BCM_GPIO_ALT3; else if (strcasecmp(func, "alt4") == 0) *nfunc = BCM_GPIO_ALT4; else if (strcasecmp(func, "alt5") == 0) *nfunc = BCM_GPIO_ALT5; else return (-1); return (0); } static uint32_t bcm_gpio_func_flag(uint32_t nfunc) { switch (nfunc) { case BCM_GPIO_INPUT: return (GPIO_PIN_INPUT); case BCM_GPIO_OUTPUT: return (GPIO_PIN_OUTPUT); } return (0); } static void bcm_gpio_set_function(struct bcm_gpio_softc *sc, uint32_t pin, uint32_t f) { uint32_t bank, data, offset; /* Must be called with lock held. */ BCM_GPIO_LOCK_ASSERT(sc); /* Five banks, 10 pins per bank, 3 bits per pin. */ bank = pin / 10; offset = (pin - bank * 10) * 3; data = BCM_GPIO_READ(sc, BCM_GPIO_GPFSEL(bank)); data &= ~(7 << offset); data |= (f << offset); BCM_GPIO_WRITE(sc, BCM_GPIO_GPFSEL(bank), data); } static void bcm_gpio_set_pud(struct bcm_gpio_softc *sc, uint32_t pin, uint32_t state) { uint32_t bank; /* Must be called with lock held. */ BCM_GPIO_LOCK_ASSERT(sc); bank = BCM_GPIO_BANK(pin); BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUD(0), state); BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUDCLK(bank), BCM_GPIO_MASK(pin)); BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUD(0), 0); BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUDCLK(bank), 0); } void bcm_gpio_set_alternate(device_t dev, uint32_t pin, uint32_t nfunc) { struct bcm_gpio_softc *sc; int i; sc = device_get_softc(dev); BCM_GPIO_LOCK(sc); /* Disable pull-up or pull-down on pin. */ bcm_gpio_set_pud(sc, pin, BCM_GPIO_NONE); /* And now set the pin function. */ bcm_gpio_set_function(sc, pin, nfunc); /* Update the pin flags. */ for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i < sc->sc_gpio_npins) sc->sc_gpio_pins[i].gp_flags = bcm_gpio_func_flag(nfunc); BCM_GPIO_UNLOCK(sc); } static void bcm_gpio_pin_configure(struct bcm_gpio_softc *sc, struct gpio_pin *pin, unsigned int flags) { BCM_GPIO_LOCK(sc); /* * Manage input/output. */ if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); if (flags & GPIO_PIN_OUTPUT) { pin->gp_flags |= GPIO_PIN_OUTPUT; bcm_gpio_set_function(sc, pin->gp_pin, BCM_GPIO_OUTPUT); } else { pin->gp_flags |= GPIO_PIN_INPUT; bcm_gpio_set_function(sc, pin->gp_pin, BCM_GPIO_INPUT); } } /* Manage Pull-up/pull-down. */ pin->gp_flags &= ~(GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN); if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) { if (flags & GPIO_PIN_PULLUP) { pin->gp_flags |= GPIO_PIN_PULLUP; bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_PULLUP); } else { pin->gp_flags |= GPIO_PIN_PULLDOWN; bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_PULLDOWN); } } else bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_NONE); BCM_GPIO_UNLOCK(sc); } static device_t bcm_gpio_get_bus(device_t dev) { struct bcm_gpio_softc *sc; sc = device_get_softc(dev); return (sc->sc_busdev); } static int bcm_gpio_pin_max(device_t dev, int *maxpin) { *maxpin = BCM_GPIO_PINS - 1; return (0); } static int bcm_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct bcm_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i >= sc->sc_gpio_npins) return (EINVAL); BCM_GPIO_LOCK(sc); *caps = sc->sc_gpio_pins[i].gp_caps; BCM_GPIO_UNLOCK(sc); return (0); } static int bcm_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct bcm_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i >= sc->sc_gpio_npins) return (EINVAL); BCM_GPIO_LOCK(sc); *flags = sc->sc_gpio_pins[i].gp_flags; BCM_GPIO_UNLOCK(sc); return (0); } static int bcm_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct bcm_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i >= sc->sc_gpio_npins) return (EINVAL); BCM_GPIO_LOCK(sc); memcpy(name, sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME); BCM_GPIO_UNLOCK(sc); return (0); } static int bcm_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct bcm_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i >= sc->sc_gpio_npins) return (EINVAL); /* We never touch on read-only/reserved pins. */ if (bcm_gpio_pin_is_ro(sc, pin)) return (EINVAL); bcm_gpio_pin_configure(sc, &sc->sc_gpio_pins[i], flags); return (0); } static int bcm_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct bcm_gpio_softc *sc = device_get_softc(dev); uint32_t bank, reg; int i; for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i >= sc->sc_gpio_npins) return (EINVAL); /* We never write to read-only/reserved pins. */ if (bcm_gpio_pin_is_ro(sc, pin)) return (EINVAL); BCM_GPIO_LOCK(sc); bank = BCM_GPIO_BANK(pin); if (value) reg = BCM_GPIO_GPSET(bank); else reg = BCM_GPIO_GPCLR(bank); BCM_GPIO_WRITE(sc, reg, BCM_GPIO_MASK(pin)); BCM_GPIO_UNLOCK(sc); return (0); } static int bcm_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct bcm_gpio_softc *sc = device_get_softc(dev); uint32_t bank, reg_data; int i; for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i >= sc->sc_gpio_npins) return (EINVAL); bank = BCM_GPIO_BANK(pin); BCM_GPIO_LOCK(sc); reg_data = BCM_GPIO_READ(sc, BCM_GPIO_GPLEV(bank)); BCM_GPIO_UNLOCK(sc); *val = (reg_data & BCM_GPIO_MASK(pin)) ? 1 : 0; return (0); } static int bcm_gpio_pin_toggle(device_t dev, uint32_t pin) { struct bcm_gpio_softc *sc = device_get_softc(dev); uint32_t bank, data, reg; int i; for (i = 0; i < sc->sc_gpio_npins; i++) { if (sc->sc_gpio_pins[i].gp_pin == pin) break; } if (i >= sc->sc_gpio_npins) return (EINVAL); /* We never write to read-only/reserved pins. */ if (bcm_gpio_pin_is_ro(sc, pin)) return (EINVAL); BCM_GPIO_LOCK(sc); bank = BCM_GPIO_BANK(pin); data = BCM_GPIO_READ(sc, BCM_GPIO_GPLEV(bank)); if (data & BCM_GPIO_MASK(pin)) reg = BCM_GPIO_GPCLR(bank); else reg = BCM_GPIO_GPSET(bank); BCM_GPIO_WRITE(sc, reg, BCM_GPIO_MASK(pin)); BCM_GPIO_UNLOCK(sc); return (0); } static int bcm_gpio_func_proc(SYSCTL_HANDLER_ARGS) { char buf[16]; struct bcm_gpio_softc *sc; struct bcm_gpio_sysctl *sc_sysctl; uint32_t nfunc; int error; sc_sysctl = arg1; sc = sc_sysctl->sc; /* Get the current pin function. */ nfunc = bcm_gpio_get_function(sc, sc_sysctl->pin); bcm_gpio_func_str(nfunc, buf, sizeof(buf)); error = sysctl_handle_string(oidp, buf, sizeof(buf), req); if (error != 0 || req->newptr == NULL) return (error); /* Ignore changes on read-only pins. */ if (bcm_gpio_pin_is_ro(sc, sc_sysctl->pin)) return (0); /* Parse the user supplied string and check for a valid pin function. */ if (bcm_gpio_str_func(buf, &nfunc) != 0) return (EINVAL); /* Update the pin alternate function. */ bcm_gpio_set_alternate(sc->sc_dev, sc_sysctl->pin, nfunc); return (0); } static void bcm_gpio_sysctl_init(struct bcm_gpio_softc *sc) { char pinbuf[3]; struct bcm_gpio_sysctl *sc_sysctl; struct sysctl_ctx_list *ctx; struct sysctl_oid *tree_node, *pin_node, *pinN_node; struct sysctl_oid_list *tree, *pin_tree, *pinN_tree; int i; /* * Add per-pin sysctl tree/handlers. */ ctx = device_get_sysctl_ctx(sc->sc_dev); tree_node = device_get_sysctl_tree(sc->sc_dev); tree = SYSCTL_CHILDREN(tree_node); pin_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "pin", CTLFLAG_RD, NULL, "GPIO Pins"); pin_tree = SYSCTL_CHILDREN(pin_node); for (i = 0; i < sc->sc_gpio_npins; i++) { snprintf(pinbuf, sizeof(pinbuf), "%d", i); pinN_node = SYSCTL_ADD_NODE(ctx, pin_tree, OID_AUTO, pinbuf, CTLFLAG_RD, NULL, "GPIO Pin"); pinN_tree = SYSCTL_CHILDREN(pinN_node); sc->sc_sysctl[i].sc = sc; sc_sysctl = &sc->sc_sysctl[i]; sc_sysctl->sc = sc; sc_sysctl->pin = sc->sc_gpio_pins[i].gp_pin; SYSCTL_ADD_PROC(ctx, pinN_tree, OID_AUTO, "function", CTLFLAG_RW | CTLTYPE_STRING, sc_sysctl, sizeof(struct bcm_gpio_sysctl), bcm_gpio_func_proc, "A", "Pin Function"); } } static int bcm_gpio_get_ro_pins(struct bcm_gpio_softc *sc, phandle_t node, const char *propname, const char *label) { int i, need_comma, npins, range_start, range_stop; pcell_t *pins; /* Get the property data. */ npins = OF_getencprop_alloc(node, propname, sizeof(*pins), (void **)&pins); if (npins < 0) return (-1); if (npins == 0) { OF_prop_free(pins); return (0); } for (i = 0; i < npins; i++) sc->sc_ro_pins[i + sc->sc_ro_npins] = pins[i]; sc->sc_ro_npins += npins; need_comma = 0; device_printf(sc->sc_dev, "%s pins: ", label); range_start = range_stop = pins[0]; for (i = 1; i < npins; i++) { if (pins[i] != range_stop + 1) { if (need_comma) printf(","); if (range_start != range_stop) printf("%d-%d", range_start, range_stop); else printf("%d", range_start); range_start = range_stop = pins[i]; need_comma = 1; } else range_stop++; } if (need_comma) printf(","); if (range_start != range_stop) printf("%d-%d.\n", range_start, range_stop); else printf("%d.\n", range_start); OF_prop_free(pins); return (0); } static int bcm_gpio_get_reserved_pins(struct bcm_gpio_softc *sc) { char *name; phandle_t gpio, node, reserved; ssize_t len; /* Get read-only pins if they're provided */ gpio = ofw_bus_get_node(sc->sc_dev); if (bcm_gpio_get_ro_pins(sc, gpio, "broadcom,read-only", "read-only") != 0) return (0); /* Traverse the GPIO subnodes to find the reserved pins node. */ reserved = 0; node = OF_child(gpio); while ((node != 0) && (reserved == 0)) { len = OF_getprop_alloc(node, "name", 1, (void **)&name); if (len == -1) return (-1); if (strcmp(name, "reserved") == 0) reserved = node; OF_prop_free(name); node = OF_peer(node); } if (reserved == 0) return (-1); /* Get the reserved pins. */ if (bcm_gpio_get_ro_pins(sc, reserved, "broadcom,pins", "reserved") != 0) return (-1); return (0); } -#ifndef INTRNG static int -bcm_gpio_intr(void *arg) -{ - int bank_last, irq; - struct bcm_gpio_softc *sc; - struct intr_event *event; - uint32_t bank, mask, reg; - - sc = (struct bcm_gpio_softc *)arg; - reg = 0; - bank_last = -1; - for (irq = 0; irq < BCM_GPIO_PINS; irq++) { - bank = BCM_GPIO_BANK(irq); - mask = BCM_GPIO_MASK(irq); - if (bank != bank_last) { - reg = BCM_GPIO_READ(sc, BCM_GPIO_GPEDS(bank)); - bank_last = bank; - } - if (reg & mask) { - event = sc->sc_events[irq]; - if (event != NULL && !TAILQ_EMPTY(&event->ie_handlers)) - intr_event_handle(event, NULL); - else { - device_printf(sc->sc_dev, "Stray IRQ %d\n", - irq); - } - /* Clear the Status bit by writing '1' to it. */ - BCM_GPIO_WRITE(sc, BCM_GPIO_GPEDS(bank), mask); - } - } - - return (FILTER_HANDLED); -} -#endif - -static int bcm_gpio_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "BCM2708/2835 GPIO controller"); return (BUS_PROBE_DEFAULT); } -#ifdef INTRNG static int bcm_gpio_intr_attach(device_t dev) { struct bcm_gpio_softc *sc; /* * Only first two interrupt lines are used. Third line is * mirrored second line and forth line is common for all banks. */ sc = device_get_softc(dev); if (sc->sc_res[1] == NULL || sc->sc_res[2] == NULL) return (-1); if (bcm_gpio_pic_attach(sc) != 0) { device_printf(dev, "unable to attach PIC\n"); return (-1); } if (bus_setup_intr(dev, sc->sc_res[1], INTR_TYPE_MISC | INTR_MPSAFE, bcm_gpio_intr_bank0, NULL, sc, &sc->sc_intrhand[0]) != 0) return (-1); if (bus_setup_intr(dev, sc->sc_res[2], INTR_TYPE_MISC | INTR_MPSAFE, bcm_gpio_intr_bank1, NULL, sc, &sc->sc_intrhand[1]) != 0) return (-1); return (0); } static void bcm_gpio_intr_detach(device_t dev) { struct bcm_gpio_softc *sc; sc = device_get_softc(dev); if (sc->sc_intrhand[0] != NULL) bus_teardown_intr(dev, sc->sc_res[1], sc->sc_intrhand[0]); if (sc->sc_intrhand[1] != NULL) bus_teardown_intr(dev, sc->sc_res[2], sc->sc_intrhand[1]); bcm_gpio_pic_detach(sc); } -#else static int -bcm_gpio_intr_attach(device_t dev) -{ - struct bcm_gpio_softc *sc; - int i; - - sc = device_get_softc(dev); - for (i = 0; i < BCM_GPIO_IRQS; i++) { - if (bus_setup_intr(dev, sc->sc_res[i + 1], - INTR_TYPE_MISC | INTR_MPSAFE, bcm_gpio_intr, - NULL, sc, &sc->sc_intrhand[i]) != 0) { - return (-1); - } - } - - return (0); -} - -static void -bcm_gpio_intr_detach(device_t dev) -{ - struct bcm_gpio_softc *sc; - int i; - - sc = device_get_softc(dev); - for (i = 0; i < BCM_GPIO_IRQS; i++) { - if (sc->sc_intrhand[i]) { - bus_teardown_intr(dev, sc->sc_res[i + 1], - sc->sc_intrhand[i]); - } - } -} -#endif - -static int bcm_gpio_attach(device_t dev) { int i, j; phandle_t gpio; struct bcm_gpio_softc *sc; uint32_t func; if (bcm_gpio_sc != NULL) return (ENXIO); bcm_gpio_sc = sc = device_get_softc(dev); sc->sc_dev = dev; mtx_init(&sc->sc_mtx, "bcm gpio", "gpio", MTX_SPIN); if (bus_alloc_resources(dev, bcm_gpio_res_spec, sc->sc_res) != 0) { device_printf(dev, "cannot allocate resources\n"); goto fail; } sc->sc_bst = rman_get_bustag(sc->sc_res[0]); sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); /* Setup the GPIO interrupt handler. */ if (bcm_gpio_intr_attach(dev)) { device_printf(dev, "unable to setup the gpio irq handler\n"); goto fail; } /* Find our node. */ gpio = ofw_bus_get_node(sc->sc_dev); if (!OF_hasprop(gpio, "gpio-controller")) /* Node is not a GPIO controller. */ goto fail; /* * Find the read-only pins. These are pins we never touch or bad * things could happen. */ if (bcm_gpio_get_reserved_pins(sc) == -1) goto fail; /* Initialize the software controlled pins. */ for (i = 0, j = 0; j < BCM_GPIO_PINS; j++) { snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME, "pin %d", j); func = bcm_gpio_get_function(sc, j); sc->sc_gpio_pins[i].gp_pin = j; sc->sc_gpio_pins[i].gp_caps = BCM_GPIO_DEFAULT_CAPS; sc->sc_gpio_pins[i].gp_flags = bcm_gpio_func_flag(func); -#ifndef INTRNG - /* The default is active-low interrupts. */ - sc->sc_irq_trigger[i] = INTR_TRIGGER_LEVEL; - sc->sc_irq_polarity[i] = INTR_POLARITY_LOW; -#endif i++; } sc->sc_gpio_npins = i; bcm_gpio_sysctl_init(sc); sc->sc_busdev = gpiobus_attach_bus(dev); if (sc->sc_busdev == NULL) goto fail; return (0); fail: bcm_gpio_intr_detach(dev); bus_release_resources(dev, bcm_gpio_res_spec, sc->sc_res); mtx_destroy(&sc->sc_mtx); return (ENXIO); } static int bcm_gpio_detach(device_t dev) { return (EBUSY); } -#ifdef INTRNG static inline void bcm_gpio_modify(struct bcm_gpio_softc *sc, uint32_t reg, uint32_t mask, bool set_bits) { if (set_bits) BCM_GPIO_SET_BITS(sc, reg, mask); else BCM_GPIO_CLEAR_BITS(sc, reg, mask); } static inline void bcm_gpio_isrc_eoi(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi) { uint32_t bank; /* Write 1 to clear. */ bank = BCM_GPIO_BANK(bgi->bgi_irq); BCM_GPIO_WRITE(sc, BCM_GPIO_GPEDS(bank), bgi->bgi_mask); } static inline bool bcm_gpio_isrc_is_level(struct bcm_gpio_irqsrc *bgi) { return (bgi->bgi_mode == GPIO_INTR_LEVEL_LOW || bgi->bgi_mode == GPIO_INTR_LEVEL_HIGH); } static inline void bcm_gpio_isrc_mask(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi) { uint32_t bank; bank = BCM_GPIO_BANK(bgi->bgi_irq); BCM_GPIO_LOCK(sc); switch (bgi->bgi_mode) { case GPIO_INTR_LEVEL_LOW: BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask); break; case GPIO_INTR_LEVEL_HIGH: BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask); break; case GPIO_INTR_EDGE_RISING: BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); break; case GPIO_INTR_EDGE_FALLING: BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); break; case GPIO_INTR_EDGE_BOTH: BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); break; } BCM_GPIO_UNLOCK(sc); } static inline void bcm_gpio_isrc_unmask(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi) { uint32_t bank; bank = BCM_GPIO_BANK(bgi->bgi_irq); BCM_GPIO_LOCK(sc); switch (bgi->bgi_mode) { case GPIO_INTR_LEVEL_LOW: BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask); break; case GPIO_INTR_LEVEL_HIGH: BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask); break; case GPIO_INTR_EDGE_RISING: BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); break; case GPIO_INTR_EDGE_FALLING: BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); break; case GPIO_INTR_EDGE_BOTH: BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); break; } BCM_GPIO_UNLOCK(sc); } static int bcm_gpio_intr_internal(struct bcm_gpio_softc *sc, uint32_t bank) { u_int irq; struct bcm_gpio_irqsrc *bgi; uint32_t reg; /* Do not care of spurious interrupt on GPIO. */ reg = BCM_GPIO_READ(sc, BCM_GPIO_GPEDS(bank)); while (reg != 0) { irq = BCM_GPIO_PINS_PER_BANK * bank + ffs(reg) - 1; bgi = sc->sc_isrcs + irq; if (!bcm_gpio_isrc_is_level(bgi)) bcm_gpio_isrc_eoi(sc, bgi); if (intr_isrc_dispatch(&bgi->bgi_isrc, curthread->td_intr_frame) != 0) { bcm_gpio_isrc_mask(sc, bgi); if (bcm_gpio_isrc_is_level(bgi)) bcm_gpio_isrc_eoi(sc, bgi); device_printf(sc->sc_dev, "Stray irq %u disabled\n", irq); } reg &= ~bgi->bgi_mask; } return (FILTER_HANDLED); } static int bcm_gpio_intr_bank0(void *arg) { return (bcm_gpio_intr_internal(arg, 0)); } static int bcm_gpio_intr_bank1(void *arg) { return (bcm_gpio_intr_internal(arg, 1)); } static int bcm_gpio_pic_attach(struct bcm_gpio_softc *sc) { int error; uint32_t irq; const char *name; name = device_get_nameunit(sc->sc_dev); for (irq = 0; irq < BCM_GPIO_PINS; irq++) { sc->sc_isrcs[irq].bgi_irq = irq; sc->sc_isrcs[irq].bgi_mask = BCM_GPIO_MASK(irq); sc->sc_isrcs[irq].bgi_mode = GPIO_INTR_CONFORM; error = intr_isrc_register(&sc->sc_isrcs[irq].bgi_isrc, sc->sc_dev, 0, "%s,%u", name, irq); if (error != 0) return (error); /* XXX deregister ISRCs */ } if (intr_pic_register(sc->sc_dev, OF_xref_from_node(ofw_bus_get_node(sc->sc_dev))) == NULL) return (ENXIO); return (0); } static int bcm_gpio_pic_detach(struct bcm_gpio_softc *sc) { /* * There has not been established any procedure yet * how to detach PIC from living system correctly. */ device_printf(sc->sc_dev, "%s: not implemented yet\n", __func__); return (EBUSY); } static void bcm_gpio_pic_config_intr(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi, uint32_t mode) { uint32_t bank; bank = BCM_GPIO_BANK(bgi->bgi_irq); BCM_GPIO_LOCK(sc); bcm_gpio_modify(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask, mode == GPIO_INTR_EDGE_RISING || mode == GPIO_INTR_EDGE_BOTH); bcm_gpio_modify(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask, mode == GPIO_INTR_EDGE_FALLING || mode == GPIO_INTR_EDGE_BOTH); bcm_gpio_modify(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask, mode == GPIO_INTR_LEVEL_HIGH); bcm_gpio_modify(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask, mode == GPIO_INTR_LEVEL_LOW); bgi->bgi_mode = mode; BCM_GPIO_UNLOCK(sc); } static void bcm_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct bcm_gpio_softc *sc = device_get_softc(dev); struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc; bcm_gpio_isrc_mask(sc, bgi); } static void bcm_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct bcm_gpio_softc *sc = device_get_softc(dev); struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc; arm_irq_memory_barrier(bgi->bgi_irq); bcm_gpio_isrc_unmask(sc, bgi); } static int bcm_gpio_pic_map_fdt(struct bcm_gpio_softc *sc, struct intr_map_data_fdt *daf, u_int *irqp, uint32_t *modep) { u_int irq; uint32_t mode, bank; /* * The first cell is the interrupt number. * The second cell is used to specify flags: * bits[3:0] trigger type and level flags: * 1 = low-to-high edge triggered. * 2 = high-to-low edge triggered. * 4 = active high level-sensitive. * 8 = active low level-sensitive. */ if (daf->ncells != 2) return (EINVAL); irq = daf->cells[0]; if (irq >= BCM_GPIO_PINS || bcm_gpio_pin_is_ro(sc, irq)) return (EINVAL); /* Only reasonable modes are supported. */ bank = BCM_GPIO_BANK(irq); if (daf->cells[1] == 1) mode = GPIO_INTR_EDGE_RISING; else if (daf->cells[1] == 2) mode = GPIO_INTR_EDGE_FALLING; else if (daf->cells[1] == 3) mode = GPIO_INTR_EDGE_BOTH; else if (daf->cells[1] == 4) mode = GPIO_INTR_LEVEL_HIGH; else if (daf->cells[1] == 8) mode = GPIO_INTR_LEVEL_LOW; else return (EINVAL); *irqp = irq; if (modep != NULL) *modep = mode; return (0); } static int bcm_gpio_pic_map_gpio(struct bcm_gpio_softc *sc, struct intr_map_data_gpio *dag, u_int *irqp, uint32_t *modep) { u_int irq; uint32_t mode; irq = dag->gpio_pin_num; if (irq >= BCM_GPIO_PINS || bcm_gpio_pin_is_ro(sc, irq)) return (EINVAL); mode = dag->gpio_intr_mode; if (mode != GPIO_INTR_LEVEL_LOW && mode != GPIO_INTR_LEVEL_HIGH && mode != GPIO_INTR_EDGE_RISING && mode != GPIO_INTR_EDGE_FALLING && mode != GPIO_INTR_EDGE_BOTH) return (EINVAL); *irqp = irq; if (modep != NULL) *modep = mode; return (0); } static int bcm_gpio_pic_map(struct bcm_gpio_softc *sc, struct intr_map_data *data, u_int *irqp, uint32_t *modep) { switch (data->type) { case INTR_MAP_DATA_FDT: return (bcm_gpio_pic_map_fdt(sc, (struct intr_map_data_fdt *)data, irqp, modep)); case INTR_MAP_DATA_GPIO: return (bcm_gpio_pic_map_gpio(sc, (struct intr_map_data_gpio *)data, irqp, modep)); default: return (ENOTSUP); } } static int bcm_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { int error; u_int irq; struct bcm_gpio_softc *sc = device_get_softc(dev); error = bcm_gpio_pic_map(sc, data, &irq, NULL); if (error == 0) *isrcp = &sc->sc_isrcs[irq].bgi_isrc; return (error); } static void bcm_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct bcm_gpio_softc *sc = device_get_softc(dev); struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc; if (bcm_gpio_isrc_is_level(bgi)) bcm_gpio_isrc_eoi(sc, bgi); } static void bcm_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) { bcm_gpio_pic_enable_intr(dev, isrc); } static void bcm_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct bcm_gpio_softc *sc = device_get_softc(dev); struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc; bcm_gpio_isrc_mask(sc, bgi); if (bcm_gpio_isrc_is_level(bgi)) bcm_gpio_isrc_eoi(sc, bgi); } static int bcm_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { u_int irq; uint32_t mode; struct bcm_gpio_softc *sc; struct bcm_gpio_irqsrc *bgi; if (data == NULL) return (ENOTSUP); sc = device_get_softc(dev); bgi = (struct bcm_gpio_irqsrc *)isrc; /* Get and check config for an interrupt. */ if (bcm_gpio_pic_map(sc, data, &irq, &mode) != 0 || bgi->bgi_irq != irq) return (EINVAL); /* * If this is a setup for another handler, * only check that its configuration match. */ if (isrc->isrc_handlers != 0) return (bgi->bgi_mode == mode ? 0 : EINVAL); bcm_gpio_pic_config_intr(sc, bgi, mode); return (0); } static int bcm_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct bcm_gpio_softc *sc = device_get_softc(dev); struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc; if (isrc->isrc_handlers == 0) bcm_gpio_pic_config_intr(sc, bgi, GPIO_INTR_CONFORM); return (0); } -#else -static uint32_t -bcm_gpio_intr_reg(struct bcm_gpio_softc *sc, unsigned int irq, uint32_t bank) -{ - - if (irq > BCM_GPIO_PINS) - return (0); - if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_LEVEL) { - if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) - return (BCM_GPIO_GPLEN(bank)); - else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) - return (BCM_GPIO_GPHEN(bank)); - } else if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_EDGE) { - if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) - return (BCM_GPIO_GPFEN(bank)); - else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) - return (BCM_GPIO_GPREN(bank)); - } - - return (0); -} - -static void -bcm_gpio_mask_irq(void *source) -{ - uint32_t bank, mask, reg; - unsigned int irq; - - irq = (unsigned int)source; - if (irq > BCM_GPIO_PINS) - return; - if (bcm_gpio_pin_is_ro(bcm_gpio_sc, irq)) - return; - bank = BCM_GPIO_BANK(irq); - mask = BCM_GPIO_MASK(irq); - BCM_GPIO_LOCK(bcm_gpio_sc); - reg = bcm_gpio_intr_reg(bcm_gpio_sc, irq, bank); - if (reg != 0) - BCM_GPIO_CLEAR_BITS(bcm_gpio_sc, reg, mask); - BCM_GPIO_UNLOCK(bcm_gpio_sc); -} - -static void -bcm_gpio_unmask_irq(void *source) -{ - uint32_t bank, mask, reg; - unsigned int irq; - - irq = (unsigned int)source; - if (irq > BCM_GPIO_PINS) - return; - if (bcm_gpio_pin_is_ro(bcm_gpio_sc, irq)) - return; - bank = BCM_GPIO_BANK(irq); - mask = BCM_GPIO_MASK(irq); - BCM_GPIO_LOCK(bcm_gpio_sc); - reg = bcm_gpio_intr_reg(bcm_gpio_sc, irq, bank); - if (reg != 0) - BCM_GPIO_SET_BITS(bcm_gpio_sc, reg, mask); - BCM_GPIO_UNLOCK(bcm_gpio_sc); -} - -static int -bcm_gpio_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *res) -{ - int pin; - - if (type != SYS_RES_IRQ) - return (ENXIO); - /* Unmask the interrupt. */ - pin = rman_get_start(res); - bcm_gpio_unmask_irq((void *)pin); - - return (0); -} - -static int -bcm_gpio_deactivate_resource(device_t bus, device_t child, int type, int rid, - struct resource *res) -{ - int pin; - - if (type != SYS_RES_IRQ) - return (ENXIO); - /* Mask the interrupt. */ - pin = rman_get_start(res); - bcm_gpio_mask_irq((void *)pin); - - return (0); -} - -static int -bcm_gpio_config_intr(device_t dev, int irq, enum intr_trigger trig, - enum intr_polarity pol) -{ - int bank; - struct bcm_gpio_softc *sc; - uint32_t mask, oldreg, reg; - - if (irq > BCM_GPIO_PINS) - return (EINVAL); - /* There is no standard trigger or polarity. */ - if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM) - return (EINVAL); - sc = device_get_softc(dev); - if (bcm_gpio_pin_is_ro(sc, irq)) - return (EINVAL); - bank = BCM_GPIO_BANK(irq); - mask = BCM_GPIO_MASK(irq); - BCM_GPIO_LOCK(sc); - oldreg = bcm_gpio_intr_reg(sc, irq, bank); - sc->sc_irq_trigger[irq] = trig; - sc->sc_irq_polarity[irq] = pol; - reg = bcm_gpio_intr_reg(sc, irq, bank); - if (reg != 0) - BCM_GPIO_SET_BITS(sc, reg, mask); - if (reg != oldreg && oldreg != 0) - BCM_GPIO_CLEAR_BITS(sc, oldreg, mask); - BCM_GPIO_UNLOCK(sc); - - return (0); -} - -static int -bcm_gpio_setup_intr(device_t bus, device_t child, struct resource *ires, - int flags, driver_filter_t *filt, driver_intr_t *handler, - void *arg, void **cookiep) -{ - struct bcm_gpio_softc *sc; - struct intr_event *event; - int pin, error; - - sc = device_get_softc(bus); - pin = rman_get_start(ires); - if (pin > BCM_GPIO_PINS) - panic("%s: bad pin %d", __func__, pin); - event = sc->sc_events[pin]; - if (event == NULL) { - error = intr_event_create(&event, (void *)pin, 0, pin, - bcm_gpio_mask_irq, bcm_gpio_unmask_irq, NULL, NULL, - "gpio%d pin%d:", device_get_unit(bus), pin); - if (error != 0) - return (error); - sc->sc_events[pin] = event; - } - intr_event_add_handler(event, device_get_nameunit(child), filt, - handler, arg, intr_priority(flags), flags, cookiep); - - return (0); -} - -static int -bcm_gpio_teardown_intr(device_t dev, device_t child, struct resource *ires, - void *cookie) -{ - struct bcm_gpio_softc *sc; - int pin, err; - - sc = device_get_softc(dev); - pin = rman_get_start(ires); - if (pin > BCM_GPIO_PINS) - panic("%s: bad pin %d", __func__, pin); - if (sc->sc_events[pin] == NULL) - panic("Trying to teardown unoccupied IRQ"); - err = intr_event_remove_handler(cookie); - if (!err) - sc->sc_events[pin] = NULL; - - return (err); -} -#endif - static phandle_t bcm_gpio_get_node(device_t bus, device_t dev) { /* We only have one child, the GPIO bus, which needs our own node. */ return (ofw_bus_get_node(bus)); } static device_method_t bcm_gpio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bcm_gpio_probe), DEVMETHOD(device_attach, bcm_gpio_attach), DEVMETHOD(device_detach, bcm_gpio_detach), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, bcm_gpio_get_bus), DEVMETHOD(gpio_pin_max, bcm_gpio_pin_max), DEVMETHOD(gpio_pin_getname, bcm_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, bcm_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, bcm_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, bcm_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, bcm_gpio_pin_get), DEVMETHOD(gpio_pin_set, bcm_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, bcm_gpio_pin_toggle), -#ifdef INTRNG /* Interrupt controller interface */ DEVMETHOD(pic_disable_intr, bcm_gpio_pic_disable_intr), DEVMETHOD(pic_enable_intr, bcm_gpio_pic_enable_intr), DEVMETHOD(pic_map_intr, bcm_gpio_pic_map_intr), DEVMETHOD(pic_post_filter, bcm_gpio_pic_post_filter), DEVMETHOD(pic_post_ithread, bcm_gpio_pic_post_ithread), DEVMETHOD(pic_pre_ithread, bcm_gpio_pic_pre_ithread), DEVMETHOD(pic_setup_intr, bcm_gpio_pic_setup_intr), DEVMETHOD(pic_teardown_intr, bcm_gpio_pic_teardown_intr), -#else - /* Bus interface */ - DEVMETHOD(bus_activate_resource, bcm_gpio_activate_resource), - DEVMETHOD(bus_deactivate_resource, bcm_gpio_deactivate_resource), - DEVMETHOD(bus_config_intr, bcm_gpio_config_intr), - DEVMETHOD(bus_setup_intr, bcm_gpio_setup_intr), - DEVMETHOD(bus_teardown_intr, bcm_gpio_teardown_intr), -#endif + /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, bcm_gpio_get_node), DEVMETHOD_END }; static devclass_t bcm_gpio_devclass; static driver_t bcm_gpio_driver = { "gpio", bcm_gpio_methods, sizeof(struct bcm_gpio_softc), }; DRIVER_MODULE(bcm_gpio, simplebus, bcm_gpio_driver, bcm_gpio_devclass, 0, 0); Index: head/sys/arm/broadcom/bcm2835/bcm2835_intr.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_intr.c (revision 308443) +++ head/sys/arm/broadcom/bcm2835/bcm2835_intr.c (revision 308444) @@ -1,574 +1,447 @@ /*- * 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 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 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 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 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 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 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 intr_map_data_fdt *daf; struct bcm_intc_softc *sc; bool valid; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); daf = (struct intr_map_data_fdt *)data; if (daf->ncells == 1) irq = daf->cells[0]; else if (daf->ncells == 2) { valid = true; switch (daf->cells[0]) { case 0: irq = daf->cells[1]; if (irq >= BANK1_START) valid = false; break; case 1: irq = daf->cells[1] + BANK1_START; if (irq > BANK1_END) valid = false; break; case 2: irq = daf->cells[1] + BANK2_START; if (irq > BANK2_END) valid = false; break; default: valid = false; break; } if (!valid) { device_printf(dev, "invalid IRQ config: bank=%d, irq=%d\n", daf->cells[0], daf->cells[1]); return (EINVAL); } } 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); } if (intr_pic_register(sc->sc_dev, xref) == NULL) return (ENXIO); return (0); } -#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") && !ofw_bus_is_compatible(dev, "brcm,bcm2836-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 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 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 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; EARLY_DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); - -#ifndef 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/broadcom/bcm2835/bcm2836.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2836.c (revision 308443) +++ head/sys/arm/broadcom/bcm2835/bcm2836.c (revision 308444) @@ -1,913 +1,735 @@ /* * Copyright 2015 Andrew Turner. * Copyright 2016 Svatopluk Kraus * All rights reserved. * * 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 #ifdef SMP #include #endif #include #include #include #ifdef SMP #include #endif #include #include -#ifdef INTRNG #include "pic_if.h" -#else -#include -#define ARM_LOCAL_BASE 0x40000000 -#define ARM_LOCAL_SIZE 0x00001000 - -#define ARM_LOCAL_CONTROL 0x00 -#define ARM_LOCAL_PRESCALER 0x08 -#define PRESCALER_19_2 0x80000000 /* 19.2 MHz */ -#define ARM_LOCAL_INT_TIMER(n) (0x40 + (n) * 4) -#define ARM_LOCAL_INT_MAILBOX(n) (0x50 + (n) * 4) -#define ARM_LOCAL_INT_PENDING(n) (0x60 + (n) * 4) -#define INT_PENDING_MASK 0x011f -#define MAILBOX0_IRQ 4 -#define MAILBOX0_IRQEN (1 << 0) -#endif - -#ifdef INTRNG #define BCM_LINTC_CONTROL_REG 0x00 #define BCM_LINTC_PRESCALER_REG 0x08 #define BCM_LINTC_GPU_ROUTING_REG 0x0c #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10 #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14 #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4) #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4) #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4) #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16) #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16) #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16) #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16) #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16) #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16) #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16) #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16) /* Prescaler Register */ #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */ /* GPU Interrupt Routing Register */ #define BCM_LINTC_GIRR_IRQ_CORE(n) (n) #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2) /* PMU Interrupt Routing Register */ #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n)) #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4)) /* Timer Config Register */ #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n)) #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4)) /* MBOX Config Register */ #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n)) #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4)) #define BCM_LINTC_CNTPSIRQ_IRQ 0 #define BCM_LINTC_CNTPNSIRQ_IRQ 1 #define BCM_LINTC_CNTHPIRQ_IRQ 2 #define BCM_LINTC_CNTVIRQ_IRQ 3 #define BCM_LINTC_MBOX0_IRQ 4 #define BCM_LINTC_MBOX1_IRQ 5 #define BCM_LINTC_MBOX2_IRQ 6 #define BCM_LINTC_MBOX3_IRQ 7 #define BCM_LINTC_GPU_IRQ 8 #define BCM_LINTC_PMU_IRQ 9 #define BCM_LINTC_AXI_IRQ 10 #define BCM_LINTC_LTIMER_IRQ 11 #define BCM_LINTC_NIRQS 12 #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ) #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ) #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ) #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ) #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ) #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ) #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ) #define BCM_LINTC_UP_PENDING_MASK \ (BCM_LINTC_TIMER0_IRQ_MASK | \ BCM_LINTC_TIMER1_IRQ_MASK | \ BCM_LINTC_TIMER2_IRQ_MASK | \ BCM_LINTC_TIMER3_IRQ_MASK | \ BCM_LINTC_GPU_IRQ_MASK | \ BCM_LINTC_PMU_IRQ_MASK) #define BCM_LINTC_SMP_PENDING_MASK \ (BCM_LINTC_UP_PENDING_MASK | \ BCM_LINTC_MBOX0_IRQ_MASK) #ifdef SMP #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK #else #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK #endif struct bcm_lintc_irqsrc { struct intr_irqsrc bli_isrc; u_int bli_irq; union { u_int bli_mask; /* for timers */ u_int bli_value; /* for GPU */ }; }; struct bcm_lintc_softc { device_t bls_dev; struct mtx bls_mtx; struct resource * bls_mem; bus_space_tag_t bls_bst; bus_space_handle_t bls_bsh; struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS]; }; static struct bcm_lintc_softc *bcm_lintc_sc; #ifdef SMP #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */ CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS); #endif #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx) #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx) #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \ device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN) #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx) #define bcm_lintc_read_4(sc, reg) \ bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg)) #define bcm_lintc_write_4(sc, reg, val) \ bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val)) static inline void bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg, uint32_t mask) { bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask); } static inline void bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg, uint32_t mask) { bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask); } static void bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu), bli->bli_mask); BCM_LINTC_UNLOCK(sc); } static void bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu), bli->bli_mask); BCM_LINTC_UNLOCK(sc); } static inline void bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { /* It's accessed just and only by one core. */ bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0); } static inline void bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { /* It's accessed just and only by one core. */ bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value); } static inline void bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu, mask; mask = 0; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); /* Write-clear register. */ bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask); BCM_LINTC_UNLOCK(sc); } static inline void bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu, mask; mask = 0; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); /* Write-set register. */ bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask); BCM_LINTC_UNLOCK(sc); } static void bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { switch (bli->bli_irq) { case BCM_LINTC_TIMER0_IRQ: case BCM_LINTC_TIMER1_IRQ: case BCM_LINTC_TIMER2_IRQ: case BCM_LINTC_TIMER3_IRQ: bcm_lintc_timer_mask(sc, bli); return; case BCM_LINTC_MBOX0_IRQ: case BCM_LINTC_MBOX1_IRQ: case BCM_LINTC_MBOX2_IRQ: case BCM_LINTC_MBOX3_IRQ: return; case BCM_LINTC_GPU_IRQ: bcm_lintc_gpu_mask(sc, bli); return; case BCM_LINTC_PMU_IRQ: bcm_lintc_pmu_mask(sc, bli); return; default: panic("%s: not implemented for irq %u", __func__, bli->bli_irq); } } static void bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { switch (bli->bli_irq) { case BCM_LINTC_TIMER0_IRQ: case BCM_LINTC_TIMER1_IRQ: case BCM_LINTC_TIMER2_IRQ: case BCM_LINTC_TIMER3_IRQ: bcm_lintc_timer_unmask(sc, bli); return; case BCM_LINTC_MBOX0_IRQ: case BCM_LINTC_MBOX1_IRQ: case BCM_LINTC_MBOX2_IRQ: case BCM_LINTC_MBOX3_IRQ: return; case BCM_LINTC_GPU_IRQ: bcm_lintc_gpu_unmask(sc, bli); return; case BCM_LINTC_PMU_IRQ: bcm_lintc_pmu_unmask(sc, bli); return; default: panic("%s: not implemented for irq %u", __func__, bli->bli_irq); } } #ifdef SMP static inline void bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi) { u_int cpu; uint32_t mask; mask = 1 << ipi; for (cpu = 0; cpu < mp_ncpus; cpu++) if (CPU_ISSET(cpu, &cpus)) bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu), mask); } static inline void bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu, struct trapframe *tf) { u_int ipi; uint32_t mask; mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu)); if (mask == 0) { device_printf(sc->bls_dev, "Spurious ipi detected\n"); return; } for (ipi = 0; mask != 0; mask >>= 1, ipi++) { if ((mask & 0x01) == 0) continue; /* * Clear an IPI before dispatching to not miss anyone * and make sure that it's observed by everybody. */ bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi); dsb(); intr_ipi_dispatch(ipi, tf); } } #endif static inline void bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq, struct trapframe *tf) { struct bcm_lintc_irqsrc *bli; bli = &sc->bls_isrcs[irq]; if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0) device_printf(sc->bls_dev, "Stray irq %u detected\n", irq); } static int bcm_lintc_intr(void *arg) { struct bcm_lintc_softc *sc; u_int cpu; uint32_t num, reg; struct trapframe *tf; sc = arg; cpu = PCPU_GET(cpuid); tf = curthread->td_intr_frame; for (num = 0; ; num++) { reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu)); if ((reg & BCM_LINTC_PENDING_MASK) == 0) break; #ifdef SMP if (reg & BCM_LINTC_MBOX0_IRQ_MASK) bcm_lintc_ipi_dispatch(sc, cpu, tf); #endif if (reg & BCM_LINTC_TIMER0_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf); if (reg & BCM_LINTC_TIMER1_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf); if (reg & BCM_LINTC_TIMER2_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf); if (reg & BCM_LINTC_TIMER3_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf); if (reg & BCM_LINTC_GPU_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf); if (reg & BCM_LINTC_PMU_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf); arm_irq_memory_barrier(0); /* XXX */ } reg &= ~BCM_LINTC_PENDING_MASK; if (reg != 0) device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg); else if (num == 0) device_printf(sc->bls_dev, "Spurious interrupt detected\n"); return (FILTER_HANDLED); } static void bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc) { bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc); } static void bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; arm_irq_memory_barrier(bli->bli_irq); bcm_lintc_unmask(device_get_softc(dev), bli); } static int bcm_lintc_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { struct intr_map_data_fdt *daf; struct bcm_lintc_softc *sc; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); daf = (struct intr_map_data_fdt *)data; if (daf->ncells != 1 || daf->cells[0] >= BCM_LINTC_NIRQS) return (EINVAL); sc = device_get_softc(dev); *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc; return (0); } static void bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; if (bli->bli_irq == BCM_LINTC_GPU_IRQ) bcm_lintc_gpu_mask(device_get_softc(dev), bli); else { /* * Handler for PPI interrupt does not make sense much unless * there is one bound ithread for each core for it. Thus the * interrupt can be masked on current core only while ithread * bounded to this core ensures unmasking on the same core. */ panic ("%s: handlers are not supported", __func__); } } static void bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc) { struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; if (bli->bli_irq == BCM_LINTC_GPU_IRQ) bcm_lintc_gpu_unmask(device_get_softc(dev), bli); else { /* See comment in bcm_lintc_pre_ithread(). */ panic ("%s: handlers are not supported", __func__); } } static void bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc) { } static int bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct bcm_lintc_softc *sc; if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) { sc = device_get_softc(dev); BCM_LINTC_LOCK(sc); CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); BCM_LINTC_UNLOCK(sc); } return (0); } #ifdef SMP static void bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq, uint32_t reg, uint32_t mask) { if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu)) bcm_lintc_rwreg_set(sc, reg, mask); } static void bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu) { struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc; if (intr_isrc_init_on_cpu(isrc, cpu)) { /* Write-set register. */ bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, BCM_LINTC_PIRR_IRQ_EN_CORE(cpu)); } } static void bcm_lintc_init_secondary(device_t dev) { u_int cpu; struct bcm_lintc_softc *sc; cpu = PCPU_GET(cpuid); sc = device_get_softc(dev); BCM_LINTC_LOCK(sc); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0)); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1)); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2)); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3)); bcm_lintc_init_pmu_on_ap(sc, cpu); BCM_LINTC_UNLOCK(sc); } static void bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, u_int ipi) { struct bcm_lintc_softc *sc = device_get_softc(dev); KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc, ("%s: bad ISRC %p argument", __func__, isrc)); bcm_lintc_ipi_write(sc, cpus, ipi); } static int bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) { struct bcm_lintc_softc *sc = device_get_softc(dev); KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi)); *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc; return (0); } #endif static int bcm_lintc_pic_attach(struct bcm_lintc_softc *sc) { struct bcm_lintc_irqsrc *bisrcs; struct intr_pic *pic; int error; u_int flags; uint32_t irq; const char *name; intptr_t xref; bisrcs = sc->bls_isrcs; name = device_get_nameunit(sc->bls_dev); for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) { bisrcs[irq].bli_irq = irq; switch (irq) { case BCM_LINTC_TIMER0_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_TIMER1_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_TIMER2_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_TIMER3_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_MBOX0_IRQ: case BCM_LINTC_MBOX1_IRQ: case BCM_LINTC_MBOX2_IRQ: case BCM_LINTC_MBOX3_IRQ: bisrcs[irq].bli_value = 0; /* not used */ flags = INTR_ISRCF_IPI; break; case BCM_LINTC_GPU_IRQ: bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0); flags = 0; break; case BCM_LINTC_PMU_IRQ: bisrcs[irq].bli_value = 0; /* not used */ flags = INTR_ISRCF_PPI; break; default: bisrcs[irq].bli_value = 0; /* not used */ flags = 0; break; } error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev, flags, "%s,%u", name, irq); if (error != 0) return (error); } xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev)); pic = intr_pic_register(sc->bls_dev, xref); if (pic == NULL) return (ENXIO); return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0)); } static int bcm_lintc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc")) return (ENXIO); device_set_desc(dev, "BCM2836 Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static int bcm_lintc_attach(device_t dev) { struct bcm_lintc_softc *sc; int cpu, rid; sc = device_get_softc(dev); sc->bls_dev = dev; if (bcm_lintc_sc != NULL) return (ENXIO); rid = 0; sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->bls_mem == NULL) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } sc->bls_bst = rman_get_bustag(sc->bls_mem); sc->bls_bsh = rman_get_bushandle(sc->bls_mem); bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0); bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2); /* Disable all timers on all cores. */ for (cpu = 0; cpu < 4; cpu++) bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0); #ifdef SMP /* Enable mailbox 0 on all cores used for IPI. */ for (cpu = 0; cpu < 4; cpu++) bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu), BCM_LINTC_MCR_IRQ_EN_MBOX(0)); #endif if (bcm_lintc_pic_attach(sc) != 0) { device_printf(dev, "could not attach PIC\n"); return (ENXIO); } BCM_LINTC_LOCK_INIT(sc); bcm_lintc_sc = sc; return (0); } static device_method_t bcm_lintc_methods[] = { DEVMETHOD(device_probe, bcm_lintc_probe), DEVMETHOD(device_attach, bcm_lintc_attach), DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr), DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr), DEVMETHOD(pic_map_intr, bcm_lintc_map_intr), DEVMETHOD(pic_post_filter, bcm_lintc_post_filter), DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread), DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread), DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr), #ifdef SMP DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary), DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send), DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup), #endif DEVMETHOD_END }; static driver_t bcm_lintc_driver = { "local_intc", bcm_lintc_methods, sizeof(struct bcm_lintc_softc), }; static devclass_t bcm_lintc_devclass; EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); -#else -/* - * A driver for features of the bcm2836. - */ - -struct bcm2836_softc { - device_t sc_dev; - struct resource *sc_mem; -}; - -static device_identify_t bcm2836_identify; -static device_probe_t bcm2836_probe; -static device_attach_t bcm2836_attach; - -struct bcm2836_softc *softc; - -static void -bcm2836_identify(driver_t *driver, device_t parent) -{ - - if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL) - device_printf(parent, "add child failed\n"); -} - -static int -bcm2836_probe(device_t dev) -{ - - if (softc != NULL) - return (ENXIO); - - device_set_desc(dev, "Broadcom bcm2836"); - - return (BUS_PROBE_DEFAULT); -} - -static int -bcm2836_attach(device_t dev) -{ - int i, rid; - - softc = device_get_softc(dev); - softc->sc_dev = dev; - - rid = 0; - softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, - ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE, - RF_ACTIVE); - if (softc->sc_mem == NULL) { - device_printf(dev, "could not allocate memory resource\n"); - return (ENXIO); - } - - bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0); - bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2); - - for (i = 0; i < 4; i++) - bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0); - - for (i = 0; i < 4; i++) - bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1); - - return (0); -} - -int -bcm2836_get_next_irq(int last_irq) -{ - uint32_t reg; - int cpu; - int irq; - - cpu = PCPU_GET(cpuid); - - reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu)); - reg &= INT_PENDING_MASK; - if (reg == 0) - return (-1); - - irq = ffs(reg) - 1; - - return (irq); -} - -void -bcm2836_mask_irq(uintptr_t irq) -{ - uint32_t reg; -#ifdef SMP - int cpu; -#endif - int i; - - if (irq < MAILBOX0_IRQ) { - for (i = 0; i < 4; i++) { - reg = bus_read_4(softc->sc_mem, - ARM_LOCAL_INT_TIMER(i)); - reg &= ~(1 << irq); - bus_write_4(softc->sc_mem, - ARM_LOCAL_INT_TIMER(i), reg); - } -#ifdef SMP - } else if (irq == MAILBOX0_IRQ) { - /* Mailbox 0 for IPI */ - cpu = PCPU_GET(cpuid); - reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu)); - reg &= ~MAILBOX0_IRQEN; - bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg); -#endif - } -} - -void -bcm2836_unmask_irq(uintptr_t irq) -{ - uint32_t reg; -#ifdef SMP - int cpu; -#endif - int i; - - if (irq < MAILBOX0_IRQ) { - for (i = 0; i < 4; i++) { - reg = bus_read_4(softc->sc_mem, - ARM_LOCAL_INT_TIMER(i)); - reg |= (1 << irq); - bus_write_4(softc->sc_mem, - ARM_LOCAL_INT_TIMER(i), reg); - } -#ifdef SMP - } else if (irq == MAILBOX0_IRQ) { - /* Mailbox 0 for IPI */ - cpu = PCPU_GET(cpuid); - reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu)); - reg |= MAILBOX0_IRQEN; - bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg); -#endif - } -} - -static device_method_t bcm2836_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, bcm2836_identify), - DEVMETHOD(device_probe, bcm2836_probe), - DEVMETHOD(device_attach, bcm2836_attach), - - DEVMETHOD_END -}; - -static devclass_t bcm2836_devclass; - -static driver_t bcm2836_driver = { - "bcm2836", - bcm2836_methods, - sizeof(struct bcm2836_softc), -}; - -EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0, - BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); -#endif Index: head/sys/arm/broadcom/bcm2835/bcm2836_mp.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2836_mp.c (revision 308443) +++ head/sys/arm/broadcom/bcm2835/bcm2836_mp.c (revision 308444) @@ -1,184 +1,144 @@ /*- * Copyright (C) 2015 Daisuke Aoyama * All rights reserved. * * 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 * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ printf("%s:%u: ", __func__, __LINE__); \ printf(fmt, ##__VA_ARGS__); \ } while (0) #else #define DPRINTF(fmt, ...) #endif #define ARM_LOCAL_BASE 0x40000000 #define ARM_LOCAL_SIZE 0x00001000 /* mailbox registers */ #define MBOXINTRCTRL_CORE(n) (0x00000050 + (0x04 * (n))) #define MBOX0SET_CORE(n) (0x00000080 + (0x10 * (n))) #define MBOX1SET_CORE(n) (0x00000084 + (0x10 * (n))) #define MBOX2SET_CORE(n) (0x00000088 + (0x10 * (n))) #define MBOX3SET_CORE(n) (0x0000008C + (0x10 * (n))) #define MBOX0CLR_CORE(n) (0x000000C0 + (0x10 * (n))) #define MBOX1CLR_CORE(n) (0x000000C4 + (0x10 * (n))) #define MBOX2CLR_CORE(n) (0x000000C8 + (0x10 * (n))) #define MBOX3CLR_CORE(n) (0x000000CC + (0x10 * (n))) static bus_space_handle_t bs_periph; #define BSRD4(addr) \ bus_space_read_4(fdtbus_bs_tag, bs_periph, (addr)) #define BSWR4(addr, val) \ bus_space_write_4(fdtbus_bs_tag, bs_periph, (addr), (val)) void bcm2836_mp_setmaxid(platform_t plat) { DPRINTF("platform_mp_setmaxid\n"); if (mp_ncpus != 0) return; mp_ncpus = 4; mp_maxid = mp_ncpus - 1; DPRINTF("mp_maxid=%d\n", mp_maxid); } void bcm2836_mp_start_ap(platform_t plat) { uint32_t val; int i, retry; DPRINTF("platform_mp_start_ap\n"); /* initialize */ if (bus_space_map(fdtbus_bs_tag, ARM_LOCAL_BASE, ARM_LOCAL_SIZE, 0, &bs_periph) != 0) panic("can't map local peripheral\n"); for (i = 0; i < mp_ncpus; i++) { /* clear mailbox 0/3 */ BSWR4(MBOX0CLR_CORE(i), 0xffffffff); BSWR4(MBOX3CLR_CORE(i), 0xffffffff); } wmb(); dcache_wbinv_poc_all(); /* boot secondary CPUs */ for (i = 1; i < mp_ncpus; i++) { /* set entry point to mailbox 3 */ BSWR4(MBOX3SET_CORE(i), (uint32_t)pmap_kextract((vm_offset_t)mpentry)); wmb(); /* wait for bootup */ retry = 1000; do { /* check entry point */ val = BSRD4(MBOX3CLR_CORE(i)); if (val == 0) break; DELAY(100); retry--; if (retry <= 0) { printf("can't start for CPU%d\n", i); break; } } while (1); /* dsb and sev */ dsb(); sev(); /* recode AP in CPU map */ CPU_SET(i, &all_cpus); } } - -#ifndef INTRNG -void -pic_ipi_send(cpuset_t cpus, u_int ipi) -{ - int i; - - dsb(); - for (i = 0; i < mp_ncpus; i++) { - if (CPU_ISSET(i, &cpus)) - BSWR4(MBOX0SET_CORE(i), 1 << ipi); - } - wmb(); -} - -int -pic_ipi_read(int i) -{ - uint32_t val; - int cpu, ipi; - - cpu = PCPU_GET(cpuid); - dsb(); - if (i != -1) { - val = BSRD4(MBOX0CLR_CORE(cpu)); - if (val == 0) - return (0); - ipi = ffs(val) - 1; - BSWR4(MBOX0CLR_CORE(cpu), 1 << ipi); - dsb(); - return (ipi); - } - return (0x3ff); -} - -void -pic_ipi_clear(int ipi) -{ -} -#endif Index: head/sys/arm/broadcom/bcm2835/files.bcm283x =================================================================== --- head/sys/arm/broadcom/bcm2835/files.bcm283x (revision 308443) +++ head/sys/arm/broadcom/bcm2835/files.bcm283x (revision 308444) @@ -1,46 +1,45 @@ # $FreeBSD$ arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc -arm/broadcom/bcm2835/bcm2835_common.c optional fdt arm/broadcom/bcm2835/bcm2835_cpufreq.c standard arm/broadcom/bcm2835/bcm2835_dma.c standard arm/broadcom/bcm2835/bcm2835_fb.c optional sc arm/broadcom/bcm2835/bcm2835_fbd.c optional vt arm/broadcom/bcm2835/bcm2835_ft5406.c optional evdev bcm2835_ft5406 arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio arm/broadcom/bcm2835/bcm2835_intr.c standard arm/broadcom/bcm2835/bcm2835_machdep.c optional platform arm/broadcom/bcm2835/bcm2835_mbox.c standard arm/broadcom/bcm2835/bcm2835_rng.c optional random arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi arm/broadcom/bcm2835/bcm2835_vcio.c standard arm/broadcom/bcm2835/bcm2835_wdog.c standard arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt kern/kern_clocksource.c standard dev/mbox/mbox_if.m standard arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" # VideoCore driver contrib/vchiq/interface/compat/vchi_bsd.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c optional vchiq \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_arm.c optional vchiq \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_connected.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_core.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_shim.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_util.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" Index: head/sys/arm/qemu/virt_common.c =================================================================== --- head/sys/arm/qemu/virt_common.c (revision 308443) +++ head/sys/arm/qemu/virt_common.c (nonexistent) @@ -1,45 +0,0 @@ -/*- - * Copyright (c) 2015 Andrew Turner - * All rights reserved. - * - * 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 - -#ifndef INTRNG -fdt_pic_decode_t fdt_pic_table[] = { - &gic_decode_fdt, - NULL -}; -#endif Property changes on: head/sys/arm/qemu/virt_common.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/arm/qemu/files.qemu =================================================================== --- head/sys/arm/qemu/files.qemu (revision 308443) +++ head/sys/arm/qemu/files.qemu (revision 308444) @@ -1,13 +1,12 @@ # $FreeBSD$ # # Standard ARM support. # kern/kern_clocksource.c standard # # Standard qemu virt devices and support. # -arm/qemu/virt_common.c standard arm/qemu/virt_machdep.c standard arm/qemu/virt_mp.c optional smp Index: head/sys/arm/ti/ti_common.c =================================================================== --- head/sys/arm/ti/ti_common.c (revision 308443) +++ head/sys/arm/ti/ti_common.c (nonexistent) @@ -1,80 +0,0 @@ -/*- - * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD. - * All rights reserved. - * - * Developed by Semihalf. - * - * 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. - * 3. Neither the name of MARVELL nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY 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 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 "opt_platform.h" - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#ifndef INTRNG -#ifdef SOC_TI_AM335X -static int -fdt_aintc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, - int *pol) -{ - - if (!fdt_is_compatible(node, "ti,aintc") && - !fdt_is_compatible(node, "ti,am33xx-intc")) - return (ENXIO); - - *interrupt = fdt32_to_cpu(intr[0]); - *trig = INTR_TRIGGER_CONFORM; - *pol = INTR_POLARITY_CONFORM; - - return (0); -} -#endif - -fdt_pic_decode_t fdt_pic_table[] = { -#if defined(SOC_OMAP4) - &gic_decode_fdt, -#endif -#ifdef SOC_TI_AM335X - &fdt_aintc_decode_ic, -#endif - NULL -}; -#endif /* !INTRNG */ Property changes on: head/sys/arm/ti/ti_common.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/arm/ti/aintc.c =================================================================== --- head/sys/arm/ti/aintc.c (revision 308443) +++ head/sys/arm/ti/aintc.c (revision 308444) @@ -1,383 +1,310 @@ /*- * 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 INTRNG #include "pic_if.h" -#endif #define INTC_REVISION 0x00 #define INTC_SYSCONFIG 0x10 #define INTC_SYSSTATUS 0x14 #define INTC_SIR_IRQ 0x40 #define INTC_CONTROL 0x48 #define INTC_THRESHOLD 0x68 #define INTC_MIR_CLEAR(x) (0x88 + ((x) * 0x20)) #define INTC_MIR_SET(x) (0x8C + ((x) * 0x20)) #define INTC_ISR_SET(x) (0x90 + ((x) * 0x20)) #define INTC_ISR_CLEAR(x) (0x94 + ((x) * 0x20)) #define INTC_SIR_SPURIOUS_MASK 0xffffff80 #define INTC_SIR_ACTIVE_MASK 0x7f #define INTC_NIRQS 128 -#ifdef 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 INTRNG struct ti_aintc_irqsrc aintc_isrcs[INTC_NIRQS]; -#endif }; static struct resource_spec ti_aintc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; -static struct ti_aintc_softc *ti_aintc_sc = NULL; - #define aintc_read_4(_sc, reg) \ bus_space_read_4((_sc)->aintc_bst, (_sc)->aintc_bsh, (reg)) #define aintc_write_4(_sc, reg, val) \ bus_space_write_4((_sc)->aintc_bst, (_sc)->aintc_bsh, (reg), (val)) /* List of compatible strings for FDT tree */ static struct ofw_compat_data compat_data[] = { {"ti,am33xx-intc", 1}, {"ti,omap2-intc", 1}, {NULL, 0}, }; -#ifdef 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 &= INTC_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 intr_map_data_fdt *daf; struct ti_aintc_softc *sc; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); daf = (struct intr_map_data_fdt *)data; if (daf->ncells != 1 || daf->cells[0] >= INTC_NIRQS) return (EINVAL); sc = device_get_softc(dev); *isrcp = &sc->aintc_isrcs[daf->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) { struct intr_pic *pic; 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)); pic = intr_pic_register(sc->sc_dev, xref); if (pic == NULL) return (ENXIO); return (intr_pic_claim_root(sc->sc_dev, xref, ti_aintc_intr, sc, 0)); } -#else -static void -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) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "TI AINTC Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static int ti_aintc_attach(device_t dev) { struct ti_aintc_softc *sc = device_get_softc(dev); uint32_t x; sc->sc_dev = dev; - if (ti_aintc_sc) - return (ENXIO); - if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]); sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]); - ti_aintc_sc = sc; - x = aintc_read_4(sc, INTC_REVISION); device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF); /* SoftReset */ aintc_write_4(sc, INTC_SYSCONFIG, 2); /* Wait for reset to complete */ while(!(aintc_read_4(sc, INTC_SYSSTATUS) & 1)); /*Set Priority Threshold */ aintc_write_4(sc, INTC_THRESHOLD, 0xFF); -#ifndef 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 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 } }; static driver_t ti_aintc_driver = { "aintc", ti_aintc_methods, sizeof(struct ti_aintc_softc), }; static devclass_t ti_aintc_devclass; 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 INTRNG -int -arm_get_next_irq(int last_irq) -{ - struct ti_aintc_softc *sc = ti_aintc_sc; - uint32_t active_irq; - - /* Get the next active interrupt */ - active_irq = aintc_read_4(sc, INTC_SIR_IRQ); - - /* Check for spurious interrupt */ - if ((active_irq & 0xffffff80)) { - device_printf(sc->sc_dev, - "Spurious interrupt detected (0x%08x)\n", active_irq); - aintc_write_4(sc, INTC_SIR_IRQ, 0); - return -1; - } - - if (active_irq != last_irq) - return active_irq; - else - return -1; -} - -void -arm_mask_irq(uintptr_t nb) -{ - struct ti_aintc_softc *sc = ti_aintc_sc; - - aintc_write_4(sc, INTC_MIR_SET(nb >> 5), (1UL << (nb & 0x1F))); - aintc_write_4(sc, INTC_CONTROL, 1); /* EOI */ -} - -void -arm_unmask_irq(uintptr_t nb) -{ - struct ti_aintc_softc *sc = ti_aintc_sc; - - arm_irq_memory_barrier(nb); - aintc_write_4(sc, INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F))); -} -#endif Index: head/sys/arm/ti/files.ti =================================================================== --- head/sys/arm/ti/files.ti (revision 308443) +++ head/sys/arm/ti/files.ti (revision 308444) @@ -1,25 +1,24 @@ #$FreeBSD$ kern/kern_clocksource.c standard -arm/ti/ti_common.c standard arm/ti/ti_cpuid.c standard arm/ti/ti_hwmods.c standard arm/ti/ti_machdep.c standard arm/ti/ti_prcm.c standard arm/ti/ti_scm.c standard arm/ti/ti_pinmux.c standard dev/mbox/mbox_if.m optional ti_mbox arm/ti/ti_mbox.c optional ti_mbox arm/ti/ti_pruss.c optional ti_pruss arm/ti/ti_wdt.c optional ti_wdt arm/ti/ti_adc.c optional ti_adc arm/ti/ti_gpio.c optional gpio arm/ti/ti_gpio_if.m optional gpio arm/ti/ti_i2c.c optional ti_i2c arm/ti/ti_sdhci.c optional sdhci arm/ti/ti_spi.c optional ti_spi dev/uart/uart_dev_ti8250.c optional uart dev/uart/uart_dev_ns8250.c optional uart Index: head/sys/arm/ti/ti_gpio.c =================================================================== --- head/sys/arm/ti/ti_gpio.c (revision 308443) +++ head/sys/arm/ti/ti_gpio.c (revision 308444) @@ -1,1379 +1,1083 @@ /*- * Copyright (c) 2011 Ben Gray . * Copyright (c) 2014 Luiz Otavio O Souza . * All rights reserved. * * 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 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 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. */ /** * Beware that the OMAP4 datasheet(s) lists GPIO banks 1-6, whereas the code * here uses 0-5. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio_if.h" #include "ti_gpio_if.h" -#ifdef INTRNG #include "pic_if.h" -#endif #if !defined(SOC_OMAP4) && !defined(SOC_TI_AM335X) #error "Unknown SoC" #endif /* Register definitions */ #define TI_GPIO_REVISION 0x0000 #define TI_GPIO_SYSCONFIG 0x0010 #define TI_GPIO_IRQSTATUS_RAW_0 0x0024 #define TI_GPIO_IRQSTATUS_RAW_1 0x0028 #define TI_GPIO_IRQSTATUS_0 0x002C /* writing a 0 has no effect */ #define TI_GPIO_IRQSTATUS_1 0x0030 /* writing a 0 has no effect */ #define TI_GPIO_IRQSTATUS_SET_0 0x0034 /* writing a 0 has no effect */ #define TI_GPIO_IRQSTATUS_SET_1 0x0038 /* writing a 0 has no effect */ #define TI_GPIO_IRQSTATUS_CLR_0 0x003C /* writing a 0 has no effect */ #define TI_GPIO_IRQSTATUS_CLR_1 0x0040 /* writing a 0 has no effect */ #define TI_GPIO_IRQWAKEN_0 0x0044 #define TI_GPIO_IRQWAKEN_1 0x0048 #define TI_GPIO_SYSSTATUS 0x0114 #define TI_GPIO_IRQSTATUS1 0x0118 #define TI_GPIO_IRQENABLE1 0x011C #define TI_GPIO_WAKEUPENABLE 0x0120 #define TI_GPIO_IRQSTATUS2 0x0128 #define TI_GPIO_IRQENABLE2 0x012C #define TI_GPIO_CTRL 0x0130 #define TI_GPIO_OE 0x0134 #define TI_GPIO_DATAIN 0x0138 #define TI_GPIO_DATAOUT 0x013C #define TI_GPIO_LEVELDETECT0 0x0140 /* RW register */ #define TI_GPIO_LEVELDETECT1 0x0144 /* RW register */ #define TI_GPIO_RISINGDETECT 0x0148 /* RW register */ #define TI_GPIO_FALLINGDETECT 0x014C /* RW register */ #define TI_GPIO_DEBOUNCENABLE 0x0150 #define TI_GPIO_DEBOUNCINGTIME 0x0154 #define TI_GPIO_CLEARWKUPENA 0x0180 #define TI_GPIO_SETWKUENA 0x0184 #define TI_GPIO_CLEARDATAOUT 0x0190 #define TI_GPIO_SETDATAOUT 0x0194 /* Other SoC Specific definitions */ #define OMAP4_FIRST_GPIO_BANK 1 #define OMAP4_INTR_PER_BANK 1 #define OMAP4_GPIO_REV 0x50600801 #define AM335X_FIRST_GPIO_BANK 0 #define AM335X_INTR_PER_BANK 2 #define AM335X_GPIO_REV 0x50600801 #define PINS_PER_BANK 32 #define TI_GPIO_MASK(p) (1U << ((p) % PINS_PER_BANK)) static int ti_gpio_intr(void *arg); static int ti_gpio_detach(device_t); -#ifdef INTRNG static int ti_gpio_pic_attach(struct ti_gpio_softc *sc); static int ti_gpio_pic_detach(struct ti_gpio_softc *sc); -#endif static u_int ti_first_gpio_bank(void) { switch(ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: return (OMAP4_FIRST_GPIO_BANK); #endif #ifdef SOC_TI_AM335X case CHIP_AM335X: return (AM335X_FIRST_GPIO_BANK); #endif } return (0); } static uint32_t ti_gpio_rev(void) { switch(ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: return (OMAP4_GPIO_REV); #endif #ifdef SOC_TI_AM335X case CHIP_AM335X: return (AM335X_GPIO_REV); #endif } return (0); } /** * Macros for driver mutex locking */ #define TI_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) #define TI_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) #define TI_GPIO_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ "ti_gpio", MTX_SPIN) #define TI_GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) #define TI_GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define TI_GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED) /** * ti_gpio_read_4 - reads a 32-bit value from one of the GPIO registers * @sc: GPIO device context * @bank: The bank to read from * @off: The offset of a register from the GPIO register address range * * * RETURNS: * 32-bit value read from the register. */ static inline uint32_t ti_gpio_read_4(struct ti_gpio_softc *sc, bus_size_t off) { return (bus_read_4(sc->sc_mem_res, off)); } /** * ti_gpio_write_4 - writes a 32-bit value to one of the GPIO registers * @sc: GPIO device context * @bank: The bank to write to * @off: The offset of a register from the GPIO register address range * @val: The value to write into the register * * RETURNS: * nothing */ static inline void ti_gpio_write_4(struct ti_gpio_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->sc_mem_res, off, val); } static inline void ti_gpio_intr_clr(struct ti_gpio_softc *sc, uint32_t mask) { /* We clear both set of registers. */ ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_CLR_0, mask); ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_CLR_1, mask); } static inline void ti_gpio_intr_set(struct ti_gpio_softc *sc, uint32_t mask) { /* * On OMAP4 we unmask only the MPU interrupt and on AM335x we * also activate only the first interrupt. */ ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_SET_0, mask); } static inline void ti_gpio_intr_ack(struct ti_gpio_softc *sc, uint32_t mask) { /* * Acknowledge the interrupt on both registers even if we use only * the first one. */ ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_0, mask); ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_1, mask); } static inline uint32_t ti_gpio_intr_status(struct ti_gpio_softc *sc) { uint32_t reg; /* Get the status from both registers. */ reg = ti_gpio_read_4(sc, TI_GPIO_IRQSTATUS_0); reg |= ti_gpio_read_4(sc, TI_GPIO_IRQSTATUS_1); return (reg); } static device_t ti_gpio_get_bus(device_t dev) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); return (sc->sc_busdev); } /** * ti_gpio_pin_max - Returns the maximum number of GPIO pins * @dev: gpio device handle * @maxpin: pointer to a value that upon return will contain the maximum number * of pins in the device. * * * LOCKING: * No locking required, returns static data. * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_max(device_t dev, int *maxpin) { *maxpin = PINS_PER_BANK - 1; return (0); } static int ti_gpio_valid_pin(struct ti_gpio_softc *sc, int pin) { if (pin >= sc->sc_maxpin || sc->sc_mem_res == NULL) return (EINVAL); return (0); } /** * ti_gpio_pin_getcaps - Gets the capabilities of a given pin * @dev: gpio device handle * @pin: the number of the pin * @caps: pointer to a value that upon return will contain the capabilities * * Currently all pins have the same capability, notably: * - GPIO_PIN_INPUT * - GPIO_PIN_OUTPUT * - GPIO_PIN_PULLUP * - GPIO_PIN_PULLDOWN * - GPIO_INTR_LEVEL_LOW * - GPIO_INTR_LEVEL_HIGH * - GPIO_INTR_EDGE_RISING * - GPIO_INTR_EDGE_FALLING * - GPIO_INTR_EDGE_BOTH * * LOCKING: * No locking required, returns static data. * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); -#ifdef INTRNG *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH | GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH); -#else - *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | - GPIO_PIN_PULLDOWN); -#endif return (0); } /** * ti_gpio_pin_getflags - Gets the current flags of a given pin * @dev: gpio device handle * @pin: the number of the pin * @flags: upon return will contain the current flags of the pin * * Reads the current flags of a given pin, here we actually read the H/W * registers to determine the flags, rather than storing the value in the * setflags call. * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Get the current pin state */ TI_GPIO_LOCK(sc); TI_GPIO_GET_FLAGS(dev, pin, flags); TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_getname - Gets the name of a given pin * @dev: gpio device handle * @pin: the number of the pin * @name: buffer to put the name in * * The driver simply calls the pins gpio_n, where 'n' is obviously the number * of the pin. * * LOCKING: * No locking required, returns static data. * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Set a very simple name */ snprintf(name, GPIOMAXNAME, "gpio_%u", pin); name[GPIOMAXNAME - 1] = '\0'; return (0); } /** * ti_gpio_pin_setflags - Sets the flags for a given pin * @dev: gpio device handle * @pin: the number of the pin * @flags: the flags to set * * The flags of the pin correspond to things like input/output mode, pull-ups, * pull-downs, etc. This driver doesn't support all flags, only the following: * - GPIO_PIN_INPUT * - GPIO_PIN_OUTPUT * - GPIO_PIN_PULLUP * - GPIO_PIN_PULLDOWN * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct ti_gpio_softc *sc; uint32_t oe; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Set the GPIO mode and state */ TI_GPIO_LOCK(sc); if (TI_GPIO_SET_FLAGS(dev, pin, flags) != 0) { TI_GPIO_UNLOCK(sc); return (EINVAL); } /* If configuring as an output set the "output enable" bit */ oe = ti_gpio_read_4(sc, TI_GPIO_OE); if (flags & GPIO_PIN_INPUT) oe |= TI_GPIO_MASK(pin); else oe &= ~TI_GPIO_MASK(pin); ti_gpio_write_4(sc, TI_GPIO_OE, oe); TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_set - Sets the current level on a GPIO pin * @dev: gpio device handle * @pin: the number of the pin * @value: non-zero value will drive the pin high, otherwise the pin is * driven low. * * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise a error code */ static int ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct ti_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); TI_GPIO_LOCK(sc); if (value == GPIO_PIN_LOW) reg = TI_GPIO_CLEARDATAOUT; else reg = TI_GPIO_SETDATAOUT; ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_get - Gets the current level on a GPIO pin * @dev: gpio device handle * @pin: the number of the pin * @value: pointer to a value that upond return will contain the pin value * * The pin must be configured as an input pin beforehand, otherwise this * function will fail. * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise a error code */ static int ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) { struct ti_gpio_softc *sc; uint32_t oe, reg, val; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* * Return data from output latch when set as output and from the * input register otherwise. */ TI_GPIO_LOCK(sc); oe = ti_gpio_read_4(sc, TI_GPIO_OE); if (oe & TI_GPIO_MASK(pin)) reg = TI_GPIO_DATAIN; else reg = TI_GPIO_DATAOUT; val = ti_gpio_read_4(sc, reg); *value = (val & TI_GPIO_MASK(pin)) ? 1 : 0; TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_toggle - Toggles a given GPIO pin * @dev: gpio device handle * @pin: the number of the pin * * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise a error code */ static int ti_gpio_pin_toggle(device_t dev, uint32_t pin) { struct ti_gpio_softc *sc; uint32_t reg, val; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Toggle the pin */ TI_GPIO_LOCK(sc); val = ti_gpio_read_4(sc, TI_GPIO_DATAOUT); if (val & TI_GPIO_MASK(pin)) reg = TI_GPIO_CLEARDATAOUT; else reg = TI_GPIO_SETDATAOUT; ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); TI_GPIO_UNLOCK(sc); return (0); } -#ifndef INTRNG -/** - * ti_gpio_intr - ISR for all GPIO modules - * @arg: the soft context pointer - * - * LOCKING: - * Internally locks the context - * - */ static int -ti_gpio_intr(void *arg) -{ - int bank_last, irq; - struct intr_event *event; - struct ti_gpio_softc *sc; - uint32_t reg; - - sc = (struct ti_gpio_softc *)arg; - bank_last = -1; - reg = 0; /* squelch bogus gcc warning */ - reg = ti_gpio_intr_status(sc); - for (irq = 0; irq < sc->sc_maxpin; irq++) { - if ((reg & TI_GPIO_MASK(irq)) == 0) - continue; - event = sc->sc_events[irq]; - if (event != NULL && !TAILQ_EMPTY(&event->ie_handlers)) - intr_event_handle(event, NULL); - else - device_printf(sc->sc_dev, "Stray IRQ %d\n", irq); - /* Ack the IRQ Status bit. */ - ti_gpio_intr_ack(sc, TI_GPIO_MASK(irq)); - } - - return (FILTER_HANDLED); -} -#endif - -static int ti_gpio_bank_init(device_t dev) { int pin; struct ti_gpio_softc *sc; uint32_t flags, reg_oe, reg_set, rev; clk_ident_t clk; sc = device_get_softc(dev); /* Enable the interface and functional clocks for the module. */ clk = ti_hwmods_get_clock(dev); if (clk == INVALID_CLK_IDENT) { device_printf(dev, "failed to get device id based on ti,hwmods\n"); return (EINVAL); } sc->sc_bank = clk - GPIO1_CLK + ti_first_gpio_bank(); ti_prcm_clk_enable(clk); /* * Read the revision number of the module. TI don't publish the * actual revision numbers, so instead the values have been * determined by experimentation. */ rev = ti_gpio_read_4(sc, TI_GPIO_REVISION); /* Check the revision. */ if (rev != ti_gpio_rev()) { device_printf(dev, "Warning: could not determine the revision " "of GPIO module (revision:0x%08x)\n", rev); return (EINVAL); } /* Disable interrupts for all pins. */ ti_gpio_intr_clr(sc, 0xffffffff); /* Init OE register based on pads configuration. */ reg_oe = 0xffffffff; reg_set = 0; for (pin = 0; pin < PINS_PER_BANK; pin++) { TI_GPIO_GET_FLAGS(dev, pin, &flags); if (flags & GPIO_PIN_OUTPUT) { reg_oe &= ~(1UL << pin); if (flags & GPIO_PIN_PULLUP) reg_set |= (1UL << pin); } } ti_gpio_write_4(sc, TI_GPIO_OE, reg_oe); if (reg_set) ti_gpio_write_4(sc, TI_GPIO_SETDATAOUT, reg_set); return (0); } /** * ti_gpio_attach - attach function for the driver * @dev: gpio device handle * * Allocates and sets up the driver context for all GPIO banks. This function * expects the memory ranges and IRQs to already be allocated to the driver. * * LOCKING: * None * * RETURNS: * Always returns 0 */ static int ti_gpio_attach(device_t dev) { struct ti_gpio_softc *sc; -#ifndef INTRNG - unsigned int i; -#endif int err; sc = device_get_softc(dev); sc->sc_dev = dev; TI_GPIO_LOCK_INIT(sc); ti_gpio_pin_max(dev, &sc->sc_maxpin); sc->sc_maxpin++; sc->sc_mem_rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mem_rid, RF_ACTIVE); if (!sc->sc_mem_res) { device_printf(dev, "Error: could not allocate mem resources\n"); ti_gpio_detach(dev); return (ENXIO); } sc->sc_irq_rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irq_rid, RF_ACTIVE); if (!sc->sc_irq_res) { device_printf(dev, "Error: could not allocate irq resources\n"); ti_gpio_detach(dev); return (ENXIO); } /* * Register our interrupt filter for each of the IRQ resources. */ if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, ti_gpio_intr, NULL, sc, &sc->sc_irq_hdl) != 0) { device_printf(dev, "WARNING: unable to register interrupt filter\n"); ti_gpio_detach(dev); return (ENXIO); } -#ifdef INTRNG if (ti_gpio_pic_attach(sc) != 0) { device_printf(dev, "WARNING: unable to attach PIC\n"); ti_gpio_detach(dev); return (ENXIO); } -#else - /* - * Initialize the interrupt settings. The default is active-low - * interrupts. - */ - sc->sc_irq_trigger = malloc( - sizeof(*sc->sc_irq_trigger) * sc->sc_maxpin, - M_DEVBUF, M_WAITOK | M_ZERO); - sc->sc_irq_polarity = malloc( - sizeof(*sc->sc_irq_polarity) * sc->sc_maxpin, - M_DEVBUF, M_WAITOK | M_ZERO); - for (i = 0; i < sc->sc_maxpin; i++) { - sc->sc_irq_trigger[i] = INTR_TRIGGER_LEVEL; - sc->sc_irq_polarity[i] = INTR_POLARITY_LOW; - } - sc->sc_events = malloc(sizeof(struct intr_event *) * sc->sc_maxpin, - M_DEVBUF, M_WAITOK | M_ZERO); - - sc->sc_mask_args = malloc(sizeof(struct ti_gpio_mask_arg) * sc->sc_maxpin, - M_DEVBUF, M_WAITOK | M_ZERO); -#endif /* We need to go through each block and ensure the clocks are running and * the module is enabled. It might be better to do this only when the * pins are configured which would result in less power used if the GPIO * pins weren't used ... */ if (sc->sc_mem_res != NULL) { /* Initialize the GPIO module. */ err = ti_gpio_bank_init(dev); if (err != 0) { ti_gpio_detach(dev); return (err); } } sc->sc_busdev = gpiobus_attach_bus(dev); if (sc->sc_busdev == NULL) { ti_gpio_detach(dev); return (ENXIO); } return (0); } /** * ti_gpio_detach - detach function for the driver * @dev: scm device handle * * Allocates and sets up the driver context, this simply entails creating a * bus mappings for the SCM register set. * * LOCKING: * None * * RETURNS: * Always returns 0 */ static int ti_gpio_detach(device_t dev) { struct ti_gpio_softc *sc = device_get_softc(dev); KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized")); /* Disable all interrupts */ if (sc->sc_mem_res != NULL) ti_gpio_intr_clr(sc, 0xffffffff); gpiobus_detach_bus(dev); -#ifdef INTRNG if (sc->sc_isrcs != NULL) ti_gpio_pic_detach(sc); -#else - if (sc->sc_events) - free(sc->sc_events, M_DEVBUF); - if (sc->sc_mask_args) - free(sc->sc_mask_args, M_DEVBUF); - if (sc->sc_irq_polarity) - free(sc->sc_irq_polarity, M_DEVBUF); - if (sc->sc_irq_trigger) - free(sc->sc_irq_trigger, M_DEVBUF); -#endif /* Release the memory and IRQ resources. */ if (sc->sc_irq_hdl) { bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_hdl); } bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, sc->sc_irq_res); bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, sc->sc_mem_res); TI_GPIO_LOCK_DESTROY(sc); return (0); } -#ifdef INTRNG static inline void ti_gpio_rwreg_modify(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask, bool set_bits) { uint32_t value; value = ti_gpio_read_4(sc, reg); ti_gpio_write_4(sc, reg, set_bits ? value | mask : value & ~mask); } static inline void ti_gpio_isrc_mask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) { /* Writing a 0 has no effect. */ ti_gpio_intr_clr(sc, tgi->tgi_mask); } static inline void ti_gpio_isrc_unmask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) { /* Writing a 0 has no effect. */ ti_gpio_intr_set(sc, tgi->tgi_mask); } static inline void ti_gpio_isrc_eoi(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi) { /* Writing a 0 has no effect. */ ti_gpio_intr_ack(sc, tgi->tgi_mask); } static inline bool ti_gpio_isrc_is_level(struct ti_gpio_irqsrc *tgi) { return (tgi->tgi_mode == GPIO_INTR_LEVEL_LOW || tgi->tgi_mode == GPIO_INTR_LEVEL_HIGH); } static int ti_gpio_intr(void *arg) { u_int irq; uint32_t reg; struct ti_gpio_softc *sc; struct trapframe *tf; struct ti_gpio_irqsrc *tgi; sc = (struct ti_gpio_softc *)arg; tf = curthread->td_intr_frame; reg = ti_gpio_intr_status(sc); for (irq = 0; irq < sc->sc_maxpin; irq++) { tgi = &sc->sc_isrcs[irq]; if ((reg & tgi->tgi_mask) == 0) continue; if (!ti_gpio_isrc_is_level(tgi)) ti_gpio_isrc_eoi(sc, tgi); if (intr_isrc_dispatch(&tgi->tgi_isrc, tf) != 0) { ti_gpio_isrc_mask(sc, tgi); if (ti_gpio_isrc_is_level(tgi)) ti_gpio_isrc_eoi(sc, tgi); device_printf(sc->sc_dev, "Stray irq %u disabled\n", irq); } } return (FILTER_HANDLED); } static int ti_gpio_pic_attach(struct ti_gpio_softc *sc) { int error; uint32_t irq; const char *name; sc->sc_isrcs = malloc(sizeof(*sc->sc_isrcs) * sc->sc_maxpin, M_DEVBUF, M_WAITOK | M_ZERO); name = device_get_nameunit(sc->sc_dev); for (irq = 0; irq < sc->sc_maxpin; irq++) { sc->sc_isrcs[irq].tgi_irq = irq; sc->sc_isrcs[irq].tgi_mask = TI_GPIO_MASK(irq); sc->sc_isrcs[irq].tgi_mode = GPIO_INTR_CONFORM; error = intr_isrc_register(&sc->sc_isrcs[irq].tgi_isrc, sc->sc_dev, 0, "%s,%u", name, irq); if (error != 0) return (error); /* XXX deregister ISRCs */ } if (intr_pic_register(sc->sc_dev, OF_xref_from_node(ofw_bus_get_node(sc->sc_dev))) == NULL) return (ENXIO); return (0); } static int ti_gpio_pic_detach(struct ti_gpio_softc *sc) { /* * There has not been established any procedure yet * how to detach PIC from living system correctly. */ device_printf(sc->sc_dev, "%s: not implemented yet\n", __func__); return (EBUSY); } static void ti_gpio_pic_config_intr(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi, uint32_t mode) { TI_GPIO_LOCK(sc); ti_gpio_rwreg_modify(sc, TI_GPIO_RISINGDETECT, tgi->tgi_mask, mode == GPIO_INTR_EDGE_RISING || mode == GPIO_INTR_EDGE_BOTH); ti_gpio_rwreg_modify(sc, TI_GPIO_FALLINGDETECT, tgi->tgi_mask, mode == GPIO_INTR_EDGE_FALLING || mode == GPIO_INTR_EDGE_BOTH); ti_gpio_rwreg_modify(sc, TI_GPIO_LEVELDETECT1, tgi->tgi_mask, mode == GPIO_INTR_LEVEL_HIGH); ti_gpio_rwreg_modify(sc, TI_GPIO_LEVELDETECT0, tgi->tgi_mask, mode == GPIO_INTR_LEVEL_LOW); tgi->tgi_mode = mode; TI_GPIO_UNLOCK(sc); } static void ti_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct ti_gpio_softc *sc = device_get_softc(dev); struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; ti_gpio_isrc_mask(sc, tgi); } static void ti_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct ti_gpio_softc *sc = device_get_softc(dev); struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; arm_irq_memory_barrier(tgi->tgi_irq); ti_gpio_isrc_unmask(sc, tgi); } static int ti_gpio_pic_map_fdt(struct ti_gpio_softc *sc, struct intr_map_data_fdt *daf, u_int *irqp, uint32_t *modep) { uint32_t mode; /* * The first cell is the interrupt number. * The second cell is used to specify flags: * bits[3:0] trigger type and level flags: * 1 = low-to-high edge triggered. * 2 = high-to-low edge triggered. * 4 = active high level-sensitive. * 8 = active low level-sensitive. */ if (daf->ncells != 2 || daf->cells[0] >= sc->sc_maxpin) return (EINVAL); /* Only reasonable modes are supported. */ if (daf->cells[1] == 1) mode = GPIO_INTR_EDGE_RISING; else if (daf->cells[1] == 2) mode = GPIO_INTR_EDGE_FALLING; else if (daf->cells[1] == 3) mode = GPIO_INTR_EDGE_BOTH; else if (daf->cells[1] == 4) mode = GPIO_INTR_LEVEL_HIGH; else if (daf->cells[1] == 8) mode = GPIO_INTR_LEVEL_LOW; else return (EINVAL); *irqp = daf->cells[0]; if (modep != NULL) *modep = mode; return (0); } static int ti_gpio_pic_map_gpio(struct ti_gpio_softc *sc, struct intr_map_data_gpio *dag, u_int *irqp, uint32_t *modep) { uint32_t mode; if (dag->gpio_pin_num >= sc->sc_maxpin) return (EINVAL); mode = dag->gpio_intr_mode; if (mode != GPIO_INTR_LEVEL_LOW && mode != GPIO_INTR_LEVEL_HIGH && mode != GPIO_INTR_EDGE_RISING && mode != GPIO_INTR_EDGE_FALLING && mode != GPIO_INTR_EDGE_BOTH) return (EINVAL); *irqp = dag->gpio_pin_num; if (modep != NULL) *modep = mode; return (0); } static int ti_gpio_pic_map(struct ti_gpio_softc *sc, struct intr_map_data *data, u_int *irqp, uint32_t *modep) { switch (data->type) { case INTR_MAP_DATA_FDT: return (ti_gpio_pic_map_fdt(sc, (struct intr_map_data_fdt *)data, irqp, modep)); case INTR_MAP_DATA_GPIO: return (ti_gpio_pic_map_gpio(sc, (struct intr_map_data_gpio *)data, irqp, modep)); default: return (ENOTSUP); } } static int ti_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { int error; u_int irq; struct ti_gpio_softc *sc = device_get_softc(dev); error = ti_gpio_pic_map(sc, data, &irq, NULL); if (error == 0) *isrcp = &sc->sc_isrcs[irq].tgi_isrc; return (error); } static void ti_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct ti_gpio_softc *sc = device_get_softc(dev); struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; if (ti_gpio_isrc_is_level(tgi)) ti_gpio_isrc_eoi(sc, tgi); } static void ti_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) { ti_gpio_pic_enable_intr(dev, isrc); } static void ti_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct ti_gpio_softc *sc = device_get_softc(dev); struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; ti_gpio_isrc_mask(sc, tgi); if (ti_gpio_isrc_is_level(tgi)) ti_gpio_isrc_eoi(sc, tgi); } static int ti_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { u_int irq; uint32_t mode; struct ti_gpio_softc *sc; struct ti_gpio_irqsrc *tgi; if (data == NULL) return (ENOTSUP); sc = device_get_softc(dev); tgi = (struct ti_gpio_irqsrc *)isrc; /* Get and check config for an interrupt. */ if (ti_gpio_pic_map(sc, data, &irq, &mode) != 0 || tgi->tgi_irq != irq) return (EINVAL); /* * If this is a setup for another handler, * only check that its configuration match. */ if (isrc->isrc_handlers != 0) return (tgi->tgi_mode == mode ? 0 : EINVAL); ti_gpio_pic_config_intr(sc, tgi, mode); return (0); } static int ti_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct ti_gpio_softc *sc = device_get_softc(dev); struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; if (isrc->isrc_handlers == 0) ti_gpio_pic_config_intr(sc, tgi, GPIO_INTR_CONFORM); return (0); } -#else -static uint32_t -ti_gpio_intr_reg(struct ti_gpio_softc *sc, int irq) -{ - - if (ti_gpio_valid_pin(sc, irq) != 0) - return (0); - - if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_LEVEL) { - if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) - return (TI_GPIO_LEVELDETECT0); - else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) - return (TI_GPIO_LEVELDETECT1); - } else if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_EDGE) { - if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) - return (TI_GPIO_FALLINGDETECT); - else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) - return (TI_GPIO_RISINGDETECT); - } - - return (0); -} - -static void -ti_gpio_mask_irq_internal(struct ti_gpio_softc *sc, int irq) -{ - uint32_t reg, val; - - if (ti_gpio_valid_pin(sc, irq) != 0) - return; - - TI_GPIO_LOCK(sc); - ti_gpio_intr_clr(sc, TI_GPIO_MASK(irq)); - reg = ti_gpio_intr_reg(sc, irq); - if (reg != 0) { - val = ti_gpio_read_4(sc, reg); - val &= ~TI_GPIO_MASK(irq); - ti_gpio_write_4(sc, reg, val); - } - TI_GPIO_UNLOCK(sc); -} - -static void -ti_gpio_unmask_irq_internal(struct ti_gpio_softc *sc, int irq) -{ - uint32_t reg, val; - - if (ti_gpio_valid_pin(sc, irq) != 0) - return; - - TI_GPIO_LOCK(sc); - reg = ti_gpio_intr_reg(sc, irq); - if (reg != 0) { - val = ti_gpio_read_4(sc, reg); - val |= TI_GPIO_MASK(irq); - ti_gpio_write_4(sc, reg, val); - ti_gpio_intr_set(sc, TI_GPIO_MASK(irq)); - } - TI_GPIO_UNLOCK(sc); -} - -static void -ti_gpio_mask_irq(void *source) -{ - struct ti_gpio_mask_arg *arg = source; - - ti_gpio_mask_irq_internal(arg->softc, arg->pin); -} - -static void -ti_gpio_unmask_irq(void *source) -{ - struct ti_gpio_mask_arg *arg = source; - - ti_gpio_unmask_irq_internal(arg->softc, arg->pin); -} - -static int -ti_gpio_activate_resource(device_t dev, device_t child, int type, int rid, - struct resource *res) -{ - struct ti_gpio_mask_arg mask_arg; - - if (type != SYS_RES_IRQ) - return (ENXIO); - - /* Unmask the interrupt. */ - mask_arg.pin = rman_get_start(res); - mask_arg.softc = device_get_softc(dev); - - ti_gpio_unmask_irq((void *)&mask_arg); - - return (0); -} - -static int -ti_gpio_deactivate_resource(device_t dev, device_t child, int type, int rid, - struct resource *res) -{ - int pin; - - if (type != SYS_RES_IRQ) - return (ENXIO); - - /* Mask the interrupt. */ - pin = rman_get_start(res); - ti_gpio_mask_irq((void *)(uintptr_t)pin); - - return (0); -} - -static int -ti_gpio_config_intr(device_t dev, int irq, enum intr_trigger trig, - enum intr_polarity pol) -{ - struct ti_gpio_softc *sc; - uint32_t oldreg, reg, val; - - sc = device_get_softc(dev); - if (ti_gpio_valid_pin(sc, irq) != 0) - return (EINVAL); - - /* There is no standard trigger or polarity. */ - if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM) - return (EINVAL); - - TI_GPIO_LOCK(sc); - /* - * TRM recommends add the new event before remove the old one to - * avoid losing interrupts. - */ - oldreg = ti_gpio_intr_reg(sc, irq); - sc->sc_irq_trigger[irq] = trig; - sc->sc_irq_polarity[irq] = pol; - reg = ti_gpio_intr_reg(sc, irq); - if (reg != 0) { - /* Apply the new settings. */ - val = ti_gpio_read_4(sc, reg); - val |= TI_GPIO_MASK(irq); - ti_gpio_write_4(sc, reg, val); - } - if (reg != oldreg && oldreg != 0) { - /* Remove the old settings. */ - val = ti_gpio_read_4(sc, oldreg); - val &= ~TI_GPIO_MASK(irq); - ti_gpio_write_4(sc, oldreg, val); - } - TI_GPIO_UNLOCK(sc); - - return (0); -} - -static int -ti_gpio_setup_intr(device_t dev, device_t child, struct resource *ires, - int flags, driver_filter_t *filt, driver_intr_t *handler, - void *arg, void **cookiep) -{ - struct ti_gpio_softc *sc; - struct intr_event *event; - int pin, error; - - sc = device_get_softc(dev); - pin = rman_get_start(ires); - if (ti_gpio_valid_pin(sc, pin) != 0) - panic("%s: bad pin %d", __func__, pin); - - event = sc->sc_events[pin]; - if (event == NULL) { - sc->sc_mask_args[pin].softc = sc; - sc->sc_mask_args[pin].pin = pin; - error = intr_event_create(&event, (void *)&sc->sc_mask_args[pin], 0, - pin, ti_gpio_mask_irq, ti_gpio_unmask_irq, NULL, NULL, - "gpio%d pin%d:", device_get_unit(dev), pin); - if (error != 0) - return (error); - sc->sc_events[pin] = event; - } - intr_event_add_handler(event, device_get_nameunit(child), filt, - handler, arg, intr_priority(flags), flags, cookiep); - - return (0); -} - -static int -ti_gpio_teardown_intr(device_t dev, device_t child, struct resource *ires, - void *cookie) -{ - struct ti_gpio_softc *sc; - int pin, err; - - sc = device_get_softc(dev); - pin = rman_get_start(ires); - if (ti_gpio_valid_pin(sc, pin) != 0) - panic("%s: bad pin %d", __func__, pin); - if (sc->sc_events[pin] == NULL) - panic("Trying to teardown unoccupied IRQ"); - err = intr_event_remove_handler(cookie); - if (!err) - sc->sc_events[pin] = NULL; - - return (err); -} -#endif - static phandle_t ti_gpio_get_node(device_t bus, device_t dev) { /* We only have one child, the GPIO bus, which needs our own node. */ return (ofw_bus_get_node(bus)); } static device_method_t ti_gpio_methods[] = { DEVMETHOD(device_attach, ti_gpio_attach), DEVMETHOD(device_detach, ti_gpio_detach), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, ti_gpio_get_bus), DEVMETHOD(gpio_pin_max, ti_gpio_pin_max), DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, ti_gpio_pin_get), DEVMETHOD(gpio_pin_set, ti_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle), -#ifdef INTRNG /* Interrupt controller interface */ DEVMETHOD(pic_disable_intr, ti_gpio_pic_disable_intr), DEVMETHOD(pic_enable_intr, ti_gpio_pic_enable_intr), DEVMETHOD(pic_map_intr, ti_gpio_pic_map_intr), DEVMETHOD(pic_setup_intr, ti_gpio_pic_setup_intr), DEVMETHOD(pic_teardown_intr, ti_gpio_pic_teardown_intr), DEVMETHOD(pic_post_filter, ti_gpio_pic_post_filter), DEVMETHOD(pic_post_ithread, ti_gpio_pic_post_ithread), DEVMETHOD(pic_pre_ithread, ti_gpio_pic_pre_ithread), -#else - /* Bus interface */ - DEVMETHOD(bus_activate_resource, ti_gpio_activate_resource), - DEVMETHOD(bus_deactivate_resource, ti_gpio_deactivate_resource), - DEVMETHOD(bus_config_intr, ti_gpio_config_intr), - DEVMETHOD(bus_setup_intr, ti_gpio_setup_intr), - DEVMETHOD(bus_teardown_intr, ti_gpio_teardown_intr), -#endif /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node), {0, 0}, }; driver_t ti_gpio_driver = { "gpio", ti_gpio_methods, sizeof(struct ti_gpio_softc), }; Index: head/sys/arm/ti/ti_gpio.h =================================================================== --- head/sys/arm/ti/ti_gpio.h (revision 308443) +++ head/sys/arm/ti/ti_gpio.h (revision 308444) @@ -1,88 +1,70 @@ /*- * Copyright (c) 2011 * Ben Gray . * All rights reserved. * * 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 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 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. * * $FreeBSD$ */ #ifndef TI_GPIO_H #define TI_GPIO_H /* The maximum number of banks for any SoC */ #define MAX_GPIO_BANKS 6 /* * Maximum GPIOS possible, max of *_MAX_GPIO_BANKS * *_INTR_PER_BANK. * These are defined in ti_gpio.c */ #define MAX_GPIO_INTRS 8 -#ifndef INTRNG -struct ti_gpio_mask_arg { - void *softc; - int pin; -}; -#else struct ti_gpio_irqsrc { struct intr_irqsrc tgi_isrc; u_int tgi_irq; uint32_t tgi_mask; uint32_t tgi_mode; }; -#endif /** * Structure that stores the driver context. * * This structure is allocated during driver attach. */ struct ti_gpio_softc { device_t sc_dev; device_t sc_busdev; -#ifndef INTRNG - /* Interrupt trigger type and level. */ - enum intr_trigger *sc_irq_trigger; - enum intr_polarity *sc_irq_polarity; -#endif int sc_bank; int sc_maxpin; struct mtx sc_mtx; int sc_mem_rid; struct resource *sc_mem_res; int sc_irq_rid; struct resource *sc_irq_res; -#ifndef INTRNG - /* Interrupt events. */ - struct intr_event **sc_events; - struct ti_gpio_mask_arg *sc_mask_args; -#else struct ti_gpio_irqsrc *sc_isrcs; -#endif /* The handle for the register IRQ handlers. */ void *sc_irq_hdl; }; #endif /* TI_GPIO_H */