The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/broadcom/bcm2835/bcm2836.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright 2015 Andrew Turner.
    3  * Copyright 2016 Svatopluk Kraus
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions are
    8  * met:
    9  *
   10  *  1. Redistributions of source code must retain the above copyright
   11  *     notice, this list of conditions and the following disclaimer.
   12  *  2. Redistributions in binary form must reproduce the above copyright
   13  *     notice, this list of conditions and the following disclaimer in the
   14  *     documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
   20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include "opt_platform.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/cpuset.h>
   38 #include <sys/kernel.h>
   39 #include <sys/lock.h>
   40 #include <sys/module.h>
   41 #include <sys/mutex.h>
   42 #include <sys/proc.h>
   43 #include <sys/rman.h>
   44 #ifdef SMP
   45 #include <sys/smp.h>
   46 #endif
   47 
   48 #include <machine/bus.h>
   49 #include <machine/intr.h>
   50 #include <machine/resource.h>
   51 #ifdef SMP
   52 #include <machine/smp.h>
   53 #endif
   54 
   55 #include <dev/ofw/ofw_bus_subr.h>
   56 #include <dev/ofw/ofw_bus.h>
   57 
   58 #include "pic_if.h"
   59 
   60 #define BCM_LINTC_CONTROL_REG           0x00
   61 #define BCM_LINTC_PRESCALER_REG         0x08
   62 #define BCM_LINTC_GPU_ROUTING_REG       0x0c
   63 #define BCM_LINTC_PMU_ROUTING_SET_REG   0x10
   64 #define BCM_LINTC_PMU_ROUTING_CLR_REG   0x14
   65 #define BCM_LINTC_TIMER_CFG_REG(n)      (0x40 + (n) * 4)
   66 #define BCM_LINTC_MBOX_CFG_REG(n)       (0x50 + (n) * 4)
   67 #define BCM_LINTC_PENDING_REG(n)        (0x60 + (n) * 4)
   68 #define BCM_LINTC_MBOX0_SET_REG(n)      (0x80 + (n) * 16)
   69 #define BCM_LINTC_MBOX1_SET_REG(n)      (0x84 + (n) * 16)
   70 #define BCM_LINTC_MBOX2_SET_REG(n)      (0x88 + (n) * 16)
   71 #define BCM_LINTC_MBOX3_SET_REG(n)      (0x8C + (n) * 16)
   72 #define BCM_LINTC_MBOX0_CLR_REG(n)      (0xC0 + (n) * 16)
   73 #define BCM_LINTC_MBOX1_CLR_REG(n)      (0xC4 + (n) * 16)
   74 #define BCM_LINTC_MBOX2_CLR_REG(n)      (0xC8 + (n) * 16)
   75 #define BCM_LINTC_MBOX3_CLR_REG(n)      (0xCC + (n) * 16)
   76 
   77 /* Prescaler Register */
   78 #define BCM_LINTC_PSR_19_2              0x80000000      /* 19.2 MHz */
   79 
   80 /* GPU Interrupt Routing Register */
   81 #define BCM_LINTC_GIRR_IRQ_CORE(n)      (n)
   82 #define BCM_LINTC_GIRR_FIQ_CORE(n)      ((n) << 2)
   83 
   84 /* PMU Interrupt Routing Register */
   85 #define BCM_LINTC_PIRR_IRQ_EN_CORE(n)   (1 << (n))
   86 #define BCM_LINTC_PIRR_FIQ_EN_CORE(n)   (1 << ((n) + 4))
   87 
   88 /* Timer Config Register */
   89 #define BCM_LINTC_TCR_IRQ_EN_TIMER(n)   (1 << (n))
   90 #define BCM_LINTC_TCR_FIQ_EN_TIMER(n)   (1 << ((n) + 4))
   91 
   92 /* MBOX Config Register */
   93 #define BCM_LINTC_MCR_IRQ_EN_MBOX(n)    (1 << (n))
   94 #define BCM_LINTC_MCR_FIQ_EN_MBOX(n)    (1 << ((n) + 4))
   95 
   96 #define BCM_LINTC_CNTPSIRQ_IRQ          0
   97 #define BCM_LINTC_CNTPNSIRQ_IRQ         1
   98 #define BCM_LINTC_CNTHPIRQ_IRQ          2
   99 #define BCM_LINTC_CNTVIRQ_IRQ           3
  100 #define BCM_LINTC_MBOX0_IRQ             4
  101 #define BCM_LINTC_MBOX1_IRQ             5
  102 #define BCM_LINTC_MBOX2_IRQ             6
  103 #define BCM_LINTC_MBOX3_IRQ             7
  104 #define BCM_LINTC_GPU_IRQ               8
  105 #define BCM_LINTC_PMU_IRQ               9
  106 #define BCM_LINTC_AXI_IRQ               10
  107 #define BCM_LINTC_LTIMER_IRQ            11
  108 
  109 #define BCM_LINTC_NIRQS                 12
  110 
  111 #define BCM_LINTC_TIMER0_IRQ            BCM_LINTC_CNTPSIRQ_IRQ
  112 #define BCM_LINTC_TIMER1_IRQ            BCM_LINTC_CNTPNSIRQ_IRQ
  113 #define BCM_LINTC_TIMER2_IRQ            BCM_LINTC_CNTHPIRQ_IRQ
  114 #define BCM_LINTC_TIMER3_IRQ            BCM_LINTC_CNTVIRQ_IRQ
  115 
  116 #define BCM_LINTC_TIMER0_IRQ_MASK       (1 << BCM_LINTC_TIMER0_IRQ)
  117 #define BCM_LINTC_TIMER1_IRQ_MASK       (1 << BCM_LINTC_TIMER1_IRQ)
  118 #define BCM_LINTC_TIMER2_IRQ_MASK       (1 << BCM_LINTC_TIMER2_IRQ)
  119 #define BCM_LINTC_TIMER3_IRQ_MASK       (1 << BCM_LINTC_TIMER3_IRQ)
  120 #define BCM_LINTC_MBOX0_IRQ_MASK        (1 << BCM_LINTC_MBOX0_IRQ)
  121 #define BCM_LINTC_GPU_IRQ_MASK          (1 << BCM_LINTC_GPU_IRQ)
  122 #define BCM_LINTC_PMU_IRQ_MASK          (1 << BCM_LINTC_PMU_IRQ)
  123 
  124 #define BCM_LINTC_UP_PENDING_MASK       \
  125     (BCM_LINTC_TIMER0_IRQ_MASK |        \
  126      BCM_LINTC_TIMER1_IRQ_MASK |        \
  127      BCM_LINTC_TIMER2_IRQ_MASK |        \
  128      BCM_LINTC_TIMER3_IRQ_MASK |        \
  129      BCM_LINTC_GPU_IRQ_MASK |           \
  130      BCM_LINTC_PMU_IRQ_MASK)
  131 
  132 #define BCM_LINTC_SMP_PENDING_MASK      \
  133     (BCM_LINTC_UP_PENDING_MASK |        \
  134      BCM_LINTC_MBOX0_IRQ_MASK)
  135 
  136 #ifdef SMP
  137 #define BCM_LINTC_PENDING_MASK          BCM_LINTC_SMP_PENDING_MASK
  138 #else
  139 #define BCM_LINTC_PENDING_MASK          BCM_LINTC_UP_PENDING_MASK
  140 #endif
  141 
  142 struct bcm_lintc_irqsrc {
  143         struct intr_irqsrc      bli_isrc;
  144         u_int                   bli_irq;
  145         union {
  146                 u_int           bli_mask;       /* for timers */
  147                 u_int           bli_value;      /* for GPU */
  148         };
  149 };
  150 
  151 struct bcm_lintc_softc {
  152         device_t                bls_dev;
  153         struct mtx              bls_mtx;
  154         struct resource *       bls_mem;
  155         bus_space_tag_t         bls_bst;
  156         bus_space_handle_t      bls_bsh;
  157         struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS];
  158 };
  159 
  160 static struct bcm_lintc_softc *bcm_lintc_sc;
  161 
  162 #ifdef SMP
  163 #define BCM_LINTC_NIPIS         32      /* only mailbox 0 is used for IPI */
  164 CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
  165 #endif
  166 
  167 #define BCM_LINTC_LOCK(sc)              mtx_lock_spin(&(sc)->bls_mtx)
  168 #define BCM_LINTC_UNLOCK(sc)            mtx_unlock_spin(&(sc)->bls_mtx)
  169 #define BCM_LINTC_LOCK_INIT(sc)         mtx_init(&(sc)->bls_mtx,        \
  170     device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
  171 #define BCM_LINTC_LOCK_DESTROY(sc)      mtx_destroy(&(sc)->bls_mtx)
  172 
  173 #define bcm_lintc_read_4(sc, reg)               \
  174     bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
  175 #define bcm_lintc_write_4(sc, reg, val)         \
  176     bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
  177 
  178 static inline void
  179 bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
  180     uint32_t mask)
  181 {
  182 
  183         bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
  184 }
  185 
  186 static inline void
  187 bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
  188     uint32_t mask)
  189 {
  190 
  191         bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
  192 }
  193 
  194 static void
  195 bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  196 {
  197         cpuset_t *cpus;
  198         uint32_t cpu;
  199 
  200         cpus = &bli->bli_isrc.isrc_cpu;
  201 
  202         BCM_LINTC_LOCK(sc);
  203         for (cpu = 0; cpu < 4; cpu++)
  204                 if (CPU_ISSET(cpu, cpus))
  205                         bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
  206                             bli->bli_mask);
  207         BCM_LINTC_UNLOCK(sc);
  208 }
  209 
  210 static void
  211 bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  212 {
  213         cpuset_t *cpus;
  214         uint32_t cpu;
  215 
  216         cpus = &bli->bli_isrc.isrc_cpu;
  217 
  218         BCM_LINTC_LOCK(sc);
  219         for (cpu = 0; cpu < 4; cpu++)
  220                 if (CPU_ISSET(cpu, cpus))
  221                         bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
  222                             bli->bli_mask);
  223         BCM_LINTC_UNLOCK(sc);
  224 }
  225 
  226 static inline void
  227 bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  228 {
  229 
  230         /* It's accessed just and only by one core. */
  231         bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
  232 }
  233 
  234 static inline void
  235 bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  236 {
  237 
  238         /* It's accessed just and only by one core. */
  239         bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
  240 }
  241 
  242 static inline void
  243 bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  244 {
  245         cpuset_t *cpus;
  246         uint32_t cpu, mask;
  247 
  248         mask = 0;
  249         cpus = &bli->bli_isrc.isrc_cpu;
  250 
  251         BCM_LINTC_LOCK(sc);
  252         for (cpu = 0; cpu < 4; cpu++)
  253                 if (CPU_ISSET(cpu, cpus))
  254                         mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
  255         /* Write-clear register. */
  256         bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
  257         BCM_LINTC_UNLOCK(sc);
  258 }
  259 
  260 static inline void
  261 bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  262 {
  263         cpuset_t *cpus;
  264         uint32_t cpu, mask;
  265 
  266         mask = 0;
  267         cpus = &bli->bli_isrc.isrc_cpu;
  268 
  269         BCM_LINTC_LOCK(sc);
  270         for (cpu = 0; cpu < 4; cpu++)
  271                 if (CPU_ISSET(cpu, cpus))
  272                         mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
  273         /* Write-set register. */
  274         bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
  275         BCM_LINTC_UNLOCK(sc);
  276 }
  277 
  278 static void
  279 bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  280 {
  281 
  282         switch (bli->bli_irq) {
  283         case BCM_LINTC_TIMER0_IRQ:
  284         case BCM_LINTC_TIMER1_IRQ:
  285         case BCM_LINTC_TIMER2_IRQ:
  286         case BCM_LINTC_TIMER3_IRQ:
  287                 bcm_lintc_timer_mask(sc, bli);
  288                 return;
  289         case BCM_LINTC_MBOX0_IRQ:
  290         case BCM_LINTC_MBOX1_IRQ:
  291         case BCM_LINTC_MBOX2_IRQ:
  292         case BCM_LINTC_MBOX3_IRQ:
  293                 return;
  294         case BCM_LINTC_GPU_IRQ:
  295                 bcm_lintc_gpu_mask(sc, bli);
  296                 return;
  297         case BCM_LINTC_PMU_IRQ:
  298                 bcm_lintc_pmu_mask(sc, bli);
  299                 return;
  300         default:
  301                 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
  302         }
  303 }
  304 
  305 static void
  306 bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
  307 {
  308 
  309         switch (bli->bli_irq) {
  310         case BCM_LINTC_TIMER0_IRQ:
  311         case BCM_LINTC_TIMER1_IRQ:
  312         case BCM_LINTC_TIMER2_IRQ:
  313         case BCM_LINTC_TIMER3_IRQ:
  314                 bcm_lintc_timer_unmask(sc, bli);
  315                 return;
  316         case BCM_LINTC_MBOX0_IRQ:
  317         case BCM_LINTC_MBOX1_IRQ:
  318         case BCM_LINTC_MBOX2_IRQ:
  319         case BCM_LINTC_MBOX3_IRQ:
  320                 return;
  321         case BCM_LINTC_GPU_IRQ:
  322                 bcm_lintc_gpu_unmask(sc, bli);
  323                 return;
  324         case BCM_LINTC_PMU_IRQ:
  325                 bcm_lintc_pmu_unmask(sc, bli);
  326                 return;
  327         default:
  328                 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
  329         }
  330 }
  331 
  332 #ifdef SMP
  333 static inline void
  334 bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
  335 {
  336         u_int cpu;
  337         uint32_t mask;
  338 
  339         mask = 1 << ipi;
  340         for (cpu = 0; cpu < mp_ncpus; cpu++)
  341                 if (CPU_ISSET(cpu, &cpus))
  342                         bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
  343                             mask);
  344 }
  345 
  346 static inline void
  347 bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
  348     struct trapframe *tf)
  349 {
  350         u_int ipi;
  351         uint32_t mask;
  352 
  353         mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
  354         if (mask == 0) {
  355                 device_printf(sc->bls_dev, "Spurious ipi detected\n");
  356                 return;
  357         }
  358 
  359         for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
  360                 if ((mask & 0x01) == 0)
  361                         continue;
  362                 /*
  363                  * Clear an IPI before dispatching to not miss anyone
  364                  * and make sure that it's observed by everybody.
  365                  */
  366                 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
  367 #if defined(__aarch64__)
  368                 dsb(sy);
  369 #else
  370                 dsb();
  371 #endif
  372                 intr_ipi_dispatch(ipi, tf);
  373         }
  374 }
  375 #endif
  376 
  377 static inline void
  378 bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
  379     struct trapframe *tf)
  380 {
  381         struct bcm_lintc_irqsrc *bli;
  382 
  383         bli = &sc->bls_isrcs[irq];
  384         if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
  385                 device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
  386 }
  387 
  388 static int
  389 bcm_lintc_intr(void *arg)
  390 {
  391         struct bcm_lintc_softc *sc;
  392         u_int cpu;
  393         uint32_t num, reg;
  394         struct trapframe *tf;
  395 
  396         sc = arg;
  397         cpu = PCPU_GET(cpuid);
  398         tf = curthread->td_intr_frame;
  399 
  400         for (num = 0; ; num++) {
  401                 reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
  402                 if ((reg & BCM_LINTC_PENDING_MASK) == 0)
  403                         break;
  404 #ifdef SMP
  405                 if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
  406                         bcm_lintc_ipi_dispatch(sc, cpu, tf);
  407 #endif
  408                 if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
  409                         bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
  410                 if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
  411                         bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
  412                 if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
  413                         bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
  414                 if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
  415                         bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
  416                 if (reg & BCM_LINTC_GPU_IRQ_MASK)
  417                         bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
  418                 if (reg & BCM_LINTC_PMU_IRQ_MASK)
  419                         bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
  420 
  421                 arm_irq_memory_barrier(0); /* XXX */
  422         }
  423         reg &= ~BCM_LINTC_PENDING_MASK;
  424         if (reg != 0)
  425                 device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
  426         else if (num == 0 && bootverbose)
  427                 device_printf(sc->bls_dev, "Spurious interrupt detected\n");
  428 
  429         return (FILTER_HANDLED);
  430 }
  431 
  432 static void
  433 bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  434 {
  435 
  436         bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
  437 }
  438 
  439 static void
  440 bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  441 {
  442         struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
  443 
  444         arm_irq_memory_barrier(bli->bli_irq);
  445         bcm_lintc_unmask(device_get_softc(dev), bli);
  446 }
  447 
  448 static int
  449 bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
  450     struct intr_irqsrc **isrcp)
  451 {
  452         struct intr_map_data_fdt *daf;
  453         struct bcm_lintc_softc *sc;
  454 
  455         if (data->type != INTR_MAP_DATA_FDT)
  456                 return (ENOTSUP);
  457 
  458         daf = (struct intr_map_data_fdt *)data;
  459         if (daf->ncells > 2 || daf->cells[0] >= BCM_LINTC_NIRQS)
  460                 return (EINVAL);
  461 
  462         /* TODO: handle IRQ type here */
  463 
  464         sc = device_get_softc(dev);
  465         *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
  466         return (0);
  467 }
  468 
  469 static void
  470 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  471 {
  472         struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
  473 
  474         if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
  475                 bcm_lintc_gpu_mask(device_get_softc(dev), bli);
  476         else {
  477                 /*
  478                  * Handler for PPI interrupt does not make sense much unless
  479                  * there is one bound ithread for each core for it. Thus the
  480                  * interrupt can be masked on current core only while ithread
  481                  * bounded to this core ensures unmasking on the same core.
  482                  */
  483                 panic ("%s: handlers are not supported", __func__);
  484         }
  485 }
  486 
  487 static void
  488 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  489 {
  490         struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
  491 
  492         if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
  493                 bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
  494         else {
  495                 /* See comment in bcm_lintc_pre_ithread(). */
  496                 panic ("%s: handlers are not supported", __func__);
  497         }
  498 }
  499 
  500 static void
  501 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
  502 {
  503 }
  504 
  505 static int
  506 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
  507     struct resource *res, struct intr_map_data *data)
  508 {
  509         struct bcm_lintc_softc *sc;
  510 
  511         if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
  512                 sc = device_get_softc(dev);
  513                 BCM_LINTC_LOCK(sc);
  514                 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
  515                 BCM_LINTC_UNLOCK(sc);
  516         }
  517         return (0);
  518 }
  519 
  520 #ifdef SMP
  521 static void
  522 bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
  523     uint32_t reg, uint32_t mask)
  524 {
  525 
  526         if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
  527                 bcm_lintc_rwreg_set(sc, reg, mask);
  528 }
  529 
  530 static void
  531 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
  532 {
  533         struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
  534 
  535         if (intr_isrc_init_on_cpu(isrc, cpu)) {
  536                 /* Write-set register. */
  537                 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
  538                     BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
  539         }
  540 }
  541 
  542 static void
  543 bcm_lintc_init_secondary(device_t dev)
  544 {
  545         u_int cpu;
  546         struct bcm_lintc_softc *sc;
  547 
  548         cpu = PCPU_GET(cpuid);
  549         sc = device_get_softc(dev);
  550 
  551         BCM_LINTC_LOCK(sc);
  552         bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
  553             BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
  554         bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
  555             BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
  556         bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
  557             BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
  558         bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
  559             BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
  560         bcm_lintc_init_pmu_on_ap(sc, cpu);
  561         BCM_LINTC_UNLOCK(sc);
  562 }
  563 
  564 static void
  565 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
  566     u_int ipi)
  567 {
  568         struct bcm_lintc_softc *sc = device_get_softc(dev);
  569 
  570         KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
  571             ("%s: bad ISRC %p argument", __func__, isrc));
  572         bcm_lintc_ipi_write(sc, cpus, ipi);
  573 }
  574 
  575 static int
  576 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
  577 {
  578         struct bcm_lintc_softc *sc = device_get_softc(dev);
  579 
  580         KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
  581 
  582         *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
  583         return (0);
  584 }
  585 #endif
  586 
  587 static int
  588 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
  589 {
  590         struct bcm_lintc_irqsrc *bisrcs;
  591         struct intr_pic *pic;
  592         int error;
  593         u_int flags;
  594         uint32_t irq;
  595         const char *name;
  596         intptr_t xref;
  597 
  598         bisrcs = sc->bls_isrcs;
  599         name = device_get_nameunit(sc->bls_dev);
  600         for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
  601                 bisrcs[irq].bli_irq = irq;
  602                 switch (irq) {
  603                 case BCM_LINTC_TIMER0_IRQ:
  604                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
  605                         flags = INTR_ISRCF_PPI;
  606                         break;
  607                 case BCM_LINTC_TIMER1_IRQ:
  608                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
  609                         flags = INTR_ISRCF_PPI;
  610                         break;
  611                 case BCM_LINTC_TIMER2_IRQ:
  612                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
  613                         flags = INTR_ISRCF_PPI;
  614                         break;
  615                 case BCM_LINTC_TIMER3_IRQ:
  616                         bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
  617                         flags = INTR_ISRCF_PPI;
  618                         break;
  619                 case BCM_LINTC_MBOX0_IRQ:
  620                 case BCM_LINTC_MBOX1_IRQ:
  621                 case BCM_LINTC_MBOX2_IRQ:
  622                 case BCM_LINTC_MBOX3_IRQ:
  623                         bisrcs[irq].bli_value = 0;      /* not used */
  624                         flags = INTR_ISRCF_IPI;
  625                         break;
  626                 case BCM_LINTC_GPU_IRQ:
  627                         bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
  628                         flags = 0;
  629                         break;
  630                 case BCM_LINTC_PMU_IRQ:
  631                         bisrcs[irq].bli_value = 0;      /* not used */
  632                         flags = INTR_ISRCF_PPI;
  633                         break;
  634                 default:
  635                         bisrcs[irq].bli_value = 0;      /* not used */
  636                         flags = 0;
  637                         break;
  638                 }
  639 
  640                 error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
  641                     flags, "%s,%u", name, irq);
  642                 if (error != 0)
  643                         return (error);
  644         }
  645 
  646         xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
  647         pic = intr_pic_register(sc->bls_dev, xref);
  648         if (pic == NULL)
  649                 return (ENXIO);
  650 
  651         return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
  652 }
  653 
  654 static int
  655 bcm_lintc_probe(device_t dev)
  656 {
  657 
  658         if (!ofw_bus_status_okay(dev))
  659                 return (ENXIO);
  660 
  661         if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
  662                 return (ENXIO);
  663         if (!ofw_bus_has_prop(dev, "interrupt-controller"))
  664                 return (ENXIO);
  665         device_set_desc(dev, "BCM2836 Interrupt Controller");
  666         return (BUS_PROBE_DEFAULT);
  667 }
  668 
  669 static int
  670 bcm_lintc_attach(device_t dev)
  671 {
  672         struct bcm_lintc_softc *sc;
  673         int cpu, rid;
  674 
  675         sc = device_get_softc(dev);
  676 
  677         sc->bls_dev = dev;
  678         if (bcm_lintc_sc != NULL)
  679                 return (ENXIO);
  680 
  681         rid = 0;
  682         sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  683             RF_ACTIVE);
  684         if (sc->bls_mem == NULL) {
  685                 device_printf(dev, "could not allocate memory resource\n");
  686                 return (ENXIO);
  687         }
  688 
  689         sc->bls_bst = rman_get_bustag(sc->bls_mem);
  690         sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
  691 
  692         bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
  693         bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
  694 
  695         /* Disable all timers on all cores. */
  696         for (cpu = 0; cpu < 4; cpu++)
  697                 bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
  698 
  699 #ifdef SMP
  700         /* Enable mailbox 0 on all cores used for IPI. */
  701         for (cpu = 0; cpu < 4; cpu++)
  702                 bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
  703                     BCM_LINTC_MCR_IRQ_EN_MBOX(0));
  704 #endif
  705 
  706         if (bcm_lintc_pic_attach(sc) != 0) {
  707                 device_printf(dev, "could not attach PIC\n");
  708                 return (ENXIO);
  709         }
  710 
  711         BCM_LINTC_LOCK_INIT(sc);
  712         bcm_lintc_sc = sc;
  713         return (0);
  714 }
  715 
  716 static device_method_t bcm_lintc_methods[] = {
  717         DEVMETHOD(device_probe,         bcm_lintc_probe),
  718         DEVMETHOD(device_attach,        bcm_lintc_attach),
  719 
  720         DEVMETHOD(pic_disable_intr,     bcm_lintc_disable_intr),
  721         DEVMETHOD(pic_enable_intr,      bcm_lintc_enable_intr),
  722         DEVMETHOD(pic_map_intr,         bcm_lintc_map_intr),
  723         DEVMETHOD(pic_post_filter,      bcm_lintc_post_filter),
  724         DEVMETHOD(pic_post_ithread,     bcm_lintc_post_ithread),
  725         DEVMETHOD(pic_pre_ithread,      bcm_lintc_pre_ithread),
  726         DEVMETHOD(pic_setup_intr,       bcm_lintc_setup_intr),
  727 #ifdef SMP
  728         DEVMETHOD(pic_init_secondary,   bcm_lintc_init_secondary),
  729         DEVMETHOD(pic_ipi_send,         bcm_lintc_ipi_send),
  730         DEVMETHOD(pic_ipi_setup,        bcm_lintc_ipi_setup),
  731 #endif
  732 
  733         DEVMETHOD_END
  734 };
  735 
  736 static driver_t bcm_lintc_driver = {
  737         "lintc",
  738         bcm_lintc_methods,
  739         sizeof(struct bcm_lintc_softc),
  740 };
  741 
  742 EARLY_DRIVER_MODULE(lintc, simplebus, bcm_lintc_driver, 0, 0,
  743     BUS_PASS_INTERRUPT);

Cache object: dbe85ec6dc9dfbe404730419892c8826


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.