1*4e46a66eSAndrew Turner /* 2*4e46a66eSAndrew Turner * Copyright 2015 Andrew Turner. 3*4e46a66eSAndrew Turner * All rights reserved. 4*4e46a66eSAndrew Turner * 5*4e46a66eSAndrew Turner * Redistribution and use in source and binary forms, with or without 6*4e46a66eSAndrew Turner * modification, are permitted provided that the following conditions are 7*4e46a66eSAndrew Turner * met: 8*4e46a66eSAndrew Turner * 9*4e46a66eSAndrew Turner * 1. Redistributions of source code must retain the above copyright 10*4e46a66eSAndrew Turner * notice, this list of conditions and the following disclaimer. 11*4e46a66eSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 12*4e46a66eSAndrew Turner * notice, this list of conditions and the following disclaimer in the 13*4e46a66eSAndrew Turner * documentation and/or other materials provided with the distribution. 14*4e46a66eSAndrew Turner * 15*4e46a66eSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*4e46a66eSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*4e46a66eSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18*4e46a66eSAndrew Turner * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 19*4e46a66eSAndrew Turner * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*4e46a66eSAndrew Turner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*4e46a66eSAndrew Turner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22*4e46a66eSAndrew Turner * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23*4e46a66eSAndrew Turner * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24*4e46a66eSAndrew Turner * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25*4e46a66eSAndrew Turner * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26*4e46a66eSAndrew Turner */ 27*4e46a66eSAndrew Turner 28*4e46a66eSAndrew Turner #include <sys/cdefs.h> 29*4e46a66eSAndrew Turner __FBSDID("$FreeBSD$"); 30*4e46a66eSAndrew Turner 31*4e46a66eSAndrew Turner #include <sys/param.h> 32*4e46a66eSAndrew Turner #include <sys/systm.h> 33*4e46a66eSAndrew Turner #include <sys/bus.h> 34*4e46a66eSAndrew Turner #include <sys/kernel.h> 35*4e46a66eSAndrew Turner #include <sys/module.h> 36*4e46a66eSAndrew Turner #include <sys/rman.h> 37*4e46a66eSAndrew Turner 38*4e46a66eSAndrew Turner #include <machine/bus.h> 39*4e46a66eSAndrew Turner #include <machine/resource.h> 40*4e46a66eSAndrew Turner 41*4e46a66eSAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 42*4e46a66eSAndrew Turner #include <dev/ofw/ofw_bus.h> 43*4e46a66eSAndrew Turner 44*4e46a66eSAndrew Turner #include <arm/broadcom/bcm2835/bcm2836.h> 45*4e46a66eSAndrew Turner 46*4e46a66eSAndrew Turner #define ARM_LOCAL_BASE 0x40000000 47*4e46a66eSAndrew Turner #define ARM_LOCAL_SIZE 0x00001000 48*4e46a66eSAndrew Turner 49*4e46a66eSAndrew Turner #define ARM_LOCAL_CONTROL 0x00 50*4e46a66eSAndrew Turner #define ARM_LOCAL_PRESCALER 0x08 51*4e46a66eSAndrew Turner #define PRESCALER_19_2 0x80000000 /* 19.2 MHz */ 52*4e46a66eSAndrew Turner #define ARM_LOCAL_INT_TIMER(n) (0x40 + (n) * 4) 53*4e46a66eSAndrew Turner #define ARM_LOCAL_INT_MAILBOX(n) (0x50 + (n) * 4) 54*4e46a66eSAndrew Turner #define ARM_LOCAL_INT_PENDING(n) (0x60 + (n) * 4) 55*4e46a66eSAndrew Turner #define INT_PENDING_MASK 0x0f 56*4e46a66eSAndrew Turner 57*4e46a66eSAndrew Turner /* 58*4e46a66eSAndrew Turner * A driver for features of the bcm2836. 59*4e46a66eSAndrew Turner */ 60*4e46a66eSAndrew Turner 61*4e46a66eSAndrew Turner struct bcm2836_softc { 62*4e46a66eSAndrew Turner device_t sc_dev; 63*4e46a66eSAndrew Turner struct resource *sc_mem; 64*4e46a66eSAndrew Turner }; 65*4e46a66eSAndrew Turner 66*4e46a66eSAndrew Turner static device_identify_t bcm2836_identify; 67*4e46a66eSAndrew Turner static device_probe_t bcm2836_probe; 68*4e46a66eSAndrew Turner static device_attach_t bcm2836_attach; 69*4e46a66eSAndrew Turner 70*4e46a66eSAndrew Turner struct bcm2836_softc *softc; 71*4e46a66eSAndrew Turner 72*4e46a66eSAndrew Turner static void 73*4e46a66eSAndrew Turner bcm2836_identify(driver_t *driver, device_t parent) 74*4e46a66eSAndrew Turner { 75*4e46a66eSAndrew Turner 76*4e46a66eSAndrew Turner if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL) 77*4e46a66eSAndrew Turner device_printf(parent, "add child failed\n"); 78*4e46a66eSAndrew Turner } 79*4e46a66eSAndrew Turner 80*4e46a66eSAndrew Turner static int 81*4e46a66eSAndrew Turner bcm2836_probe(device_t dev) 82*4e46a66eSAndrew Turner { 83*4e46a66eSAndrew Turner 84*4e46a66eSAndrew Turner if (softc != NULL) 85*4e46a66eSAndrew Turner return (ENXIO); 86*4e46a66eSAndrew Turner 87*4e46a66eSAndrew Turner device_set_desc(dev, "Broadcom bcm2836"); 88*4e46a66eSAndrew Turner 89*4e46a66eSAndrew Turner return (BUS_PROBE_DEFAULT); 90*4e46a66eSAndrew Turner } 91*4e46a66eSAndrew Turner 92*4e46a66eSAndrew Turner static int 93*4e46a66eSAndrew Turner bcm2836_attach(device_t dev) 94*4e46a66eSAndrew Turner { 95*4e46a66eSAndrew Turner int i, rid; 96*4e46a66eSAndrew Turner 97*4e46a66eSAndrew Turner softc = device_get_softc(dev); 98*4e46a66eSAndrew Turner softc->sc_dev = dev; 99*4e46a66eSAndrew Turner 100*4e46a66eSAndrew Turner rid = 0; 101*4e46a66eSAndrew Turner softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 102*4e46a66eSAndrew Turner ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE, 103*4e46a66eSAndrew Turner RF_ACTIVE); 104*4e46a66eSAndrew Turner if (softc->sc_mem == NULL) { 105*4e46a66eSAndrew Turner device_printf(dev, "could not allocate memory resource\n"); 106*4e46a66eSAndrew Turner return (ENXIO); 107*4e46a66eSAndrew Turner } 108*4e46a66eSAndrew Turner 109*4e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0); 110*4e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2); 111*4e46a66eSAndrew Turner 112*4e46a66eSAndrew Turner for (i = 0; i < 4; i++) 113*4e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0); 114*4e46a66eSAndrew Turner 115*4e46a66eSAndrew Turner for (i = 0; i < 4; i++) 116*4e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1); 117*4e46a66eSAndrew Turner 118*4e46a66eSAndrew Turner return (0); 119*4e46a66eSAndrew Turner } 120*4e46a66eSAndrew Turner 121*4e46a66eSAndrew Turner int 122*4e46a66eSAndrew Turner bcm2836_get_next_irq(int last_irq) 123*4e46a66eSAndrew Turner { 124*4e46a66eSAndrew Turner uint32_t reg; 125*4e46a66eSAndrew Turner int cpu; 126*4e46a66eSAndrew Turner int irq; 127*4e46a66eSAndrew Turner 128*4e46a66eSAndrew Turner cpu = PCPU_GET(cpuid); 129*4e46a66eSAndrew Turner 130*4e46a66eSAndrew Turner reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu)); 131*4e46a66eSAndrew Turner reg &= INT_PENDING_MASK; 132*4e46a66eSAndrew Turner if (reg == 0) 133*4e46a66eSAndrew Turner return (-1); 134*4e46a66eSAndrew Turner 135*4e46a66eSAndrew Turner irq = ffs(reg) - 1; 136*4e46a66eSAndrew Turner 137*4e46a66eSAndrew Turner return (irq); 138*4e46a66eSAndrew Turner } 139*4e46a66eSAndrew Turner 140*4e46a66eSAndrew Turner void 141*4e46a66eSAndrew Turner bcm2836_mask_irq(uintptr_t irq) 142*4e46a66eSAndrew Turner { 143*4e46a66eSAndrew Turner uint32_t reg; 144*4e46a66eSAndrew Turner int i; 145*4e46a66eSAndrew Turner 146*4e46a66eSAndrew Turner for (i = 0; i < 4; i++) { 147*4e46a66eSAndrew Turner reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i)); 148*4e46a66eSAndrew Turner reg &= ~(1 << irq); 149*4e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), reg); 150*4e46a66eSAndrew Turner } 151*4e46a66eSAndrew Turner } 152*4e46a66eSAndrew Turner 153*4e46a66eSAndrew Turner void 154*4e46a66eSAndrew Turner bcm2836_unmask_irq(uintptr_t irq) 155*4e46a66eSAndrew Turner { 156*4e46a66eSAndrew Turner uint32_t reg; 157*4e46a66eSAndrew Turner int i; 158*4e46a66eSAndrew Turner 159*4e46a66eSAndrew Turner for (i = 0; i < 4; i++) { 160*4e46a66eSAndrew Turner reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i)); 161*4e46a66eSAndrew Turner reg |= (1 << irq); 162*4e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), reg); 163*4e46a66eSAndrew Turner } 164*4e46a66eSAndrew Turner } 165*4e46a66eSAndrew Turner 166*4e46a66eSAndrew Turner static device_method_t bcm2836_methods[] = { 167*4e46a66eSAndrew Turner /* Device interface */ 168*4e46a66eSAndrew Turner DEVMETHOD(device_identify, bcm2836_identify), 169*4e46a66eSAndrew Turner DEVMETHOD(device_probe, bcm2836_probe), 170*4e46a66eSAndrew Turner DEVMETHOD(device_attach, bcm2836_attach), 171*4e46a66eSAndrew Turner 172*4e46a66eSAndrew Turner DEVMETHOD_END 173*4e46a66eSAndrew Turner }; 174*4e46a66eSAndrew Turner 175*4e46a66eSAndrew Turner static devclass_t bcm2836_devclass; 176*4e46a66eSAndrew Turner 177*4e46a66eSAndrew Turner static driver_t bcm2836_driver = { 178*4e46a66eSAndrew Turner "bcm2836", 179*4e46a66eSAndrew Turner bcm2836_methods, 180*4e46a66eSAndrew Turner sizeof(struct bcm2836_softc), 181*4e46a66eSAndrew Turner }; 182*4e46a66eSAndrew Turner 183*4e46a66eSAndrew Turner EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0, 184*4e46a66eSAndrew Turner BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 185