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/ti/aintc.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_REVISION           0x00
   54 #define INTC_SYSCONFIG          0x10
   55 #define INTC_SYSSTATUS          0x14
   56 #define INTC_SIR_IRQ            0x40
   57 #define INTC_CONTROL            0x48
   58 #define INTC_THRESHOLD          0x68
   59 #define INTC_MIR_CLEAR(x)       (0x88 + ((x) * 0x20))
   60 #define INTC_MIR_SET(x)         (0x8C + ((x) * 0x20))
   61 #define INTC_ISR_SET(x)         (0x90 + ((x) * 0x20))
   62 #define INTC_ISR_CLEAR(x)       (0x94 + ((x) * 0x20))
   63 
   64 #define INTC_SIR_SPURIOUS_MASK  0xffffff80
   65 #define INTC_SIR_ACTIVE_MASK    0x7f
   66 
   67 #define INTC_NIRQS      128
   68 
   69 struct ti_aintc_irqsrc {
   70         struct intr_irqsrc      tai_isrc;
   71         u_int                   tai_irq;
   72 };
   73 
   74 struct ti_aintc_softc {
   75         device_t                sc_dev;
   76         struct resource *       aintc_res[3];
   77         bus_space_tag_t         aintc_bst;
   78         bus_space_handle_t      aintc_bsh;
   79         uint8_t                 ver;
   80         struct ti_aintc_irqsrc  aintc_isrcs[INTC_NIRQS];
   81 };
   82 
   83 static struct resource_spec ti_aintc_spec[] = {
   84         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
   85         { -1, 0 }
   86 };
   87 
   88 #define aintc_read_4(_sc, reg)          \
   89     bus_space_read_4((_sc)->aintc_bst, (_sc)->aintc_bsh, (reg))
   90 #define aintc_write_4(_sc, reg, val)            \
   91     bus_space_write_4((_sc)->aintc_bst, (_sc)->aintc_bsh, (reg), (val))
   92 
   93 /* List of compatible strings for FDT tree */
   94 static struct ofw_compat_data compat_data[] = {
   95         {"ti,am33xx-intc",      1},
   96         {"ti,omap2-intc",       1},
   97         {NULL,                  0},
   98 };
   99 
  100 static inline void
  101 ti_aintc_irq_eoi(struct ti_aintc_softc *sc)
  102 {
  103 
  104         aintc_write_4(sc, INTC_CONTROL, 1);
  105 }
  106 
  107 static inline void
  108 ti_aintc_irq_mask(struct ti_aintc_softc *sc, u_int irq)
  109 {
  110 
  111         aintc_write_4(sc, INTC_MIR_SET(irq >> 5), (1UL << (irq & 0x1F)));
  112 }
  113 
  114 static inline void
  115 ti_aintc_irq_unmask(struct ti_aintc_softc *sc, u_int irq)
  116 {
  117 
  118         aintc_write_4(sc, INTC_MIR_CLEAR(irq >> 5), (1UL << (irq & 0x1F)));
  119 }
  120 
  121 static int
  122 ti_aintc_intr(void *arg)
  123 {
  124         uint32_t irq;
  125         struct ti_aintc_softc *sc = arg;
  126 
  127         /* Get active interrupt */
  128         irq = aintc_read_4(sc, INTC_SIR_IRQ);
  129         if ((irq & INTC_SIR_SPURIOUS_MASK) != 0) {
  130                 device_printf(sc->sc_dev,
  131                     "Spurious interrupt detected (0x%08x)\n", irq);
  132                 ti_aintc_irq_eoi(sc);
  133                 return (FILTER_HANDLED);
  134         }
  135 
  136         /* Only level-sensitive interrupts detection is supported. */
  137         irq &= INTC_SIR_ACTIVE_MASK;
  138         if (intr_isrc_dispatch(&sc->aintc_isrcs[irq].tai_isrc,
  139             curthread->td_intr_frame) != 0) {
  140                 ti_aintc_irq_mask(sc, irq);
  141                 ti_aintc_irq_eoi(sc);
  142                 device_printf(sc->sc_dev, "Stray irq %u disabled\n", irq);
  143         }
  144 
  145         arm_irq_memory_barrier(irq); /* XXX */
  146         return (FILTER_HANDLED);
  147 }
  148 
  149 static void
  150 ti_aintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  151 {
  152         u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
  153         struct ti_aintc_softc *sc = device_get_softc(dev);
  154 
  155         arm_irq_memory_barrier(irq);
  156         ti_aintc_irq_unmask(sc, irq);
  157 }
  158 
  159 static void
  160 ti_aintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  161 {
  162         u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
  163         struct ti_aintc_softc *sc = device_get_softc(dev);
  164 
  165         ti_aintc_irq_mask(sc, irq);
  166 }
  167 
  168 static int
  169 ti_aintc_map_intr(device_t dev, struct intr_map_data *data,
  170     struct intr_irqsrc **isrcp)
  171 {
  172         struct intr_map_data_fdt *daf;
  173         struct ti_aintc_softc *sc;
  174 
  175         if (data->type != INTR_MAP_DATA_FDT)
  176                 return (ENOTSUP);
  177 
  178         daf = (struct intr_map_data_fdt *)data;
  179         if (daf->ncells != 1 || daf->cells[0] >= INTC_NIRQS)
  180                 return (EINVAL);
  181 
  182         sc = device_get_softc(dev);
  183         *isrcp = &sc->aintc_isrcs[daf->cells[0]].tai_isrc;
  184         return (0);
  185 }
  186 
  187 static void
  188 ti_aintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  189 {
  190         u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
  191         struct ti_aintc_softc *sc = device_get_softc(dev);
  192 
  193         ti_aintc_irq_mask(sc, irq);
  194         ti_aintc_irq_eoi(sc);
  195 }
  196 
  197 static void
  198 ti_aintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  199 {
  200 
  201         ti_aintc_enable_intr(dev, isrc);
  202 }
  203 
  204 static void
  205 ti_aintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
  206 {
  207 
  208         ti_aintc_irq_eoi(device_get_softc(dev));
  209 }
  210 
  211 static int
  212 ti_aintc_pic_attach(struct ti_aintc_softc *sc)
  213 {
  214         struct intr_pic *pic;
  215         int error;
  216         uint32_t irq;
  217         const char *name;
  218         intptr_t xref;
  219 
  220         name = device_get_nameunit(sc->sc_dev);
  221         for (irq = 0; irq < INTC_NIRQS; irq++) {
  222                 sc->aintc_isrcs[irq].tai_irq = irq;
  223 
  224                 error = intr_isrc_register(&sc->aintc_isrcs[irq].tai_isrc,
  225                     sc->sc_dev, 0, "%s,%u", name, irq);
  226                 if (error != 0)
  227                         return (error);
  228         }
  229 
  230         xref = OF_xref_from_node(ofw_bus_get_node(sc->sc_dev));
  231         pic = intr_pic_register(sc->sc_dev, xref);
  232         if (pic == NULL)
  233                 return (ENXIO);
  234 
  235         return (intr_pic_claim_root(sc->sc_dev, xref, ti_aintc_intr, sc, 0));
  236 }
  237 
  238 static int
  239 ti_aintc_probe(device_t dev)
  240 {
  241         if (!ofw_bus_status_okay(dev))
  242                 return (ENXIO);
  243 
  244         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  245                 return (ENXIO);
  246 
  247         device_set_desc(dev, "TI AINTC Interrupt Controller");
  248         return (BUS_PROBE_DEFAULT);
  249 }
  250 
  251 static int
  252 ti_aintc_attach(device_t dev)
  253 {
  254         struct          ti_aintc_softc *sc = device_get_softc(dev);
  255         uint32_t x;
  256 
  257         sc->sc_dev = dev;
  258 
  259         if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) {
  260                 device_printf(dev, "could not allocate resources\n");
  261                 return (ENXIO);
  262         }
  263 
  264         sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]);
  265         sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]);
  266 
  267         x = aintc_read_4(sc, INTC_REVISION);
  268         device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF);
  269 
  270         /* SoftReset */
  271         aintc_write_4(sc, INTC_SYSCONFIG, 2);
  272 
  273         /* Wait for reset to complete */
  274         while(!(aintc_read_4(sc, INTC_SYSSTATUS) & 1));
  275 
  276         /*Set Priority Threshold */
  277         aintc_write_4(sc, INTC_THRESHOLD, 0xFF);
  278 
  279         if (ti_aintc_pic_attach(sc) != 0) {
  280                 device_printf(dev, "could not attach PIC\n");
  281                 return (ENXIO);
  282         }
  283         return (0);
  284 }
  285 
  286 static device_method_t ti_aintc_methods[] = {
  287         DEVMETHOD(device_probe,         ti_aintc_probe),
  288         DEVMETHOD(device_attach,        ti_aintc_attach),
  289 
  290         DEVMETHOD(pic_disable_intr,     ti_aintc_disable_intr),
  291         DEVMETHOD(pic_enable_intr,      ti_aintc_enable_intr),
  292         DEVMETHOD(pic_map_intr,         ti_aintc_map_intr),
  293         DEVMETHOD(pic_post_filter,      ti_aintc_post_filter),
  294         DEVMETHOD(pic_post_ithread,     ti_aintc_post_ithread),
  295         DEVMETHOD(pic_pre_ithread,      ti_aintc_pre_ithread),
  296         { 0, 0 }
  297 };
  298 
  299 static driver_t ti_aintc_driver = {
  300         "ti_aintc",
  301         ti_aintc_methods,
  302         sizeof(struct ti_aintc_softc),
  303 };
  304 
  305 static devclass_t ti_aintc_devclass;
  306 
  307 EARLY_DRIVER_MODULE(ti_aintc, simplebus, ti_aintc_driver, ti_aintc_devclass,
  308     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
  309 SIMPLEBUS_PNP_INFO(compat_data);

Cache object: 7c6aa629ceecf9ad07cff08a30035daf


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