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/bcm2835_intr.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
    5  * All rights reserved.
    6  *
    7  * Based on OMAP3 INTC code by Ben Gray
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include "opt_platform.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/kernel.h>
   40 #include <sys/ktr.h>
   41 #include <sys/module.h>
   42 #include <sys/proc.h>
   43 #include <sys/rman.h>
   44 #include <machine/bus.h>
   45 #include <machine/intr.h>
   46 
   47 #include <dev/ofw/openfirm.h>
   48 #include <dev/ofw/ofw_bus.h>
   49 #include <dev/ofw/ofw_bus_subr.h>
   50 
   51 #include "pic_if.h"
   52 
   53 #define INTC_PENDING_BASIC      0x00
   54 #define INTC_PENDING_BANK1      0x04
   55 #define INTC_PENDING_BANK2      0x08
   56 #define INTC_FIQ_CONTROL        0x0C
   57 #define INTC_ENABLE_BANK1       0x10
   58 #define INTC_ENABLE_BANK2       0x14
   59 #define INTC_ENABLE_BASIC       0x18
   60 #define INTC_DISABLE_BANK1      0x1C
   61 #define INTC_DISABLE_BANK2      0x20
   62 #define INTC_DISABLE_BASIC      0x24
   63 
   64 #define INTC_PENDING_BASIC_ARM          0x0000FF
   65 #define INTC_PENDING_BASIC_GPU1_PEND    0x000100
   66 #define INTC_PENDING_BASIC_GPU2_PEND    0x000200
   67 #define INTC_PENDING_BASIC_GPU1_7       0x000400
   68 #define INTC_PENDING_BASIC_GPU1_9       0x000800
   69 #define INTC_PENDING_BASIC_GPU1_10      0x001000
   70 #define INTC_PENDING_BASIC_GPU1_18      0x002000
   71 #define INTC_PENDING_BASIC_GPU1_19      0x004000
   72 #define INTC_PENDING_BASIC_GPU2_21      0x008000
   73 #define INTC_PENDING_BASIC_GPU2_22      0x010000
   74 #define INTC_PENDING_BASIC_GPU2_23      0x020000
   75 #define INTC_PENDING_BASIC_GPU2_24      0x040000
   76 #define INTC_PENDING_BASIC_GPU2_25      0x080000
   77 #define INTC_PENDING_BASIC_GPU2_30      0x100000
   78 #define INTC_PENDING_BASIC_MASK         0x1FFFFF
   79 
   80 #define INTC_PENDING_BASIC_GPU1_MASK    (INTC_PENDING_BASIC_GPU1_7 |    \
   81                                          INTC_PENDING_BASIC_GPU1_9 |    \
   82                                          INTC_PENDING_BASIC_GPU1_10 |   \
   83                                          INTC_PENDING_BASIC_GPU1_18 |   \
   84                                          INTC_PENDING_BASIC_GPU1_19)
   85 
   86 #define INTC_PENDING_BASIC_GPU2_MASK    (INTC_PENDING_BASIC_GPU2_21 |   \
   87                                          INTC_PENDING_BASIC_GPU2_22 |   \
   88                                          INTC_PENDING_BASIC_GPU2_23 |   \
   89                                          INTC_PENDING_BASIC_GPU2_24 |   \
   90                                          INTC_PENDING_BASIC_GPU2_25 |   \
   91                                          INTC_PENDING_BASIC_GPU2_30)
   92 
   93 #define INTC_PENDING_BANK1_MASK (~((1 << 7) | (1 << 9) | (1 << 10) | \
   94     (1 << 18) | (1 << 19)))
   95 #define INTC_PENDING_BANK2_MASK (~((1 << 21) | (1 << 22) | (1 << 23) | \
   96     (1 << 24) | (1 << 25) | (1 << 30)))
   97 
   98 #define BANK1_START     8
   99 #define BANK1_END       (BANK1_START + 32 - 1)
  100 #define BANK2_START     (BANK1_START + 32)
  101 #define BANK2_END       (BANK2_START + 32 - 1)
  102 
  103 #define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START))
  104 #define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END))
  105 #define IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END))
  106 #define IRQ_BANK1(n)    ((n) - BANK1_START)
  107 #define IRQ_BANK2(n)    ((n) - BANK2_START)
  108 
  109 #ifdef  DEBUG
  110 #define dprintf(fmt, args...) printf(fmt, ##args)
  111 #else
  112 #define dprintf(fmt, args...)
  113 #endif
  114 
  115 #define BCM_INTC_NIRQS          72      /* 8 + 32 + 32 */
  116 
  117 struct bcm_intc_irqsrc {
  118         struct intr_irqsrc      bii_isrc;
  119         u_int                   bii_irq;
  120         uint16_t                bii_disable_reg;
  121         uint16_t                bii_enable_reg;
  122         uint32_t                bii_mask;
  123 };
  124 
  125 struct bcm_intc_softc {
  126         device_t                sc_dev;
  127         struct resource *       intc_res;
  128         bus_space_tag_t         intc_bst;
  129         bus_space_handle_t      intc_bsh;
  130         struct resource *       intc_irq_res;
  131         void *                  intc_irq_hdl;
  132         struct bcm_intc_irqsrc  intc_isrcs[BCM_INTC_NIRQS];
  133 };
  134 
  135 static struct ofw_compat_data compat_data[] = {
  136         {"broadcom,bcm2835-armctrl-ic",         1},
  137         {"brcm,bcm2835-armctrl-ic",             1},
  138         {"brcm,bcm2836-armctrl-ic",             1},
  139         {NULL,                                  0}
  140 };
  141 
  142 static struct bcm_intc_softc *bcm_intc_sc = NULL;
  143 
  144 #define intc_read_4(_sc, reg)           \
  145     bus_space_read_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg))
  146 #define intc_write_4(_sc, reg, val)             \
  147     bus_space_write_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg), (val))
  148 
  149 static inline void
  150 bcm_intc_isrc_mask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii)
  151 {
  152 
  153         intc_write_4(sc, bii->bii_disable_reg,  bii->bii_mask);
  154 }
  155 
  156 static inline void
  157 bcm_intc_isrc_unmask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii)
  158 {
  159 
  160         intc_write_4(sc, bii->bii_enable_reg,  bii->bii_mask);
  161 }
  162 
  163 static inline int
  164 bcm2835_intc_active_intr(struct bcm_intc_softc *sc)
  165 {
  166         uint32_t pending, pending_gpu;
  167 
  168         pending = intc_read_4(sc, INTC_PENDING_BASIC) & INTC_PENDING_BASIC_MASK;
  169         if (pending == 0)
  170                 return (-1);
  171         if (pending & INTC_PENDING_BASIC_ARM)
  172                 return (ffs(pending) - 1);
  173         if (pending & INTC_PENDING_BASIC_GPU1_MASK) {
  174                 if (pending & INTC_PENDING_BASIC_GPU1_7)
  175                         return (BANK1_START + 7);
  176                 if (pending & INTC_PENDING_BASIC_GPU1_9)
  177                         return (BANK1_START + 9);
  178                 if (pending & INTC_PENDING_BASIC_GPU1_10)
  179                         return (BANK1_START + 10);
  180                 if (pending & INTC_PENDING_BASIC_GPU1_18)
  181                         return (BANK1_START + 18);
  182                 if (pending & INTC_PENDING_BASIC_GPU1_19)
  183                         return (BANK1_START + 19);
  184         }
  185         if (pending & INTC_PENDING_BASIC_GPU2_MASK) {
  186                 if (pending & INTC_PENDING_BASIC_GPU2_21)
  187                         return (BANK2_START + 21);
  188                 if (pending & INTC_PENDING_BASIC_GPU2_22)
  189                         return (BANK2_START + 22);
  190                 if (pending & INTC_PENDING_BASIC_GPU2_23)
  191                         return (BANK2_START + 23);
  192                 if (pending & INTC_PENDING_BASIC_GPU2_24)
  193                         return (BANK2_START + 24);
  194                 if (pending & INTC_PENDING_BASIC_GPU2_25)
  195                         return (BANK2_START + 25);
  196                 if (pending & INTC_PENDING_BASIC_GPU2_30)
  197                         return (BANK2_START + 30);
  198         }
  199         if (pending & INTC_PENDING_BASIC_GPU1_PEND) {
  200                 pending_gpu = intc_read_4(sc, INTC_PENDING_BANK1);
  201                 pending_gpu &= INTC_PENDING_BANK1_MASK;
  202                 if (pending_gpu != 0)
  203                         return (BANK1_START + ffs(pending_gpu) - 1);
  204         }
  205         if (pending & INTC_PENDING_BASIC_GPU2_PEND) {
  206                 pending_gpu = intc_read_4(sc, INTC_PENDING_BANK2);
  207                 pending_gpu &= INTC_PENDING_BANK2_MASK;
  208                 if (pending_gpu != 0)
  209                         return (BANK2_START + ffs(pending_gpu) - 1);
  210         }
  211         return (-1);    /* It shouldn't end here, but it's hardware. */
  212 }
  213 
  214 static int
  215 bcm2835_intc_intr(void *arg)
  216 {
  217         int irq, num;
  218         struct bcm_intc_softc *sc = arg;
  219 
  220         for (num = 0; ; num++) {
  221                 irq = bcm2835_intc_active_intr(sc);
  222                 if (irq == -1)
  223                         break;
  224                 if (intr_isrc_dispatch(&sc->intc_isrcs[irq].bii_isrc,
  225                     curthread->td_intr_frame) != 0) {
  226                         bcm_intc_isrc_mask(sc, &sc->intc_isrcs[irq]);
  227                         device_printf(sc->sc_dev, "Stray irq %u disabled\n",
  228                             irq);
  229                 }
  230                 arm_irq_memory_barrier(0); /* XXX */
  231         }
  232         if (num == 0 && bootverbose)
  233                 device_printf(sc->sc_dev, "Spurious interrupt detected\n");
  234 
  235         return (FILTER_HANDLED);
  236 }
  237 
  238 static void
  239 bcm_intc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  240 {
  241         struct bcm_intc_irqsrc *bii = (struct bcm_intc_irqsrc *)isrc;
  242 
  243         arm_irq_memory_barrier(bii->bii_irq);
  244         bcm_intc_isrc_unmask(device_get_softc(dev), bii);
  245 }
  246 
  247 static void
  248 bcm_intc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  249 {
  250 
  251         bcm_intc_isrc_mask(device_get_softc(dev),
  252             (struct bcm_intc_irqsrc *)isrc);
  253 }
  254 
  255 static int
  256 bcm_intc_map_intr(device_t dev, struct intr_map_data *data,
  257     struct intr_irqsrc **isrcp)
  258 {
  259         u_int irq;
  260         struct intr_map_data_fdt *daf;
  261         struct bcm_intc_softc *sc;
  262         bool valid;
  263 
  264         if (data->type != INTR_MAP_DATA_FDT)
  265                 return (ENOTSUP);
  266 
  267         daf = (struct intr_map_data_fdt *)data;
  268         if (daf->ncells == 1)
  269                 irq = daf->cells[0];
  270         else if (daf->ncells == 2) {
  271                 valid = true;
  272                 switch (daf->cells[0]) {
  273                 case 0:
  274                         irq = daf->cells[1];
  275                         if (irq >= BANK1_START)
  276                                 valid = false;
  277                         break;
  278                 case 1:
  279                         irq = daf->cells[1] + BANK1_START;
  280                         if (irq > BANK1_END)
  281                                 valid = false;
  282                         break;
  283                 case 2:
  284                         irq = daf->cells[1] + BANK2_START;
  285                         if (irq > BANK2_END)
  286                                 valid = false;
  287                         break;
  288                 default:
  289                         valid = false;
  290                         break;
  291                 }
  292 
  293                 if (!valid) {
  294                         device_printf(dev,
  295                             "invalid IRQ config: bank=%d, irq=%d\n",
  296                             daf->cells[0], daf->cells[1]);
  297                         return (EINVAL);
  298                 }
  299         }
  300         else
  301                 return (EINVAL);
  302 
  303         if (irq >= BCM_INTC_NIRQS)
  304                 return (EINVAL);
  305 
  306         sc = device_get_softc(dev);
  307         *isrcp = &sc->intc_isrcs[irq].bii_isrc;
  308         return (0);
  309 }
  310 
  311 static void
  312 bcm_intc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  313 {
  314 
  315         bcm_intc_disable_intr(dev, isrc);
  316 }
  317 
  318 static void
  319 bcm_intc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  320 {
  321 
  322         bcm_intc_enable_intr(dev, isrc);
  323 }
  324 
  325 static void
  326 bcm_intc_post_filter(device_t dev, struct intr_irqsrc *isrc)
  327 {
  328 }
  329 
  330 static int
  331 bcm_intc_pic_register(struct bcm_intc_softc *sc, intptr_t xref)
  332 {
  333         struct bcm_intc_irqsrc *bii;
  334         int error;
  335         uint32_t irq;
  336         const char *name;
  337 
  338         name = device_get_nameunit(sc->sc_dev);
  339         for (irq = 0; irq < BCM_INTC_NIRQS; irq++) {
  340                 bii = &sc->intc_isrcs[irq];
  341                 bii->bii_irq = irq;
  342                 if (IS_IRQ_BASIC(irq)) {
  343                         bii->bii_disable_reg = INTC_DISABLE_BASIC;
  344                         bii->bii_enable_reg = INTC_ENABLE_BASIC;
  345                         bii->bii_mask = 1 << irq;
  346                 } else if (IS_IRQ_BANK1(irq)) {
  347                         bii->bii_disable_reg = INTC_DISABLE_BANK1;
  348                         bii->bii_enable_reg = INTC_ENABLE_BANK1;
  349                         bii->bii_mask = 1 << IRQ_BANK1(irq);
  350                 } else if (IS_IRQ_BANK2(irq)) {
  351                         bii->bii_disable_reg = INTC_DISABLE_BANK2;
  352                         bii->bii_enable_reg = INTC_ENABLE_BANK2;
  353                         bii->bii_mask = 1 << IRQ_BANK2(irq);
  354                 } else
  355                         return (ENXIO);
  356 
  357                 error = intr_isrc_register(&bii->bii_isrc, sc->sc_dev, 0,
  358                     "%s,%u", name, irq);
  359                 if (error != 0)
  360                         return (error);
  361         }
  362         if (intr_pic_register(sc->sc_dev, xref) == NULL)
  363                 return (ENXIO);
  364 
  365         return (0);
  366 }
  367 
  368 static int
  369 bcm_intc_probe(device_t dev)
  370 {
  371 
  372         if (!ofw_bus_status_okay(dev))
  373                 return (ENXIO);
  374 
  375         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  376                 return (ENXIO);
  377 
  378         device_set_desc(dev, "BCM2835 Interrupt Controller");
  379         return (BUS_PROBE_DEFAULT);
  380 }
  381 
  382 static int
  383 bcm_intc_attach(device_t dev)
  384 {
  385         struct          bcm_intc_softc *sc = device_get_softc(dev);
  386         int             rid = 0;
  387         intptr_t        xref;
  388         sc->sc_dev = dev;
  389 
  390         if (bcm_intc_sc)
  391                 return (ENXIO);
  392 
  393         sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  394         if (sc->intc_res == NULL) {
  395                 device_printf(dev, "could not allocate memory resource\n");
  396                 return (ENXIO);
  397         }
  398 
  399         xref = OF_xref_from_node(ofw_bus_get_node(dev));
  400         if (bcm_intc_pic_register(sc, xref) != 0) {
  401                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->intc_res);
  402                 device_printf(dev, "could not register PIC\n");
  403                 return (ENXIO);
  404         }
  405 
  406         rid = 0;
  407         sc->intc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  408             RF_ACTIVE);
  409         if (sc->intc_irq_res == NULL) {
  410                 if (intr_pic_claim_root(dev, xref, bcm2835_intc_intr, sc, 0) != 0) {
  411                         /* XXX clean up */
  412                         device_printf(dev, "could not set PIC as a root\n");
  413                         return (ENXIO);
  414                 }
  415         } else {
  416                 if (bus_setup_intr(dev, sc->intc_irq_res, INTR_TYPE_CLK,
  417                     bcm2835_intc_intr, NULL, sc, &sc->intc_irq_hdl)) {
  418                         /* XXX clean up */
  419                         device_printf(dev, "could not setup irq handler\n");
  420                         return (ENXIO);
  421                 }
  422         }
  423         sc->intc_bst = rman_get_bustag(sc->intc_res);
  424         sc->intc_bsh = rman_get_bushandle(sc->intc_res);
  425 
  426         bcm_intc_sc = sc;
  427 
  428         return (0);
  429 }
  430 
  431 static device_method_t bcm_intc_methods[] = {
  432         DEVMETHOD(device_probe,         bcm_intc_probe),
  433         DEVMETHOD(device_attach,        bcm_intc_attach),
  434 
  435         DEVMETHOD(pic_disable_intr,     bcm_intc_disable_intr),
  436         DEVMETHOD(pic_enable_intr,      bcm_intc_enable_intr),
  437         DEVMETHOD(pic_map_intr,         bcm_intc_map_intr),
  438         DEVMETHOD(pic_post_filter,      bcm_intc_post_filter),
  439         DEVMETHOD(pic_post_ithread,     bcm_intc_post_ithread),
  440         DEVMETHOD(pic_pre_ithread,      bcm_intc_pre_ithread),
  441         { 0, 0 }
  442 };
  443 
  444 static driver_t bcm_intc_driver = {
  445         "intc",
  446         bcm_intc_methods,
  447         sizeof(struct bcm_intc_softc),
  448 };
  449 
  450 EARLY_DRIVER_MODULE(intc, simplebus, bcm_intc_driver, 0, 0,
  451     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);

Cache object: cc620ffb7defc06b9248c3a85ddd4470


[ 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.