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/mips/cavium/octeon_gpio.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) 2011, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * GPIO driver for Cavium Octeon 
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/11.1/sys/mips/cavium/octeon_gpio.c 277996 2015-01-31 19:32:14Z loos $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 
   39 #include <sys/kernel.h>
   40 #include <sys/module.h>
   41 #include <sys/rman.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 #include <sys/gpio.h>
   45 
   46 #include <machine/bus.h>
   47 #include <machine/resource.h>
   48 
   49 #include <contrib/octeon-sdk/cvmx.h>
   50 #include <contrib/octeon-sdk/cvmx-gpio.h>
   51 #include <mips/cavium/octeon_irq.h>
   52 
   53 #include <mips/cavium/octeon_gpiovar.h>
   54 #include <dev/gpio/gpiobusvar.h>
   55 
   56 #include "gpio_if.h"
   57 
   58 #define DEFAULT_CAPS    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
   59 
   60 struct octeon_gpio_pin {
   61         const char *name;
   62         int pin;
   63         int flags;
   64 };
   65 
   66 /*
   67  * on CAP100 GPIO 7 is "Factory defaults" button
   68  *
   69  */
   70 static struct octeon_gpio_pin octeon_gpio_pins[] = {
   71         { "F/D", 7,  GPIO_PIN_INPUT},
   72         { NULL, 0, 0},
   73 };
   74 
   75 /*
   76  * Helpers
   77  */
   78 static void octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, 
   79     struct gpio_pin *pin, uint32_t flags);
   80 
   81 /*
   82  * Driver stuff
   83  */
   84 static void octeon_gpio_identify(driver_t *, device_t);
   85 static int octeon_gpio_probe(device_t dev);
   86 static int octeon_gpio_attach(device_t dev);
   87 static int octeon_gpio_detach(device_t dev);
   88 static int octeon_gpio_filter(void *arg);
   89 static void octeon_gpio_intr(void *arg);
   90 
   91 /*
   92  * GPIO interface
   93  */
   94 static device_t octeon_gpio_get_bus(device_t);
   95 static int octeon_gpio_pin_max(device_t dev, int *maxpin);
   96 static int octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
   97 static int octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
   98     *flags);
   99 static int octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
  100 static int octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
  101 static int octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
  102 static int octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
  103 static int octeon_gpio_pin_toggle(device_t dev, uint32_t pin);
  104 
  105 static void
  106 octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, struct gpio_pin *pin,
  107     unsigned int flags)
  108 {
  109         uint32_t mask;
  110         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  111 
  112         mask = 1 << pin->gp_pin;
  113         GPIO_LOCK(sc);
  114 
  115         /*
  116          * Manage input/output
  117          */
  118         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
  119                 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin));
  120                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
  121                 if (flags & GPIO_PIN_OUTPUT) {
  122                         pin->gp_flags |= GPIO_PIN_OUTPUT;
  123                         gpio_cfgx.s.tx_oe = 1;
  124                 }
  125                 else {
  126                         pin->gp_flags |= GPIO_PIN_INPUT;
  127                         gpio_cfgx.s.tx_oe = 0;
  128                 }
  129                 if (flags & GPIO_PIN_INVIN)
  130                         gpio_cfgx.s.rx_xor = 1;
  131                 else
  132                         gpio_cfgx.s.rx_xor = 0;
  133                 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin), gpio_cfgx.u64);
  134         }
  135 
  136         GPIO_UNLOCK(sc);
  137 }
  138 
  139 static device_t
  140 octeon_gpio_get_bus(device_t dev)
  141 {
  142         struct octeon_gpio_softc *sc;
  143 
  144         sc = device_get_softc(dev);
  145 
  146         return (sc->busdev);
  147 }
  148 
  149 static int
  150 octeon_gpio_pin_max(device_t dev, int *maxpin)
  151 {
  152 
  153         *maxpin = OCTEON_GPIO_PINS - 1;
  154         return (0);
  155 }
  156 
  157 static int
  158 octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  159 {
  160         struct octeon_gpio_softc *sc = device_get_softc(dev);
  161         int i;
  162 
  163         for (i = 0; i < sc->gpio_npins; i++) {
  164                 if (sc->gpio_pins[i].gp_pin == pin)
  165                         break;
  166         }
  167 
  168         if (i >= sc->gpio_npins)
  169                 return (EINVAL);
  170 
  171         GPIO_LOCK(sc);
  172         *caps = sc->gpio_pins[i].gp_caps;
  173         GPIO_UNLOCK(sc);
  174 
  175         return (0);
  176 }
  177 
  178 static int
  179 octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
  180 {
  181         struct octeon_gpio_softc *sc = device_get_softc(dev);
  182         int i;
  183 
  184         for (i = 0; i < sc->gpio_npins; i++) {
  185                 if (sc->gpio_pins[i].gp_pin == pin)
  186                         break;
  187         }
  188 
  189         if (i >= sc->gpio_npins)
  190                 return (EINVAL);
  191 
  192         GPIO_LOCK(sc);
  193         *flags = sc->gpio_pins[i].gp_flags;
  194         GPIO_UNLOCK(sc);
  195 
  196         return (0);
  197 }
  198 
  199 static int
  200 octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
  201 {
  202         struct octeon_gpio_softc *sc = device_get_softc(dev);
  203         int i;
  204 
  205         for (i = 0; i < sc->gpio_npins; i++) {
  206                 if (sc->gpio_pins[i].gp_pin == pin)
  207                         break;
  208         }
  209 
  210         if (i >= sc->gpio_npins)
  211                 return (EINVAL);
  212 
  213         GPIO_LOCK(sc);
  214         memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
  215         GPIO_UNLOCK(sc);
  216 
  217         return (0);
  218 }
  219 
  220 static int
  221 octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  222 {
  223         int i;
  224         struct octeon_gpio_softc *sc = device_get_softc(dev);
  225 
  226         for (i = 0; i < sc->gpio_npins; i++) {
  227                 if (sc->gpio_pins[i].gp_pin == pin)
  228                         break;
  229         }
  230 
  231         if (i >= sc->gpio_npins)
  232                 return (EINVAL);
  233 
  234         octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
  235 
  236         return (0);
  237 }
  238 
  239 static int
  240 octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
  241 {
  242         struct octeon_gpio_softc *sc = device_get_softc(dev);
  243         int i;
  244 
  245         for (i = 0; i < sc->gpio_npins; i++) {
  246                 if (sc->gpio_pins[i].gp_pin == pin)
  247                         break;
  248         }
  249 
  250         if (i >= sc->gpio_npins)
  251                 return (EINVAL);
  252 
  253         GPIO_LOCK(sc);
  254         if (value)
  255                 cvmx_gpio_set(1 << pin);
  256         else
  257                 cvmx_gpio_clear(1 << pin);
  258         GPIO_UNLOCK(sc);
  259 
  260         return (0);
  261 }
  262 
  263 static int
  264 octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
  265 {
  266         struct octeon_gpio_softc *sc = device_get_softc(dev);
  267         int i;
  268         uint64_t state;
  269 
  270         for (i = 0; i < sc->gpio_npins; i++) {
  271                 if (sc->gpio_pins[i].gp_pin == pin)
  272                         break;
  273         }
  274 
  275         if (i >= sc->gpio_npins)
  276                 return (EINVAL);
  277 
  278         GPIO_LOCK(sc);
  279         state = cvmx_gpio_read();
  280         *val = (state & (1 << pin)) ? 1 : 0;
  281         GPIO_UNLOCK(sc);
  282 
  283         return (0);
  284 }
  285 
  286 static int
  287 octeon_gpio_pin_toggle(device_t dev, uint32_t pin)
  288 {
  289         int i;
  290         uint64_t state;
  291         struct octeon_gpio_softc *sc = device_get_softc(dev);
  292 
  293         for (i = 0; i < sc->gpio_npins; i++) {
  294                 if (sc->gpio_pins[i].gp_pin == pin)
  295                         break;
  296         }
  297 
  298         if (i >= sc->gpio_npins)
  299                 return (EINVAL);
  300 
  301         GPIO_LOCK(sc);
  302         /*
  303          * XXX: Need to check if read returns actual state of output 
  304          * pins or we need to keep this information by ourself
  305          */
  306         state = cvmx_gpio_read();
  307         if (state & (1 << pin))
  308                 cvmx_gpio_clear(1 << pin);
  309         else
  310                 cvmx_gpio_set(1 << pin);
  311         GPIO_UNLOCK(sc);
  312 
  313         return (0);
  314 }
  315 
  316 static int
  317 octeon_gpio_filter(void *arg)
  318 {
  319         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  320         void **cookie = arg;
  321         struct octeon_gpio_softc *sc = *cookie;
  322         long int irq = (cookie - sc->gpio_intr_cookies);
  323         
  324         if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS))
  325                 return (FILTER_STRAY);
  326 
  327         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq));
  328         /* Clear rising edge detector */
  329         if (gpio_cfgx.s.int_type == OCTEON_GPIO_IRQ_EDGE)
  330                 cvmx_gpio_interrupt_clear(1 << irq);
  331         /* disable interrupt  */
  332         gpio_cfgx.s.int_en = 0;
  333         cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64);
  334 
  335         return (FILTER_SCHEDULE_THREAD);
  336 }
  337 
  338 static void
  339 octeon_gpio_intr(void *arg)
  340 {
  341         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  342         void **cookie = arg;
  343         struct octeon_gpio_softc *sc = *cookie;
  344         long int irq = (cookie - sc->gpio_intr_cookies);
  345 
  346         if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) {
  347                 printf("%s: invalid GPIO IRQ: %ld\n", 
  348                     __func__, irq);
  349                 return;
  350         }
  351 
  352         GPIO_LOCK(sc);
  353         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq));
  354         /* disable interrupt  */
  355         gpio_cfgx.s.int_en = 1;
  356         cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64);
  357 
  358         /* TODO: notify bus here or something */
  359         printf("GPIO IRQ for pin %ld\n", irq);
  360         GPIO_UNLOCK(sc);
  361 }
  362 
  363 static void
  364 octeon_gpio_identify(driver_t *drv, device_t parent)
  365 {
  366 
  367         BUS_ADD_CHILD(parent, 0, "gpio", 0);
  368 }
  369 
  370 static int
  371 octeon_gpio_probe(device_t dev)
  372 {
  373 
  374         device_set_desc(dev, "Cavium Octeon GPIO driver");
  375         return (0);
  376 }
  377 
  378 static int
  379 octeon_gpio_attach(device_t dev)
  380 {
  381         struct octeon_gpio_softc *sc = device_get_softc(dev);
  382         struct octeon_gpio_pin *pinp;
  383         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  384         
  385         int i;
  386 
  387         KASSERT((device_get_unit(dev) == 0),
  388             ("octeon_gpio: Only one gpio module supported"));
  389 
  390         mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  391 
  392         for ( i = 0; i < OCTEON_GPIO_IRQS; i++) {
  393                 if ((sc->gpio_irq_res[i] = bus_alloc_resource(dev, 
  394                     SYS_RES_IRQ, &sc->gpio_irq_rid[i], 
  395                     OCTEON_IRQ_GPIO0 + i, OCTEON_IRQ_GPIO0 + i, 1, 
  396                     RF_SHAREABLE | RF_ACTIVE)) == NULL) {
  397                         device_printf(dev, "unable to allocate IRQ resource\n");
  398                         octeon_gpio_detach(dev);
  399                         return (ENXIO);
  400                 }
  401 
  402                 sc->gpio_intr_cookies[i] = sc;
  403                 if ((bus_setup_intr(dev, sc->gpio_irq_res[i], INTR_TYPE_MISC, 
  404                     octeon_gpio_filter, octeon_gpio_intr, 
  405                     &(sc->gpio_intr_cookies[i]), &sc->gpio_ih[i]))) {
  406                         device_printf(dev,
  407                         "WARNING: unable to register interrupt handler\n");
  408                         octeon_gpio_detach(dev);
  409                         return (ENXIO);
  410                 }
  411         }
  412 
  413         sc->dev = dev;
  414         /* Configure all pins as input */
  415         /* disable interrupts for all pins */
  416         pinp = octeon_gpio_pins;
  417         i = 0;
  418         while (pinp->name) {
  419                 strncpy(sc->gpio_pins[i].gp_name, pinp->name, GPIOMAXNAME);
  420                 sc->gpio_pins[i].gp_pin = pinp->pin;
  421                 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
  422                 sc->gpio_pins[i].gp_flags = 0;
  423                 octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], pinp->flags);
  424                 pinp++;
  425                 i++;
  426         }
  427 
  428         sc->gpio_npins = i;
  429 
  430 #if 0
  431         /*
  432          * Sample: how to enable edge-triggered interrupt
  433          * for GPIO pin
  434          */
  435         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(7));
  436         gpio_cfgx.s.int_en = 1;
  437         gpio_cfgx.s.int_type = OCTEON_GPIO_IRQ_EDGE;
  438         cvmx_write_csr(CVMX_GPIO_BIT_CFGX(7), gpio_cfgx.u64);
  439 #endif
  440 
  441         if (bootverbose) {
  442                 for (i = 0; i < 16; i++) {
  443                         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(i));
  444                         device_printf(dev, "[pin%d] output=%d, invinput=%d, intr=%d, intr_type=%s\n", 
  445                             i, gpio_cfgx.s.tx_oe, gpio_cfgx.s.rx_xor, 
  446                             gpio_cfgx.s.int_en, gpio_cfgx.s.int_type ? "rising edge" : "level");
  447                 }
  448         }
  449         sc->busdev = gpiobus_attach_bus(dev);
  450         if (sc->busdev == NULL) {
  451                 octeon_gpio_detach(dev);
  452                 return (ENXIO);
  453         }
  454 
  455         return (0);
  456 }
  457 
  458 static int
  459 octeon_gpio_detach(device_t dev)
  460 {
  461         struct octeon_gpio_softc *sc = device_get_softc(dev);
  462         int i;
  463 
  464         KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized"));
  465 
  466         for ( i = 0; i < OCTEON_GPIO_IRQS; i++) {
  467                 if (sc->gpio_ih[i])
  468                         bus_teardown_intr(dev, sc->gpio_irq_res[i],
  469                             sc->gpio_ih[i]);
  470                 if (sc->gpio_irq_res[i])
  471                         bus_release_resource(dev, SYS_RES_IRQ,
  472                             sc->gpio_irq_rid[i], sc->gpio_irq_res[i]);
  473         }
  474         gpiobus_detach_bus(dev);
  475         mtx_destroy(&sc->gpio_mtx);
  476 
  477         return(0);
  478 }
  479 
  480 static device_method_t octeon_gpio_methods[] = {
  481         DEVMETHOD(device_identify, octeon_gpio_identify),
  482         DEVMETHOD(device_probe, octeon_gpio_probe),
  483         DEVMETHOD(device_attach, octeon_gpio_attach),
  484         DEVMETHOD(device_detach, octeon_gpio_detach),
  485 
  486         /* GPIO protocol */
  487         DEVMETHOD(gpio_get_bus, octeon_gpio_get_bus),
  488         DEVMETHOD(gpio_pin_max, octeon_gpio_pin_max),
  489         DEVMETHOD(gpio_pin_getname, octeon_gpio_pin_getname),
  490         DEVMETHOD(gpio_pin_getflags, octeon_gpio_pin_getflags),
  491         DEVMETHOD(gpio_pin_getcaps, octeon_gpio_pin_getcaps),
  492         DEVMETHOD(gpio_pin_setflags, octeon_gpio_pin_setflags),
  493         DEVMETHOD(gpio_pin_get, octeon_gpio_pin_get),
  494         DEVMETHOD(gpio_pin_set, octeon_gpio_pin_set),
  495         DEVMETHOD(gpio_pin_toggle, octeon_gpio_pin_toggle),
  496         {0, 0},
  497 };
  498 
  499 static driver_t octeon_gpio_driver = {
  500         "gpio",
  501         octeon_gpio_methods,
  502         sizeof(struct octeon_gpio_softc),
  503 };
  504 static devclass_t octeon_gpio_devclass;
  505 
  506 DRIVER_MODULE(octeon_gpio, ciu, octeon_gpio_driver, octeon_gpio_devclass, 0, 0);

Cache object: 5e9d77bb3fab6aa967e0c5c4eef7b5b5


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