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/allwinner/aw_r_intc.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 (c) 2021 Emmanuel Vadot <manu@freebsd.org>
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD$");
   28 
   29 #include "opt_platform.h"
   30 
   31 #include <sys/param.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <machine/intr.h>
   36 
   37 #include <dev/ofw/openfirm.h>
   38 #include <dev/ofw/ofw_bus.h>
   39 #include <dev/ofw/ofw_bus_subr.h>
   40 
   41 #include "pic_if.h"
   42 
   43 struct aw_r_intc_gicp_softc {
   44         device_t                dev;
   45         device_t                parent;
   46         struct resource         *res;
   47 
   48         struct intr_map_data_fdt *parent_map_data;
   49 };
   50 
   51 static struct ofw_compat_data compat_data[] = {
   52         {"allwinner,sun6i-a31-r-intc",  1},
   53         {NULL,                          0}
   54 };
   55 
   56 static int
   57 aw_r_intc_gicp_probe(device_t dev)
   58 {
   59 
   60         if (!ofw_bus_status_okay(dev))
   61                 return (ENXIO);
   62 
   63         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
   64                 return (ENXIO);
   65 
   66         device_set_desc(dev, "Allwinner R INTC");
   67         return (BUS_PROBE_DEFAULT);
   68 }
   69 
   70 static int
   71 aw_r_intc_gicp_attach(device_t dev)
   72 {
   73         struct aw_r_intc_gicp_softc *sc;
   74         phandle_t node, xref, intr_parent;
   75 
   76         sc = device_get_softc(dev);
   77         sc->dev = dev;
   78         node = ofw_bus_get_node(dev);
   79 
   80         /* Look for our parent */
   81         if ((intr_parent = ofw_bus_find_iparent(node)) == 0) {
   82                 device_printf(dev,
   83                      "Cannot find our parent interrupt controller\n");
   84                 return (ENXIO);
   85         }
   86         if ((sc->parent = OF_device_from_xref(intr_parent)) == NULL) {
   87                 device_printf(dev,
   88                      "cannot find parent interrupt controller device\n");
   89                 return (ENXIO);
   90         }
   91 
   92         /* Register ourself as a interrupt controller */
   93         xref = OF_xref_from_node(node);
   94         if (intr_pic_register(dev, xref) == NULL) {
   95                 device_printf(dev, "Cannot register GICP\n");
   96                 return (ENXIO);
   97         }
   98 
   99         /* Allocate GIC compatible mapping */
  100         sc->parent_map_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
  101             INTR_MAP_DATA_FDT, sizeof(struct intr_map_data_fdt) +
  102             + 3 * sizeof(phandle_t), M_WAITOK | M_ZERO);
  103 
  104         /* Register ourself to device can find us */
  105         OF_device_register_xref(xref, dev);
  106 
  107         return (0);
  108 }
  109 
  110 static int
  111 aw_r_intc_gicp_detach(device_t dev)
  112 {
  113 
  114         return (EBUSY);
  115 }
  116 
  117 static struct intr_map_data *
  118 aw_r_intc_gicp_convert_map_data(struct aw_r_intc_gicp_softc *sc,
  119     struct intr_map_data *data)
  120 {
  121         struct intr_map_data_fdt *daf;
  122 
  123         daf = (struct intr_map_data_fdt *)data;
  124 
  125         /* We only support GIC forward for now */
  126         if (daf->ncells != 3)
  127                 return (NULL);
  128 
  129         /* Check if this is a GIC_SPI type */
  130         if (daf->cells[0] != 0)
  131                 return (NULL);
  132 
  133         sc->parent_map_data->ncells = 3;
  134         sc->parent_map_data->cells[0] = 0;
  135         sc->parent_map_data->cells[1] = daf->cells[1];
  136         sc->parent_map_data->cells[2] = daf->cells[2];
  137 
  138         return ((struct intr_map_data *)sc->parent_map_data);
  139 }
  140 
  141 static int
  142 aw_r_intc_gicp_activate_intr(device_t dev, struct intr_irqsrc *isrc,
  143     struct resource *res, struct intr_map_data *data)
  144 {
  145         struct aw_r_intc_gicp_softc *sc;
  146 
  147         sc = device_get_softc(dev);
  148         data = aw_r_intc_gicp_convert_map_data(sc, data);
  149         if (data == NULL)
  150                 return (EINVAL);
  151 
  152         return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
  153 }
  154 
  155 static void
  156 aw_r_intc_gicp_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  157 {
  158         struct aw_r_intc_gicp_softc *sc;
  159 
  160         sc = device_get_softc(dev);
  161 
  162         PIC_ENABLE_INTR(sc->parent, isrc);
  163 }
  164 
  165 static void
  166 aw_r_intc_gicp_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  167 {
  168         struct aw_r_intc_gicp_softc *sc;
  169 
  170         sc = device_get_softc(dev);
  171 
  172         PIC_DISABLE_INTR(sc->parent, isrc);
  173 }
  174 
  175 static int
  176 aw_r_intc_gicp_map_intr(device_t dev, struct intr_map_data *data,
  177     struct intr_irqsrc **isrcp)
  178 {
  179         struct aw_r_intc_gicp_softc *sc;
  180         int ret;
  181 
  182         sc = device_get_softc(dev);
  183 
  184         if (data->type != INTR_MAP_DATA_FDT)
  185                 return (ENOTSUP);
  186 
  187         data = aw_r_intc_gicp_convert_map_data(sc, data);
  188         if (data == NULL)
  189                 return (EINVAL);
  190 
  191         ret = PIC_MAP_INTR(sc->parent, data, isrcp);
  192         (*isrcp)->isrc_dev = sc->dev;
  193         return(ret);
  194 }
  195 
  196 static int
  197 aw_r_intc_gicp_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
  198     struct resource *res, struct intr_map_data *data)
  199 {
  200         struct aw_r_intc_gicp_softc *sc;
  201 
  202         sc = device_get_softc(dev);
  203 
  204         data = aw_r_intc_gicp_convert_map_data(sc, data);
  205         if (data == NULL)
  206                 return (EINVAL);
  207 
  208         return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
  209 }
  210 
  211 static int
  212 aw_r_intc_gicp_setup_intr(device_t dev, struct intr_irqsrc *isrc,
  213     struct resource *res, struct intr_map_data *data)
  214 {
  215         struct aw_r_intc_gicp_softc *sc;
  216 
  217         sc = device_get_softc(dev);
  218         data = aw_r_intc_gicp_convert_map_data(sc, data);
  219         if (data == NULL)
  220                 return (EINVAL);
  221 
  222         return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
  223 }
  224 
  225 static int
  226 aw_r_intc_gicp_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
  227     struct resource *res, struct intr_map_data *data)
  228 {
  229         struct aw_r_intc_gicp_softc *sc;
  230 
  231         sc = device_get_softc(dev);
  232         data = aw_r_intc_gicp_convert_map_data(sc, data);
  233         if (data == NULL)
  234                 return (EINVAL);
  235 
  236         return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
  237 }
  238 
  239 static void
  240 aw_r_intc_gicp_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  241 {
  242         struct aw_r_intc_gicp_softc *sc;
  243 
  244         sc = device_get_softc(dev);
  245 
  246         PIC_PRE_ITHREAD(sc->parent, isrc);
  247 }
  248 
  249 static void
  250 aw_r_intc_gicp_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  251 {
  252         struct aw_r_intc_gicp_softc *sc;
  253 
  254         sc = device_get_softc(dev);
  255 
  256         PIC_POST_ITHREAD(sc->parent, isrc);
  257 }
  258 
  259 static void
  260 aw_r_intc_gicp_post_filter(device_t dev, struct intr_irqsrc *isrc)
  261 {
  262         struct aw_r_intc_gicp_softc *sc;
  263 
  264         sc = device_get_softc(dev);
  265 
  266         PIC_POST_FILTER(sc->parent, isrc);
  267 }
  268 
  269 static device_method_t aw_r_intc_gicp_methods[] = {
  270         /* Device interface */
  271         DEVMETHOD(device_probe,         aw_r_intc_gicp_probe),
  272         DEVMETHOD(device_attach,        aw_r_intc_gicp_attach),
  273         DEVMETHOD(device_detach,        aw_r_intc_gicp_detach),
  274 
  275         /* Interrupt controller interface */
  276         DEVMETHOD(pic_activate_intr,    aw_r_intc_gicp_activate_intr),
  277         DEVMETHOD(pic_disable_intr,     aw_r_intc_gicp_disable_intr),
  278         DEVMETHOD(pic_enable_intr,      aw_r_intc_gicp_enable_intr),
  279         DEVMETHOD(pic_map_intr,         aw_r_intc_gicp_map_intr),
  280         DEVMETHOD(pic_deactivate_intr,  aw_r_intc_gicp_deactivate_intr),
  281         DEVMETHOD(pic_setup_intr,       aw_r_intc_gicp_setup_intr),
  282         DEVMETHOD(pic_teardown_intr,    aw_r_intc_gicp_teardown_intr),
  283         DEVMETHOD(pic_post_filter,      aw_r_intc_gicp_post_filter),
  284         DEVMETHOD(pic_post_ithread,     aw_r_intc_gicp_post_ithread),
  285         DEVMETHOD(pic_pre_ithread,      aw_r_intc_gicp_pre_ithread),
  286 
  287         DEVMETHOD_END
  288 };
  289 
  290 static devclass_t aw_r_intc_gicp_devclass;
  291 
  292 static driver_t aw_r_intc_gicp_driver = {
  293         "aw_r_intc_gicp",
  294         aw_r_intc_gicp_methods,
  295         sizeof(struct aw_r_intc_gicp_softc),
  296 };
  297 
  298 EARLY_DRIVER_MODULE(aw_r_intc_gicp, simplebus, aw_r_intc_gicp_driver,
  299     aw_r_intc_gicp_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);

Cache object: 84bd137c96edd3aa051ddc49e40adbcd


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