14e46a66eSAndrew Turner /* 24e46a66eSAndrew Turner * Copyright 2015 Andrew Turner. 3*120b6fc9SSvatopluk 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 32*120b6fc9SSvatopluk Kraus #include "opt_platform.h" 33*120b6fc9SSvatopluk Kraus 344e46a66eSAndrew Turner #include <sys/param.h> 354e46a66eSAndrew Turner #include <sys/systm.h> 364e46a66eSAndrew Turner #include <sys/bus.h> 37*120b6fc9SSvatopluk Kraus #include <sys/cpuset.h> 384e46a66eSAndrew Turner #include <sys/kernel.h> 394e46a66eSAndrew Turner #include <sys/module.h> 40*120b6fc9SSvatopluk Kraus #include <sys/proc.h> 414e46a66eSAndrew Turner #include <sys/rman.h> 42*120b6fc9SSvatopluk Kraus #ifdef SMP 43*120b6fc9SSvatopluk Kraus #include <sys/smp.h> 44*120b6fc9SSvatopluk Kraus #endif 454e46a66eSAndrew Turner 464e46a66eSAndrew Turner #include <machine/bus.h> 47*120b6fc9SSvatopluk Kraus #include <machine/intr.h> 484e46a66eSAndrew Turner #include <machine/resource.h> 49*120b6fc9SSvatopluk Kraus #ifdef SMP 50*120b6fc9SSvatopluk Kraus #include <machine/smp.h> 51*120b6fc9SSvatopluk Kraus #endif 524e46a66eSAndrew Turner 534e46a66eSAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 544e46a66eSAndrew Turner #include <dev/ofw/ofw_bus.h> 554e46a66eSAndrew Turner 56*120b6fc9SSvatopluk Kraus #ifdef ARM_INTRNG 57*120b6fc9SSvatopluk Kraus #include "pic_if.h" 58*120b6fc9SSvatopluk 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) 73*120b6fc9SSvatopluk Kraus #endif 744e46a66eSAndrew Turner 75*120b6fc9SSvatopluk Kraus #ifdef ARM_INTRNG 76*120b6fc9SSvatopluk Kraus #define BCM_LINTC_CONTROL_REG 0x00 77*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PRESCALER_REG 0x08 78*120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_ROUTING_REG 0x0c 79*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10 80*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14 81*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4) 82*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4) 83*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4) 84*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16) 85*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16) 86*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16) 87*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16) 88*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16) 89*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16) 90*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16) 91*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16) 92*120b6fc9SSvatopluk Kraus 93*120b6fc9SSvatopluk Kraus /* Prescaler Register */ 94*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */ 95*120b6fc9SSvatopluk Kraus 96*120b6fc9SSvatopluk Kraus /* GPU Interrupt Routing Register */ 97*120b6fc9SSvatopluk Kraus #define BCM_LINTC_GIRR_IRQ_CORE(n) (n) 98*120b6fc9SSvatopluk Kraus #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2) 99*120b6fc9SSvatopluk Kraus 100*120b6fc9SSvatopluk Kraus /* PMU Interrupt Routing Register */ 101*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n)) 102*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4)) 103*120b6fc9SSvatopluk Kraus 104*120b6fc9SSvatopluk Kraus /* Timer Config Register */ 105*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n)) 106*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4)) 107*120b6fc9SSvatopluk Kraus 108*120b6fc9SSvatopluk Kraus /* MBOX Config Register */ 109*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n)) 110*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4)) 111*120b6fc9SSvatopluk Kraus 112*120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTPSIRQ_IRQ 0 113*120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTPNSIRQ_IRQ 1 114*120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTHPIRQ_IRQ 2 115*120b6fc9SSvatopluk Kraus #define BCM_LINTC_CNTVIRQ_IRQ 3 116*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_IRQ 4 117*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX1_IRQ 5 118*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX2_IRQ 6 119*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX3_IRQ 7 120*120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_IRQ 8 121*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_IRQ 9 122*120b6fc9SSvatopluk Kraus #define BCM_LINTC_AXI_IRQ 10 123*120b6fc9SSvatopluk Kraus #define BCM_LINTC_LTIMER_IRQ 11 124*120b6fc9SSvatopluk Kraus 125*120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIRQS 12 126*120b6fc9SSvatopluk Kraus 127*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ 128*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ 129*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ 130*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ 131*120b6fc9SSvatopluk Kraus 132*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ) 133*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ) 134*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ) 135*120b6fc9SSvatopluk Kraus #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ) 136*120b6fc9SSvatopluk Kraus #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ) 137*120b6fc9SSvatopluk Kraus #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ) 138*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ) 139*120b6fc9SSvatopluk Kraus 140*120b6fc9SSvatopluk Kraus #define BCM_LINTC_UP_PENDING_MASK \ 141*120b6fc9SSvatopluk Kraus (BCM_LINTC_TIMER0_IRQ_MASK | \ 142*120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER1_IRQ_MASK | \ 143*120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER2_IRQ_MASK | \ 144*120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER3_IRQ_MASK | \ 145*120b6fc9SSvatopluk Kraus BCM_LINTC_GPU_IRQ_MASK | \ 146*120b6fc9SSvatopluk Kraus BCM_LINTC_PMU_IRQ_MASK) 147*120b6fc9SSvatopluk Kraus 148*120b6fc9SSvatopluk Kraus #define BCM_LINTC_SMP_PENDING_MASK \ 149*120b6fc9SSvatopluk Kraus (BCM_LINTC_UP_PENDING_MASK | \ 150*120b6fc9SSvatopluk Kraus BCM_LINTC_MBOX0_IRQ_MASK) 151*120b6fc9SSvatopluk Kraus 152*120b6fc9SSvatopluk Kraus #ifdef SMP 153*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK 154*120b6fc9SSvatopluk Kraus #else 155*120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK 156*120b6fc9SSvatopluk Kraus #endif 157*120b6fc9SSvatopluk Kraus 158*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc { 159*120b6fc9SSvatopluk Kraus struct intr_irqsrc bli_isrc; 160*120b6fc9SSvatopluk Kraus u_int bli_irq; 161*120b6fc9SSvatopluk Kraus union { 162*120b6fc9SSvatopluk Kraus u_int bli_mask; /* for timers */ 163*120b6fc9SSvatopluk Kraus u_int bli_value; /* for GPU */ 164*120b6fc9SSvatopluk Kraus }; 165*120b6fc9SSvatopluk Kraus }; 166*120b6fc9SSvatopluk Kraus 167*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc { 168*120b6fc9SSvatopluk Kraus device_t bls_dev; 169*120b6fc9SSvatopluk Kraus struct mtx bls_mtx; 170*120b6fc9SSvatopluk Kraus struct resource * bls_mem; 171*120b6fc9SSvatopluk Kraus bus_space_tag_t bls_bst; 172*120b6fc9SSvatopluk Kraus bus_space_handle_t bls_bsh; 173*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS]; 174*120b6fc9SSvatopluk Kraus }; 175*120b6fc9SSvatopluk Kraus 176*120b6fc9SSvatopluk Kraus static struct bcm_lintc_softc *bcm_lintc_sc; 177*120b6fc9SSvatopluk Kraus 178*120b6fc9SSvatopluk Kraus #ifdef SMP 179*120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */ 180*120b6fc9SSvatopluk Kraus CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS); 181*120b6fc9SSvatopluk Kraus #endif 182*120b6fc9SSvatopluk Kraus 183*120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx) 184*120b6fc9SSvatopluk Kraus #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx) 185*120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \ 186*120b6fc9SSvatopluk Kraus device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN) 187*120b6fc9SSvatopluk Kraus #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx) 188*120b6fc9SSvatopluk Kraus 189*120b6fc9SSvatopluk Kraus #define bcm_lintc_read_4(sc, reg) \ 190*120b6fc9SSvatopluk Kraus bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg)) 191*120b6fc9SSvatopluk Kraus #define bcm_lintc_write_4(sc, reg, val) \ 192*120b6fc9SSvatopluk Kraus bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val)) 193*120b6fc9SSvatopluk Kraus 194*120b6fc9SSvatopluk Kraus static inline void 195*120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg, 196*120b6fc9SSvatopluk Kraus uint32_t mask) 197*120b6fc9SSvatopluk Kraus { 198*120b6fc9SSvatopluk Kraus 199*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask); 200*120b6fc9SSvatopluk Kraus } 201*120b6fc9SSvatopluk Kraus 202*120b6fc9SSvatopluk Kraus static inline void 203*120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg, 204*120b6fc9SSvatopluk Kraus uint32_t mask) 205*120b6fc9SSvatopluk Kraus { 206*120b6fc9SSvatopluk Kraus 207*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask); 208*120b6fc9SSvatopluk Kraus } 209*120b6fc9SSvatopluk Kraus 210*120b6fc9SSvatopluk Kraus static void 211*120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 212*120b6fc9SSvatopluk Kraus { 213*120b6fc9SSvatopluk Kraus cpuset_t *cpus; 214*120b6fc9SSvatopluk Kraus uint32_t cpu; 215*120b6fc9SSvatopluk Kraus 216*120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 217*120b6fc9SSvatopluk Kraus 218*120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 219*120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 220*120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 221*120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 222*120b6fc9SSvatopluk Kraus bli->bli_mask); 223*120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 224*120b6fc9SSvatopluk Kraus } 225*120b6fc9SSvatopluk Kraus 226*120b6fc9SSvatopluk Kraus static void 227*120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 228*120b6fc9SSvatopluk Kraus { 229*120b6fc9SSvatopluk Kraus cpuset_t *cpus; 230*120b6fc9SSvatopluk Kraus uint32_t cpu; 231*120b6fc9SSvatopluk Kraus 232*120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 233*120b6fc9SSvatopluk Kraus 234*120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 235*120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 236*120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 237*120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 238*120b6fc9SSvatopluk Kraus bli->bli_mask); 239*120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 240*120b6fc9SSvatopluk Kraus } 241*120b6fc9SSvatopluk Kraus 242*120b6fc9SSvatopluk Kraus static inline void 243*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 244*120b6fc9SSvatopluk Kraus { 245*120b6fc9SSvatopluk Kraus 246*120b6fc9SSvatopluk Kraus /* It's accessed just and only by one core. */ 247*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0); 248*120b6fc9SSvatopluk Kraus } 249*120b6fc9SSvatopluk Kraus 250*120b6fc9SSvatopluk Kraus static inline void 251*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 252*120b6fc9SSvatopluk Kraus { 253*120b6fc9SSvatopluk Kraus 254*120b6fc9SSvatopluk Kraus /* It's accessed just and only by one core. */ 255*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value); 256*120b6fc9SSvatopluk Kraus } 257*120b6fc9SSvatopluk Kraus 258*120b6fc9SSvatopluk Kraus static inline void 259*120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 260*120b6fc9SSvatopluk Kraus { 261*120b6fc9SSvatopluk Kraus cpuset_t *cpus; 262*120b6fc9SSvatopluk Kraus uint32_t cpu, mask; 263*120b6fc9SSvatopluk Kraus 264*120b6fc9SSvatopluk Kraus mask = 0; 265*120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 266*120b6fc9SSvatopluk Kraus 267*120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 268*120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 269*120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 270*120b6fc9SSvatopluk Kraus mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); 271*120b6fc9SSvatopluk Kraus /* Write-clear register. */ 272*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask); 273*120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 274*120b6fc9SSvatopluk Kraus } 275*120b6fc9SSvatopluk Kraus 276*120b6fc9SSvatopluk Kraus static inline void 277*120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 278*120b6fc9SSvatopluk Kraus { 279*120b6fc9SSvatopluk Kraus cpuset_t *cpus; 280*120b6fc9SSvatopluk Kraus uint32_t cpu, mask; 281*120b6fc9SSvatopluk Kraus 282*120b6fc9SSvatopluk Kraus mask = 0; 283*120b6fc9SSvatopluk Kraus cpus = &bli->bli_isrc.isrc_cpu; 284*120b6fc9SSvatopluk Kraus 285*120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 286*120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 287*120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, cpus)) 288*120b6fc9SSvatopluk Kraus mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); 289*120b6fc9SSvatopluk Kraus /* Write-set register. */ 290*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask); 291*120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 292*120b6fc9SSvatopluk Kraus } 293*120b6fc9SSvatopluk Kraus 294*120b6fc9SSvatopluk Kraus static void 295*120b6fc9SSvatopluk Kraus bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 296*120b6fc9SSvatopluk Kraus { 297*120b6fc9SSvatopluk Kraus 298*120b6fc9SSvatopluk Kraus switch (bli->bli_irq) { 299*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ: 300*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ: 301*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ: 302*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ: 303*120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(sc, bli); 304*120b6fc9SSvatopluk Kraus return; 305*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ: 306*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ: 307*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ: 308*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ: 309*120b6fc9SSvatopluk Kraus return; 310*120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ: 311*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(sc, bli); 312*120b6fc9SSvatopluk Kraus return; 313*120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ: 314*120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(sc, bli); 315*120b6fc9SSvatopluk Kraus return; 316*120b6fc9SSvatopluk Kraus default: 317*120b6fc9SSvatopluk Kraus panic("%s: not implemented for irq %u", __func__, bli->bli_irq); 318*120b6fc9SSvatopluk Kraus } 319*120b6fc9SSvatopluk Kraus } 320*120b6fc9SSvatopluk Kraus 321*120b6fc9SSvatopluk Kraus static void 322*120b6fc9SSvatopluk Kraus bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) 323*120b6fc9SSvatopluk Kraus { 324*120b6fc9SSvatopluk Kraus 325*120b6fc9SSvatopluk Kraus switch (bli->bli_irq) { 326*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ: 327*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ: 328*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ: 329*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ: 330*120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(sc, bli); 331*120b6fc9SSvatopluk Kraus return; 332*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ: 333*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ: 334*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ: 335*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ: 336*120b6fc9SSvatopluk Kraus return; 337*120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ: 338*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(sc, bli); 339*120b6fc9SSvatopluk Kraus return; 340*120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ: 341*120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(sc, bli); 342*120b6fc9SSvatopluk Kraus return; 343*120b6fc9SSvatopluk Kraus default: 344*120b6fc9SSvatopluk Kraus panic("%s: not implemented for irq %u", __func__, bli->bli_irq); 345*120b6fc9SSvatopluk Kraus } 346*120b6fc9SSvatopluk Kraus } 347*120b6fc9SSvatopluk Kraus 348*120b6fc9SSvatopluk Kraus #ifdef SMP 349*120b6fc9SSvatopluk Kraus static inline void 350*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi) 351*120b6fc9SSvatopluk Kraus { 352*120b6fc9SSvatopluk Kraus u_int cpu; 353*120b6fc9SSvatopluk Kraus uint32_t mask; 354*120b6fc9SSvatopluk Kraus 355*120b6fc9SSvatopluk Kraus mask = 1 << ipi; 356*120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < mp_ncpus; cpu++) 357*120b6fc9SSvatopluk Kraus if (CPU_ISSET(cpu, &cpus)) 358*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu), 359*120b6fc9SSvatopluk Kraus mask); 360*120b6fc9SSvatopluk Kraus } 361*120b6fc9SSvatopluk Kraus 362*120b6fc9SSvatopluk Kraus static inline void 363*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu, 364*120b6fc9SSvatopluk Kraus struct trapframe *tf) 365*120b6fc9SSvatopluk Kraus { 366*120b6fc9SSvatopluk Kraus u_int ipi; 367*120b6fc9SSvatopluk Kraus uint32_t mask; 368*120b6fc9SSvatopluk Kraus 369*120b6fc9SSvatopluk Kraus mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu)); 370*120b6fc9SSvatopluk Kraus if (mask == 0) { 371*120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Spurious ipi detected\n"); 372*120b6fc9SSvatopluk Kraus return; 373*120b6fc9SSvatopluk Kraus } 374*120b6fc9SSvatopluk Kraus 375*120b6fc9SSvatopluk Kraus for (ipi = 0; mask != 0; mask >>= 1, ipi++) { 376*120b6fc9SSvatopluk Kraus if ((mask & 0x01) == 0) 377*120b6fc9SSvatopluk Kraus continue; 378*120b6fc9SSvatopluk Kraus /* 379*120b6fc9SSvatopluk Kraus * Clear an IPI before dispatching to not miss anyone 380*120b6fc9SSvatopluk Kraus * and make sure that it's observed by everybody. 381*120b6fc9SSvatopluk Kraus */ 382*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi); 383*120b6fc9SSvatopluk Kraus dsb(); 384*120b6fc9SSvatopluk Kraus intr_ipi_dispatch(ipi, tf); 385*120b6fc9SSvatopluk Kraus } 386*120b6fc9SSvatopluk Kraus } 387*120b6fc9SSvatopluk Kraus #endif 388*120b6fc9SSvatopluk Kraus 389*120b6fc9SSvatopluk Kraus static inline void 390*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq, 391*120b6fc9SSvatopluk Kraus struct trapframe *tf) 392*120b6fc9SSvatopluk Kraus { 393*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli; 394*120b6fc9SSvatopluk Kraus 395*120b6fc9SSvatopluk Kraus bli = &sc->bls_isrcs[irq]; 396*120b6fc9SSvatopluk Kraus if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0) 397*120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Stray irq %u detected\n", irq); 398*120b6fc9SSvatopluk Kraus } 399*120b6fc9SSvatopluk Kraus 400*120b6fc9SSvatopluk Kraus static int 401*120b6fc9SSvatopluk Kraus bcm_lintc_intr(void *arg) 402*120b6fc9SSvatopluk Kraus { 403*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 404*120b6fc9SSvatopluk Kraus u_int cpu; 405*120b6fc9SSvatopluk Kraus uint32_t num, reg; 406*120b6fc9SSvatopluk Kraus struct trapframe *tf; 407*120b6fc9SSvatopluk Kraus 408*120b6fc9SSvatopluk Kraus sc = arg; 409*120b6fc9SSvatopluk Kraus cpu = PCPU_GET(cpuid); 410*120b6fc9SSvatopluk Kraus tf = curthread->td_intr_frame; 411*120b6fc9SSvatopluk Kraus 412*120b6fc9SSvatopluk Kraus for (num = 0; ; num++) { 413*120b6fc9SSvatopluk Kraus reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu)); 414*120b6fc9SSvatopluk Kraus if ((reg & BCM_LINTC_PENDING_MASK) == 0) 415*120b6fc9SSvatopluk Kraus break; 416*120b6fc9SSvatopluk Kraus #ifdef SMP 417*120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_MBOX0_IRQ_MASK) 418*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(sc, cpu, tf); 419*120b6fc9SSvatopluk Kraus #endif 420*120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER0_IRQ_MASK) 421*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf); 422*120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER1_IRQ_MASK) 423*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf); 424*120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER2_IRQ_MASK) 425*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf); 426*120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_TIMER3_IRQ_MASK) 427*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf); 428*120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_GPU_IRQ_MASK) 429*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf); 430*120b6fc9SSvatopluk Kraus if (reg & BCM_LINTC_PMU_IRQ_MASK) 431*120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf); 432*120b6fc9SSvatopluk Kraus 433*120b6fc9SSvatopluk Kraus arm_irq_memory_barrier(0); /* XXX */ 434*120b6fc9SSvatopluk Kraus } 435*120b6fc9SSvatopluk Kraus reg &= ~BCM_LINTC_PENDING_MASK; 436*120b6fc9SSvatopluk Kraus if (reg != 0) 437*120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg); 438*120b6fc9SSvatopluk Kraus else if (num == 0) 439*120b6fc9SSvatopluk Kraus device_printf(sc->bls_dev, "Spurious interrupt detected\n"); 440*120b6fc9SSvatopluk Kraus 441*120b6fc9SSvatopluk Kraus return (FILTER_HANDLED); 442*120b6fc9SSvatopluk Kraus } 443*120b6fc9SSvatopluk Kraus 444*120b6fc9SSvatopluk Kraus static void 445*120b6fc9SSvatopluk Kraus bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc) 446*120b6fc9SSvatopluk Kraus { 447*120b6fc9SSvatopluk Kraus 448*120b6fc9SSvatopluk Kraus bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc); 449*120b6fc9SSvatopluk Kraus } 450*120b6fc9SSvatopluk Kraus 451*120b6fc9SSvatopluk Kraus static void 452*120b6fc9SSvatopluk Kraus bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc) 453*120b6fc9SSvatopluk Kraus { 454*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 455*120b6fc9SSvatopluk Kraus 456*120b6fc9SSvatopluk Kraus arm_irq_memory_barrier(bli->bli_irq); 457*120b6fc9SSvatopluk Kraus bcm_lintc_unmask(device_get_softc(dev), bli); 458*120b6fc9SSvatopluk Kraus } 459*120b6fc9SSvatopluk Kraus 460*120b6fc9SSvatopluk Kraus static int 461*120b6fc9SSvatopluk Kraus bcm_lintc_map_intr(device_t dev, struct intr_map_data *data, 462*120b6fc9SSvatopluk Kraus struct intr_irqsrc **isrcp) 463*120b6fc9SSvatopluk Kraus { 464*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 465*120b6fc9SSvatopluk Kraus 466*120b6fc9SSvatopluk Kraus if (data->type != INTR_MAP_DATA_FDT) 467*120b6fc9SSvatopluk Kraus return (ENOTSUP); 468*120b6fc9SSvatopluk Kraus if (data->fdt.ncells != 1 || data->fdt.cells[0] >= BCM_LINTC_NIRQS) 469*120b6fc9SSvatopluk Kraus return (EINVAL); 470*120b6fc9SSvatopluk Kraus 471*120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 472*120b6fc9SSvatopluk Kraus *isrcp = &sc->bls_isrcs[data->fdt.cells[0]].bli_isrc; 473*120b6fc9SSvatopluk Kraus return (0); 474*120b6fc9SSvatopluk Kraus } 475*120b6fc9SSvatopluk Kraus 476*120b6fc9SSvatopluk Kraus static void 477*120b6fc9SSvatopluk Kraus bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 478*120b6fc9SSvatopluk Kraus { 479*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 480*120b6fc9SSvatopluk Kraus 481*120b6fc9SSvatopluk Kraus if (bli->bli_irq == BCM_LINTC_GPU_IRQ) 482*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(device_get_softc(dev), bli); 483*120b6fc9SSvatopluk Kraus else { 484*120b6fc9SSvatopluk Kraus /* 485*120b6fc9SSvatopluk Kraus * Handler for PPI interrupt does not make sense much unless 486*120b6fc9SSvatopluk Kraus * there is one bound ithread for each core for it. Thus the 487*120b6fc9SSvatopluk Kraus * interrupt can be masked on current core only while ithread 488*120b6fc9SSvatopluk Kraus * bounded to this core ensures unmasking on the same core. 489*120b6fc9SSvatopluk Kraus */ 490*120b6fc9SSvatopluk Kraus panic ("%s: handlers are not supported", __func__); 491*120b6fc9SSvatopluk Kraus } 492*120b6fc9SSvatopluk Kraus } 493*120b6fc9SSvatopluk Kraus 494*120b6fc9SSvatopluk Kraus static void 495*120b6fc9SSvatopluk Kraus bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc) 496*120b6fc9SSvatopluk Kraus { 497*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; 498*120b6fc9SSvatopluk Kraus 499*120b6fc9SSvatopluk Kraus if (bli->bli_irq == BCM_LINTC_GPU_IRQ) 500*120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(device_get_softc(dev), bli); 501*120b6fc9SSvatopluk Kraus else { 502*120b6fc9SSvatopluk Kraus /* See comment in bcm_lintc_pre_ithread(). */ 503*120b6fc9SSvatopluk Kraus panic ("%s: handlers are not supported", __func__); 504*120b6fc9SSvatopluk Kraus } 505*120b6fc9SSvatopluk Kraus } 506*120b6fc9SSvatopluk Kraus 507*120b6fc9SSvatopluk Kraus static void 508*120b6fc9SSvatopluk Kraus bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc) 509*120b6fc9SSvatopluk Kraus { 510*120b6fc9SSvatopluk Kraus } 511*120b6fc9SSvatopluk Kraus 512*120b6fc9SSvatopluk Kraus static int 513*120b6fc9SSvatopluk Kraus bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc, 514*120b6fc9SSvatopluk Kraus struct resource *res, struct intr_map_data *data) 515*120b6fc9SSvatopluk Kraus { 516*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 517*120b6fc9SSvatopluk Kraus 518*120b6fc9SSvatopluk Kraus if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) { 519*120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 520*120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 521*120b6fc9SSvatopluk Kraus CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 522*120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 523*120b6fc9SSvatopluk Kraus } 524*120b6fc9SSvatopluk Kraus return (0); 525*120b6fc9SSvatopluk Kraus } 526*120b6fc9SSvatopluk Kraus 527*120b6fc9SSvatopluk Kraus #ifdef SMP 528*120b6fc9SSvatopluk Kraus static bool 529*120b6fc9SSvatopluk Kraus bcm_lint_init_on_ap(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli, 530*120b6fc9SSvatopluk Kraus u_int cpu) 531*120b6fc9SSvatopluk Kraus { 532*120b6fc9SSvatopluk Kraus struct intr_irqsrc *isrc; 533*120b6fc9SSvatopluk Kraus 534*120b6fc9SSvatopluk Kraus isrc = &bli->bli_isrc; 535*120b6fc9SSvatopluk Kraus 536*120b6fc9SSvatopluk Kraus KASSERT(isrc->isrc_flags & INTR_ISRCF_PPI, 537*120b6fc9SSvatopluk Kraus ("%s: irq %d is not PPI", __func__, bli->bli_irq)); 538*120b6fc9SSvatopluk Kraus 539*120b6fc9SSvatopluk Kraus if (isrc->isrc_handlers == 0) 540*120b6fc9SSvatopluk Kraus return (false); 541*120b6fc9SSvatopluk Kraus if (isrc->isrc_flags & INTR_ISRCF_BOUND) 542*120b6fc9SSvatopluk Kraus return (CPU_ISSET(cpu, &isrc->isrc_cpu)); 543*120b6fc9SSvatopluk Kraus 544*120b6fc9SSvatopluk Kraus CPU_SET(cpu, &isrc->isrc_cpu); 545*120b6fc9SSvatopluk Kraus return (true); 546*120b6fc9SSvatopluk Kraus } 547*120b6fc9SSvatopluk Kraus 548*120b6fc9SSvatopluk Kraus static void 549*120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq, 550*120b6fc9SSvatopluk Kraus uint32_t reg, uint32_t mask) 551*120b6fc9SSvatopluk Kraus { 552*120b6fc9SSvatopluk Kraus 553*120b6fc9SSvatopluk Kraus if (bcm_lint_init_on_ap(sc, &sc->bls_isrcs[irq], cpu)) 554*120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(sc, reg, mask); 555*120b6fc9SSvatopluk Kraus } 556*120b6fc9SSvatopluk Kraus 557*120b6fc9SSvatopluk Kraus static void 558*120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu) 559*120b6fc9SSvatopluk Kraus { 560*120b6fc9SSvatopluk Kraus 561*120b6fc9SSvatopluk Kraus if (bcm_lint_init_on_ap(sc, &sc->bls_isrcs[BCM_LINTC_PMU_IRQ], cpu)) { 562*120b6fc9SSvatopluk Kraus /* Write-set register. */ 563*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, 564*120b6fc9SSvatopluk Kraus BCM_LINTC_PIRR_IRQ_EN_CORE(cpu)); 565*120b6fc9SSvatopluk Kraus } 566*120b6fc9SSvatopluk Kraus } 567*120b6fc9SSvatopluk Kraus 568*120b6fc9SSvatopluk Kraus static void 569*120b6fc9SSvatopluk Kraus bcm_lintc_init_secondary(device_t dev) 570*120b6fc9SSvatopluk Kraus { 571*120b6fc9SSvatopluk Kraus u_int cpu; 572*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 573*120b6fc9SSvatopluk Kraus 574*120b6fc9SSvatopluk Kraus cpu = PCPU_GET(cpuid); 575*120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 576*120b6fc9SSvatopluk Kraus 577*120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK(sc); 578*120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ, 579*120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0)); 580*120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ, 581*120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1)); 582*120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ, 583*120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2)); 584*120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ, 585*120b6fc9SSvatopluk Kraus BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3)); 586*120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(sc, cpu); 587*120b6fc9SSvatopluk Kraus BCM_LINTC_UNLOCK(sc); 588*120b6fc9SSvatopluk Kraus } 589*120b6fc9SSvatopluk Kraus 590*120b6fc9SSvatopluk Kraus static void 591*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, 592*120b6fc9SSvatopluk Kraus u_int ipi) 593*120b6fc9SSvatopluk Kraus { 594*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc = device_get_softc(dev); 595*120b6fc9SSvatopluk Kraus 596*120b6fc9SSvatopluk Kraus KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc, 597*120b6fc9SSvatopluk Kraus ("%s: bad ISRC %p argument", __func__, isrc)); 598*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(sc, cpus, ipi); 599*120b6fc9SSvatopluk Kraus } 600*120b6fc9SSvatopluk Kraus 601*120b6fc9SSvatopluk Kraus static int 602*120b6fc9SSvatopluk Kraus bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) 603*120b6fc9SSvatopluk Kraus { 604*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc = device_get_softc(dev); 605*120b6fc9SSvatopluk Kraus 606*120b6fc9SSvatopluk Kraus KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi)); 607*120b6fc9SSvatopluk Kraus 608*120b6fc9SSvatopluk Kraus *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc; 609*120b6fc9SSvatopluk Kraus return (0); 610*120b6fc9SSvatopluk Kraus } 611*120b6fc9SSvatopluk Kraus #endif 612*120b6fc9SSvatopluk Kraus 613*120b6fc9SSvatopluk Kraus static int 614*120b6fc9SSvatopluk Kraus bcm_lintc_pic_attach(struct bcm_lintc_softc *sc) 615*120b6fc9SSvatopluk Kraus { 616*120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc *bisrcs; 617*120b6fc9SSvatopluk Kraus int error; 618*120b6fc9SSvatopluk Kraus u_int flags; 619*120b6fc9SSvatopluk Kraus uint32_t irq; 620*120b6fc9SSvatopluk Kraus const char *name; 621*120b6fc9SSvatopluk Kraus intptr_t xref; 622*120b6fc9SSvatopluk Kraus 623*120b6fc9SSvatopluk Kraus bisrcs = sc->bls_isrcs; 624*120b6fc9SSvatopluk Kraus name = device_get_nameunit(sc->bls_dev); 625*120b6fc9SSvatopluk Kraus for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) { 626*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_irq = irq; 627*120b6fc9SSvatopluk Kraus switch (irq) { 628*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER0_IRQ: 629*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0); 630*120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 631*120b6fc9SSvatopluk Kraus break; 632*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER1_IRQ: 633*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1); 634*120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 635*120b6fc9SSvatopluk Kraus break; 636*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER2_IRQ: 637*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2); 638*120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 639*120b6fc9SSvatopluk Kraus break; 640*120b6fc9SSvatopluk Kraus case BCM_LINTC_TIMER3_IRQ: 641*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3); 642*120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 643*120b6fc9SSvatopluk Kraus break; 644*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX0_IRQ: 645*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX1_IRQ: 646*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX2_IRQ: 647*120b6fc9SSvatopluk Kraus case BCM_LINTC_MBOX3_IRQ: 648*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */ 649*120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_IPI; 650*120b6fc9SSvatopluk Kraus break; 651*120b6fc9SSvatopluk Kraus case BCM_LINTC_GPU_IRQ: 652*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0); 653*120b6fc9SSvatopluk Kraus flags = 0; 654*120b6fc9SSvatopluk Kraus break; 655*120b6fc9SSvatopluk Kraus case BCM_LINTC_PMU_IRQ: 656*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */ 657*120b6fc9SSvatopluk Kraus flags = INTR_ISRCF_PPI; 658*120b6fc9SSvatopluk Kraus break; 659*120b6fc9SSvatopluk Kraus default: 660*120b6fc9SSvatopluk Kraus bisrcs[irq].bli_value = 0; /* not used */ 661*120b6fc9SSvatopluk Kraus flags = 0; 662*120b6fc9SSvatopluk Kraus break; 663*120b6fc9SSvatopluk Kraus } 664*120b6fc9SSvatopluk Kraus 665*120b6fc9SSvatopluk Kraus error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev, 666*120b6fc9SSvatopluk Kraus flags, "%s,%u", name, irq); 667*120b6fc9SSvatopluk Kraus if (error != 0) 668*120b6fc9SSvatopluk Kraus return (error); 669*120b6fc9SSvatopluk Kraus } 670*120b6fc9SSvatopluk Kraus 671*120b6fc9SSvatopluk Kraus xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev)); 672*120b6fc9SSvatopluk Kraus error = intr_pic_register(sc->bls_dev, xref); 673*120b6fc9SSvatopluk Kraus if (error != 0) 674*120b6fc9SSvatopluk Kraus return (error); 675*120b6fc9SSvatopluk Kraus 676*120b6fc9SSvatopluk Kraus return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0)); 677*120b6fc9SSvatopluk Kraus } 678*120b6fc9SSvatopluk Kraus 679*120b6fc9SSvatopluk Kraus static int 680*120b6fc9SSvatopluk Kraus bcm_lintc_probe(device_t dev) 681*120b6fc9SSvatopluk Kraus { 682*120b6fc9SSvatopluk Kraus 683*120b6fc9SSvatopluk Kraus if (!ofw_bus_status_okay(dev)) 684*120b6fc9SSvatopluk Kraus return (ENXIO); 685*120b6fc9SSvatopluk Kraus 686*120b6fc9SSvatopluk Kraus if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc")) 687*120b6fc9SSvatopluk Kraus return (ENXIO); 688*120b6fc9SSvatopluk Kraus device_set_desc(dev, "BCM2836 Interrupt Controller"); 689*120b6fc9SSvatopluk Kraus return (BUS_PROBE_DEFAULT); 690*120b6fc9SSvatopluk Kraus } 691*120b6fc9SSvatopluk Kraus 692*120b6fc9SSvatopluk Kraus static int 693*120b6fc9SSvatopluk Kraus bcm_lintc_attach(device_t dev) 694*120b6fc9SSvatopluk Kraus { 695*120b6fc9SSvatopluk Kraus struct bcm_lintc_softc *sc; 696*120b6fc9SSvatopluk Kraus int cpu, rid; 697*120b6fc9SSvatopluk Kraus 698*120b6fc9SSvatopluk Kraus sc = device_get_softc(dev); 699*120b6fc9SSvatopluk Kraus 700*120b6fc9SSvatopluk Kraus sc->bls_dev = dev; 701*120b6fc9SSvatopluk Kraus if (bcm_lintc_sc != NULL) 702*120b6fc9SSvatopluk Kraus return (ENXIO); 703*120b6fc9SSvatopluk Kraus 704*120b6fc9SSvatopluk Kraus rid = 0; 705*120b6fc9SSvatopluk Kraus sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 706*120b6fc9SSvatopluk Kraus RF_ACTIVE); 707*120b6fc9SSvatopluk Kraus if (sc->bls_mem == NULL) { 708*120b6fc9SSvatopluk Kraus device_printf(dev, "could not allocate memory resource\n"); 709*120b6fc9SSvatopluk Kraus return (ENXIO); 710*120b6fc9SSvatopluk Kraus } 711*120b6fc9SSvatopluk Kraus 712*120b6fc9SSvatopluk Kraus sc->bls_bst = rman_get_bustag(sc->bls_mem); 713*120b6fc9SSvatopluk Kraus sc->bls_bsh = rman_get_bushandle(sc->bls_mem); 714*120b6fc9SSvatopluk Kraus 715*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0); 716*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2); 717*120b6fc9SSvatopluk Kraus 718*120b6fc9SSvatopluk Kraus /* Disable all timers on all cores. */ 719*120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 720*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0); 721*120b6fc9SSvatopluk Kraus 722*120b6fc9SSvatopluk Kraus #ifdef SMP 723*120b6fc9SSvatopluk Kraus /* Enable mailbox 0 on all cores used for IPI. */ 724*120b6fc9SSvatopluk Kraus for (cpu = 0; cpu < 4; cpu++) 725*120b6fc9SSvatopluk Kraus bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu), 726*120b6fc9SSvatopluk Kraus BCM_LINTC_MCR_IRQ_EN_MBOX(0)); 727*120b6fc9SSvatopluk Kraus #endif 728*120b6fc9SSvatopluk Kraus 729*120b6fc9SSvatopluk Kraus if (bcm_lintc_pic_attach(sc) != 0) { 730*120b6fc9SSvatopluk Kraus device_printf(dev, "could not attach PIC\n"); 731*120b6fc9SSvatopluk Kraus return (ENXIO); 732*120b6fc9SSvatopluk Kraus } 733*120b6fc9SSvatopluk Kraus 734*120b6fc9SSvatopluk Kraus BCM_LINTC_LOCK_INIT(sc); 735*120b6fc9SSvatopluk Kraus bcm_lintc_sc = sc; 736*120b6fc9SSvatopluk Kraus return (0); 737*120b6fc9SSvatopluk Kraus } 738*120b6fc9SSvatopluk Kraus 739*120b6fc9SSvatopluk Kraus static device_method_t bcm_lintc_methods[] = { 740*120b6fc9SSvatopluk Kraus DEVMETHOD(device_probe, bcm_lintc_probe), 741*120b6fc9SSvatopluk Kraus DEVMETHOD(device_attach, bcm_lintc_attach), 742*120b6fc9SSvatopluk Kraus 743*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr), 744*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr), 745*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_map_intr, bcm_lintc_map_intr), 746*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_post_filter, bcm_lintc_post_filter), 747*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread), 748*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread), 749*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr), 750*120b6fc9SSvatopluk Kraus #ifdef SMP 751*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary), 752*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send), 753*120b6fc9SSvatopluk Kraus DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup), 754*120b6fc9SSvatopluk Kraus #endif 755*120b6fc9SSvatopluk Kraus 756*120b6fc9SSvatopluk Kraus DEVMETHOD_END 757*120b6fc9SSvatopluk Kraus }; 758*120b6fc9SSvatopluk Kraus 759*120b6fc9SSvatopluk Kraus static driver_t bcm_lintc_driver = { 760*120b6fc9SSvatopluk Kraus "local_intc", 761*120b6fc9SSvatopluk Kraus bcm_lintc_methods, 762*120b6fc9SSvatopluk Kraus sizeof(struct bcm_lintc_softc), 763*120b6fc9SSvatopluk Kraus }; 764*120b6fc9SSvatopluk Kraus 765*120b6fc9SSvatopluk Kraus static devclass_t bcm_lintc_devclass; 766*120b6fc9SSvatopluk Kraus 767*120b6fc9SSvatopluk Kraus EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass, 768*120b6fc9SSvatopluk Kraus 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 769*120b6fc9SSvatopluk Kraus #else 7704e46a66eSAndrew Turner /* 7714e46a66eSAndrew Turner * A driver for features of the bcm2836. 7724e46a66eSAndrew Turner */ 7734e46a66eSAndrew Turner 7744e46a66eSAndrew Turner struct bcm2836_softc { 7754e46a66eSAndrew Turner device_t sc_dev; 7764e46a66eSAndrew Turner struct resource *sc_mem; 7774e46a66eSAndrew Turner }; 7784e46a66eSAndrew Turner 7794e46a66eSAndrew Turner static device_identify_t bcm2836_identify; 7804e46a66eSAndrew Turner static device_probe_t bcm2836_probe; 7814e46a66eSAndrew Turner static device_attach_t bcm2836_attach; 7824e46a66eSAndrew Turner 7834e46a66eSAndrew Turner struct bcm2836_softc *softc; 7844e46a66eSAndrew Turner 7854e46a66eSAndrew Turner static void 7864e46a66eSAndrew Turner bcm2836_identify(driver_t *driver, device_t parent) 7874e46a66eSAndrew Turner { 7884e46a66eSAndrew Turner 7894e46a66eSAndrew Turner if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL) 7904e46a66eSAndrew Turner device_printf(parent, "add child failed\n"); 7914e46a66eSAndrew Turner } 7924e46a66eSAndrew Turner 7934e46a66eSAndrew Turner static int 7944e46a66eSAndrew Turner bcm2836_probe(device_t dev) 7954e46a66eSAndrew Turner { 7964e46a66eSAndrew Turner 7974e46a66eSAndrew Turner if (softc != NULL) 7984e46a66eSAndrew Turner return (ENXIO); 7994e46a66eSAndrew Turner 8004e46a66eSAndrew Turner device_set_desc(dev, "Broadcom bcm2836"); 8014e46a66eSAndrew Turner 8024e46a66eSAndrew Turner return (BUS_PROBE_DEFAULT); 8034e46a66eSAndrew Turner } 8044e46a66eSAndrew Turner 8054e46a66eSAndrew Turner static int 8064e46a66eSAndrew Turner bcm2836_attach(device_t dev) 8074e46a66eSAndrew Turner { 8084e46a66eSAndrew Turner int i, rid; 8094e46a66eSAndrew Turner 8104e46a66eSAndrew Turner softc = device_get_softc(dev); 8114e46a66eSAndrew Turner softc->sc_dev = dev; 8124e46a66eSAndrew Turner 8134e46a66eSAndrew Turner rid = 0; 8144e46a66eSAndrew Turner softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 8154e46a66eSAndrew Turner ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE, 8164e46a66eSAndrew Turner RF_ACTIVE); 8174e46a66eSAndrew Turner if (softc->sc_mem == NULL) { 8184e46a66eSAndrew Turner device_printf(dev, "could not allocate memory resource\n"); 8194e46a66eSAndrew Turner return (ENXIO); 8204e46a66eSAndrew Turner } 8214e46a66eSAndrew Turner 8224e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0); 8234e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2); 8244e46a66eSAndrew Turner 8254e46a66eSAndrew Turner for (i = 0; i < 4; i++) 8264e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0); 8274e46a66eSAndrew Turner 8284e46a66eSAndrew Turner for (i = 0; i < 4; i++) 8294e46a66eSAndrew Turner bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1); 8304e46a66eSAndrew Turner 8314e46a66eSAndrew Turner return (0); 8324e46a66eSAndrew Turner } 8334e46a66eSAndrew Turner 8344e46a66eSAndrew Turner int 8354e46a66eSAndrew Turner bcm2836_get_next_irq(int last_irq) 8364e46a66eSAndrew Turner { 8374e46a66eSAndrew Turner uint32_t reg; 8384e46a66eSAndrew Turner int cpu; 8394e46a66eSAndrew Turner int irq; 8404e46a66eSAndrew Turner 8414e46a66eSAndrew Turner cpu = PCPU_GET(cpuid); 8424e46a66eSAndrew Turner 8434e46a66eSAndrew Turner reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu)); 8444e46a66eSAndrew Turner reg &= INT_PENDING_MASK; 8454e46a66eSAndrew Turner if (reg == 0) 8464e46a66eSAndrew Turner return (-1); 8474e46a66eSAndrew Turner 8484e46a66eSAndrew Turner irq = ffs(reg) - 1; 8494e46a66eSAndrew Turner 8504e46a66eSAndrew Turner return (irq); 8514e46a66eSAndrew Turner } 8524e46a66eSAndrew Turner 8534e46a66eSAndrew Turner void 8544e46a66eSAndrew Turner bcm2836_mask_irq(uintptr_t irq) 8554e46a66eSAndrew Turner { 8564e46a66eSAndrew Turner uint32_t reg; 857962940ceSLuiz Otavio O Souza #ifdef SMP 858962940ceSLuiz Otavio O Souza int cpu; 859962940ceSLuiz Otavio O Souza #endif 8604e46a66eSAndrew Turner int i; 8614e46a66eSAndrew Turner 862962940ceSLuiz Otavio O Souza if (irq < MAILBOX0_IRQ) { 8634e46a66eSAndrew Turner for (i = 0; i < 4; i++) { 864962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, 865962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i)); 8664e46a66eSAndrew Turner reg &= ~(1 << irq); 867962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, 868962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i), reg); 869962940ceSLuiz Otavio O Souza } 870962940ceSLuiz Otavio O Souza #ifdef SMP 871962940ceSLuiz Otavio O Souza } else if (irq == MAILBOX0_IRQ) { 872962940ceSLuiz Otavio O Souza /* Mailbox 0 for IPI */ 873962940ceSLuiz Otavio O Souza cpu = PCPU_GET(cpuid); 874962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu)); 875962940ceSLuiz Otavio O Souza reg &= ~MAILBOX0_IRQEN; 876962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg); 877962940ceSLuiz Otavio O Souza #endif 8784e46a66eSAndrew Turner } 8794e46a66eSAndrew Turner } 8804e46a66eSAndrew Turner 8814e46a66eSAndrew Turner void 8824e46a66eSAndrew Turner bcm2836_unmask_irq(uintptr_t irq) 8834e46a66eSAndrew Turner { 8844e46a66eSAndrew Turner uint32_t reg; 885962940ceSLuiz Otavio O Souza #ifdef SMP 886962940ceSLuiz Otavio O Souza int cpu; 887962940ceSLuiz Otavio O Souza #endif 8884e46a66eSAndrew Turner int i; 8894e46a66eSAndrew Turner 890962940ceSLuiz Otavio O Souza if (irq < MAILBOX0_IRQ) { 8914e46a66eSAndrew Turner for (i = 0; i < 4; i++) { 892962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, 893962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i)); 8944e46a66eSAndrew Turner reg |= (1 << irq); 895962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, 896962940ceSLuiz Otavio O Souza ARM_LOCAL_INT_TIMER(i), reg); 897962940ceSLuiz Otavio O Souza } 898962940ceSLuiz Otavio O Souza #ifdef SMP 899962940ceSLuiz Otavio O Souza } else if (irq == MAILBOX0_IRQ) { 900962940ceSLuiz Otavio O Souza /* Mailbox 0 for IPI */ 901962940ceSLuiz Otavio O Souza cpu = PCPU_GET(cpuid); 902962940ceSLuiz Otavio O Souza reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu)); 903962940ceSLuiz Otavio O Souza reg |= MAILBOX0_IRQEN; 904962940ceSLuiz Otavio O Souza bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg); 905962940ceSLuiz Otavio O Souza #endif 9064e46a66eSAndrew Turner } 9074e46a66eSAndrew Turner } 9084e46a66eSAndrew Turner 9094e46a66eSAndrew Turner static device_method_t bcm2836_methods[] = { 9104e46a66eSAndrew Turner /* Device interface */ 9114e46a66eSAndrew Turner DEVMETHOD(device_identify, bcm2836_identify), 9124e46a66eSAndrew Turner DEVMETHOD(device_probe, bcm2836_probe), 9134e46a66eSAndrew Turner DEVMETHOD(device_attach, bcm2836_attach), 9144e46a66eSAndrew Turner 9154e46a66eSAndrew Turner DEVMETHOD_END 9164e46a66eSAndrew Turner }; 9174e46a66eSAndrew Turner 9184e46a66eSAndrew Turner static devclass_t bcm2836_devclass; 9194e46a66eSAndrew Turner 9204e46a66eSAndrew Turner static driver_t bcm2836_driver = { 9214e46a66eSAndrew Turner "bcm2836", 9224e46a66eSAndrew Turner bcm2836_methods, 9234e46a66eSAndrew Turner sizeof(struct bcm2836_softc), 9244e46a66eSAndrew Turner }; 9254e46a66eSAndrew Turner 9264e46a66eSAndrew Turner EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0, 9274e46a66eSAndrew Turner BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 928*120b6fc9SSvatopluk Kraus #endif 929