11b1a53cfSOleksandr Tymoshenko /*- 2af3dc4a7SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3af3dc4a7SPedro 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 13681cb170fSMichal Meloun static struct ofw_compat_data compat_data[] = { 13781cb170fSMichal Meloun {"broadcom,bcm2835-armctrl-ic", 1}, 13881cb170fSMichal Meloun {"brcm,bcm2835-armctrl-ic", 1}, 13981cb170fSMichal Meloun {"brcm,bcm2836-armctrl-ic", 1}, 14081cb170fSMichal Meloun {NULL, 0} 14181cb170fSMichal Meloun }; 14281cb170fSMichal Meloun 1431b1a53cfSOleksandr Tymoshenko static struct bcm_intc_softc *bcm_intc_sc = NULL; 1441b1a53cfSOleksandr Tymoshenko 145171af33cSAndrew Turner #define intc_read_4(_sc, reg) \ 146171af33cSAndrew Turner bus_space_read_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg)) 147171af33cSAndrew Turner #define intc_write_4(_sc, reg, val) \ 148171af33cSAndrew Turner bus_space_write_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg), (val)) 1491b1a53cfSOleksandr Tymoshenko 150472f2ccaSSvatopluk Kraus static inline void 151472f2ccaSSvatopluk Kraus bcm_intc_isrc_mask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) 152472f2ccaSSvatopluk Kraus { 153472f2ccaSSvatopluk Kraus 154472f2ccaSSvatopluk Kraus intc_write_4(sc, bii->bii_disable_reg, bii->bii_mask); 155472f2ccaSSvatopluk Kraus } 156472f2ccaSSvatopluk Kraus 157472f2ccaSSvatopluk Kraus static inline void 158472f2ccaSSvatopluk Kraus bcm_intc_isrc_unmask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) 159472f2ccaSSvatopluk Kraus { 160472f2ccaSSvatopluk Kraus 161472f2ccaSSvatopluk Kraus intc_write_4(sc, bii->bii_enable_reg, bii->bii_mask); 162472f2ccaSSvatopluk Kraus } 163472f2ccaSSvatopluk Kraus 164472f2ccaSSvatopluk Kraus static inline int 165472f2ccaSSvatopluk Kraus bcm2835_intc_active_intr(struct bcm_intc_softc *sc) 166472f2ccaSSvatopluk Kraus { 167472f2ccaSSvatopluk Kraus uint32_t pending, pending_gpu; 168472f2ccaSSvatopluk Kraus 169472f2ccaSSvatopluk Kraus pending = intc_read_4(sc, INTC_PENDING_BASIC) & INTC_PENDING_BASIC_MASK; 170472f2ccaSSvatopluk Kraus if (pending == 0) 171472f2ccaSSvatopluk Kraus return (-1); 172472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_ARM) 173472f2ccaSSvatopluk Kraus return (ffs(pending) - 1); 174472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_MASK) { 175472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_7) 176472f2ccaSSvatopluk Kraus return (BANK1_START + 7); 177472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_9) 178472f2ccaSSvatopluk Kraus return (BANK1_START + 9); 179472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_10) 180472f2ccaSSvatopluk Kraus return (BANK1_START + 10); 181472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_18) 182472f2ccaSSvatopluk Kraus return (BANK1_START + 18); 183472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_19) 184472f2ccaSSvatopluk Kraus return (BANK1_START + 19); 185472f2ccaSSvatopluk Kraus } 186472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_MASK) { 187472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_21) 188472f2ccaSSvatopluk Kraus return (BANK2_START + 21); 189472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_22) 190472f2ccaSSvatopluk Kraus return (BANK2_START + 22); 191472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_23) 192472f2ccaSSvatopluk Kraus return (BANK2_START + 23); 193472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_24) 194472f2ccaSSvatopluk Kraus return (BANK2_START + 24); 195472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_25) 196472f2ccaSSvatopluk Kraus return (BANK2_START + 25); 197472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_30) 198472f2ccaSSvatopluk Kraus return (BANK2_START + 30); 199472f2ccaSSvatopluk Kraus } 200472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU1_PEND) { 201472f2ccaSSvatopluk Kraus pending_gpu = intc_read_4(sc, INTC_PENDING_BANK1); 202472f2ccaSSvatopluk Kraus pending_gpu &= INTC_PENDING_BANK1_MASK; 203472f2ccaSSvatopluk Kraus if (pending_gpu != 0) 204472f2ccaSSvatopluk Kraus return (BANK1_START + ffs(pending_gpu) - 1); 205472f2ccaSSvatopluk Kraus } 206472f2ccaSSvatopluk Kraus if (pending & INTC_PENDING_BASIC_GPU2_PEND) { 207472f2ccaSSvatopluk Kraus pending_gpu = intc_read_4(sc, INTC_PENDING_BANK2); 208472f2ccaSSvatopluk Kraus pending_gpu &= INTC_PENDING_BANK2_MASK; 209472f2ccaSSvatopluk Kraus if (pending_gpu != 0) 210472f2ccaSSvatopluk Kraus return (BANK2_START + ffs(pending_gpu) - 1); 211472f2ccaSSvatopluk Kraus } 212472f2ccaSSvatopluk Kraus return (-1); /* It shouldn't end here, but it's hardware. */ 213472f2ccaSSvatopluk Kraus } 214472f2ccaSSvatopluk Kraus 215472f2ccaSSvatopluk Kraus static int 216472f2ccaSSvatopluk Kraus bcm2835_intc_intr(void *arg) 217472f2ccaSSvatopluk Kraus { 218472f2ccaSSvatopluk Kraus int irq, num; 219472f2ccaSSvatopluk Kraus struct bcm_intc_softc *sc = arg; 220472f2ccaSSvatopluk Kraus 221472f2ccaSSvatopluk Kraus for (num = 0; ; num++) { 222472f2ccaSSvatopluk Kraus irq = bcm2835_intc_active_intr(sc); 223472f2ccaSSvatopluk Kraus if (irq == -1) 224472f2ccaSSvatopluk Kraus break; 225472f2ccaSSvatopluk Kraus if (intr_isrc_dispatch(&sc->intc_isrcs[irq].bii_isrc, 226472f2ccaSSvatopluk Kraus curthread->td_intr_frame) != 0) { 227472f2ccaSSvatopluk Kraus bcm_intc_isrc_mask(sc, &sc->intc_isrcs[irq]); 228472f2ccaSSvatopluk Kraus device_printf(sc->sc_dev, "Stray irq %u disabled\n", 229472f2ccaSSvatopluk Kraus irq); 230472f2ccaSSvatopluk Kraus } 231472f2ccaSSvatopluk Kraus arm_irq_memory_barrier(0); /* XXX */ 232472f2ccaSSvatopluk Kraus } 233*9e655cd5SIan Lepore if (num == 0 && bootverbose) 234472f2ccaSSvatopluk Kraus device_printf(sc->sc_dev, "Spurious interrupt detected\n"); 235472f2ccaSSvatopluk Kraus 236472f2ccaSSvatopluk Kraus return (FILTER_HANDLED); 237472f2ccaSSvatopluk Kraus } 238472f2ccaSSvatopluk Kraus 239472f2ccaSSvatopluk Kraus static void 240472f2ccaSSvatopluk Kraus bcm_intc_enable_intr(device_t dev, struct intr_irqsrc *isrc) 241472f2ccaSSvatopluk Kraus { 242472f2ccaSSvatopluk Kraus struct bcm_intc_irqsrc *bii = (struct bcm_intc_irqsrc *)isrc; 243472f2ccaSSvatopluk Kraus 244472f2ccaSSvatopluk Kraus arm_irq_memory_barrier(bii->bii_irq); 245472f2ccaSSvatopluk Kraus bcm_intc_isrc_unmask(device_get_softc(dev), bii); 246472f2ccaSSvatopluk Kraus } 247472f2ccaSSvatopluk Kraus 248472f2ccaSSvatopluk Kraus static void 249472f2ccaSSvatopluk Kraus bcm_intc_disable_intr(device_t dev, struct intr_irqsrc *isrc) 250472f2ccaSSvatopluk Kraus { 251472f2ccaSSvatopluk Kraus 252472f2ccaSSvatopluk Kraus bcm_intc_isrc_mask(device_get_softc(dev), 253472f2ccaSSvatopluk Kraus (struct bcm_intc_irqsrc *)isrc); 254472f2ccaSSvatopluk Kraus } 255472f2ccaSSvatopluk Kraus 256472f2ccaSSvatopluk Kraus static int 257472f2ccaSSvatopluk Kraus bcm_intc_map_intr(device_t dev, struct intr_map_data *data, 258472f2ccaSSvatopluk Kraus struct intr_irqsrc **isrcp) 259472f2ccaSSvatopluk Kraus { 260472f2ccaSSvatopluk Kraus u_int irq; 261cd642c88SSvatopluk Kraus struct intr_map_data_fdt *daf; 262472f2ccaSSvatopluk Kraus struct bcm_intc_softc *sc; 26398884a9eSOleksandr Tymoshenko bool valid; 264472f2ccaSSvatopluk Kraus 265472f2ccaSSvatopluk Kraus if (data->type != INTR_MAP_DATA_FDT) 266472f2ccaSSvatopluk Kraus return (ENOTSUP); 267cd642c88SSvatopluk Kraus 268cd642c88SSvatopluk Kraus daf = (struct intr_map_data_fdt *)data; 269cd642c88SSvatopluk Kraus if (daf->ncells == 1) 270cd642c88SSvatopluk Kraus irq = daf->cells[0]; 27198884a9eSOleksandr Tymoshenko else if (daf->ncells == 2) { 27298884a9eSOleksandr Tymoshenko valid = true; 27398884a9eSOleksandr Tymoshenko switch (daf->cells[0]) { 27498884a9eSOleksandr Tymoshenko case 0: 27598884a9eSOleksandr Tymoshenko irq = daf->cells[1]; 27698884a9eSOleksandr Tymoshenko if (irq >= BANK1_START) 27798884a9eSOleksandr Tymoshenko valid = false; 27898884a9eSOleksandr Tymoshenko break; 27998884a9eSOleksandr Tymoshenko case 1: 28098884a9eSOleksandr Tymoshenko irq = daf->cells[1] + BANK1_START; 28198884a9eSOleksandr Tymoshenko if (irq > BANK1_END) 28298884a9eSOleksandr Tymoshenko valid = false; 28398884a9eSOleksandr Tymoshenko break; 28498884a9eSOleksandr Tymoshenko case 2: 28598884a9eSOleksandr Tymoshenko irq = daf->cells[1] + BANK2_START; 28698884a9eSOleksandr Tymoshenko if (irq > BANK2_END) 28798884a9eSOleksandr Tymoshenko valid = false; 28898884a9eSOleksandr Tymoshenko break; 28998884a9eSOleksandr Tymoshenko default: 29098884a9eSOleksandr Tymoshenko valid = false; 29198884a9eSOleksandr Tymoshenko break; 29298884a9eSOleksandr Tymoshenko } 29398884a9eSOleksandr Tymoshenko 29498884a9eSOleksandr Tymoshenko if (!valid) { 29598884a9eSOleksandr Tymoshenko device_printf(dev, 29698884a9eSOleksandr Tymoshenko "invalid IRQ config: bank=%d, irq=%d\n", 29798884a9eSOleksandr Tymoshenko daf->cells[0], daf->cells[1]); 29898884a9eSOleksandr Tymoshenko return (EINVAL); 29998884a9eSOleksandr Tymoshenko } 30098884a9eSOleksandr Tymoshenko } 301472f2ccaSSvatopluk Kraus else 302472f2ccaSSvatopluk Kraus return (EINVAL); 303472f2ccaSSvatopluk Kraus 304472f2ccaSSvatopluk Kraus if (irq >= BCM_INTC_NIRQS) 305472f2ccaSSvatopluk Kraus return (EINVAL); 306472f2ccaSSvatopluk Kraus 307472f2ccaSSvatopluk Kraus sc = device_get_softc(dev); 308472f2ccaSSvatopluk Kraus *isrcp = &sc->intc_isrcs[irq].bii_isrc; 309472f2ccaSSvatopluk Kraus return (0); 310472f2ccaSSvatopluk Kraus } 311472f2ccaSSvatopluk Kraus 312472f2ccaSSvatopluk Kraus static void 313472f2ccaSSvatopluk Kraus bcm_intc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 314472f2ccaSSvatopluk Kraus { 315472f2ccaSSvatopluk Kraus 316472f2ccaSSvatopluk Kraus bcm_intc_disable_intr(dev, isrc); 317472f2ccaSSvatopluk Kraus } 318472f2ccaSSvatopluk Kraus 319472f2ccaSSvatopluk Kraus static void 320472f2ccaSSvatopluk Kraus bcm_intc_post_ithread(device_t dev, struct intr_irqsrc *isrc) 321472f2ccaSSvatopluk Kraus { 322472f2ccaSSvatopluk Kraus 323472f2ccaSSvatopluk Kraus bcm_intc_enable_intr(dev, isrc); 324472f2ccaSSvatopluk Kraus } 325472f2ccaSSvatopluk Kraus 326472f2ccaSSvatopluk Kraus static void 327472f2ccaSSvatopluk Kraus bcm_intc_post_filter(device_t dev, struct intr_irqsrc *isrc) 328472f2ccaSSvatopluk Kraus { 329472f2ccaSSvatopluk Kraus } 330472f2ccaSSvatopluk Kraus 331472f2ccaSSvatopluk Kraus static int 332472f2ccaSSvatopluk Kraus bcm_intc_pic_register(struct bcm_intc_softc *sc, intptr_t xref) 333472f2ccaSSvatopluk Kraus { 334472f2ccaSSvatopluk Kraus struct bcm_intc_irqsrc *bii; 335472f2ccaSSvatopluk Kraus int error; 336472f2ccaSSvatopluk Kraus uint32_t irq; 337472f2ccaSSvatopluk Kraus const char *name; 338472f2ccaSSvatopluk Kraus 339472f2ccaSSvatopluk Kraus name = device_get_nameunit(sc->sc_dev); 340472f2ccaSSvatopluk Kraus for (irq = 0; irq < BCM_INTC_NIRQS; irq++) { 341472f2ccaSSvatopluk Kraus bii = &sc->intc_isrcs[irq]; 342472f2ccaSSvatopluk Kraus bii->bii_irq = irq; 343472f2ccaSSvatopluk Kraus if (IS_IRQ_BASIC(irq)) { 344472f2ccaSSvatopluk Kraus bii->bii_disable_reg = INTC_DISABLE_BASIC; 345472f2ccaSSvatopluk Kraus bii->bii_enable_reg = INTC_ENABLE_BASIC; 346472f2ccaSSvatopluk Kraus bii->bii_mask = 1 << irq; 347472f2ccaSSvatopluk Kraus } else if (IS_IRQ_BANK1(irq)) { 348472f2ccaSSvatopluk Kraus bii->bii_disable_reg = INTC_DISABLE_BANK1; 349472f2ccaSSvatopluk Kraus bii->bii_enable_reg = INTC_ENABLE_BANK1; 350472f2ccaSSvatopluk Kraus bii->bii_mask = 1 << IRQ_BANK1(irq); 351472f2ccaSSvatopluk Kraus } else if (IS_IRQ_BANK2(irq)) { 352472f2ccaSSvatopluk Kraus bii->bii_disable_reg = INTC_DISABLE_BANK2; 353472f2ccaSSvatopluk Kraus bii->bii_enable_reg = INTC_ENABLE_BANK2; 354472f2ccaSSvatopluk Kraus bii->bii_mask = 1 << IRQ_BANK2(irq); 355472f2ccaSSvatopluk Kraus } else 356472f2ccaSSvatopluk Kraus return (ENXIO); 357472f2ccaSSvatopluk Kraus 358472f2ccaSSvatopluk Kraus error = intr_isrc_register(&bii->bii_isrc, sc->sc_dev, 0, 359472f2ccaSSvatopluk Kraus "%s,%u", name, irq); 360472f2ccaSSvatopluk Kraus if (error != 0) 361472f2ccaSSvatopluk Kraus return (error); 362472f2ccaSSvatopluk Kraus } 3639346e913SAndrew Turner if (intr_pic_register(sc->sc_dev, xref) == NULL) 3649346e913SAndrew Turner return (ENXIO); 3659346e913SAndrew Turner 3669346e913SAndrew Turner return (0); 367472f2ccaSSvatopluk Kraus } 368472f2ccaSSvatopluk Kraus 3691b1a53cfSOleksandr Tymoshenko static int 3701b1a53cfSOleksandr Tymoshenko bcm_intc_probe(device_t dev) 3711b1a53cfSOleksandr Tymoshenko { 372add35ed5SIan Lepore 373add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 374add35ed5SIan Lepore return (ENXIO); 375add35ed5SIan Lepore 37681cb170fSMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 3771b1a53cfSOleksandr Tymoshenko return (ENXIO); 37881cb170fSMichal Meloun 3791b1a53cfSOleksandr Tymoshenko device_set_desc(dev, "BCM2835 Interrupt Controller"); 3801b1a53cfSOleksandr Tymoshenko return (BUS_PROBE_DEFAULT); 3811b1a53cfSOleksandr Tymoshenko } 3821b1a53cfSOleksandr Tymoshenko 3831b1a53cfSOleksandr Tymoshenko static int 3841b1a53cfSOleksandr Tymoshenko bcm_intc_attach(device_t dev) 3851b1a53cfSOleksandr Tymoshenko { 3861b1a53cfSOleksandr Tymoshenko struct bcm_intc_softc *sc = device_get_softc(dev); 3871b1a53cfSOleksandr Tymoshenko int rid = 0; 388472f2ccaSSvatopluk Kraus intptr_t xref; 3891b1a53cfSOleksandr Tymoshenko sc->sc_dev = dev; 3901b1a53cfSOleksandr Tymoshenko 3911b1a53cfSOleksandr Tymoshenko if (bcm_intc_sc) 3921b1a53cfSOleksandr Tymoshenko return (ENXIO); 3931b1a53cfSOleksandr Tymoshenko 3941b1a53cfSOleksandr Tymoshenko sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 3951b1a53cfSOleksandr Tymoshenko if (sc->intc_res == NULL) { 3961b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate memory resource\n"); 3971b1a53cfSOleksandr Tymoshenko return (ENXIO); 3981b1a53cfSOleksandr Tymoshenko } 3991b1a53cfSOleksandr Tymoshenko 400472f2ccaSSvatopluk Kraus xref = OF_xref_from_node(ofw_bus_get_node(dev)); 401472f2ccaSSvatopluk Kraus if (bcm_intc_pic_register(sc, xref) != 0) { 402472f2ccaSSvatopluk Kraus bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->intc_res); 403472f2ccaSSvatopluk Kraus device_printf(dev, "could not register PIC\n"); 404472f2ccaSSvatopluk Kraus return (ENXIO); 405472f2ccaSSvatopluk Kraus } 406472f2ccaSSvatopluk Kraus 407472f2ccaSSvatopluk Kraus rid = 0; 408472f2ccaSSvatopluk Kraus sc->intc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 409472f2ccaSSvatopluk Kraus RF_ACTIVE); 410472f2ccaSSvatopluk Kraus if (sc->intc_irq_res == NULL) { 411472f2ccaSSvatopluk Kraus if (intr_pic_claim_root(dev, xref, bcm2835_intc_intr, sc, 0) != 0) { 412472f2ccaSSvatopluk Kraus /* XXX clean up */ 413472f2ccaSSvatopluk Kraus device_printf(dev, "could not set PIC as a root\n"); 414472f2ccaSSvatopluk Kraus return (ENXIO); 415472f2ccaSSvatopluk Kraus } 416472f2ccaSSvatopluk Kraus } else { 417472f2ccaSSvatopluk Kraus if (bus_setup_intr(dev, sc->intc_irq_res, INTR_TYPE_CLK, 418472f2ccaSSvatopluk Kraus bcm2835_intc_intr, NULL, sc, &sc->intc_irq_hdl)) { 419472f2ccaSSvatopluk Kraus /* XXX clean up */ 420472f2ccaSSvatopluk Kraus device_printf(dev, "could not setup irq handler\n"); 421472f2ccaSSvatopluk Kraus return (ENXIO); 422472f2ccaSSvatopluk Kraus } 423472f2ccaSSvatopluk Kraus } 4241b1a53cfSOleksandr Tymoshenko sc->intc_bst = rman_get_bustag(sc->intc_res); 4251b1a53cfSOleksandr Tymoshenko sc->intc_bsh = rman_get_bushandle(sc->intc_res); 4261b1a53cfSOleksandr Tymoshenko 4271b1a53cfSOleksandr Tymoshenko bcm_intc_sc = sc; 4281b1a53cfSOleksandr Tymoshenko 4291b1a53cfSOleksandr Tymoshenko return (0); 4301b1a53cfSOleksandr Tymoshenko } 4311b1a53cfSOleksandr Tymoshenko 4321b1a53cfSOleksandr Tymoshenko static device_method_t bcm_intc_methods[] = { 4331b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_probe, bcm_intc_probe), 4341b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_attach, bcm_intc_attach), 435472f2ccaSSvatopluk Kraus 436472f2ccaSSvatopluk Kraus DEVMETHOD(pic_disable_intr, bcm_intc_disable_intr), 437472f2ccaSSvatopluk Kraus DEVMETHOD(pic_enable_intr, bcm_intc_enable_intr), 438472f2ccaSSvatopluk Kraus DEVMETHOD(pic_map_intr, bcm_intc_map_intr), 439472f2ccaSSvatopluk Kraus DEVMETHOD(pic_post_filter, bcm_intc_post_filter), 440472f2ccaSSvatopluk Kraus DEVMETHOD(pic_post_ithread, bcm_intc_post_ithread), 441472f2ccaSSvatopluk Kraus DEVMETHOD(pic_pre_ithread, bcm_intc_pre_ithread), 442472f2ccaSSvatopluk Kraus 4431b1a53cfSOleksandr Tymoshenko { 0, 0 } 4441b1a53cfSOleksandr Tymoshenko }; 4451b1a53cfSOleksandr Tymoshenko 4461b1a53cfSOleksandr Tymoshenko static driver_t bcm_intc_driver = { 4471b1a53cfSOleksandr Tymoshenko "intc", 4481b1a53cfSOleksandr Tymoshenko bcm_intc_methods, 4491b1a53cfSOleksandr Tymoshenko sizeof(struct bcm_intc_softc), 4501b1a53cfSOleksandr Tymoshenko }; 4511b1a53cfSOleksandr Tymoshenko 4521b1a53cfSOleksandr Tymoshenko static devclass_t bcm_intc_devclass; 4531b1a53cfSOleksandr Tymoshenko 454511bc527SOleksandr Tymoshenko EARLY_DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 45591cc58afSOleksandr Tymoshenko 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 456