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/10.1/sys/mips/cavium/octeon_gpio.c 249449 2013-04-13 21:21:13Z dim $");
   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 
   55 #include "gpio_if.h"
   56 
   57 #define DEFAULT_CAPS    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
   58 
   59 struct octeon_gpio_pin {
   60         const char *name;
   61         int pin;
   62         int flags;
   63 };
   64 
   65 /*
   66  * on CAP100 GPIO 7 is "Factory defaults" button
   67  *
   68  */
   69 static struct octeon_gpio_pin octeon_gpio_pins[] = {
   70         { "F/D", 7,  GPIO_PIN_INPUT},
   71         { NULL, 0, 0},
   72 };
   73 
   74 /*
   75  * Helpers
   76  */
   77 static void octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, 
   78     struct gpio_pin *pin, uint32_t flags);
   79 
   80 /*
   81  * Driver stuff
   82  */
   83 static void octeon_gpio_identify(driver_t *, device_t);
   84 static int octeon_gpio_probe(device_t dev);
   85 static int octeon_gpio_attach(device_t dev);
   86 static int octeon_gpio_detach(device_t dev);
   87 static int octeon_gpio_filter(void *arg);
   88 static void octeon_gpio_intr(void *arg);
   89 
   90 /*
   91  * GPIO interface
   92  */
   93 static int octeon_gpio_pin_max(device_t dev, int *maxpin);
   94 static int octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
   95 static int octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
   96     *flags);
   97 static int octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
   98 static int octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
   99 static int octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
  100 static int octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
  101 static int octeon_gpio_pin_toggle(device_t dev, uint32_t pin);
  102 
  103 static void
  104 octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, struct gpio_pin *pin,
  105     unsigned int flags)
  106 {
  107         uint32_t mask;
  108         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  109 
  110         mask = 1 << pin->gp_pin;
  111         GPIO_LOCK(sc);
  112 
  113         /*
  114          * Manage input/output
  115          */
  116         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
  117                 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin));
  118                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
  119                 if (flags & GPIO_PIN_OUTPUT) {
  120                         pin->gp_flags |= GPIO_PIN_OUTPUT;
  121                         gpio_cfgx.s.tx_oe = 1;
  122                 }
  123                 else {
  124                         pin->gp_flags |= GPIO_PIN_INPUT;
  125                         gpio_cfgx.s.tx_oe = 0;
  126                 }
  127                 if (flags & GPIO_PIN_INVIN)
  128                         gpio_cfgx.s.rx_xor = 1;
  129                 else
  130                         gpio_cfgx.s.rx_xor = 0;
  131                 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin), gpio_cfgx.u64);
  132         }
  133 
  134         GPIO_UNLOCK(sc);
  135 }
  136 
  137 static int
  138 octeon_gpio_pin_max(device_t dev, int *maxpin)
  139 {
  140 
  141         *maxpin = OCTEON_GPIO_PINS - 1;
  142         return (0);
  143 }
  144 
  145 static int
  146 octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  147 {
  148         struct octeon_gpio_softc *sc = device_get_softc(dev);
  149         int i;
  150 
  151         for (i = 0; i < sc->gpio_npins; i++) {
  152                 if (sc->gpio_pins[i].gp_pin == pin)
  153                         break;
  154         }
  155 
  156         if (i >= sc->gpio_npins)
  157                 return (EINVAL);
  158 
  159         GPIO_LOCK(sc);
  160         *caps = sc->gpio_pins[i].gp_caps;
  161         GPIO_UNLOCK(sc);
  162 
  163         return (0);
  164 }
  165 
  166 static int
  167 octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
  168 {
  169         struct octeon_gpio_softc *sc = device_get_softc(dev);
  170         int i;
  171 
  172         for (i = 0; i < sc->gpio_npins; i++) {
  173                 if (sc->gpio_pins[i].gp_pin == pin)
  174                         break;
  175         }
  176 
  177         if (i >= sc->gpio_npins)
  178                 return (EINVAL);
  179 
  180         GPIO_LOCK(sc);
  181         *flags = sc->gpio_pins[i].gp_flags;
  182         GPIO_UNLOCK(sc);
  183 
  184         return (0);
  185 }
  186 
  187 static int
  188 octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
  189 {
  190         struct octeon_gpio_softc *sc = device_get_softc(dev);
  191         int i;
  192 
  193         for (i = 0; i < sc->gpio_npins; i++) {
  194                 if (sc->gpio_pins[i].gp_pin == pin)
  195                         break;
  196         }
  197 
  198         if (i >= sc->gpio_npins)
  199                 return (EINVAL);
  200 
  201         GPIO_LOCK(sc);
  202         memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
  203         GPIO_UNLOCK(sc);
  204 
  205         return (0);
  206 }
  207 
  208 static int
  209 octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  210 {
  211         int i;
  212         struct octeon_gpio_softc *sc = device_get_softc(dev);
  213 
  214         for (i = 0; i < sc->gpio_npins; i++) {
  215                 if (sc->gpio_pins[i].gp_pin == pin)
  216                         break;
  217         }
  218 
  219         if (i >= sc->gpio_npins)
  220                 return (EINVAL);
  221 
  222         /* Check for unwanted flags. */
  223         if ((flags & sc->gpio_pins[i].gp_caps) != flags)
  224                 return (EINVAL);
  225 
  226         /* Can't mix input/output together */
  227         if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
  228             (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
  229                 return (EINVAL);
  230 
  231         octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
  232         return (0);
  233 }
  234 
  235 static int
  236 octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
  237 {
  238         struct octeon_gpio_softc *sc = device_get_softc(dev);
  239         int i;
  240 
  241         for (i = 0; i < sc->gpio_npins; i++) {
  242                 if (sc->gpio_pins[i].gp_pin == pin)
  243                         break;
  244         }
  245 
  246         if (i >= sc->gpio_npins)
  247                 return (EINVAL);
  248 
  249         GPIO_LOCK(sc);
  250         if (value)
  251                 cvmx_gpio_set(1 << pin);
  252         else
  253                 cvmx_gpio_clear(1 << pin);
  254         GPIO_UNLOCK(sc);
  255 
  256         return (0);
  257 }
  258 
  259 static int
  260 octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
  261 {
  262         struct octeon_gpio_softc *sc = device_get_softc(dev);
  263         int i;
  264         uint64_t state;
  265 
  266         for (i = 0; i < sc->gpio_npins; i++) {
  267                 if (sc->gpio_pins[i].gp_pin == pin)
  268                         break;
  269         }
  270 
  271         if (i >= sc->gpio_npins)
  272                 return (EINVAL);
  273 
  274         GPIO_LOCK(sc);
  275         state = cvmx_gpio_read();
  276         *val = (state & (1 << pin)) ? 1 : 0;
  277         GPIO_UNLOCK(sc);
  278 
  279         return (0);
  280 }
  281 
  282 static int
  283 octeon_gpio_pin_toggle(device_t dev, uint32_t pin)
  284 {
  285         int i;
  286         uint64_t state;
  287         struct octeon_gpio_softc *sc = device_get_softc(dev);
  288 
  289         for (i = 0; i < sc->gpio_npins; i++) {
  290                 if (sc->gpio_pins[i].gp_pin == pin)
  291                         break;
  292         }
  293 
  294         if (i >= sc->gpio_npins)
  295                 return (EINVAL);
  296 
  297         GPIO_LOCK(sc);
  298         /*
  299          * XXX: Need to check if read returns actual state of output 
  300          * pins or we need to keep this information by ourself
  301          */
  302         state = cvmx_gpio_read();
  303         if (state & (1 << pin))
  304                 cvmx_gpio_clear(1 << pin);
  305         else
  306                 cvmx_gpio_set(1 << pin);
  307         GPIO_UNLOCK(sc);
  308 
  309         return (0);
  310 }
  311 
  312 static int
  313 octeon_gpio_filter(void *arg)
  314 {
  315         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  316         void **cookie = arg;
  317         struct octeon_gpio_softc *sc = *cookie;
  318         long int irq = (cookie - sc->gpio_intr_cookies);
  319         
  320         if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS))
  321                 return (FILTER_STRAY);
  322 
  323         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq));
  324         /* Clear rising edge detector */
  325         if (gpio_cfgx.s.int_type == OCTEON_GPIO_IRQ_EDGE)
  326                 cvmx_gpio_interrupt_clear(1 << irq);
  327         /* disable interrupt  */
  328         gpio_cfgx.s.int_en = 0;
  329         cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64);
  330 
  331         return (FILTER_SCHEDULE_THREAD);
  332 }
  333 
  334 static void
  335 octeon_gpio_intr(void *arg)
  336 {
  337         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  338         void **cookie = arg;
  339         struct octeon_gpio_softc *sc = *cookie;
  340         long int irq = (cookie - sc->gpio_intr_cookies);
  341 
  342         if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) {
  343                 printf("%s: invalid GPIO IRQ: %ld\n", 
  344                     __func__, irq);
  345                 return;
  346         }
  347 
  348         GPIO_LOCK(sc);
  349         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq));
  350         /* disable interrupt  */
  351         gpio_cfgx.s.int_en = 1;
  352         cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64);
  353 
  354         /* TODO: notify bus here or something */
  355         printf("GPIO IRQ for pin %ld\n", irq);
  356         GPIO_UNLOCK(sc);
  357 }
  358 
  359 static void
  360 octeon_gpio_identify(driver_t *drv, device_t parent)
  361 {
  362 
  363         BUS_ADD_CHILD(parent, 0, "gpio", 0);
  364 }
  365 
  366 static int
  367 octeon_gpio_probe(device_t dev)
  368 {
  369 
  370         device_set_desc(dev, "Cavium Octeon GPIO driver");
  371         return (0);
  372 }
  373 
  374 static int
  375 octeon_gpio_attach(device_t dev)
  376 {
  377         struct octeon_gpio_softc *sc = device_get_softc(dev);
  378         struct octeon_gpio_pin *pinp;
  379         cvmx_gpio_bit_cfgx_t gpio_cfgx;
  380         
  381         int i;
  382 
  383         KASSERT((device_get_unit(dev) == 0),
  384             ("octeon_gpio: Only one gpio module supported"));
  385 
  386         mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  387 
  388         for ( i = 0; i < OCTEON_GPIO_IRQS; i++) {
  389                 if ((sc->gpio_irq_res[i] = bus_alloc_resource(dev, 
  390                     SYS_RES_IRQ, &sc->gpio_irq_rid[i], 
  391                     OCTEON_IRQ_GPIO0 + i, OCTEON_IRQ_GPIO0 + i, 1, 
  392                     RF_SHAREABLE | RF_ACTIVE)) == NULL) {
  393                         device_printf(dev, "unable to allocate IRQ resource\n");
  394                         return (ENXIO);
  395                 }
  396 
  397                 sc->gpio_intr_cookies[i] = sc;
  398                 if ((bus_setup_intr(dev, sc->gpio_irq_res[i], INTR_TYPE_MISC, 
  399                     octeon_gpio_filter, octeon_gpio_intr, 
  400                     &(sc->gpio_intr_cookies[i]), &sc->gpio_ih[i]))) {
  401                         device_printf(dev,
  402                         "WARNING: unable to register interrupt handler\n");
  403                         return (ENXIO);
  404                 }
  405         }
  406 
  407         sc->dev = dev;
  408         /* Configure all pins as input */
  409         /* disable interrupts for all pins */
  410         pinp = octeon_gpio_pins;
  411         i = 0;
  412         while (pinp->name) {
  413                 strncpy(sc->gpio_pins[i].gp_name, pinp->name, GPIOMAXNAME);
  414                 sc->gpio_pins[i].gp_pin = pinp->pin;
  415                 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
  416                 sc->gpio_pins[i].gp_flags = 0;
  417                 octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], pinp->flags);
  418                 pinp++;
  419                 i++;
  420         }
  421 
  422         sc->gpio_npins = i;
  423 
  424 #if 0
  425         /*
  426          * Sample: how to enable edge-triggered interrupt
  427          * for GPIO pin
  428          */
  429         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(7));
  430         gpio_cfgx.s.int_en = 1;
  431         gpio_cfgx.s.int_type = OCTEON_GPIO_IRQ_EDGE;
  432         cvmx_write_csr(CVMX_GPIO_BIT_CFGX(7), gpio_cfgx.u64);
  433 #endif
  434 
  435         if (bootverbose) {
  436                 for (i = 0; i < 16; i++) {
  437                         gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(i));
  438                         device_printf(dev, "[pin%d] output=%d, invinput=%d, intr=%d, intr_type=%s\n", 
  439                             i, gpio_cfgx.s.tx_oe, gpio_cfgx.s.rx_xor, 
  440                             gpio_cfgx.s.int_en, gpio_cfgx.s.int_type ? "rising edge" : "level");
  441                 }
  442         }
  443 
  444         device_add_child(dev, "gpioc", device_get_unit(dev));
  445         device_add_child(dev, "gpiobus", device_get_unit(dev));
  446         return (bus_generic_attach(dev));
  447 }
  448 
  449 static int
  450 octeon_gpio_detach(device_t dev)
  451 {
  452         struct octeon_gpio_softc *sc = device_get_softc(dev);
  453         int i;
  454 
  455         KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized"));
  456 
  457         for ( i = 0; i < OCTEON_GPIO_IRQS; i++) {
  458                 bus_release_resource(dev, SYS_RES_IRQ,
  459                     sc->gpio_irq_rid[i], sc->gpio_irq_res[i]);
  460         }
  461         bus_generic_detach(dev);
  462 
  463         mtx_destroy(&sc->gpio_mtx);
  464 
  465         return(0);
  466 }
  467 
  468 static device_method_t octeon_gpio_methods[] = {
  469         DEVMETHOD(device_identify, octeon_gpio_identify),
  470         DEVMETHOD(device_probe, octeon_gpio_probe),
  471         DEVMETHOD(device_attach, octeon_gpio_attach),
  472         DEVMETHOD(device_detach, octeon_gpio_detach),
  473 
  474         /* GPIO protocol */
  475         DEVMETHOD(gpio_pin_max, octeon_gpio_pin_max),
  476         DEVMETHOD(gpio_pin_getname, octeon_gpio_pin_getname),
  477         DEVMETHOD(gpio_pin_getflags, octeon_gpio_pin_getflags),
  478         DEVMETHOD(gpio_pin_getcaps, octeon_gpio_pin_getcaps),
  479         DEVMETHOD(gpio_pin_setflags, octeon_gpio_pin_setflags),
  480         DEVMETHOD(gpio_pin_get, octeon_gpio_pin_get),
  481         DEVMETHOD(gpio_pin_set, octeon_gpio_pin_set),
  482         DEVMETHOD(gpio_pin_toggle, octeon_gpio_pin_toggle),
  483         {0, 0},
  484 };
  485 
  486 static driver_t octeon_gpio_driver = {
  487         "gpio",
  488         octeon_gpio_methods,
  489         sizeof(struct octeon_gpio_softc),
  490 };
  491 static devclass_t octeon_gpio_devclass;
  492 
  493 DRIVER_MODULE(octeon_gpio, ciu, octeon_gpio_driver, octeon_gpio_devclass, 0, 0);

Cache object: 59b0ae65b8fe9c01d91ebe2e65231257


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