11b1a53cfSOleksandr Tymoshenko /*- 2*af3dc4a7SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*af3dc4a7SPedro F. Giffuni * 41b1a53cfSOleksandr Tymoshenko * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> 51b1a53cfSOleksandr Tymoshenko * All rights reserved. 61b1a53cfSOleksandr Tymoshenko * 71b1a53cfSOleksandr Tymoshenko * Based on OMAP3 INTC code by Ben Gray 81b1a53cfSOleksandr Tymoshenko * 91b1a53cfSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 101b1a53cfSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 111b1a53cfSOleksandr Tymoshenko * are met: 121b1a53cfSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 131b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 141b1a53cfSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 151b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 161b1a53cfSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 171b1a53cfSOleksandr Tymoshenko * 181b1a53cfSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 191b1a53cfSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 201b1a53cfSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 211b1a53cfSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 221b1a53cfSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 231b1a53cfSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 241b1a53cfSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 251b1a53cfSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 261b1a53cfSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 271b1a53cfSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 281b1a53cfSOleksandr Tymoshenko * SUCH DAMAGE. 291b1a53cfSOleksandr Tymoshenko */ 301b1a53cfSOleksandr Tymoshenko 311b1a53cfSOleksandr Tymoshenko 321b1a53cfSOleksandr Tymoshenko #include <sys/cdefs.h> 331b1a53cfSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 341b1a53cfSOleksandr Tymoshenko 35472f2ccaSSvatopluk Kraus #include "opt_platform.h" 36472f2ccaSSvatopluk Kraus 371b1a53cfSOleksandr Tymoshenko #include <sys/param.h> 381b1a53cfSOleksandr Tymoshenko #include <sys/systm.h> 391b1a53cfSOleksandr Tymoshenko #include <sys/bus.h> 401b1a53cfSOleksandr Tymoshenko #include <sys/kernel.h> 411b1a53cfSOleksandr Tymoshenko #include <sys/ktr.h> 421b1a53cfSOleksandr Tymoshenko #include <sys/module.h> 43472f2ccaSSvatopluk Kraus #include <sys/proc.h> 441b1a53cfSOleksandr Tymoshenko #include <sys/rman.h> 451b1a53cfSOleksandr Tymoshenko #include <machine/bus.h> 461b1a53cfSOleksandr Tymoshenko #include <machine/intr.h> 471b1a53cfSOleksandr Tymoshenko 481b1a53cfSOleksandr Tymoshenko #include <dev/ofw/openfirm.h> 491b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h> 501b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h> 511b1a53cfSOleksandr Tymoshenko 52472f2ccaSSvatopluk Kraus #include "pic_if.h" 53472f2ccaSSvatopluk Kraus 541b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BASIC 0x00 551b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BANK1 0x04 561b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BANK2 0x08 571b1a53cfSOleksandr Tymoshenko #define INTC_FIQ_CONTROL 0x0C 581b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BANK1 0x10 591b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BANK2 0x14 601b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BASIC 0x18 611b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BANK1 0x1C 621b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BANK2 0x20 631b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BASIC 0x24 641b1a53cfSOleksandr Tymoshenko 65472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_ARM 0x0000FF 66472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU1_PEND 0x000100 67472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_PEND 0x000200 68472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU1_7 0x000400 69472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU1_9 0x000800 70472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU1_10 0x001000 71472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU1_18 0x002000 72472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU1_19 0x004000 73472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_21 0x008000 74472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_22 0x010000 75472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_23 0x020000 76472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_24 0x040000 77472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_25 0x080000 78472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_30 0x100000 79472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_MASK 0x1FFFFF 80472f2ccaSSvatopluk Kraus 81472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU1_MASK (INTC_PENDING_BASIC_GPU1_7 | \ 82472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU1_9 | \ 83472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU1_10 | \ 84472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU1_18 | \ 85472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU1_19) 86472f2ccaSSvatopluk Kraus 87472f2ccaSSvatopluk Kraus #define INTC_PENDING_BASIC_GPU2_MASK (INTC_PENDING_BASIC_GPU2_21 | \ 88472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU2_22 | \ 89472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU2_23 | \ 90472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU2_24 | \ 91472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU2_25 | \ 92472f2ccaSSvatopluk Kraus INTC_PENDING_BASIC_GPU2_30) 93472f2ccaSSvatopluk Kraus 94472f2ccaSSvatopluk Kraus #define INTC_PENDING_BANK1_MASK (~((1 << 7) | (1 << 9) | (1 << 10) | \ 95472f2ccaSSvatopluk Kraus (1 << 18) | (1 << 19))) 96472f2ccaSSvatopluk Kraus #define INTC_PENDING_BANK2_MASK (~((1 << 21) | (1 << 22) | (1 << 23) | \ 97472f2ccaSSvatopluk Kraus (1 << 24) | (1 << 25) | (1 << 30))) 98472f2ccaSSvatopluk Kraus 991b1a53cfSOleksandr Tymoshenko #define BANK1_START 8 1001b1a53cfSOleksandr Tymoshenko #define BANK1_END (BANK1_START + 32 - 1) 1011b1a53cfSOleksandr Tymoshenko #define BANK2_START (BANK1_START + 32) 1021b1a53cfSOleksandr Tymoshenko #define BANK2_END (BANK2_START + 32 - 1) 1031b1a53cfSOleksandr Tymoshenko 1041b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START)) 1051b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END)) 1061b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END)) 1071b1a53cfSOleksandr Tymoshenko #define IRQ_BANK1(n) ((n) - BANK1_START) 1081b1a53cfSOleksandr Tymoshenko #define IRQ_BANK2(n) ((n) - BANK2_START) 1091b1a53cfSOleksandr Tymoshenko 1101b1a53cfSOleksandr Tymoshenko #ifdef DEBUG 1111b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) printf(fmt, ##args) 1121b1a53cfSOleksandr Tymoshenko #else 1131b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) 1141b1a53cfSOleksandr Tymoshenko #endif 1151b1a53cfSOleksandr Tymoshenko 116472f2ccaSSvatopluk Kraus #define BCM_INTC_NIRQS 72 /* 8 + 32 + 32 */ 117472f2ccaSSvatopluk Kraus 118472f2ccaSSvatopluk Kraus struct bcm_intc_irqsrc { 119472f2ccaSSvatopluk Kraus struct intr_irqsrc bii_isrc; 120472f2ccaSSvatopluk Kraus u_int bii_irq; 121472f2ccaSSvatopluk Kraus uint16_t bii_disable_reg; 122472f2ccaSSvatopluk Kraus uint16_t bii_enable_reg; 123472f2ccaSSvatopluk Kraus uint32_t bii_mask; 124472f2ccaSSvatopluk Kraus }; 125472f2ccaSSvatopluk Kraus 1261b1a53cfSOleksandr Tymoshenko struct bcm_intc_softc { 1271b1a53cfSOleksandr Tymoshenko device_t sc_dev; 1281b1a53cfSOleksandr Tymoshenko struct resource * intc_res; 1291b1a53cfSOleksandr Tymoshenko bus_space_tag_t intc_bst; 1301b1a53cfSOleksandr Tymoshenko bus_space_handle_t intc_bsh; 131472f2ccaSSvatopluk Kraus struct resource * intc_irq_res; 132472f2ccaSSvatopluk Kraus void * intc_irq_hdl; 133472f2ccaSSvatopluk Kraus struct bcm_intc_irqsrc intc_isrcs[BCM_INTC_NIRQS]; 1341b1a53cfSOleksandr Tymoshenko }; 1351b1a53cfSOleksandr Tymoshenko 1361b1a53cfSOleksandr Tymoshenko static struct bcm_intc_softc *bcm_intc_sc = NULL; 1371b1a53cfSOleksandr Tymoshenko 138171af33cSAndrew Turner #define intc_read_4(_sc, reg) \ 139171af33cSAndrew Turner bus_space_read_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg)) 140171af33cSAndrew Turner #define intc_write_4(_sc, reg, val) \ 141171af33cSAndrew Turner bus_space_write_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg), (val)) 1421b1a53cfSOleksandr Tymoshenko 143472f2ccaSSvatopluk Kraus static inline void 144472f2ccaSSvatopluk Kraus bcm_intc_isrc_mask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) 145472f2ccaSSvatopluk Kraus { 146472f2ccaSSvatopluk Kraus 147472f2ccaSSvatopluk Kraus intc_write_4(sc, bii->bii_disable_reg, bii->bii_mask); 148472f2ccaSSvatopluk Kraus } 149472f2ccaSSvatopluk Kraus 150472f2ccaSSvatopluk Kraus static inline void 151472f2ccaSSvatopluk Kraus bcm_intc_isrc_unmask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) 152472f2ccaSSvatopluk Kraus { 153472f2ccaSSvatopluk Kraus 154472f2ccaSSvatopluk Kraus intc_write_4(sc, bii->bii_enable_reg, bii->bii_mask); 155472f2ccaSSvatopluk Kraus } 156472f2ccaSSvatopluk Kraus 157472f2ccaSSvatopluk Kraus static inline int 158472f2ccaSSvatopluk Kraus bcm2835_intc_active_intr(struct bcm_intc_softc *sc) 159472f2ccaSSvatopluk Kraus { 160472f2ccaSSvatopluk Kraus uint32_t pending, pending_gpu; 161472f2ccaSSvatopluk Kraus 162472f2ccaSSvatopluk Kraus pending = intc_read_4(sc, INTC_PENDING_BASIC) & INTC_PENDING_BASIC_MASK; 163472f2ccaSSvatopluk Kraus if (pending == 0) 164472f2ccaSSvatopluk Kraus return (-1); 165472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_ARM) 166472f2ccaSSvatopluk Kraus return (ffs(pending) - 1); 167472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_MASK) { 168472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_7) 169472f2ccaSSvatopluk Kraus return (BANK1_START + 7); 170472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_9) 171472f2ccaSSvatopluk Kraus return (BANK1_START + 9); 172472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_10) 173472f2ccaSSvatopluk Kraus return (BANK1_START + 10); 174472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_18) 175472f2ccaSSvatopluk Kraus return (BANK1_START + 18); 176472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_19) 177472f2ccaSSvatopluk Kraus return (BANK1_START + 19); 178472f2ccaSSvatopluk Kraus } 179472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_MASK) { 180472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_21) 181472f2ccaSSvatopluk Kraus return (BANK2_START + 21); 182472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_22) 183472f2ccaSSvatopluk Kraus return (BANK2_START + 22); 184472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_23) 185472f2ccaSSvatopluk Kraus return (BANK2_START + 23); 186472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_24) 187472f2ccaSSvatopluk Kraus return (BANK2_START + 24); 188472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_25) 189472f2ccaSSvatopluk Kraus return (BANK2_START + 25); 190472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_30) 191472f2ccaSSvatopluk Kraus return (BANK2_START + 30); 192472f2ccaSSvatopluk Kraus } 193472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_PEND) { 194472f2ccaSSvatopluk Kraus pending_gpu = intc_read_4(sc, INTC_PENDING_BANK1); 195472f2ccaSSvatopluk Kraus pending_gpu &= INTC_PENDING_BANK1_MASK; 196472f2ccaSSvatopluk Kraus if (pending_gpu != 0) 197472f2ccaSSvatopluk Kraus return (BANK1_START + ffs(pending_gpu) - 1); 198472f2ccaSSvatopluk Kraus } 199472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_PEND) { 200472f2ccaSSvatopluk Kraus pending_gpu = intc_read_4(sc, INTC_PENDING_BANK2); 201472f2ccaSSvatopluk Kraus pending_gpu &= INTC_PENDING_BANK2_MASK; 202472f2ccaSSvatopluk Kraus if (pending_gpu != 0) 203472f2ccaSSvatopluk Kraus return (BANK2_START + ffs(pending_gpu) - 1); 204472f2ccaSSvatopluk Kraus } 205472f2ccaSSvatopluk Kraus return (-1); /* It shouldn't end here, but it's hardware. */ 206472f2ccaSSvatopluk Kraus } 207472f2ccaSSvatopluk Kraus 208472f2ccaSSvatopluk Kraus static int 209472f2ccaSSvatopluk Kraus bcm2835_intc_intr(void *arg) 210472f2ccaSSvatopluk Kraus { 211472f2ccaSSvatopluk Kraus int irq, num; 212472f2ccaSSvatopluk Kraus struct bcm_intc_softc *sc = arg; 213472f2ccaSSvatopluk Kraus 214472f2ccaSSvatopluk Kraus for (num = 0; ; num++) { 215472f2ccaSSvatopluk Kraus irq = bcm2835_intc_active_intr(sc); 216472f2ccaSSvatopluk Kraus if (irq == -1) 217472f2ccaSSvatopluk Kraus break; 218472f2ccaSSvatopluk Kraus if (intr_isrc_dispatch(&sc->intc_isrcs[irq].bii_isrc, 219472f2ccaSSvatopluk Kraus curthread->td_intr_frame) != 0) { 220472f2ccaSSvatopluk Kraus bcm_intc_isrc_mask(sc, &sc->intc_isrcs[irq]); 221472f2ccaSSvatopluk Kraus device_printf(sc->sc_dev, "Stray irq %u disabled\n", 222472f2ccaSSvatopluk Kraus irq); 223472f2ccaSSvatopluk Kraus } 224472f2ccaSSvatopluk Kraus arm_irq_memory_barrier(0); /* XXX */ 225472f2ccaSSvatopluk Kraus } 226472f2ccaSSvatopluk Kraus if (num == 0) 227472f2ccaSSvatopluk Kraus device_printf(sc->sc_dev, "Spurious interrupt detected\n"); 228472f2ccaSSvatopluk Kraus 229472f2ccaSSvatopluk Kraus return (FILTER_HANDLED); 230472f2ccaSSvatopluk Kraus } 231472f2ccaSSvatopluk Kraus 232472f2ccaSSvatopluk Kraus static void 233472f2ccaSSvatopluk Kraus bcm_intc_enable_intr(device_t dev, struct intr_irqsrc *isrc) 234472f2ccaSSvatopluk Kraus { 235472f2ccaSSvatopluk Kraus struct bcm_intc_irqsrc *bii = (struct bcm_intc_irqsrc *)isrc; 236472f2ccaSSvatopluk Kraus 237472f2ccaSSvatopluk Kraus arm_irq_memory_barrier(bii->bii_irq); 238472f2ccaSSvatopluk Kraus bcm_intc_isrc_unmask(device_get_softc(dev), bii); 239472f2ccaSSvatopluk Kraus } 240472f2ccaSSvatopluk Kraus 241472f2ccaSSvatopluk Kraus static void 242472f2ccaSSvatopluk Kraus bcm_intc_disable_intr(device_t dev, struct intr_irqsrc *isrc) 243472f2ccaSSvatopluk Kraus { 244472f2ccaSSvatopluk Kraus 245472f2ccaSSvatopluk Kraus bcm_intc_isrc_mask(device_get_softc(dev), 246472f2ccaSSvatopluk Kraus (struct bcm_intc_irqsrc *)isrc); 247472f2ccaSSvatopluk Kraus } 248472f2ccaSSvatopluk Kraus 249472f2ccaSSvatopluk Kraus static int 250472f2ccaSSvatopluk Kraus bcm_intc_map_intr(device_t dev, struct intr_map_data *data, 251472f2ccaSSvatopluk Kraus struct intr_irqsrc **isrcp) 252472f2ccaSSvatopluk Kraus { 253472f2ccaSSvatopluk Kraus u_int irq; 254cd642c88SSvatopluk Kraus struct intr_map_data_fdt *daf; 255472f2ccaSSvatopluk Kraus struct bcm_intc_softc *sc; 25698884a9eSOleksandr Tymoshenko bool valid; 257472f2ccaSSvatopluk Kraus 258472f2ccaSSvatopluk Kraus if (data->type != INTR_MAP_DATA_FDT) 259472f2ccaSSvatopluk Kraus return (ENOTSUP); 260cd642c88SSvatopluk Kraus 261cd642c88SSvatopluk Kraus daf = (struct intr_map_data_fdt *)data; 262cd642c88SSvatopluk Kraus if (daf->ncells == 1) 263cd642c88SSvatopluk Kraus irq = daf->cells[0]; 26498884a9eSOleksandr Tymoshenko else if (daf->ncells == 2) { 26598884a9eSOleksandr Tymoshenko valid = true; 26698884a9eSOleksandr Tymoshenko switch (daf->cells[0]) { 26798884a9eSOleksandr Tymoshenko case 0: 26898884a9eSOleksandr Tymoshenko irq = daf->cells[1]; 26998884a9eSOleksandr Tymoshenko if (irq >= BANK1_START) 27098884a9eSOleksandr Tymoshenko valid = false; 27198884a9eSOleksandr Tymoshenko break; 27298884a9eSOleksandr Tymoshenko case 1: 27398884a9eSOleksandr Tymoshenko irq = daf->cells[1] + BANK1_START; 27498884a9eSOleksandr Tymoshenko if (irq > BANK1_END) 27598884a9eSOleksandr Tymoshenko valid = false; 27698884a9eSOleksandr Tymoshenko break; 27798884a9eSOleksandr Tymoshenko case 2: 27898884a9eSOleksandr Tymoshenko irq = daf->cells[1] + BANK2_START; 27998884a9eSOleksandr Tymoshenko if (irq > BANK2_END) 28098884a9eSOleksandr Tymoshenko valid = false; 28198884a9eSOleksandr Tymoshenko break; 28298884a9eSOleksandr Tymoshenko default: 28398884a9eSOleksandr Tymoshenko valid = false; 28498884a9eSOleksandr Tymoshenko break; 28598884a9eSOleksandr Tymoshenko } 28698884a9eSOleksandr Tymoshenko 28798884a9eSOleksandr Tymoshenko if (!valid) { 28898884a9eSOleksandr Tymoshenko device_printf(dev, 28998884a9eSOleksandr Tymoshenko "invalid IRQ config: bank=%d, irq=%d\n", 29098884a9eSOleksandr Tymoshenko daf->cells[0], daf->cells[1]); 29198884a9eSOleksandr Tymoshenko return (EINVAL); 29298884a9eSOleksandr Tymoshenko } 29398884a9eSOleksandr Tymoshenko } 294472f2ccaSSvatopluk Kraus else 295472f2ccaSSvatopluk Kraus return (EINVAL); 296472f2ccaSSvatopluk Kraus 297472f2ccaSSvatopluk Kraus if (irq >= BCM_INTC_NIRQS) 298472f2ccaSSvatopluk Kraus return (EINVAL); 299472f2ccaSSvatopluk Kraus 300472f2ccaSSvatopluk Kraus sc = device_get_softc(dev); 301472f2ccaSSvatopluk Kraus *isrcp = &sc->intc_isrcs[irq].bii_isrc; 302472f2ccaSSvatopluk Kraus return (0); 303472f2ccaSSvatopluk Kraus } 304472f2ccaSSvatopluk Kraus 305472f2ccaSSvatopluk Kraus static void 306472f2ccaSSvatopluk Kraus bcm_intc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 307472f2ccaSSvatopluk Kraus { 308472f2ccaSSvatopluk Kraus 309472f2ccaSSvatopluk Kraus bcm_intc_disable_intr(dev, isrc); 310472f2ccaSSvatopluk Kraus } 311472f2ccaSSvatopluk Kraus 312472f2ccaSSvatopluk Kraus static void 313472f2ccaSSvatopluk Kraus bcm_intc_post_ithread(device_t dev, struct intr_irqsrc *isrc) 314472f2ccaSSvatopluk Kraus { 315472f2ccaSSvatopluk Kraus 316472f2ccaSSvatopluk Kraus bcm_intc_enable_intr(dev, isrc); 317472f2ccaSSvatopluk Kraus } 318472f2ccaSSvatopluk Kraus 319472f2ccaSSvatopluk Kraus static void 320472f2ccaSSvatopluk Kraus bcm_intc_post_filter(device_t dev, struct intr_irqsrc *isrc) 321472f2ccaSSvatopluk Kraus { 322472f2ccaSSvatopluk Kraus } 323472f2ccaSSvatopluk Kraus 324472f2ccaSSvatopluk Kraus static int 325472f2ccaSSvatopluk Kraus bcm_intc_pic_register(struct bcm_intc_softc *sc, intptr_t xref) 326472f2ccaSSvatopluk Kraus { 327472f2ccaSSvatopluk Kraus struct bcm_intc_irqsrc *bii; 328472f2ccaSSvatopluk Kraus int error; 329472f2ccaSSvatopluk Kraus uint32_t irq; 330472f2ccaSSvatopluk Kraus const char *name; 331472f2ccaSSvatopluk Kraus 332472f2ccaSSvatopluk Kraus name = device_get_nameunit(sc->sc_dev); 333472f2ccaSSvatopluk Kraus for (irq = 0; irq < BCM_INTC_NIRQS; irq++) { 334472f2ccaSSvatopluk Kraus bii = &sc->intc_isrcs[irq]; 335472f2ccaSSvatopluk Kraus bii->bii_irq = irq; 336472f2ccaSSvatopluk Kraus if (IS_IRQ_BASIC(irq)) { 337472f2ccaSSvatopluk Kraus bii->bii_disable_reg = INTC_DISABLE_BASIC; 338472f2ccaSSvatopluk Kraus bii->bii_enable_reg = INTC_ENABLE_BASIC; 339472f2ccaSSvatopluk Kraus bii->bii_mask = 1 << irq; 340472f2ccaSSvatopluk Kraus } else if (IS_IRQ_BANK1(irq)) { 341472f2ccaSSvatopluk Kraus bii->bii_disable_reg = INTC_DISABLE_BANK1; 342472f2ccaSSvatopluk Kraus bii->bii_enable_reg = INTC_ENABLE_BANK1; 343472f2ccaSSvatopluk Kraus bii->bii_mask = 1 << IRQ_BANK1(irq); 344472f2ccaSSvatopluk Kraus } else if (IS_IRQ_BANK2(irq)) { 345472f2ccaSSvatopluk Kraus bii->bii_disable_reg = INTC_DISABLE_BANK2; 346472f2ccaSSvatopluk Kraus bii->bii_enable_reg = INTC_ENABLE_BANK2; 347472f2ccaSSvatopluk Kraus bii->bii_mask = 1 << IRQ_BANK2(irq); 348472f2ccaSSvatopluk Kraus } else 349472f2ccaSSvatopluk Kraus return (ENXIO); 350472f2ccaSSvatopluk Kraus 351472f2ccaSSvatopluk Kraus error = intr_isrc_register(&bii->bii_isrc, sc->sc_dev, 0, 352472f2ccaSSvatopluk Kraus "%s,%u", name, irq); 353472f2ccaSSvatopluk Kraus if (error != 0) 354472f2ccaSSvatopluk Kraus return (error); 355472f2ccaSSvatopluk Kraus } 3569346e913SAndrew Turner if (intr_pic_register(sc->sc_dev, xref) == NULL) 3579346e913SAndrew Turner return (ENXIO); 3589346e913SAndrew Turner 3599346e913SAndrew Turner return (0); 360472f2ccaSSvatopluk Kraus } 361472f2ccaSSvatopluk Kraus 3621b1a53cfSOleksandr Tymoshenko static int 3631b1a53cfSOleksandr Tymoshenko bcm_intc_probe(device_t dev) 3641b1a53cfSOleksandr Tymoshenko { 365add35ed5SIan Lepore 366add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 367add35ed5SIan Lepore return (ENXIO); 368add35ed5SIan Lepore 36998884a9eSOleksandr Tymoshenko if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-armctrl-ic") && 37098884a9eSOleksandr Tymoshenko !ofw_bus_is_compatible(dev, "brcm,bcm2836-armctrl-ic")) 3711b1a53cfSOleksandr Tymoshenko return (ENXIO); 3721b1a53cfSOleksandr Tymoshenko device_set_desc(dev, "BCM2835 Interrupt Controller"); 3731b1a53cfSOleksandr Tymoshenko return (BUS_PROBE_DEFAULT); 3741b1a53cfSOleksandr Tymoshenko } 3751b1a53cfSOleksandr Tymoshenko 3761b1a53cfSOleksandr Tymoshenko static int 3771b1a53cfSOleksandr Tymoshenko bcm_intc_attach(device_t dev) 3781b1a53cfSOleksandr Tymoshenko { 3791b1a53cfSOleksandr Tymoshenko struct bcm_intc_softc *sc = device_get_softc(dev); 3801b1a53cfSOleksandr Tymoshenko int rid = 0; 381472f2ccaSSvatopluk Kraus intptr_t xref; 3821b1a53cfSOleksandr Tymoshenko sc->sc_dev = dev; 3831b1a53cfSOleksandr Tymoshenko 3841b1a53cfSOleksandr Tymoshenko if (bcm_intc_sc) 3851b1a53cfSOleksandr Tymoshenko return (ENXIO); 3861b1a53cfSOleksandr Tymoshenko 3871b1a53cfSOleksandr Tymoshenko sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 3881b1a53cfSOleksandr Tymoshenko if (sc->intc_res == NULL) { 3891b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate memory resource\n"); 3901b1a53cfSOleksandr Tymoshenko return (ENXIO); 3911b1a53cfSOleksandr Tymoshenko } 3921b1a53cfSOleksandr Tymoshenko 393472f2ccaSSvatopluk Kraus xref = OF_xref_from_node(ofw_bus_get_node(dev)); 394472f2ccaSSvatopluk Kraus if (bcm_intc_pic_register(sc, xref) != 0) { 395472f2ccaSSvatopluk Kraus bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->intc_res); 396472f2ccaSSvatopluk Kraus device_printf(dev, "could not register PIC\n"); 397472f2ccaSSvatopluk Kraus return (ENXIO); 398472f2ccaSSvatopluk Kraus } 399472f2ccaSSvatopluk Kraus 400472f2ccaSSvatopluk Kraus rid = 0; 401472f2ccaSSvatopluk Kraus sc->intc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 402472f2ccaSSvatopluk Kraus RF_ACTIVE); 403472f2ccaSSvatopluk Kraus if (sc->intc_irq_res == NULL) { 404472f2ccaSSvatopluk Kraus if (intr_pic_claim_root(dev, xref, bcm2835_intc_intr, sc, 0) != 0) { 405472f2ccaSSvatopluk Kraus /* XXX clean up */ 406472f2ccaSSvatopluk Kraus device_printf(dev, "could not set PIC as a root\n"); 407472f2ccaSSvatopluk Kraus return (ENXIO); 408472f2ccaSSvatopluk Kraus } 409472f2ccaSSvatopluk Kraus } else { 410472f2ccaSSvatopluk Kraus if (bus_setup_intr(dev, sc->intc_irq_res, INTR_TYPE_CLK, 411472f2ccaSSvatopluk Kraus bcm2835_intc_intr, NULL, sc, &sc->intc_irq_hdl)) { 412472f2ccaSSvatopluk Kraus /* XXX clean up */ 413472f2ccaSSvatopluk Kraus device_printf(dev, "could not setup irq handler\n"); 414472f2ccaSSvatopluk Kraus return (ENXIO); 415472f2ccaSSvatopluk Kraus } 416472f2ccaSSvatopluk Kraus } 4171b1a53cfSOleksandr Tymoshenko sc->intc_bst = rman_get_bustag(sc->intc_res); 4181b1a53cfSOleksandr Tymoshenko sc->intc_bsh = rman_get_bushandle(sc->intc_res); 4191b1a53cfSOleksandr Tymoshenko 4201b1a53cfSOleksandr Tymoshenko bcm_intc_sc = sc; 4211b1a53cfSOleksandr Tymoshenko 4221b1a53cfSOleksandr Tymoshenko return (0); 4231b1a53cfSOleksandr Tymoshenko } 4241b1a53cfSOleksandr Tymoshenko 4251b1a53cfSOleksandr Tymoshenko static device_method_t bcm_intc_methods[] = { 4261b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_probe, bcm_intc_probe), 4271b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_attach, bcm_intc_attach), 428472f2ccaSSvatopluk Kraus 429472f2ccaSSvatopluk Kraus DEVMETHOD(pic_disable_intr, bcm_intc_disable_intr), 430472f2ccaSSvatopluk Kraus DEVMETHOD(pic_enable_intr, bcm_intc_enable_intr), 431472f2ccaSSvatopluk Kraus DEVMETHOD(pic_map_intr, bcm_intc_map_intr), 432472f2ccaSSvatopluk Kraus DEVMETHOD(pic_post_filter, bcm_intc_post_filter), 433472f2ccaSSvatopluk Kraus DEVMETHOD(pic_post_ithread, bcm_intc_post_ithread), 434472f2ccaSSvatopluk Kraus DEVMETHOD(pic_pre_ithread, bcm_intc_pre_ithread), 435472f2ccaSSvatopluk Kraus 4361b1a53cfSOleksandr Tymoshenko { 0, 0 } 4371b1a53cfSOleksandr Tymoshenko }; 4381b1a53cfSOleksandr Tymoshenko 4391b1a53cfSOleksandr Tymoshenko static driver_t bcm_intc_driver = { 4401b1a53cfSOleksandr Tymoshenko "intc", 4411b1a53cfSOleksandr Tymoshenko bcm_intc_methods, 4421b1a53cfSOleksandr Tymoshenko sizeof(struct bcm_intc_softc), 4431b1a53cfSOleksandr Tymoshenko }; 4441b1a53cfSOleksandr Tymoshenko 4451b1a53cfSOleksandr Tymoshenko static devclass_t bcm_intc_devclass; 4461b1a53cfSOleksandr Tymoshenko 447511bc527SOleksandr Tymoshenko EARLY_DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 448511bc527SOleksandr Tymoshenko 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 449