14e46a66eSAndrew Turner /* 24e46a66eSAndrew Turner * Copyright 2015 Andrew Turner. 3120b6fc9SSvatopluk Kraus * Copyright 2016 Svatopluk Kraus 44e46a66eSAndrew Turner * All rights reserved. 54e46a66eSAndrew Turner * 64e46a66eSAndrew Turner * Redistribution and use in source and binary forms, with or without 74e46a66eSAndrew Turner * modification, are permitted provided that the following conditions are 84e46a66eSAndrew Turner * met: 94e46a66eSAndrew Turner * 104e46a66eSAndrew Turner * 1. Redistributions of source code must retain the above copyright 114e46a66eSAndrew Turner * notice, this list of conditions and the following disclaimer. 124e46a66eSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 134e46a66eSAndrew Turner * notice, this list of conditions and the following disclaimer in the 144e46a66eSAndrew Turner * documentation and/or other materials provided with the distribution. 154e46a66eSAndrew Turner * 164e46a66eSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174e46a66eSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184e46a66eSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 194e46a66eSAndrew Turner * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 204e46a66eSAndrew Turner * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 214e46a66eSAndrew Turner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 224e46a66eSAndrew Turner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 234e46a66eSAndrew Turner * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 244e46a66eSAndrew Turner * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 254e46a66eSAndrew Turner * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 264e46a66eSAndrew Turner * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274e46a66eSAndrew Turner */ 284e46a66eSAndrew Turner 294e46a66eSAndrew Turner #include <sys/cdefs.h> 304e46a66eSAndrew Turner __FBSDID("$FreeBSD$"); 314e46a66eSAndrew Turner 32120b6fc9SSvatopluk Kraus #include "opt_platform.h" 33120b6fc9SSvatopluk Kraus 344e46a66eSAndrew Turner #include <sys/param.h> 354e46a66eSAndrew Turner #include <sys/systm.h> 364e46a66eSAndrew Turner #include <sys/bus.h> 37120b6fc9SSvatopluk Kraus #include <sys/cpuset.h> 384e46a66eSAndrew Turner #include <sys/kernel.h> 394e46a66eSAndrew Turner #include <sys/module.h> 40120b6fc9SSvatopluk Kraus #include <sys/proc.h> 414e46a66eSAndrew Turner #include <sys/rman.h> 42120b6fc9SSvatopluk Kraus #ifdef SMP 43120b6fc9SSvatopluk Kraus #include <sys/smp.h> 44120b6fc9SSvatopluk Kraus #endif 454e46a66eSAndrew Turner 464e46a66eSAndrew Turner #include <machine/bus.h> 47120b6fc9SSvatopluk Kraus #include <machine/intr.h> 484e46a66eSAndrew Turner #include <machine/resource.h> 49120b6fc9SSvatopluk Kraus #ifdef SMP 50120b6fc9SSvatopluk Kraus #include <machine/smp.h> 51120b6fc9SSvatopluk Kraus #endif 524e46a66eSAndrew Turner 534e46a66eSAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 544e46a66eSAndrew Turner #include <dev/ofw/ofw_bus.h> 554e46a66eSAndrew Turner 5659c3cb81SAndrew Turner #ifdef INTRNG 57120b6fc9SSvatopluk Kraus #include "pic_if.h" 58120b6fc9SSvatopluk Kraus #else 594e46a66eSAndrew Turner #include <arm/broadcom/bcm2835/bcm2836.h> 604e46a66eSAndrew Turner 614e46a66eSAndrew Turner #define ARM_LOCAL_BASE 0x40000000 624e46a66eSAndrew Turner #define ARM_LOCAL_SIZE 0x00001000 634e46a66eSAndrew Turner 644e46a66eSAndrew Turner #define ARM_LOCAL_CONTROL 0x00 654e46a66eSAndrew Turner #define ARM_LOCAL_PRESCALER 0x08 664e46a66eSAndrew Turner #define PRESCALER_19_2 0x80000000 /* 19.2 MHz */ 674e46a66eSAndrew Turner #define ARM_LOCAL_INT_TIMER(n) (0x40 + (n) * 4) 684e46a66eSAndrew Turner #define ARM_LOCAL_INT_MAILBOX(n) (0x50 + (n) * 4) 694e46a66eSAndrew Turner #define ARM_LOCAL_INT_PENDING(n) (0x60 + (n) * 4) 703084b64cSSvatopluk Kraus #define INT_PENDING_MASK 0x011f 71962940ceSLuiz Otavio O Souza #define MAILBOX0_IRQ 4 72962940ceSLuiz Otavio O Souza #define MAILBOX0_IRQEN (1 << 0) 73120b6fc9SSvatopluk Kraus #endif 744e46a66eSAndrew Turner 7559c3cb81SAndrew Turner #ifdef INTRNG 76120b6fc9SSvatopluk Kraus #define BCM_LINTC_CONTROL_REG 0x00 77120b6fc9SSvatopluk Kraus #define BCM_LINTC_PRESCALER_REG 0x08 78120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_ROUTING_REG 0x0c 79120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10 80120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14 81120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4) 82120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4) 83120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4) 84120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16) 85120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16) 86120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16) 87120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16) 88120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16) 89120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16) 90120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16) 91120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16) 92120b6fc9SSvatopluk Kraus 93120b6fc9SSvatopluk Kraus /* Prescaler Register */ 94120b6fc9SSvatopluk Kraus #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */ 95120b6fc9SSvatopluk Kraus 96120b6fc9SSvatopluk Kraus /* GPU Interrupt Routing Register */ 97120b6fc9SSvatopluk Kraus #define BCM_LINTC_GIRR_IRQ_CORE(n) (n) 98120b6fc9SSvatopluk Kraus #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2) 99120b6fc9SSvatopluk Kraus 100120b6fc9SSvatopluk Kraus /* PMU Interrupt Routing Register */ 101120b6fc9SSvatopluk Kraus #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n)) 102120b6fc9SSvatopluk Kraus #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4)) 103120b6fc9SSvatopluk Kraus 104120b6fc9SSvatopluk Kraus /* Timer Config Register */ 105120b6fc9SSvatopluk Kraus #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n)) 106120b6fc9SSvatopluk Kraus #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4)) 107120b6fc9SSvatopluk Kraus 108120b6fc9SSvatopluk Kraus /* MBOX Config Register */ 109120b6fc9SSvatopluk Kraus #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n)) 110120b6fc9SSvatopluk Kraus #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4)) 111120b6fc9SSvatopluk Kraus 112120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTPSIRQ_IRQ 0 113120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTPNSIRQ_IRQ 1 114120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTHPIRQ_IRQ 2 115120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTVIRQ_IRQ 3 116120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_IRQ 4 117120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_IRQ 5 118120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_IRQ 6 119120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_IRQ 7 120120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_IRQ 8 121120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_IRQ 9 122120b6fc9SSvatopluk Kraus #define BCM_LINTC_AXI_IRQ 10 123120b6fc9SSvatopluk Kraus #define BCM_LINTC_LTIMER_IRQ 11 124120b6fc9SSvatopluk Kraus 125120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIRQS 12 126120b6fc9SSvatopluk Kraus 127120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ 128120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ 129120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ 130120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ 131120b6fc9SSvatopluk Kraus 132120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ) 133120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ) 134120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ) 135120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ) 136120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ) 137120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ) 138120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ) 139120b6fc9SSvatopluk Kraus 140120b6fc9SSvatopluk Kraus #define BCM_LINTC_UP_PENDING_MASK \ 141120b6fc9SSvatopluk Kraus (BCM_LINTC_TIMER0_IRQ_MASK | \ 142120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER1_IRQ_MASK | \ 143120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER2_IRQ_MASK | \ 144120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER3_IRQ_MASK | \ 145120b6fc9SSvatopluk Kraus BCM_LINTC_GPU_IRQ_MASK | \ 146120b6fc9SSvatopluk Kraus BCM_LINTC_PMU_IRQ_MASK) 147120b6fc9SSvatopluk Kraus 148120b6fc9SSvatopluk Kraus #define BCM_LINTC_SMP_PENDING_MASK \ 149120b6fc9SSvatopluk Kraus (BCM_LINTC_UP_PENDING_MASK | \ 150120b6fc9SSvatopluk Kraus BCM_LINTC_MBOX0_IRQ_MASK) 151120b6fc9SSvatopluk Kraus 152120b6fc9SSvatopluk Kraus #ifdef SMP 153120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK 154120b6fc9SSvatopluk Kraus #else 155120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK 156120b6fc9SSvatopluk Kraus #endif 157120b6fc9SSvatopluk Kraus 158120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc { 159120b6fc9SSvatopluk Kraus struct intr_irqsrc bli_isrc; 160120b6fc9SSvatopluk Kraus u_int bli_irq; 161120b6fc9SSvatopluk Kraus union { 162120b6fc9SSvatopluk Kraus u_int bli_mask; /* for timers */ 163120b6fc9SSvatopluk Kraus u_int bli_value; /* for GPU */ 164120b6fc9SSvatopluk Kraus }; 165120b6fc9SSvatopluk Kraus }; 166120b6fc9SSvatopluk Kraus 167120b6fc9SSvatopluk Kraus struct bcm_lintc_softc { 168120b6fc9SSvatopluk Kraus device_t bls_dev; 169120b6fc9SSvatopluk Kraus struct mtx bls_mtx; 170120b6fc9SSvatopluk Kraus struct resource * bls_mem; 171120b6fc9SSvatopluk Kraus bus_space_tag_t bls_bst; 172120b6fc9SSvatopluk Kraus bus_space_handle_t bls_bsh; 173120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS]; 174120b6fc9SSvatopluk Kraus }; 175120b6fc9SSvatopluk Kraus 176120b6fc9SSvatopluk Kraus static struct bcm_lintc_softc *bcm_lintc_sc; 177120b6fc9SSvatopluk Kraus 178120b6fc9SSvatopluk Kraus #ifdef SMP 179120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */ 180120b6fc9SSvatopluk Kraus CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS); 181120b6fc9SSvatopluk Kraus #endif 182120b6fc9SSvatopluk Kraus 183120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx) 184120b6fc9SSvatopluk Kraus #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx) 185120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \ 186120b6fc9SSvatopluk Kraus device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN) 187120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx) 188120b6fc9SSvatopluk Kraus 189120b6fc9SSvatopluk Kraus #define bcm_lintc_read_4(sc, reg) \ 190120b6fc9SSvatopluk Kraus bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg)) 191120b6fc9SSvatopluk Kraus #define bcm_lintc_write_4(sc, reg, val) \ 192120b6fc9SSvatopluk Kraus bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val)) 193120b6fc9SSvatopluk Kraus 194120b6fc9SSvatopluk Kraus static inline void 195120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg, 196120b6fc9SSvatopluk Kraus uint32_t mask) 197120b6fc9SSvatopluk Kraus { 198120b6fc9SSvatopluk Kraus 199120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask); 200120b6fc9SSvatopluk Kraus } 201120b6fc9SSvatopluk Kraus 202120b6fc9SSvatopluk Kraus static inline void 203120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg, 204120b6fc9SSvatopluk Kraus uint32_t mask) 205120b6fc9SSvatopluk Kraus { 206120b6fc9SSvatopluk Kraus 207120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask); 208120b6fc9SSvatopluk Kraus } 209120b6fc9SSvatopluk Kraus 210120b6fc9SSvatopluk Kraus static void 211120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 212120b6fc9SSvatopluk Kraus { 213120b6fc9SSvatopluk Kraus cpuset_t *cpus; 214120b6fc9SSvatopluk Kraus uint32_t cpu; 215120b6fc9SSvatopluk Kraus 216120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 217120b6fc9SSvatopluk Kraus 218120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 219120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 220120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 221120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 222120b6fc9SSvatopluk Kraus bli->bli_mask); 223120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 224120b6fc9SSvatopluk Kraus } 225120b6fc9SSvatopluk Kraus 226120b6fc9SSvatopluk Kraus static void 227120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 228120b6fc9SSvatopluk Kraus { 229120b6fc9SSvatopluk Kraus cpuset_t *cpus; 230120b6fc9SSvatopluk Kraus uint32_t cpu; 231120b6fc9SSvatopluk Kraus 232120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 233120b6fc9SSvatopluk Kraus 234120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 235120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 236120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 237120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 238120b6fc9SSvatopluk Kraus bli->bli_mask); 239120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 240120b6fc9SSvatopluk Kraus } 241120b6fc9SSvatopluk Kraus 242120b6fc9SSvatopluk Kraus static inline void 243120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 244120b6fc9SSvatopluk Kraus { 245120b6fc9SSvatopluk Kraus 246120b6fc9SSvatopluk Kraus /* It's accessed just and only by one core. */ 247120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0); 248120b6fc9SSvatopluk Kraus } 249120b6fc9SSvatopluk Kraus 250120b6fc9SSvatopluk Kraus static inline void 251120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 252120b6fc9SSvatopluk Kraus { 253120b6fc9SSvatopluk Kraus 254120b6fc9SSvatopluk Kraus /* It's accessed just and only by one core. */ 255120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value); 256120b6fc9SSvatopluk Kraus } 257120b6fc9SSvatopluk Kraus 258120b6fc9SSvatopluk Kraus static inline void 259120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 260120b6fc9SSvatopluk Kraus { 261120b6fc9SSvatopluk Kraus cpuset_t *cpus; 262120b6fc9SSvatopluk Kraus uint32_t cpu, mask; 263120b6fc9SSvatopluk Kraus 264120b6fc9SSvatopluk Kraus mask = 0; 265120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 266120b6fc9SSvatopluk Kraus 267120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 268120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 269120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 270120b6fc9SSvatopluk Kraus mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); 271120b6fc9SSvatopluk Kraus /* Write-clear register. */ 272120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask); 273120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 274120b6fc9SSvatopluk Kraus } 275120b6fc9SSvatopluk Kraus 276120b6fc9SSvatopluk Kraus static inline void 277120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 278120b6fc9SSvatopluk Kraus { 279120b6fc9SSvatopluk Kraus cpuset_t *cpus; 280120b6fc9SSvatopluk Kraus uint32_t cpu, mask; 281120b6fc9SSvatopluk Kraus 282120b6fc9SSvatopluk Kraus mask = 0; 283120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 284120b6fc9SSvatopluk Kraus 285120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 286120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 287120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 288120b6fc9SSvatopluk Kraus mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); 289120b6fc9SSvatopluk Kraus /* Write-set register. */ 290120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask); 291120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 292120b6fc9SSvatopluk Kraus } 293120b6fc9SSvatopluk Kraus 294120b6fc9SSvatopluk Kraus static void 295120b6fc9SSvatopluk Kraus bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 296120b6fc9SSvatopluk Kraus { 297120b6fc9SSvatopluk Kraus 298120b6fc9SSvatopluk Kraus switch (bli->bli_irq) { 299120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ: 300120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ: 301120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ: 302120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ: 303120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(sc, bli); 304120b6fc9SSvatopluk Kraus return; 305120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ: 306120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ: 307120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ: 308120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ: 309120b6fc9SSvatopluk Kraus return; 310120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ: 311120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(sc, bli); 312120b6fc9SSvatopluk Kraus return; 313120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ: 314120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(sc, bli); 315120b6fc9SSvatopluk Kraus return; 316120b6fc9SSvatopluk Kraus default: 317120b6fc9SSvatopluk Kraus panic("%s: not implemented for irq %u", __func__, bli->bli_irq); 318120b6fc9SSvatopluk Kraus } 319120b6fc9SSvatopluk Kraus } 320120b6fc9SSvatopluk Kraus 321120b6fc9SSvatopluk Kraus static void 322120b6fc9SSvatopluk Kraus bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 323120b6fc9SSvatopluk Kraus { 324120b6fc9SSvatopluk Kraus 325120b6fc9SSvatopluk Kraus switch (bli->bli_irq) { 326120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ: 327120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ: 328120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ: 329120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ: 330120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(sc, bli); 331120b6fc9SSvatopluk Kraus return; 332120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ: 333120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ: 334120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ: 335120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ: 336120b6fc9SSvatopluk Kraus return; 337120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ: 338120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(sc, bli); 339120b6fc9SSvatopluk Kraus return; 340120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ: 341120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(sc, bli); 342120b6fc9SSvatopluk Kraus return; 343120b6fc9SSvatopluk Kraus default: 344120b6fc9SSvatopluk Kraus panic("%s: not implemented for irq %u", __func__, bli->bli_irq); 345120b6fc9SSvatopluk Kraus } 346120b6fc9SSvatopluk Kraus } 347120b6fc9SSvatopluk Kraus 348120b6fc9SSvatopluk Kraus #ifdef SMP 349120b6fc9SSvatopluk Kraus static inline void 350120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi) 351120b6fc9SSvatopluk Kraus { 352120b6fc9SSvatopluk Kraus u_int cpu; 353120b6fc9SSvatopluk Kraus uint32_t mask; 354120b6fc9SSvatopluk Kraus 355120b6fc9SSvatopluk Kraus mask = 1 << ipi; 356120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < mp_ncpus; cpu++) 357120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, &cpus)) 358120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu), 359120b6fc9SSvatopluk Kraus mask); 360120b6fc9SSvatopluk Kraus } 361120b6fc9SSvatopluk Kraus 362120b6fc9SSvatopluk Kraus static inline void 363120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu, 364120b6fc9SSvatopluk Kraus struct trapframe *tf) 365120b6fc9SSvatopluk Kraus { 366120b6fc9SSvatopluk Kraus u_int ipi; 367120b6fc9SSvatopluk Kraus uint32_t mask; 368120b6fc9SSvatopluk Kraus 369120b6fc9SSvatopluk Kraus mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu)); 370120b6fc9SSvatopluk Kraus if (mask == 0) { 371120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Spurious ipi detected\n"); 372120b6fc9SSvatopluk Kraus return; 373120b6fc9SSvatopluk Kraus } 374120b6fc9SSvatopluk Kraus 375120b6fc9SSvatopluk Kraus for (ipi = 0; mask != 0; mask >>= 1, ipi++) { 376120b6fc9SSvatopluk Kraus if ((mask & 0x01) == 0) 377120b6fc9SSvatopluk Kraus continue; 378120b6fc9SSvatopluk Kraus /* 379120b6fc9SSvatopluk Kraus * Clear an IPI before dispatching to not miss anyone 380120b6fc9SSvatopluk Kraus * and make sure that it's observed by everybody. 381120b6fc9SSvatopluk Kraus */ 382120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi); 383120b6fc9SSvatopluk Kraus dsb(); 384120b6fc9SSvatopluk Kraus intr_ipi_dispatch(ipi, tf); 385120b6fc9SSvatopluk Kraus } 386120b6fc9SSvatopluk Kraus } 387120b6fc9SSvatopluk Kraus #endif 388120b6fc9SSvatopluk Kraus 389120b6fc9SSvatopluk Kraus static inline void 390120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq, 391120b6fc9SSvatopluk Kraus struct trapframe *tf) 392120b6fc9SSvatopluk Kraus { 393120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli; 394120b6fc9SSvatopluk Kraus 395120b6fc9SSvatopluk Kraus bli = &sc->bls_isrcs[irq]; 396120b6fc9SSvatopluk Kraus if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0) 397120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Stray irq %u detected\n", irq); 398120b6fc9SSvatopluk Kraus } 399120b6fc9SSvatopluk Kraus 400120b6fc9SSvatopluk Kraus static int 401120b6fc9SSvatopluk Kraus bcm_lintc_intr(void *arg) 402120b6fc9SSvatopluk Kraus { 403120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 404120b6fc9SSvatopluk Kraus u_int cpu; 405120b6fc9SSvatopluk Kraus uint32_t num, reg; 406120b6fc9SSvatopluk Kraus struct trapframe *tf; 407120b6fc9SSvatopluk Kraus 408120b6fc9SSvatopluk Kraus sc = arg; 409120b6fc9SSvatopluk Kraus cpu = PCPU_GET(cpuid); 410120b6fc9SSvatopluk Kraus tf = curthread->td_intr_frame; 411120b6fc9SSvatopluk Kraus 412120b6fc9SSvatopluk Kraus for (num = 0; ; num++) { 413120b6fc9SSvatopluk Kraus reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu)); 414120b6fc9SSvatopluk Kraus if ((reg & BCM_LINTC_PENDING_MASK) == 0) 415120b6fc9SSvatopluk Kraus break; 416120b6fc9SSvatopluk Kraus #ifdef SMP 417120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_MBOX0_IRQ_MASK) 418120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(sc, cpu, tf); 419120b6fc9SSvatopluk Kraus #endif 420120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER0_IRQ_MASK) 421120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf); 422120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER1_IRQ_MASK) 423120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf); 424120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER2_IRQ_MASK) 425120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf); 426120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER3_IRQ_MASK) 427120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf); 428120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_GPU_IRQ_MASK) 429120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf); 430120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_PMU_IRQ_MASK) 431120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf); 432120b6fc9SSvatopluk Kraus 433120b6fc9SSvatopluk Kraus arm_irq_memory_barrier(0); /* XXX */ 434120b6fc9SSvatopluk Kraus } 435120b6fc9SSvatopluk Kraus reg &= ~BCM_LINTC_PENDING_MASK; 436120b6fc9SSvatopluk Kraus if (reg != 0) 437120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg); 438120b6fc9SSvatopluk Kraus else if (num == 0) 439120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Spurious interrupt detected\n"); 440120b6fc9SSvatopluk Kraus 441120b6fc9SSvatopluk Kraus return (FILTER_HANDLED); 442120b6fc9SSvatopluk Kraus } 443120b6fc9SSvatopluk Kraus 444120b6fc9SSvatopluk Kraus static void 445120b6fc9SSvatopluk Kraus bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc) 446120b6fc9SSvatopluk Kraus { 447120b6fc9SSvatopluk Kraus 448120b6fc9SSvatopluk Kraus bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc); 449120b6fc9SSvatopluk Kraus } 450120b6fc9SSvatopluk Kraus 451120b6fc9SSvatopluk Kraus static void 452120b6fc9SSvatopluk Kraus bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc) 453120b6fc9SSvatopluk Kraus { 454120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 455120b6fc9SSvatopluk Kraus 456120b6fc9SSvatopluk Kraus arm_irq_memory_barrier(bli->bli_irq); 457120b6fc9SSvatopluk Kraus bcm_lintc_unmask(device_get_softc(dev), bli); 458120b6fc9SSvatopluk Kraus } 459120b6fc9SSvatopluk Kraus 460120b6fc9SSvatopluk Kraus static int 461120b6fc9SSvatopluk Kraus bcm_lintc_map_intr(device_t dev, struct intr_map_data *data, 462120b6fc9SSvatopluk Kraus struct intr_irqsrc **isrcp) 463120b6fc9SSvatopluk Kraus { 464cd642c88SSvatopluk Kraus struct intr_map_data_fdt *daf; 465120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 466120b6fc9SSvatopluk Kraus 467120b6fc9SSvatopluk Kraus if (data->type != INTR_MAP_DATA_FDT) 468120b6fc9SSvatopluk Kraus return (ENOTSUP); 469cd642c88SSvatopluk Kraus 470cd642c88SSvatopluk Kraus daf = (struct intr_map_data_fdt *)data; 471cd642c88SSvatopluk Kraus if (daf->ncells != 1 || daf->cells[0] >= BCM_LINTC_NIRQS) 472120b6fc9SSvatopluk Kraus return (EINVAL); 473120b6fc9SSvatopluk Kraus 474120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 475cd642c88SSvatopluk Kraus *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc; 476120b6fc9SSvatopluk Kraus return (0); 477120b6fc9SSvatopluk Kraus } 478120b6fc9SSvatopluk Kraus 479120b6fc9SSvatopluk Kraus static void 480120b6fc9SSvatopluk Kraus bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 481120b6fc9SSvatopluk Kraus { 482120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 483120b6fc9SSvatopluk Kraus 484120b6fc9SSvatopluk Kraus if (bli->bli_irq == BCM_LINTC_GPU_IRQ) 485120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(device_get_softc(dev), bli); 486120b6fc9SSvatopluk Kraus else { 487120b6fc9SSvatopluk Kraus /* 488120b6fc9SSvatopluk Kraus * Handler for PPI interrupt does not make sense much unless 489120b6fc9SSvatopluk Kraus * there is one bound ithread for each core for it. Thus the 490120b6fc9SSvatopluk Kraus * interrupt can be masked on current core only while ithread 491120b6fc9SSvatopluk Kraus * bounded to this core ensures unmasking on the same core. 492120b6fc9SSvatopluk Kraus */ 493120b6fc9SSvatopluk Kraus panic ("%s: handlers are not supported", __func__); 494120b6fc9SSvatopluk Kraus } 495120b6fc9SSvatopluk Kraus } 496120b6fc9SSvatopluk Kraus 497120b6fc9SSvatopluk Kraus static void 498120b6fc9SSvatopluk Kraus bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc) 499120b6fc9SSvatopluk Kraus { 500120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 501120b6fc9SSvatopluk Kraus 502120b6fc9SSvatopluk Kraus if (bli->bli_irq == BCM_LINTC_GPU_IRQ) 503120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(device_get_softc(dev), bli); 504120b6fc9SSvatopluk Kraus else { 505120b6fc9SSvatopluk Kraus /* See comment in bcm_lintc_pre_ithread(). */ 506120b6fc9SSvatopluk Kraus panic ("%s: handlers are not supported", __func__); 507120b6fc9SSvatopluk Kraus } 508120b6fc9SSvatopluk Kraus } 509120b6fc9SSvatopluk Kraus 510120b6fc9SSvatopluk Kraus static void 511120b6fc9SSvatopluk Kraus bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc) 512120b6fc9SSvatopluk Kraus { 513120b6fc9SSvatopluk Kraus } 514120b6fc9SSvatopluk Kraus 515120b6fc9SSvatopluk Kraus static int 516120b6fc9SSvatopluk Kraus bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc, 517120b6fc9SSvatopluk Kraus struct resource *res, struct intr_map_data *data) 518120b6fc9SSvatopluk Kraus { 519120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 520120b6fc9SSvatopluk Kraus 521120b6fc9SSvatopluk Kraus if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) { 522120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 523120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 524120b6fc9SSvatopluk Kraus CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 525120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 526120b6fc9SSvatopluk Kraus } 527120b6fc9SSvatopluk Kraus return (0); 528120b6fc9SSvatopluk Kraus } 529120b6fc9SSvatopluk Kraus 530120b6fc9SSvatopluk Kraus #ifdef SMP 531120b6fc9SSvatopluk Kraus static void 532120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq, 533120b6fc9SSvatopluk Kraus uint32_t reg, uint32_t mask) 534120b6fc9SSvatopluk Kraus { 535120b6fc9SSvatopluk Kraus 5365b613c19SSvatopluk Kraus if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu)) 537120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(sc, reg, mask); 538120b6fc9SSvatopluk Kraus } 539120b6fc9SSvatopluk Kraus 540120b6fc9SSvatopluk Kraus static void 541120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu) 542120b6fc9SSvatopluk Kraus { 5435b613c19SSvatopluk Kraus struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc; 544120b6fc9SSvatopluk Kraus 5455b613c19SSvatopluk Kraus if (intr_isrc_init_on_cpu(isrc, cpu)) { 546120b6fc9SSvatopluk Kraus /* Write-set register. */ 547120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, 548120b6fc9SSvatopluk Kraus BCM_LINTC_PIRR_IRQ_EN_CORE(cpu)); 549120b6fc9SSvatopluk Kraus } 550120b6fc9SSvatopluk Kraus } 551120b6fc9SSvatopluk Kraus 552120b6fc9SSvatopluk Kraus static void 553120b6fc9SSvatopluk Kraus bcm_lintc_init_secondary(device_t dev) 554120b6fc9SSvatopluk Kraus { 555120b6fc9SSvatopluk Kraus u_int cpu; 556120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 557120b6fc9SSvatopluk Kraus 558120b6fc9SSvatopluk Kraus cpu = PCPU_GET(cpuid); 559120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 560120b6fc9SSvatopluk Kraus 561120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 562120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ, 563120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0)); 564120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ, 565120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1)); 566120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ, 567120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2)); 568120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ, 569120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3)); 570120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(sc, cpu); 571120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 572120b6fc9SSvatopluk Kraus } 573120b6fc9SSvatopluk Kraus 574120b6fc9SSvatopluk Kraus static void 575120b6fc9SSvatopluk Kraus bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, 576120b6fc9SSvatopluk Kraus u_int ipi) 577120b6fc9SSvatopluk Kraus { 578120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc = device_get_softc(dev); 579120b6fc9SSvatopluk Kraus 580120b6fc9SSvatopluk Kraus KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc, 581120b6fc9SSvatopluk Kraus ("%s: bad ISRC %p argument", __func__, isrc)); 582120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(sc, cpus, ipi); 583120b6fc9SSvatopluk Kraus } 584120b6fc9SSvatopluk Kraus 585120b6fc9SSvatopluk Kraus static int 586120b6fc9SSvatopluk Kraus bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) 587120b6fc9SSvatopluk Kraus { 588120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc = device_get_softc(dev); 589120b6fc9SSvatopluk Kraus 590120b6fc9SSvatopluk Kraus KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi)); 591120b6fc9SSvatopluk Kraus 592120b6fc9SSvatopluk Kraus *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc; 593120b6fc9SSvatopluk Kraus return (0); 594120b6fc9SSvatopluk Kraus } 595120b6fc9SSvatopluk Kraus #endif 596120b6fc9SSvatopluk Kraus 597120b6fc9SSvatopluk Kraus static int 598120b6fc9SSvatopluk Kraus bcm_lintc_pic_attach(struct bcm_lintc_softc *sc) 599120b6fc9SSvatopluk Kraus { 600120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bisrcs; 601*9346e913SAndrew Turner struct intr_pic *pic; 602120b6fc9SSvatopluk Kraus int error; 603120b6fc9SSvatopluk Kraus u_int flags; 604120b6fc9SSvatopluk Kraus uint32_t irq; 605120b6fc9SSvatopluk Kraus const char *name; 606120b6fc9SSvatopluk Kraus intptr_t xref; 607120b6fc9SSvatopluk Kraus 608120b6fc9SSvatopluk Kraus bisrcs = sc->bls_isrcs; 609120b6fc9SSvatopluk Kraus name = device_get_nameunit(sc->bls_dev); 610120b6fc9SSvatopluk Kraus for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) { 611120b6fc9SSvatopluk Kraus bisrcs[irq].bli_irq = irq; 612120b6fc9SSvatopluk Kraus switch (irq) { 613120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ: 614120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0); 615120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 616120b6fc9SSvatopluk Kraus break; 617120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ: 618120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1); 619120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 620120b6fc9SSvatopluk Kraus break; 621120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ: 622120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2); 623120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 624120b6fc9SSvatopluk Kraus break; 625120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ: 626120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3); 627120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 628120b6fc9SSvatopluk Kraus break; 629120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ: 630120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ: 631120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ: 632120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ: 633120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */ 634120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_IPI; 635120b6fc9SSvatopluk Kraus break; 636120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ: 637120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0); 638120b6fc9SSvatopluk Kraus flags = 0; 639120b6fc9SSvatopluk Kraus break; 640120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ: 641120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */ 642120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 643120b6fc9SSvatopluk Kraus break; 644120b6fc9SSvatopluk Kraus default: 645120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */ 646120b6fc9SSvatopluk Kraus flags = 0; 647120b6fc9SSvatopluk Kraus break; 648120b6fc9SSvatopluk Kraus } 649120b6fc9SSvatopluk Kraus 650120b6fc9SSvatopluk Kraus error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev, 651120b6fc9SSvatopluk Kraus flags, "%s,%u", name, irq); 652120b6fc9SSvatopluk Kraus if (error != 0) 653120b6fc9SSvatopluk Kraus return (error); 654120b6fc9SSvatopluk Kraus } 655120b6fc9SSvatopluk Kraus 656120b6fc9SSvatopluk Kraus xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev)); 657*9346e913SAndrew Turner pic = intr_pic_register(sc->bls_dev, xref); 658*9346e913SAndrew Turner if (pic == NULL) 659*9346e913SAndrew Turner return (ENXIO); 660120b6fc9SSvatopluk Kraus 661120b6fc9SSvatopluk Kraus return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0)); 662120b6fc9SSvatopluk Kraus } 663120b6fc9SSvatopluk Kraus 664120b6fc9SSvatopluk Kraus static int 665120b6fc9SSvatopluk Kraus bcm_lintc_probe(device_t dev) 666120b6fc9SSvatopluk Kraus { 667120b6fc9SSvatopluk Kraus 668120b6fc9SSvatopluk Kraus if (!ofw_bus_status_okay(dev)) 669120b6fc9SSvatopluk Kraus return (ENXIO); 670120b6fc9SSvatopluk Kraus 671120b6fc9SSvatopluk Kraus if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc")) 672120b6fc9SSvatopluk Kraus return (ENXIO); 673120b6fc9SSvatopluk Kraus device_set_desc(dev, "BCM2836 Interrupt Controller"); 674120b6fc9SSvatopluk Kraus return (BUS_PROBE_DEFAULT); 675120b6fc9SSvatopluk Kraus } 676120b6fc9SSvatopluk Kraus 677120b6fc9SSvatopluk Kraus static int 678120b6fc9SSvatopluk Kraus bcm_lintc_attach(device_t dev) 679120b6fc9SSvatopluk Kraus { 680120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 681120b6fc9SSvatopluk Kraus int cpu, rid; 682120b6fc9SSvatopluk Kraus 683120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 684120b6fc9SSvatopluk Kraus 685120b6fc9SSvatopluk Kraus sc->bls_dev = dev; 686120b6fc9SSvatopluk Kraus if (bcm_lintc_sc != NULL) 687120b6fc9SSvatopluk Kraus return (ENXIO); 688120b6fc9SSvatopluk Kraus 689120b6fc9SSvatopluk Kraus rid = 0; 690120b6fc9SSvatopluk Kraus sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 691120b6fc9SSvatopluk Kraus RF_ACTIVE); 692120b6fc9SSvatopluk Kraus if (sc->bls_mem == NULL) { 693120b6fc9SSvatopluk Kraus device_printf(dev, "could not allocate memory resource\n"); 694120b6fc9SSvatopluk Kraus return (ENXIO); 695120b6fc9SSvatopluk Kraus } 696120b6fc9SSvatopluk Kraus 697120b6fc9SSvatopluk Kraus sc->bls_bst = rman_get_bustag(sc->bls_mem); 698120b6fc9SSvatopluk Kraus sc->bls_bsh = rman_get_bushandle(sc->bls_mem); 699120b6fc9SSvatopluk Kraus 700120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0); 701120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2); 702120b6fc9SSvatopluk Kraus 703120b6fc9SSvatopluk Kraus /* Disable all timers on all cores. */ 704120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 705120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0); 706120b6fc9SSvatopluk Kraus 707120b6fc9SSvatopluk Kraus #ifdef SMP 708120b6fc9SSvatopluk Kraus /* Enable mailbox 0 on all cores used for IPI. */ 709120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 710120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu), 711120b6fc9SSvatopluk Kraus BCM_LINTC_MCR_IRQ_EN_MBOX(0)); 712120b6fc9SSvatopluk Kraus #endif 713120b6fc9SSvatopluk Kraus 714120b6fc9SSvatopluk Kraus if (bcm_lintc_pic_attach(sc) != 0) { 715120b6fc9SSvatopluk Kraus device_printf(dev, "could not attach PIC\n"); 716120b6fc9SSvatopluk Kraus return (ENXIO); 717120b6fc9SSvatopluk Kraus } 718120b6fc9SSvatopluk Kraus 719120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK_INIT(sc); 720120b6fc9SSvatopluk Kraus bcm_lintc_sc = sc; 721120b6fc9SSvatopluk Kraus return (0); 722120b6fc9SSvatopluk Kraus } 723120b6fc9SSvatopluk Kraus 724120b6fc9SSvatopluk Kraus static device_method_t bcm_lintc_methods[] = { 725120b6fc9SSvatopluk Kraus DEVMETHOD(device_probe, bcm_lintc_probe), 726120b6fc9SSvatopluk Kraus DEVMETHOD(device_attach, bcm_lintc_attach), 727120b6fc9SSvatopluk Kraus 728120b6fc9SSvatopluk Kraus DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr), 729120b6fc9SSvatopluk Kraus DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr), 730120b6fc9SSvatopluk Kraus DEVMETHOD(pic_map_intr, bcm_lintc_map_intr), 731120b6fc9SSvatopluk Kraus DEVMETHOD(pic_post_filter, bcm_lintc_post_filter), 732120b6fc9SSvatopluk Kraus DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread), 733120b6fc9SSvatopluk Kraus DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread), 734120b6fc9SSvatopluk Kraus DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr), 735120b6fc9SSvatopluk Kraus #ifdef SMP 736120b6fc9SSvatopluk Kraus DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary), 737120b6fc9SSvatopluk Kraus DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send), 738120b6fc9SSvatopluk Kraus DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup), 739120b6fc9SSvatopluk Kraus #endif 740120b6fc9SSvatopluk Kraus 741120b6fc9SSvatopluk Kraus DEVMETHOD_END 742120b6fc9SSvatopluk Kraus }; 743120b6fc9SSvatopluk Kraus 744120b6fc9SSvatopluk Kraus static driver_t bcm_lintc_driver = { 745120b6fc9SSvatopluk Kraus "local_intc", 746120b6fc9SSvatopluk Kraus bcm_lintc_methods, 747120b6fc9SSvatopluk Kraus sizeof(struct bcm_lintc_softc), 748120b6fc9SSvatopluk Kraus }; 749120b6fc9SSvatopluk Kraus 750120b6fc9SSvatopluk Kraus static devclass_t bcm_lintc_devclass; 751120b6fc9SSvatopluk Kraus 752120b6fc9SSvatopluk Kraus EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass, 753120b6fc9SSvatopluk Kraus 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 754120b6fc9SSvatopluk Kraus #else 7554e46a66eSAndrew Turner /* 7564e46a66eSAndrew Turner * A driver for features of the bcm2836. 7574e46a66eSAndrew Turner */ 7584e46a66eSAndrew Turner 7594e46a66eSAndrew Turner struct bcm2836_softc { 7604e46a66eSAndrew Turner device_t sc_dev; 7614e46a66eSAndrew Turner struct resource *sc_mem; 7624e46a66eSAndrew Turner }; 7634e46a66eSAndrew Turner 7644e46a66eSAndrew Turner static device_identify_t bcm2836_identify; 7654e46a66eSAndrew Turner static device_probe_t bcm2836_probe; 7664e46a66eSAndrew Turner static device_attach_t bcm2836_attach; 7674e46a66eSAndrew Turner 7684e46a66eSAndrew Turner struct bcm2836_softc *softc; 7694e46a66eSAndrew Turner 7704e46a66eSAndrew Turner static void 7714e46a66eSAndrew Turner bcm2836_identify(driver_t *driver, device_t parent) 7724e46a66eSAndrew Turner { 7734e46a66eSAndrew Turner 7744e46a66eSAndrew Turner if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL) 7754e46a66eSAndrew Turner device_printf(parent, "add child failed\n"); 7764e46a66eSAndrew Turner } 7774e46a66eSAndrew Turner 7784e46a66eSAndrew Turner static int 7794e46a66eSAndrew Turner bcm2836_probe(device_t dev) 7804e46a66eSAndrew Turner { 7814e46a66eSAndrew Turner 7824e46a66eSAndrew Turner if (softc != NULL) 7834e46a66eSAndrew Turner return (ENXIO); 7844e46a66eSAndrew Turner 7854e46a66eSAndrew Turner device_set_desc(dev, "Broadcom bcm2836"); 7864e46a66eSAndrew Turner 7874e46a66eSAndrew Turner return (BUS_PROBE_DEFAULT); 7884e46a66eSAndrew Turner } 7894e46a66eSAndrew Turner 7904e46a66eSAndrew Turner static int 7914e46a66eSAndrew Turner bcm2836_attach(device_t dev) 7924e46a66eSAndrew Turner { 7934e46a66eSAndrew Turner int i, rid; 7944e46a66eSAndrew Turner 7954e46a66eSAndrew Turner softc = device_get_softc(dev); 7964e46a66eSAndrew Turner softc->sc_dev = dev; 7974e46a66eSAndrew Turner 7984e46a66eSAndrew Turner rid = 0; 7994e46a66eSAndrew Turner softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 8004e46a66eSAndrew Turner ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE, 8014e46a66eSAndrew Turner RF_ACTIVE); 8024e46a66eSAndrew Turner if (softc->sc_mem == NULL) { 8034e46a66eSAndrew Turner device_printf(dev, "could not allocate memory resource\n"); 8044e46a66eSAndrew Turner return (ENXIO); 8054e46a66eSAndrew Turner } 8064e46a66eSAndrew Turner 8074e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0); 8084e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2); 8094e46a66eSAndrew Turner 8104e46a66eSAndrew Turner for (i = 0; i < 4; i++) 8114e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0); 8124e46a66eSAndrew Turner 8134e46a66eSAndrew Turner for (i = 0; i < 4; i++) 8144e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1); 8154e46a66eSAndrew Turner 8164e46a66eSAndrew Turner return (0); 8174e46a66eSAndrew Turner } 8184e46a66eSAndrew Turner 8194e46a66eSAndrew Turner int 8204e46a66eSAndrew Turner bcm2836_get_next_irq(int last_irq) 8214e46a66eSAndrew Turner { 8224e46a66eSAndrew Turner uint32_t reg; 8234e46a66eSAndrew Turner int cpu; 8244e46a66eSAndrew Turner int irq; 8254e46a66eSAndrew Turner 8264e46a66eSAndrew Turner cpu = PCPU_GET(cpuid); 8274e46a66eSAndrew Turner 8284e46a66eSAndrew Turner reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu)); 8294e46a66eSAndrew Turner reg &= INT_PENDING_MASK; 8304e46a66eSAndrew Turner if (reg == 0) 8314e46a66eSAndrew Turner return (-1); 8324e46a66eSAndrew Turner 8334e46a66eSAndrew Turner irq = ffs(reg) - 1; 8344e46a66eSAndrew Turner 8354e46a66eSAndrew Turner return (irq); 8364e46a66eSAndrew Turner } 8374e46a66eSAndrew Turner 8384e46a66eSAndrew Turner void 8394e46a66eSAndrew Turner bcm2836_mask_irq(uintptr_t irq) 8404e46a66eSAndrew Turner { 8414e46a66eSAndrew Turner uint32_t reg; 842962940ceSLuiz Otavio O Souza #ifdef SMP 843962940ceSLuiz Otavio O Souza int cpu; 844962940ceSLuiz Otavio O Souza #endif 8454e46a66eSAndrew Turner int i; 8464e46a66eSAndrew Turner 847962940ceSLuiz Otavio O Souza if (irq < MAILBOX0_IRQ) { 8484e46a66eSAndrew Turner for (i = 0; i < 4; i++) { 849962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, 850962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i)); 8514e46a66eSAndrew Turner reg &= ~(1 << irq); 852962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, 853962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i), reg); 854962940ceSLuiz Otavio O Souza } 855962940ceSLuiz Otavio O Souza #ifdef SMP 856962940ceSLuiz Otavio O Souza } else if (irq == MAILBOX0_IRQ) { 857962940ceSLuiz Otavio O Souza /* Mailbox 0 for IPI */ 858962940ceSLuiz Otavio O Souza cpu = PCPU_GET(cpuid); 859962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu)); 860962940ceSLuiz Otavio O Souza reg &= ~MAILBOX0_IRQEN; 861962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg); 862962940ceSLuiz Otavio O Souza #endif 8634e46a66eSAndrew Turner } 8644e46a66eSAndrew Turner } 8654e46a66eSAndrew Turner 8664e46a66eSAndrew Turner void 8674e46a66eSAndrew Turner bcm2836_unmask_irq(uintptr_t irq) 8684e46a66eSAndrew Turner { 8694e46a66eSAndrew Turner uint32_t reg; 870962940ceSLuiz Otavio O Souza #ifdef SMP 871962940ceSLuiz Otavio O Souza int cpu; 872962940ceSLuiz Otavio O Souza #endif 8734e46a66eSAndrew Turner int i; 8744e46a66eSAndrew Turner 875962940ceSLuiz Otavio O Souza if (irq < MAILBOX0_IRQ) { 8764e46a66eSAndrew Turner for (i = 0; i < 4; i++) { 877962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, 878962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i)); 8794e46a66eSAndrew Turner reg |= (1 << irq); 880962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, 881962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i), reg); 882962940ceSLuiz Otavio O Souza } 883962940ceSLuiz Otavio O Souza #ifdef SMP 884962940ceSLuiz Otavio O Souza } else if (irq == MAILBOX0_IRQ) { 885962940ceSLuiz Otavio O Souza /* Mailbox 0 for IPI */ 886962940ceSLuiz Otavio O Souza cpu = PCPU_GET(cpuid); 887962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu)); 888962940ceSLuiz Otavio O Souza reg |= MAILBOX0_IRQEN; 889962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg); 890962940ceSLuiz Otavio O Souza #endif 8914e46a66eSAndrew Turner } 8924e46a66eSAndrew Turner } 8934e46a66eSAndrew Turner 8944e46a66eSAndrew Turner static device_method_t bcm2836_methods[] = { 8954e46a66eSAndrew Turner /* Device interface */ 8964e46a66eSAndrew Turner DEVMETHOD(device_identify, bcm2836_identify), 8974e46a66eSAndrew Turner DEVMETHOD(device_probe, bcm2836_probe), 8984e46a66eSAndrew Turner DEVMETHOD(device_attach, bcm2836_attach), 8994e46a66eSAndrew Turner 9004e46a66eSAndrew Turner DEVMETHOD_END 9014e46a66eSAndrew Turner }; 9024e46a66eSAndrew Turner 9034e46a66eSAndrew Turner static devclass_t bcm2836_devclass; 9044e46a66eSAndrew Turner 9054e46a66eSAndrew Turner static driver_t bcm2836_driver = { 9064e46a66eSAndrew Turner "bcm2836", 9074e46a66eSAndrew Turner bcm2836_methods, 9084e46a66eSAndrew Turner sizeof(struct bcm2836_softc), 9094e46a66eSAndrew Turner }; 9104e46a66eSAndrew Turner 9114e46a66eSAndrew Turner EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0, 9124e46a66eSAndrew Turner BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 913120b6fc9SSvatopluk Kraus #endif 914