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/arm64/qoriq/qoriq_gpio_pic.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) 2021 Alstom Group.
    5  * Copyright (c) 2021 Semihalf.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   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 ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/conf.h>
   34 #include <sys/bus.h>
   35 #include <sys/kernel.h>
   36 #include <sys/module.h>
   37 #include <sys/mutex.h>
   38 #include <sys/proc.h>
   39 #include <sys/rman.h>
   40 #include <sys/gpio.h>
   41 
   42 #include <machine/bus.h>
   43 #include <machine/resource.h>
   44 #include <machine/stdarg.h>
   45 
   46 #include <dev/gpio/gpiobusvar.h>
   47 #include <dev/gpio/qoriq_gpio.h>
   48 #include <dev/ofw/ofw_bus.h>
   49 #include <dev/ofw/ofw_bus_subr.h>
   50 
   51 #include <dt-bindings/interrupt-controller/irq.h>
   52 
   53 #include "gpio_if.h"
   54 #include "pic_if.h"
   55 
   56 struct qoriq_gpio_pic_irqsrc {
   57         struct intr_irqsrc isrc;
   58         int pin;
   59 };
   60 
   61 struct qoriq_gpio_pic_softc {
   62         struct qoriq_gpio_softc base;
   63 
   64         struct resource *res_irq;
   65         void *irq_cookie;
   66         struct qoriq_gpio_pic_irqsrc isrcs[MAXPIN + 1];
   67         struct intr_map_data_gpio gdata;
   68 };
   69 
   70 #define RD4(sc, off) bus_read_4((sc)->base.sc_mem, (off))
   71 #define WR4(sc, off, data) bus_write_4((sc)->base.sc_mem, (off), (data))
   72 
   73 static device_probe_t qoriq_gpio_pic_probe;
   74 static device_attach_t qoriq_gpio_pic_attach;
   75 static device_detach_t qoriq_gpio_pic_detach;
   76 
   77 static void
   78 qoriq_gpio_pic_set_intr(struct qoriq_gpio_pic_softc *sc, int pin, bool enable)
   79 {
   80         uint32_t reg;
   81 
   82         reg = RD4(sc, GPIO_GPIMR);
   83         if (enable)
   84                 reg |= BIT(31 - pin);
   85         else
   86                 reg &= ~BIT(31 - pin);
   87         WR4(sc, GPIO_GPIMR, reg);
   88 }
   89 
   90 static void
   91 qoriq_gpio_pic_ack_intr(struct qoriq_gpio_pic_softc *sc, int pin)
   92 {
   93         uint32_t reg;
   94 
   95         reg = BIT(31 - pin);
   96         WR4(sc, GPIO_GPIER, reg);
   97 }
   98 
   99 static int
  100 qoriq_gpio_pic_intr(void *arg)
  101 {
  102         struct qoriq_gpio_pic_softc *sc;
  103         struct trapframe *tf;
  104         uint32_t status;
  105         int pin;
  106 
  107         sc = (struct qoriq_gpio_pic_softc *)arg;
  108         tf = curthread->td_intr_frame;
  109 
  110         status = RD4(sc, GPIO_GPIER);
  111         status &= RD4(sc, GPIO_GPIMR);
  112         while (status != 0) {
  113                 pin = ffs(status) - 1;
  114                 status &= ~BIT(pin);
  115                 pin = 31 - pin;
  116 
  117                 if (intr_isrc_dispatch(&sc->isrcs[pin].isrc, tf) != 0) {
  118                         GPIO_LOCK(&sc->base);
  119                         qoriq_gpio_pic_set_intr(sc, pin, false);
  120                         qoriq_gpio_pic_ack_intr(sc, pin);
  121                         GPIO_UNLOCK(&sc->base);
  122                         device_printf(sc->base.dev,
  123                             "Masking spurious pin interrupt %d\n",
  124                             pin);
  125                 }
  126         }
  127 
  128         return (FILTER_HANDLED);
  129 }
  130 
  131 static void
  132 qoriq_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  133 {
  134         struct qoriq_gpio_pic_softc *sc;
  135         struct qoriq_gpio_pic_irqsrc *qisrc;
  136 
  137         sc = device_get_softc(dev);
  138         qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
  139 
  140         GPIO_LOCK(&sc->base);
  141         qoriq_gpio_pic_set_intr(sc, qisrc->pin, false);
  142         GPIO_UNLOCK(&sc->base);
  143 }
  144 
  145 static void
  146 qoriq_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  147 {
  148         struct qoriq_gpio_pic_softc *sc;
  149         struct qoriq_gpio_pic_irqsrc *qisrc;
  150 
  151         sc = device_get_softc(dev);
  152         qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
  153 
  154         GPIO_LOCK(&sc->base);
  155         qoriq_gpio_pic_set_intr(sc, qisrc->pin, true);
  156         GPIO_UNLOCK(&sc->base);
  157 }
  158 
  159 static struct intr_map_data_gpio*
  160 qoriq_gpio_pic_convert_map_data(struct qoriq_gpio_pic_softc *sc, struct intr_map_data *data)
  161 {
  162         struct intr_map_data_gpio *gdata;
  163         struct intr_map_data_fdt *daf;
  164 
  165         switch (data->type) {
  166         case INTR_MAP_DATA_GPIO:
  167                 gdata = (struct intr_map_data_gpio *)data;
  168                 break;
  169         case INTR_MAP_DATA_FDT:
  170                 daf = (struct intr_map_data_fdt *)data;
  171                 if (daf->ncells != 2)
  172                         return (NULL);
  173 
  174                 gdata = &sc->gdata;
  175                 gdata->gpio_pin_num = daf->cells[0];
  176                 switch (daf->cells[1]) {
  177                 case IRQ_TYPE_LEVEL_LOW:
  178                         gdata->gpio_intr_mode = GPIO_INTR_LEVEL_LOW;
  179                         break;
  180                 case IRQ_TYPE_LEVEL_HIGH:
  181                         gdata->gpio_intr_mode = GPIO_INTR_LEVEL_HIGH;
  182                         break;
  183                 case IRQ_TYPE_EDGE_RISING:
  184                         gdata->gpio_intr_mode = GPIO_INTR_EDGE_RISING;
  185                         break;
  186                 case IRQ_TYPE_EDGE_FALLING:
  187                         gdata->gpio_intr_mode = GPIO_INTR_EDGE_FALLING;
  188                         break;
  189                 case IRQ_TYPE_EDGE_BOTH:
  190                         gdata->gpio_intr_mode = GPIO_INTR_EDGE_BOTH;
  191                         break;
  192                 default:
  193                         return (NULL);
  194                 }
  195                 break;
  196         default:
  197                 return (NULL);
  198         }
  199 
  200         return (gdata);
  201 }
  202 
  203 
  204 static int
  205 qoriq_gpio_pic_map_intr(device_t dev, struct intr_map_data *data,
  206     struct intr_irqsrc **isrcp)
  207 {
  208         struct qoriq_gpio_pic_softc *sc;
  209         struct intr_map_data_gpio *gdata;
  210         int pin;
  211 
  212         sc = device_get_softc(dev);
  213 
  214         gdata = qoriq_gpio_pic_convert_map_data(sc, data);
  215         if (gdata == NULL)
  216                 return (EINVAL);
  217 
  218         pin = gdata->gpio_pin_num;
  219         if (pin > MAXPIN)
  220                 return (EINVAL);
  221 
  222         *isrcp = &sc->isrcs[pin].isrc;
  223         return (0);
  224 }
  225 
  226 static int
  227 qoriq_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
  228     struct resource *res, struct intr_map_data *data)
  229 {
  230         struct qoriq_gpio_pic_softc *sc;
  231         struct intr_map_data_gpio *gdata;
  232         struct qoriq_gpio_pic_irqsrc *qisrc;
  233         bool falling;
  234         uint32_t reg;
  235 
  236         sc = device_get_softc(dev);
  237         qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
  238 
  239         gdata = qoriq_gpio_pic_convert_map_data(sc, data);
  240         if (gdata == NULL)
  241                 return (EINVAL);
  242 
  243         if (gdata->gpio_intr_mode & GPIO_INTR_EDGE_BOTH)
  244                 falling = false;
  245         else if (gdata->gpio_intr_mode & GPIO_INTR_EDGE_FALLING)
  246                 falling = true;
  247         else
  248                 return (EOPNOTSUPP);
  249 
  250         GPIO_LOCK(&sc->base);
  251         reg = RD4(sc, GPIO_GPICR);
  252         if (falling)
  253                 reg |= BIT(31 - qisrc->pin);
  254         else
  255                 reg &= ~BIT(31 - qisrc->pin);
  256         WR4(sc, GPIO_GPICR, reg);
  257         GPIO_UNLOCK(&sc->base);
  258 
  259         return (0);
  260 }
  261 
  262 static int
  263 qoriq_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
  264     struct resource *res, struct intr_map_data *data)
  265 {
  266         struct qoriq_gpio_pic_softc *sc;
  267         struct qoriq_gpio_pic_irqsrc *qisrc;
  268 
  269         sc = device_get_softc(dev);
  270         qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
  271 
  272         if (isrc->isrc_handlers > 0)
  273                 return (0);
  274 
  275         GPIO_LOCK(&sc->base);
  276         qoriq_gpio_pic_set_intr(sc, qisrc->pin, false);
  277         GPIO_UNLOCK(&sc->base);
  278         return (0);
  279 }
  280 
  281 static void
  282 qoriq_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
  283 {
  284         struct qoriq_gpio_pic_softc *sc;
  285         struct qoriq_gpio_pic_irqsrc *qisrc;
  286 
  287         sc = device_get_softc(dev);
  288         qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
  289 
  290         GPIO_LOCK(&sc->base);
  291         qoriq_gpio_pic_ack_intr(sc, qisrc->pin);
  292         GPIO_UNLOCK(&sc->base);
  293 }
  294 
  295 
  296 static void
  297 qoriq_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  298 {
  299         struct qoriq_gpio_pic_softc *sc;
  300         struct qoriq_gpio_pic_irqsrc *qisrc;
  301 
  302         sc = device_get_softc(dev);
  303         qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
  304 
  305         GPIO_LOCK(&sc->base);
  306         qoriq_gpio_pic_ack_intr(sc, qisrc->pin);
  307         qoriq_gpio_pic_set_intr(sc, qisrc->pin, true);
  308         GPIO_UNLOCK(&sc->base);
  309 }
  310 
  311 static void
  312 qoriq_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  313 {
  314         struct qoriq_gpio_pic_softc *sc;
  315         struct qoriq_gpio_pic_irqsrc *qisrc;
  316 
  317         sc = device_get_softc(dev);
  318         qisrc = (struct qoriq_gpio_pic_irqsrc *)isrc;
  319 
  320         GPIO_LOCK(&sc->base);
  321         qoriq_gpio_pic_set_intr(sc, qisrc->pin, false);
  322         GPIO_UNLOCK(&sc->base);
  323 
  324 }
  325 static int
  326 qoriq_gpio_pic_probe(device_t dev)
  327 {
  328         if (!ofw_bus_status_okay(dev))
  329                 return (ENXIO);
  330 
  331         if (!ofw_bus_is_compatible(dev, "fsl,qoriq-gpio"))
  332                 return (ENXIO);
  333 
  334         device_set_desc(dev, "Freescale QorIQ GPIO PIC driver");
  335 
  336         return (BUS_PROBE_DEFAULT);
  337 }
  338 
  339 static int
  340 qoriq_gpio_pic_attach(device_t dev)
  341 {
  342         struct qoriq_gpio_pic_softc *sc;
  343         int error, rid, i;
  344         const char *name;
  345         intptr_t xref;
  346 
  347         sc = device_get_softc(dev);
  348 
  349         error = qoriq_gpio_attach(dev);
  350         if (error != 0)
  351                 return (error);
  352 
  353         rid = 0;
  354         sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  355             RF_ACTIVE | RF_SHAREABLE);
  356         if (sc->res_irq == NULL) {
  357                 device_printf(dev, "Can't allocate interrupt resource.\n");
  358                 error = ENOMEM;
  359                 goto fail;
  360         }
  361 
  362         error = bus_setup_intr(dev, sc->res_irq, INTR_TYPE_MISC | INTR_MPSAFE,
  363             qoriq_gpio_pic_intr, NULL, sc, &sc->irq_cookie);
  364         if (error != 0) {
  365                 device_printf(dev, "Failed to setup interrupt.\n");
  366                 goto fail;
  367         }
  368 
  369         name = device_get_nameunit(dev);
  370         for (i = 0; i <= MAXPIN; i++) {
  371                 sc->isrcs[i].pin = i;
  372                 error = intr_isrc_register(&sc->isrcs[i].isrc,
  373                     dev, 0, "%s,%u", name, i);
  374                 if (error != 0)
  375                         goto fail;
  376         }
  377 
  378         xref = OF_xref_from_node(ofw_bus_get_node(dev));
  379         if (intr_pic_register(dev, xref) == NULL) {
  380                 error = ENXIO;
  381                 goto fail;
  382         }
  383 
  384         /* ACK and mask all interrupts. */
  385         WR4(sc, GPIO_GPIER, 0xffffffff);
  386         WR4(sc, GPIO_GPIMR, 0);
  387 
  388         return (0);
  389 fail:
  390         qoriq_gpio_pic_detach(dev);
  391         return (error);
  392 }
  393 
  394 static int
  395 qoriq_gpio_pic_detach(device_t dev)
  396 {
  397         struct qoriq_gpio_pic_softc *sc;
  398 
  399         sc = device_get_softc(dev);
  400 
  401         if (sc->irq_cookie != NULL)
  402                 bus_teardown_intr(dev, sc->res_irq, sc->irq_cookie);
  403 
  404         if (sc->res_irq != NULL)
  405                 bus_release_resource(dev, SYS_RES_IRQ,
  406                     rman_get_rid(sc->res_irq), sc->res_irq);
  407 
  408         return (qoriq_gpio_detach(dev));
  409 }
  410 
  411 
  412 static device_method_t qoriq_gpio_pic_methods[] = {
  413         DEVMETHOD(device_probe,         qoriq_gpio_pic_probe),
  414         DEVMETHOD(device_attach,        qoriq_gpio_pic_attach),
  415         DEVMETHOD(device_detach,        qoriq_gpio_pic_detach),
  416 
  417         DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
  418         DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
  419         DEVMETHOD(bus_deactivate_resource,      bus_generic_deactivate_resource),
  420 
  421         DEVMETHOD(pic_disable_intr,     qoriq_gpio_pic_disable_intr),
  422         DEVMETHOD(pic_enable_intr,      qoriq_gpio_pic_enable_intr),
  423         DEVMETHOD(pic_map_intr,         qoriq_gpio_pic_map_intr),
  424         DEVMETHOD(pic_setup_intr,       qoriq_gpio_pic_setup_intr),
  425         DEVMETHOD(pic_teardown_intr,    qoriq_gpio_pic_teardown_intr),
  426         DEVMETHOD(pic_post_filter,      qoriq_gpio_pic_post_filter),
  427         DEVMETHOD(pic_post_ithread,     qoriq_gpio_pic_post_ithread),
  428         DEVMETHOD(pic_pre_ithread,      qoriq_gpio_pic_pre_ithread),
  429 
  430         DEVMETHOD_END
  431 };
  432 
  433 DEFINE_CLASS_1(gpio, qoriq_gpio_pic_driver, qoriq_gpio_pic_methods,
  434     sizeof(struct qoriq_gpio_pic_softc), qoriq_gpio_driver);
  435 EARLY_DRIVER_MODULE(qoriq_gpio_pic, simplebus, qoriq_gpio_pic_driver, NULL, NULL,
  436     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);

Cache object: b77300db183892f27f44c5140073a17c


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