1239922Sgonzo/*- 2239922Sgonzo * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> 3239922Sgonzo * All rights reserved. 4239922Sgonzo * 5239922Sgonzo * Based on OMAP3 INTC code by Ben Gray 6239922Sgonzo * 7239922Sgonzo * Redistribution and use in source and binary forms, with or without 8239922Sgonzo * modification, are permitted provided that the following conditions 9239922Sgonzo * are met: 10239922Sgonzo * 1. Redistributions of source code must retain the above copyright 11239922Sgonzo * notice, this list of conditions and the following disclaimer. 12239922Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 13239922Sgonzo * notice, this list of conditions and the following disclaimer in the 14239922Sgonzo * documentation and/or other materials provided with the distribution. 15239922Sgonzo * 16239922Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17239922Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18239922Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19239922Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20239922Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21239922Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22239922Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23239922Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24239922Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25239922Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26239922Sgonzo * SUCH DAMAGE. 27239922Sgonzo */ 28239922Sgonzo 29239922Sgonzo 30239922Sgonzo#include <sys/cdefs.h> 31239922Sgonzo__FBSDID("$FreeBSD$"); 32239922Sgonzo 33239922Sgonzo#include <sys/param.h> 34239922Sgonzo#include <sys/systm.h> 35239922Sgonzo#include <sys/bus.h> 36239922Sgonzo#include <sys/kernel.h> 37239922Sgonzo#include <sys/ktr.h> 38239922Sgonzo#include <sys/module.h> 39239922Sgonzo#include <sys/rman.h> 40239922Sgonzo#include <machine/bus.h> 41239922Sgonzo#include <machine/intr.h> 42239922Sgonzo 43239922Sgonzo#include <dev/fdt/fdt_common.h> 44239922Sgonzo#include <dev/ofw/openfirm.h> 45239922Sgonzo#include <dev/ofw/ofw_bus.h> 46239922Sgonzo#include <dev/ofw/ofw_bus_subr.h> 47239922Sgonzo 48239922Sgonzo#define INTC_PENDING_BASIC 0x00 49239922Sgonzo#define INTC_PENDING_BANK1 0x04 50239922Sgonzo#define INTC_PENDING_BANK2 0x08 51239922Sgonzo#define INTC_FIQ_CONTROL 0x0C 52239922Sgonzo#define INTC_ENABLE_BANK1 0x10 53239922Sgonzo#define INTC_ENABLE_BANK2 0x14 54239922Sgonzo#define INTC_ENABLE_BASIC 0x18 55239922Sgonzo#define INTC_DISABLE_BANK1 0x1C 56239922Sgonzo#define INTC_DISABLE_BANK2 0x20 57239922Sgonzo#define INTC_DISABLE_BASIC 0x24 58239922Sgonzo 59239922Sgonzo#define BANK1_START 8 60239922Sgonzo#define BANK1_END (BANK1_START + 32 - 1) 61239922Sgonzo#define BANK2_START (BANK1_START + 32) 62239922Sgonzo#define BANK2_END (BANK2_START + 32 - 1) 63239922Sgonzo 64239922Sgonzo#define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START)) 65239922Sgonzo#define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END)) 66239922Sgonzo#define IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END)) 67239922Sgonzo#define IRQ_BANK1(n) ((n) - BANK1_START) 68239922Sgonzo#define IRQ_BANK2(n) ((n) - BANK2_START) 69239922Sgonzo 70239922Sgonzo#ifdef DEBUG 71239922Sgonzo#define dprintf(fmt, args...) printf(fmt, ##args) 72239922Sgonzo#else 73239922Sgonzo#define dprintf(fmt, args...) 74239922Sgonzo#endif 75239922Sgonzo 76239922Sgonzostruct bcm_intc_softc { 77239922Sgonzo device_t sc_dev; 78239922Sgonzo struct resource * intc_res; 79239922Sgonzo bus_space_tag_t intc_bst; 80239922Sgonzo bus_space_handle_t intc_bsh; 81239922Sgonzo}; 82239922Sgonzo 83239922Sgonzostatic struct bcm_intc_softc *bcm_intc_sc = NULL; 84239922Sgonzo 85239922Sgonzo#define intc_read_4(reg) \ 86239922Sgonzo bus_space_read_4(bcm_intc_sc->intc_bst, bcm_intc_sc->intc_bsh, reg) 87239922Sgonzo#define intc_write_4(reg, val) \ 88239922Sgonzo bus_space_write_4(bcm_intc_sc->intc_bst, bcm_intc_sc->intc_bsh, reg, val) 89239922Sgonzo 90239922Sgonzostatic int 91239922Sgonzobcm_intc_probe(device_t dev) 92239922Sgonzo{ 93266152Sian 94266152Sian if (!ofw_bus_status_okay(dev)) 95266152Sian return (ENXIO); 96266152Sian 97239922Sgonzo if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-armctrl-ic")) 98239922Sgonzo return (ENXIO); 99239922Sgonzo device_set_desc(dev, "BCM2835 Interrupt Controller"); 100239922Sgonzo return (BUS_PROBE_DEFAULT); 101239922Sgonzo} 102239922Sgonzo 103239922Sgonzostatic int 104239922Sgonzobcm_intc_attach(device_t dev) 105239922Sgonzo{ 106239922Sgonzo struct bcm_intc_softc *sc = device_get_softc(dev); 107239922Sgonzo int rid = 0; 108239922Sgonzo 109239922Sgonzo sc->sc_dev = dev; 110239922Sgonzo 111239922Sgonzo if (bcm_intc_sc) 112239922Sgonzo return (ENXIO); 113239922Sgonzo 114239922Sgonzo sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 115239922Sgonzo if (sc->intc_res == NULL) { 116239922Sgonzo device_printf(dev, "could not allocate memory resource\n"); 117239922Sgonzo return (ENXIO); 118239922Sgonzo } 119239922Sgonzo 120239922Sgonzo sc->intc_bst = rman_get_bustag(sc->intc_res); 121239922Sgonzo sc->intc_bsh = rman_get_bushandle(sc->intc_res); 122239922Sgonzo 123239922Sgonzo bcm_intc_sc = sc; 124239922Sgonzo 125239922Sgonzo return (0); 126239922Sgonzo} 127239922Sgonzo 128239922Sgonzostatic device_method_t bcm_intc_methods[] = { 129239922Sgonzo DEVMETHOD(device_probe, bcm_intc_probe), 130239922Sgonzo DEVMETHOD(device_attach, bcm_intc_attach), 131239922Sgonzo { 0, 0 } 132239922Sgonzo}; 133239922Sgonzo 134239922Sgonzostatic driver_t bcm_intc_driver = { 135239922Sgonzo "intc", 136239922Sgonzo bcm_intc_methods, 137239922Sgonzo sizeof(struct bcm_intc_softc), 138239922Sgonzo}; 139239922Sgonzo 140239922Sgonzostatic devclass_t bcm_intc_devclass; 141239922Sgonzo 142239922SgonzoDRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 0, 0); 143239922Sgonzo 144239922Sgonzoint 145239922Sgonzoarm_get_next_irq(int last_irq) 146239922Sgonzo{ 147239922Sgonzo uint32_t pending; 148239922Sgonzo int32_t irq = last_irq + 1; 149239922Sgonzo 150239922Sgonzo /* Sanity check */ 151239922Sgonzo if (irq < 0) 152239922Sgonzo irq = 0; 153239922Sgonzo 154239922Sgonzo /* TODO: should we mask last_irq? */ 155239922Sgonzo pending = intc_read_4(INTC_PENDING_BASIC); 156239922Sgonzo while (irq < BANK1_START) { 157239922Sgonzo if (pending & (1 << irq)) 158239922Sgonzo return irq; 159239922Sgonzo irq++; 160239922Sgonzo } 161239922Sgonzo 162239922Sgonzo pending = intc_read_4(INTC_PENDING_BANK1); 163239922Sgonzo while (irq < BANK2_START) { 164239922Sgonzo if (pending & (1 << IRQ_BANK1(irq))) 165239922Sgonzo return irq; 166239922Sgonzo irq++; 167239922Sgonzo } 168239922Sgonzo 169239922Sgonzo pending = intc_read_4(INTC_PENDING_BANK2); 170239922Sgonzo while (irq <= BANK2_END) { 171239922Sgonzo if (pending & (1 << IRQ_BANK2(irq))) 172239922Sgonzo return irq; 173239922Sgonzo irq++; 174239922Sgonzo } 175239922Sgonzo 176239922Sgonzo return (-1); 177239922Sgonzo} 178239922Sgonzo 179239922Sgonzovoid 180239922Sgonzoarm_mask_irq(uintptr_t nb) 181239922Sgonzo{ 182239922Sgonzo dprintf("%s: %d\n", __func__, nb); 183239922Sgonzo 184239922Sgonzo if (IS_IRQ_BASIC(nb)) 185239922Sgonzo intc_write_4(INTC_DISABLE_BASIC, (1 << nb)); 186239922Sgonzo else if (IS_IRQ_BANK1(nb)) 187239922Sgonzo intc_write_4(INTC_DISABLE_BANK1, (1 << IRQ_BANK1(nb))); 188239922Sgonzo else if (IS_IRQ_BANK2(nb)) 189239922Sgonzo intc_write_4(INTC_DISABLE_BANK2, (1 << IRQ_BANK2(nb))); 190239922Sgonzo else 191239922Sgonzo printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); 192239922Sgonzo} 193239922Sgonzo 194239922Sgonzovoid 195239922Sgonzoarm_unmask_irq(uintptr_t nb) 196239922Sgonzo{ 197239922Sgonzo dprintf("%s: %d\n", __func__, nb); 198239922Sgonzo 199239922Sgonzo if (IS_IRQ_BASIC(nb)) 200239922Sgonzo intc_write_4(INTC_ENABLE_BASIC, (1 << nb)); 201239922Sgonzo else if (IS_IRQ_BANK1(nb)) 202239922Sgonzo intc_write_4(INTC_ENABLE_BANK1, (1 << IRQ_BANK1(nb))); 203239922Sgonzo else if (IS_IRQ_BANK2(nb)) 204239922Sgonzo intc_write_4(INTC_ENABLE_BANK2, (1 << IRQ_BANK2(nb))); 205239922Sgonzo else 206239922Sgonzo printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); 207239922Sgonzo} 208