11b1a53cfSOleksandr Tymoshenko /*- 21b1a53cfSOleksandr Tymoshenko * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> 31b1a53cfSOleksandr Tymoshenko * All rights reserved. 41b1a53cfSOleksandr Tymoshenko * 51b1a53cfSOleksandr Tymoshenko * Based on OMAP3 INTC code by Ben Gray 61b1a53cfSOleksandr Tymoshenko * 71b1a53cfSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 81b1a53cfSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 91b1a53cfSOleksandr Tymoshenko * are met: 101b1a53cfSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 111b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 121b1a53cfSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 131b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 141b1a53cfSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 151b1a53cfSOleksandr Tymoshenko * 161b1a53cfSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 171b1a53cfSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181b1a53cfSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191b1a53cfSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 201b1a53cfSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211b1a53cfSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221b1a53cfSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231b1a53cfSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241b1a53cfSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251b1a53cfSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261b1a53cfSOleksandr Tymoshenko * SUCH DAMAGE. 271b1a53cfSOleksandr Tymoshenko */ 281b1a53cfSOleksandr Tymoshenko 291b1a53cfSOleksandr Tymoshenko 301b1a53cfSOleksandr Tymoshenko #include <sys/cdefs.h> 311b1a53cfSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 321b1a53cfSOleksandr Tymoshenko 331b1a53cfSOleksandr Tymoshenko #include <sys/param.h> 341b1a53cfSOleksandr Tymoshenko #include <sys/systm.h> 351b1a53cfSOleksandr Tymoshenko #include <sys/bus.h> 361b1a53cfSOleksandr Tymoshenko #include <sys/kernel.h> 371b1a53cfSOleksandr Tymoshenko #include <sys/ktr.h> 381b1a53cfSOleksandr Tymoshenko #include <sys/module.h> 391b1a53cfSOleksandr Tymoshenko #include <sys/rman.h> 401b1a53cfSOleksandr Tymoshenko #include <machine/bus.h> 411b1a53cfSOleksandr Tymoshenko #include <machine/intr.h> 421b1a53cfSOleksandr Tymoshenko 431b1a53cfSOleksandr Tymoshenko #include <dev/fdt/fdt_common.h> 441b1a53cfSOleksandr Tymoshenko #include <dev/ofw/openfirm.h> 451b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h> 461b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h> 471b1a53cfSOleksandr Tymoshenko 481b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BASIC 0x00 491b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BANK1 0x04 501b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BANK2 0x08 511b1a53cfSOleksandr Tymoshenko #define INTC_FIQ_CONTROL 0x0C 521b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BANK1 0x10 531b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BANK2 0x14 541b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BASIC 0x18 551b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BANK1 0x1C 561b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BANK2 0x20 571b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BASIC 0x24 581b1a53cfSOleksandr Tymoshenko 591b1a53cfSOleksandr Tymoshenko #define BANK1_START 8 601b1a53cfSOleksandr Tymoshenko #define BANK1_END (BANK1_START + 32 - 1) 611b1a53cfSOleksandr Tymoshenko #define BANK2_START (BANK1_START + 32) 621b1a53cfSOleksandr Tymoshenko #define BANK2_END (BANK2_START + 32 - 1) 635c657683SHans Petter Selasky #define BANK3_START (BANK2_START + 32) 641b1a53cfSOleksandr Tymoshenko 651b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START)) 661b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END)) 671b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END)) 681b1a53cfSOleksandr Tymoshenko #define IRQ_BANK1(n) ((n) - BANK1_START) 691b1a53cfSOleksandr Tymoshenko #define IRQ_BANK2(n) ((n) - BANK2_START) 701b1a53cfSOleksandr Tymoshenko 711b1a53cfSOleksandr Tymoshenko #ifdef DEBUG 721b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) printf(fmt, ##args) 731b1a53cfSOleksandr Tymoshenko #else 741b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) 751b1a53cfSOleksandr Tymoshenko #endif 761b1a53cfSOleksandr Tymoshenko 771b1a53cfSOleksandr Tymoshenko struct bcm_intc_softc { 781b1a53cfSOleksandr Tymoshenko device_t sc_dev; 791b1a53cfSOleksandr Tymoshenko struct resource * intc_res; 801b1a53cfSOleksandr Tymoshenko bus_space_tag_t intc_bst; 811b1a53cfSOleksandr Tymoshenko bus_space_handle_t intc_bsh; 821b1a53cfSOleksandr Tymoshenko }; 831b1a53cfSOleksandr Tymoshenko 841b1a53cfSOleksandr Tymoshenko static struct bcm_intc_softc *bcm_intc_sc = NULL; 851b1a53cfSOleksandr Tymoshenko 86*171af33cSAndrew Turner #define intc_read_4(_sc, reg) \ 87*171af33cSAndrew Turner bus_space_read_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg)) 88*171af33cSAndrew Turner #define intc_write_4(_sc, reg, val) \ 89*171af33cSAndrew Turner bus_space_write_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg), (val)) 901b1a53cfSOleksandr Tymoshenko 911b1a53cfSOleksandr Tymoshenko static int 921b1a53cfSOleksandr Tymoshenko bcm_intc_probe(device_t dev) 931b1a53cfSOleksandr Tymoshenko { 94add35ed5SIan Lepore 95add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 96add35ed5SIan Lepore return (ENXIO); 97add35ed5SIan Lepore 981b1a53cfSOleksandr Tymoshenko if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-armctrl-ic")) 991b1a53cfSOleksandr Tymoshenko return (ENXIO); 1001b1a53cfSOleksandr Tymoshenko device_set_desc(dev, "BCM2835 Interrupt Controller"); 1011b1a53cfSOleksandr Tymoshenko return (BUS_PROBE_DEFAULT); 1021b1a53cfSOleksandr Tymoshenko } 1031b1a53cfSOleksandr Tymoshenko 1041b1a53cfSOleksandr Tymoshenko static int 1051b1a53cfSOleksandr Tymoshenko bcm_intc_attach(device_t dev) 1061b1a53cfSOleksandr Tymoshenko { 1071b1a53cfSOleksandr Tymoshenko struct bcm_intc_softc *sc = device_get_softc(dev); 1081b1a53cfSOleksandr Tymoshenko int rid = 0; 1091b1a53cfSOleksandr Tymoshenko 1101b1a53cfSOleksandr Tymoshenko sc->sc_dev = dev; 1111b1a53cfSOleksandr Tymoshenko 1121b1a53cfSOleksandr Tymoshenko if (bcm_intc_sc) 1131b1a53cfSOleksandr Tymoshenko return (ENXIO); 1141b1a53cfSOleksandr Tymoshenko 1151b1a53cfSOleksandr Tymoshenko sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 1161b1a53cfSOleksandr Tymoshenko if (sc->intc_res == NULL) { 1171b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate memory resource\n"); 1181b1a53cfSOleksandr Tymoshenko return (ENXIO); 1191b1a53cfSOleksandr Tymoshenko } 1201b1a53cfSOleksandr Tymoshenko 1211b1a53cfSOleksandr Tymoshenko sc->intc_bst = rman_get_bustag(sc->intc_res); 1221b1a53cfSOleksandr Tymoshenko sc->intc_bsh = rman_get_bushandle(sc->intc_res); 1231b1a53cfSOleksandr Tymoshenko 1241b1a53cfSOleksandr Tymoshenko bcm_intc_sc = sc; 1251b1a53cfSOleksandr Tymoshenko 1261b1a53cfSOleksandr Tymoshenko return (0); 1271b1a53cfSOleksandr Tymoshenko } 1281b1a53cfSOleksandr Tymoshenko 1291b1a53cfSOleksandr Tymoshenko static device_method_t bcm_intc_methods[] = { 1301b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_probe, bcm_intc_probe), 1311b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_attach, bcm_intc_attach), 1321b1a53cfSOleksandr Tymoshenko { 0, 0 } 1331b1a53cfSOleksandr Tymoshenko }; 1341b1a53cfSOleksandr Tymoshenko 1351b1a53cfSOleksandr Tymoshenko static driver_t bcm_intc_driver = { 1361b1a53cfSOleksandr Tymoshenko "intc", 1371b1a53cfSOleksandr Tymoshenko bcm_intc_methods, 1381b1a53cfSOleksandr Tymoshenko sizeof(struct bcm_intc_softc), 1391b1a53cfSOleksandr Tymoshenko }; 1401b1a53cfSOleksandr Tymoshenko 1411b1a53cfSOleksandr Tymoshenko static devclass_t bcm_intc_devclass; 1421b1a53cfSOleksandr Tymoshenko 1431b1a53cfSOleksandr Tymoshenko DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 0, 0); 1441b1a53cfSOleksandr Tymoshenko 1451b1a53cfSOleksandr Tymoshenko int 1461b1a53cfSOleksandr Tymoshenko arm_get_next_irq(int last_irq) 1471b1a53cfSOleksandr Tymoshenko { 148*171af33cSAndrew Turner struct bcm_intc_softc *sc = bcm_intc_sc; 1491b1a53cfSOleksandr Tymoshenko uint32_t pending; 1501b1a53cfSOleksandr Tymoshenko int32_t irq = last_irq + 1; 1511b1a53cfSOleksandr Tymoshenko 1521b1a53cfSOleksandr Tymoshenko /* Sanity check */ 1531b1a53cfSOleksandr Tymoshenko if (irq < 0) 1541b1a53cfSOleksandr Tymoshenko irq = 0; 1551b1a53cfSOleksandr Tymoshenko 1561b1a53cfSOleksandr Tymoshenko /* TODO: should we mask last_irq? */ 1575c657683SHans Petter Selasky if (irq < BANK1_START) { 158*171af33cSAndrew Turner pending = intc_read_4(sc, INTC_PENDING_BASIC); 1595c657683SHans Petter Selasky if ((pending & 0xFF) == 0) { 1605c657683SHans Petter Selasky irq = BANK1_START; /* skip to next bank */ 1615c657683SHans Petter Selasky } else do { 1621b1a53cfSOleksandr Tymoshenko if (pending & (1 << irq)) 1631b1a53cfSOleksandr Tymoshenko return irq; 1641b1a53cfSOleksandr Tymoshenko irq++; 1655c657683SHans Petter Selasky } while (irq < BANK1_START); 1661b1a53cfSOleksandr Tymoshenko } 1675c657683SHans Petter Selasky if (irq < BANK2_START) { 168*171af33cSAndrew Turner pending = intc_read_4(sc, INTC_PENDING_BANK1); 1695c657683SHans Petter Selasky if (pending == 0) { 1705c657683SHans Petter Selasky irq = BANK2_START; /* skip to next bank */ 1715c657683SHans Petter Selasky } else do { 1721b1a53cfSOleksandr Tymoshenko if (pending & (1 << IRQ_BANK1(irq))) 1731b1a53cfSOleksandr Tymoshenko return irq; 1741b1a53cfSOleksandr Tymoshenko irq++; 1755c657683SHans Petter Selasky } while (irq < BANK2_START); 1761b1a53cfSOleksandr Tymoshenko } 1775c657683SHans Petter Selasky if (irq < BANK3_START) { 178*171af33cSAndrew Turner pending = intc_read_4(sc, INTC_PENDING_BANK2); 1795c657683SHans Petter Selasky if (pending != 0) do { 1801b1a53cfSOleksandr Tymoshenko if (pending & (1 << IRQ_BANK2(irq))) 1811b1a53cfSOleksandr Tymoshenko return irq; 1821b1a53cfSOleksandr Tymoshenko irq++; 1835c657683SHans Petter Selasky } while (irq < BANK3_START); 1841b1a53cfSOleksandr Tymoshenko } 1851b1a53cfSOleksandr Tymoshenko return (-1); 1861b1a53cfSOleksandr Tymoshenko } 1871b1a53cfSOleksandr Tymoshenko 1881b1a53cfSOleksandr Tymoshenko void 1891b1a53cfSOleksandr Tymoshenko arm_mask_irq(uintptr_t nb) 1901b1a53cfSOleksandr Tymoshenko { 191*171af33cSAndrew Turner struct bcm_intc_softc *sc = bcm_intc_sc; 1921b1a53cfSOleksandr Tymoshenko dprintf("%s: %d\n", __func__, nb); 1931b1a53cfSOleksandr Tymoshenko 1941b1a53cfSOleksandr Tymoshenko if (IS_IRQ_BASIC(nb)) 195*171af33cSAndrew Turner intc_write_4(sc, INTC_DISABLE_BASIC, (1 << nb)); 1961b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK1(nb)) 197*171af33cSAndrew Turner intc_write_4(sc, INTC_DISABLE_BANK1, (1 << IRQ_BANK1(nb))); 1981b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK2(nb)) 199*171af33cSAndrew Turner intc_write_4(sc, INTC_DISABLE_BANK2, (1 << IRQ_BANK2(nb))); 2001b1a53cfSOleksandr Tymoshenko else 2011b1a53cfSOleksandr Tymoshenko printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); 2021b1a53cfSOleksandr Tymoshenko } 2031b1a53cfSOleksandr Tymoshenko 2041b1a53cfSOleksandr Tymoshenko void 2051b1a53cfSOleksandr Tymoshenko arm_unmask_irq(uintptr_t nb) 2061b1a53cfSOleksandr Tymoshenko { 207*171af33cSAndrew Turner struct bcm_intc_softc *sc = bcm_intc_sc; 2081b1a53cfSOleksandr Tymoshenko dprintf("%s: %d\n", __func__, nb); 2091b1a53cfSOleksandr Tymoshenko 2101b1a53cfSOleksandr Tymoshenko if (IS_IRQ_BASIC(nb)) 211*171af33cSAndrew Turner intc_write_4(sc, INTC_ENABLE_BASIC, (1 << nb)); 2121b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK1(nb)) 213*171af33cSAndrew Turner intc_write_4(sc, INTC_ENABLE_BANK1, (1 << IRQ_BANK1(nb))); 2141b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK2(nb)) 215*171af33cSAndrew Turner intc_write_4(sc, INTC_ENABLE_BANK2, (1 << IRQ_BANK2(nb))); 2161b1a53cfSOleksandr Tymoshenko else 2171b1a53cfSOleksandr Tymoshenko printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); 2181b1a53cfSOleksandr Tymoshenko } 219