1*1b1a53cfSOleksandr Tymoshenko /*- 2*1b1a53cfSOleksandr Tymoshenko * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> 3*1b1a53cfSOleksandr Tymoshenko * All rights reserved. 4*1b1a53cfSOleksandr Tymoshenko * 5*1b1a53cfSOleksandr Tymoshenko * Based on OMAP3 INTC code by Ben Gray 6*1b1a53cfSOleksandr Tymoshenko * 7*1b1a53cfSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 8*1b1a53cfSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 9*1b1a53cfSOleksandr Tymoshenko * are met: 10*1b1a53cfSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 11*1b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 12*1b1a53cfSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 13*1b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 14*1b1a53cfSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 15*1b1a53cfSOleksandr Tymoshenko * 16*1b1a53cfSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*1b1a53cfSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*1b1a53cfSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*1b1a53cfSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*1b1a53cfSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*1b1a53cfSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*1b1a53cfSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*1b1a53cfSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*1b1a53cfSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*1b1a53cfSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*1b1a53cfSOleksandr Tymoshenko * SUCH DAMAGE. 27*1b1a53cfSOleksandr Tymoshenko */ 28*1b1a53cfSOleksandr Tymoshenko 29*1b1a53cfSOleksandr Tymoshenko 30*1b1a53cfSOleksandr Tymoshenko #include <sys/cdefs.h> 31*1b1a53cfSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 32*1b1a53cfSOleksandr Tymoshenko 33*1b1a53cfSOleksandr Tymoshenko #include <sys/param.h> 34*1b1a53cfSOleksandr Tymoshenko #include <sys/systm.h> 35*1b1a53cfSOleksandr Tymoshenko #include <sys/bus.h> 36*1b1a53cfSOleksandr Tymoshenko #include <sys/kernel.h> 37*1b1a53cfSOleksandr Tymoshenko #include <sys/ktr.h> 38*1b1a53cfSOleksandr Tymoshenko #include <sys/module.h> 39*1b1a53cfSOleksandr Tymoshenko #include <sys/rman.h> 40*1b1a53cfSOleksandr Tymoshenko #include <machine/bus.h> 41*1b1a53cfSOleksandr Tymoshenko #include <machine/intr.h> 42*1b1a53cfSOleksandr Tymoshenko 43*1b1a53cfSOleksandr Tymoshenko #include <dev/fdt/fdt_common.h> 44*1b1a53cfSOleksandr Tymoshenko #include <dev/ofw/openfirm.h> 45*1b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h> 46*1b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h> 47*1b1a53cfSOleksandr Tymoshenko 48*1b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BASIC 0x00 49*1b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BANK1 0x04 50*1b1a53cfSOleksandr Tymoshenko #define INTC_PENDING_BANK2 0x08 51*1b1a53cfSOleksandr Tymoshenko #define INTC_FIQ_CONTROL 0x0C 52*1b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BANK1 0x10 53*1b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BANK2 0x14 54*1b1a53cfSOleksandr Tymoshenko #define INTC_ENABLE_BASIC 0x18 55*1b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BANK1 0x1C 56*1b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BANK2 0x20 57*1b1a53cfSOleksandr Tymoshenko #define INTC_DISABLE_BASIC 0x24 58*1b1a53cfSOleksandr Tymoshenko 59*1b1a53cfSOleksandr Tymoshenko #define BANK1_START 8 60*1b1a53cfSOleksandr Tymoshenko #define BANK1_END (BANK1_START + 32 - 1) 61*1b1a53cfSOleksandr Tymoshenko #define BANK2_START (BANK1_START + 32) 62*1b1a53cfSOleksandr Tymoshenko #define BANK2_END (BANK2_START + 32 - 1) 63*1b1a53cfSOleksandr Tymoshenko 64*1b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START)) 65*1b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END)) 66*1b1a53cfSOleksandr Tymoshenko #define IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END)) 67*1b1a53cfSOleksandr Tymoshenko #define IRQ_BANK1(n) ((n) - BANK1_START) 68*1b1a53cfSOleksandr Tymoshenko #define IRQ_BANK2(n) ((n) - BANK2_START) 69*1b1a53cfSOleksandr Tymoshenko 70*1b1a53cfSOleksandr Tymoshenko #ifdef DEBUG 71*1b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) printf(fmt, ##args) 72*1b1a53cfSOleksandr Tymoshenko #else 73*1b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) 74*1b1a53cfSOleksandr Tymoshenko #endif 75*1b1a53cfSOleksandr Tymoshenko 76*1b1a53cfSOleksandr Tymoshenko struct bcm_intc_softc { 77*1b1a53cfSOleksandr Tymoshenko device_t sc_dev; 78*1b1a53cfSOleksandr Tymoshenko struct resource * intc_res; 79*1b1a53cfSOleksandr Tymoshenko bus_space_tag_t intc_bst; 80*1b1a53cfSOleksandr Tymoshenko bus_space_handle_t intc_bsh; 81*1b1a53cfSOleksandr Tymoshenko }; 82*1b1a53cfSOleksandr Tymoshenko 83*1b1a53cfSOleksandr Tymoshenko static struct bcm_intc_softc *bcm_intc_sc = NULL; 84*1b1a53cfSOleksandr Tymoshenko 85*1b1a53cfSOleksandr Tymoshenko #define intc_read_4(reg) \ 86*1b1a53cfSOleksandr Tymoshenko bus_space_read_4(bcm_intc_sc->intc_bst, bcm_intc_sc->intc_bsh, reg) 87*1b1a53cfSOleksandr Tymoshenko #define intc_write_4(reg, val) \ 88*1b1a53cfSOleksandr Tymoshenko bus_space_write_4(bcm_intc_sc->intc_bst, bcm_intc_sc->intc_bsh, reg, val) 89*1b1a53cfSOleksandr Tymoshenko 90*1b1a53cfSOleksandr Tymoshenko static int 91*1b1a53cfSOleksandr Tymoshenko bcm_intc_probe(device_t dev) 92*1b1a53cfSOleksandr Tymoshenko { 93*1b1a53cfSOleksandr Tymoshenko if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-armctrl-ic")) 94*1b1a53cfSOleksandr Tymoshenko return (ENXIO); 95*1b1a53cfSOleksandr Tymoshenko device_set_desc(dev, "BCM2835 Interrupt Controller"); 96*1b1a53cfSOleksandr Tymoshenko return (BUS_PROBE_DEFAULT); 97*1b1a53cfSOleksandr Tymoshenko } 98*1b1a53cfSOleksandr Tymoshenko 99*1b1a53cfSOleksandr Tymoshenko static int 100*1b1a53cfSOleksandr Tymoshenko bcm_intc_attach(device_t dev) 101*1b1a53cfSOleksandr Tymoshenko { 102*1b1a53cfSOleksandr Tymoshenko struct bcm_intc_softc *sc = device_get_softc(dev); 103*1b1a53cfSOleksandr Tymoshenko int rid = 0; 104*1b1a53cfSOleksandr Tymoshenko 105*1b1a53cfSOleksandr Tymoshenko sc->sc_dev = dev; 106*1b1a53cfSOleksandr Tymoshenko 107*1b1a53cfSOleksandr Tymoshenko if (bcm_intc_sc) 108*1b1a53cfSOleksandr Tymoshenko return (ENXIO); 109*1b1a53cfSOleksandr Tymoshenko 110*1b1a53cfSOleksandr Tymoshenko sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 111*1b1a53cfSOleksandr Tymoshenko if (sc->intc_res == NULL) { 112*1b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate memory resource\n"); 113*1b1a53cfSOleksandr Tymoshenko return (ENXIO); 114*1b1a53cfSOleksandr Tymoshenko } 115*1b1a53cfSOleksandr Tymoshenko 116*1b1a53cfSOleksandr Tymoshenko sc->intc_bst = rman_get_bustag(sc->intc_res); 117*1b1a53cfSOleksandr Tymoshenko sc->intc_bsh = rman_get_bushandle(sc->intc_res); 118*1b1a53cfSOleksandr Tymoshenko 119*1b1a53cfSOleksandr Tymoshenko bcm_intc_sc = sc; 120*1b1a53cfSOleksandr Tymoshenko 121*1b1a53cfSOleksandr Tymoshenko return (0); 122*1b1a53cfSOleksandr Tymoshenko } 123*1b1a53cfSOleksandr Tymoshenko 124*1b1a53cfSOleksandr Tymoshenko static device_method_t bcm_intc_methods[] = { 125*1b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_probe, bcm_intc_probe), 126*1b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_attach, bcm_intc_attach), 127*1b1a53cfSOleksandr Tymoshenko { 0, 0 } 128*1b1a53cfSOleksandr Tymoshenko }; 129*1b1a53cfSOleksandr Tymoshenko 130*1b1a53cfSOleksandr Tymoshenko static driver_t bcm_intc_driver = { 131*1b1a53cfSOleksandr Tymoshenko "intc", 132*1b1a53cfSOleksandr Tymoshenko bcm_intc_methods, 133*1b1a53cfSOleksandr Tymoshenko sizeof(struct bcm_intc_softc), 134*1b1a53cfSOleksandr Tymoshenko }; 135*1b1a53cfSOleksandr Tymoshenko 136*1b1a53cfSOleksandr Tymoshenko static devclass_t bcm_intc_devclass; 137*1b1a53cfSOleksandr Tymoshenko 138*1b1a53cfSOleksandr Tymoshenko DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 0, 0); 139*1b1a53cfSOleksandr Tymoshenko 140*1b1a53cfSOleksandr Tymoshenko int 141*1b1a53cfSOleksandr Tymoshenko arm_get_next_irq(int last_irq) 142*1b1a53cfSOleksandr Tymoshenko { 143*1b1a53cfSOleksandr Tymoshenko uint32_t pending; 144*1b1a53cfSOleksandr Tymoshenko int32_t irq = last_irq + 1; 145*1b1a53cfSOleksandr Tymoshenko 146*1b1a53cfSOleksandr Tymoshenko /* Sanity check */ 147*1b1a53cfSOleksandr Tymoshenko if (irq < 0) 148*1b1a53cfSOleksandr Tymoshenko irq = 0; 149*1b1a53cfSOleksandr Tymoshenko 150*1b1a53cfSOleksandr Tymoshenko /* TODO: should we mask last_irq? */ 151*1b1a53cfSOleksandr Tymoshenko pending = intc_read_4(INTC_PENDING_BASIC); 152*1b1a53cfSOleksandr Tymoshenko while (irq < BANK1_START) { 153*1b1a53cfSOleksandr Tymoshenko if (pending & (1 << irq)) 154*1b1a53cfSOleksandr Tymoshenko return irq; 155*1b1a53cfSOleksandr Tymoshenko irq++; 156*1b1a53cfSOleksandr Tymoshenko } 157*1b1a53cfSOleksandr Tymoshenko 158*1b1a53cfSOleksandr Tymoshenko pending = intc_read_4(INTC_PENDING_BANK1); 159*1b1a53cfSOleksandr Tymoshenko while (irq < BANK2_START) { 160*1b1a53cfSOleksandr Tymoshenko if (pending & (1 << IRQ_BANK1(irq))) 161*1b1a53cfSOleksandr Tymoshenko return irq; 162*1b1a53cfSOleksandr Tymoshenko irq++; 163*1b1a53cfSOleksandr Tymoshenko } 164*1b1a53cfSOleksandr Tymoshenko 165*1b1a53cfSOleksandr Tymoshenko pending = intc_read_4(INTC_PENDING_BANK2); 166*1b1a53cfSOleksandr Tymoshenko while (irq <= BANK2_END) { 167*1b1a53cfSOleksandr Tymoshenko if (pending & (1 << IRQ_BANK2(irq))) 168*1b1a53cfSOleksandr Tymoshenko return irq; 169*1b1a53cfSOleksandr Tymoshenko irq++; 170*1b1a53cfSOleksandr Tymoshenko } 171*1b1a53cfSOleksandr Tymoshenko 172*1b1a53cfSOleksandr Tymoshenko return (-1); 173*1b1a53cfSOleksandr Tymoshenko } 174*1b1a53cfSOleksandr Tymoshenko 175*1b1a53cfSOleksandr Tymoshenko void 176*1b1a53cfSOleksandr Tymoshenko arm_mask_irq(uintptr_t nb) 177*1b1a53cfSOleksandr Tymoshenko { 178*1b1a53cfSOleksandr Tymoshenko dprintf("%s: %d\n", __func__, nb); 179*1b1a53cfSOleksandr Tymoshenko 180*1b1a53cfSOleksandr Tymoshenko if (IS_IRQ_BASIC(nb)) 181*1b1a53cfSOleksandr Tymoshenko intc_write_4(INTC_DISABLE_BASIC, (1 << nb)); 182*1b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK1(nb)) 183*1b1a53cfSOleksandr Tymoshenko intc_write_4(INTC_DISABLE_BANK1, (1 << IRQ_BANK1(nb))); 184*1b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK2(nb)) 185*1b1a53cfSOleksandr Tymoshenko intc_write_4(INTC_DISABLE_BANK2, (1 << IRQ_BANK2(nb))); 186*1b1a53cfSOleksandr Tymoshenko else 187*1b1a53cfSOleksandr Tymoshenko printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); 188*1b1a53cfSOleksandr Tymoshenko } 189*1b1a53cfSOleksandr Tymoshenko 190*1b1a53cfSOleksandr Tymoshenko void 191*1b1a53cfSOleksandr Tymoshenko arm_unmask_irq(uintptr_t nb) 192*1b1a53cfSOleksandr Tymoshenko { 193*1b1a53cfSOleksandr Tymoshenko dprintf("%s: %d\n", __func__, nb); 194*1b1a53cfSOleksandr Tymoshenko 195*1b1a53cfSOleksandr Tymoshenko if (IS_IRQ_BASIC(nb)) 196*1b1a53cfSOleksandr Tymoshenko intc_write_4(INTC_ENABLE_BASIC, (1 << nb)); 197*1b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK1(nb)) 198*1b1a53cfSOleksandr Tymoshenko intc_write_4(INTC_ENABLE_BANK1, (1 << IRQ_BANK1(nb))); 199*1b1a53cfSOleksandr Tymoshenko else if (IS_IRQ_BANK2(nb)) 200*1b1a53cfSOleksandr Tymoshenko intc_write_4(INTC_ENABLE_BANK2, (1 << IRQ_BANK2(nb))); 201*1b1a53cfSOleksandr Tymoshenko else 202*1b1a53cfSOleksandr Tymoshenko printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); 203*1b1a53cfSOleksandr Tymoshenko } 204