socfpga_gpio.c revision 277968
1276533Sbr/*- 2276533Sbr * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3276533Sbr * All rights reserved. 4276533Sbr * 5276533Sbr * This software was developed by SRI International and the University of 6276533Sbr * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7276533Sbr * ("CTSRD"), as part of the DARPA CRASH research programme. 8276533Sbr * 9276533Sbr * Redistribution and use in source and binary forms, with or without 10276533Sbr * modification, are permitted provided that the following conditions 11276533Sbr * are met: 12276533Sbr * 1. Redistributions of source code must retain the above copyright 13276533Sbr * notice, this list of conditions and the following disclaimer. 14276533Sbr * 2. Redistributions in binary form must reproduce the above copyright 15276533Sbr * notice, this list of conditions and the following disclaimer in the 16276533Sbr * documentation and/or other materials provided with the distribution. 17276533Sbr * 18276533Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19276533Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20276533Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21276533Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22276533Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23276533Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24276533Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25276533Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26276533Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27276533Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28276533Sbr * SUCH DAMAGE. 29276533Sbr */ 30276533Sbr 31276533Sbr/* 32276533Sbr * SOCFPGA General-Purpose I/O Interface. 33276533Sbr * Chapter 22, Cyclone V Device Handbook (CV-5V2 2014.07.22) 34276533Sbr */ 35276533Sbr 36276533Sbr/* 37276533Sbr * The GPIO modules are instances of the Synopsys�� DesignWare�� APB General 38276533Sbr * Purpose Programming I/O (DW_apb_gpio) peripheral. 39276533Sbr */ 40276533Sbr 41276533Sbr#include <sys/cdefs.h> 42276533Sbr__FBSDID("$FreeBSD: head/sys/arm/altera/socfpga/socfpga_gpio.c 277968 2015-01-31 12:17:07Z loos $"); 43276533Sbr 44276533Sbr#include <sys/param.h> 45276533Sbr#include <sys/systm.h> 46276533Sbr#include <sys/bus.h> 47276533Sbr#include <sys/kernel.h> 48276533Sbr#include <sys/module.h> 49276533Sbr#include <sys/malloc.h> 50276533Sbr#include <sys/rman.h> 51276533Sbr#include <sys/timeet.h> 52276533Sbr#include <sys/timetc.h> 53276533Sbr#include <sys/watchdog.h> 54276533Sbr#include <sys/mutex.h> 55276533Sbr#include <sys/gpio.h> 56276533Sbr 57276533Sbr#include <dev/fdt/fdt_common.h> 58276533Sbr#include <dev/ofw/openfirm.h> 59276533Sbr#include <dev/ofw/ofw_bus.h> 60276533Sbr#include <dev/ofw/ofw_bus_subr.h> 61276533Sbr 62276533Sbr#include <machine/bus.h> 63276533Sbr#include <machine/fdt.h> 64276533Sbr#include <machine/cpu.h> 65276533Sbr#include <machine/intr.h> 66276533Sbr 67276533Sbr#include "gpio_if.h" 68276533Sbr 69276533Sbr#define READ4(_sc, _reg) \ 70276533Sbr bus_read_4((_sc)->res[0], _reg) 71276533Sbr#define WRITE4(_sc, _reg, _val) \ 72276533Sbr bus_write_4((_sc)->res[0], _reg, _val) 73276533Sbr 74276533Sbr#define GPIO_SWPORTA_DR 0x00 /* Port A Data Register */ 75276533Sbr#define GPIO_SWPORTA_DDR 0x04 /* Port A Data Direction Register */ 76276533Sbr#define GPIO_INTEN 0x30 /* Interrupt Enable Register */ 77276533Sbr#define GPIO_INTMASK 0x34 /* Interrupt Mask Register */ 78276533Sbr#define GPIO_INTTYPE_LEVEL 0x38 /* Interrupt Level Register */ 79276533Sbr#define GPIO_INT_POLARITY 0x3C /* Interrupt Polarity Register */ 80276533Sbr#define GPIO_INTSTATUS 0x40 /* Interrupt Status Register */ 81276533Sbr#define GPIO_RAW_INTSTATUS 0x44 /* Raw Interrupt Status Register */ 82276533Sbr#define GPIO_DEBOUNCE 0x48 /* Debounce Enable Register */ 83276533Sbr#define GPIO_PORTA_EOI 0x4C /* Clear Interrupt Register */ 84276533Sbr#define GPIO_EXT_PORTA 0x50 /* External Port A Register */ 85276533Sbr#define GPIO_LS_SYNC 0x60 /* Synchronization Level Register */ 86276533Sbr#define GPIO_ID_CODE 0x64 /* ID Code Register */ 87276533Sbr#define GPIO_VER_ID_CODE 0x6C /* GPIO Version Register */ 88276533Sbr#define GPIO_CONFIG_REG2 0x70 /* Configuration Register 2 */ 89276533Sbr#define ENCODED_ID_PWIDTH_M 0x1f /* Width of GPIO Port N Mask */ 90276533Sbr#define ENCODED_ID_PWIDTH_S(n) (5 * n) /* Width of GPIO Port N Shift */ 91276533Sbr#define GPIO_CONFIG_REG1 0x74 /* Configuration Register 1 */ 92276533Sbr 93276533Sbrenum port_no { 94276533Sbr PORTA, 95276533Sbr PORTB, 96276533Sbr PORTC, 97276533Sbr PORTD, 98276533Sbr}; 99276533Sbr 100276533Sbr#define NR_GPIO_MAX 32 /* Maximum pins per port */ 101276533Sbr 102276533Sbr#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 103276533Sbr#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 104276533Sbr 105276533Sbr#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 106276533Sbr 107276533Sbr/* 108276533Sbr * GPIO interface 109276533Sbr */ 110276533Sbrstatic int socfpga_gpio_pin_max(device_t, int *); 111276533Sbrstatic int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); 112276533Sbrstatic int socfpga_gpio_pin_getname(device_t, uint32_t, char *); 113276533Sbrstatic int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *); 114276533Sbrstatic int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t); 115276533Sbrstatic int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int); 116276533Sbrstatic int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *); 117276533Sbrstatic int socfpga_gpio_pin_toggle(device_t, uint32_t pin); 118276533Sbr 119276533Sbrstruct socfpga_gpio_softc { 120276533Sbr struct resource *res[1]; 121276533Sbr bus_space_tag_t bst; 122276533Sbr bus_space_handle_t bsh; 123276533Sbr 124276533Sbr device_t dev; 125276533Sbr struct mtx sc_mtx; 126276533Sbr int gpio_npins; 127276533Sbr struct gpio_pin gpio_pins[NR_GPIO_MAX]; 128276533Sbr}; 129276533Sbr 130276533Sbrstruct socfpga_gpio_softc *gpio_sc; 131276533Sbr 132276533Sbrstatic struct resource_spec socfpga_gpio_spec[] = { 133276533Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 134276533Sbr { -1, 0 } 135276533Sbr}; 136276533Sbr 137276533Sbrstatic int 138276533Sbrsocfpga_gpio_probe(device_t dev) 139276533Sbr{ 140276533Sbr 141276533Sbr if (!ofw_bus_status_okay(dev)) 142276533Sbr return (ENXIO); 143276533Sbr 144276533Sbr if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio")) 145276533Sbr return (ENXIO); 146276533Sbr 147276533Sbr device_set_desc(dev, "DesignWare General-Purpose I/O Interface"); 148276533Sbr return (BUS_PROBE_DEFAULT); 149276533Sbr} 150276533Sbr 151276533Sbrstatic int 152276533Sbrsocfpga_gpio_attach(device_t dev) 153276533Sbr{ 154276533Sbr struct socfpga_gpio_softc *sc; 155276533Sbr int version; 156276533Sbr int nr_pins; 157276533Sbr int cfg2; 158276533Sbr int i; 159276533Sbr 160276533Sbr sc = device_get_softc(dev); 161276533Sbr sc->dev = dev; 162276533Sbr mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 163276533Sbr 164276533Sbr if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) { 165276533Sbr device_printf(dev, "could not allocate resources\n"); 166277968Sloos mtx_destroy(&sc->sc_mtx); 167276533Sbr return (ENXIO); 168276533Sbr } 169276533Sbr 170276533Sbr /* Memory interface */ 171276533Sbr sc->bst = rman_get_bustag(sc->res[0]); 172276533Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 173276533Sbr 174276533Sbr gpio_sc = sc; 175276533Sbr 176276533Sbr version = READ4(sc, GPIO_VER_ID_CODE); 177276533Sbr#if 0 178276533Sbr device_printf(sc->dev, "Version = 0x%08x\n", version); 179276533Sbr#endif 180276533Sbr 181276533Sbr /* 182276533Sbr * Take number of pins from hardware. 183276533Sbr * XXX: Assume we have GPIO port A only. 184276533Sbr */ 185276533Sbr cfg2 = READ4(sc, GPIO_CONFIG_REG2); 186276533Sbr nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \ 187276533Sbr ENCODED_ID_PWIDTH_M; 188276533Sbr sc->gpio_npins = nr_pins + 1; 189276533Sbr 190276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 191276533Sbr sc->gpio_pins[i].gp_pin = i; 192276533Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 193276533Sbr sc->gpio_pins[i].gp_flags = 194276533Sbr (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ? 195276533Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 196276533Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 197276533Sbr "socfpga_gpio%d.%d", device_get_unit(dev), i); 198276533Sbr } 199276533Sbr 200276533Sbr device_add_child(dev, "gpioc", -1); 201276533Sbr device_add_child(dev, "gpiobus", -1); 202276533Sbr 203276533Sbr return (bus_generic_attach(dev)); 204276533Sbr} 205276533Sbr 206276533Sbrstatic int 207276533Sbrsocfpga_gpio_pin_max(device_t dev, int *maxpin) 208276533Sbr{ 209276533Sbr struct socfpga_gpio_softc *sc; 210276533Sbr 211276533Sbr sc = device_get_softc(dev); 212276533Sbr 213276533Sbr *maxpin = sc->gpio_npins - 1; 214276533Sbr 215276533Sbr return (0); 216276533Sbr} 217276533Sbr 218276533Sbrstatic int 219276533Sbrsocfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 220276533Sbr{ 221276533Sbr struct socfpga_gpio_softc *sc; 222276533Sbr int i; 223276533Sbr 224276533Sbr sc = device_get_softc(dev); 225276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 226276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 227276533Sbr break; 228276533Sbr } 229276533Sbr 230276533Sbr if (i >= sc->gpio_npins) 231276533Sbr return (EINVAL); 232276533Sbr 233276533Sbr GPIO_LOCK(sc); 234276533Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 235276533Sbr GPIO_UNLOCK(sc); 236276533Sbr 237276533Sbr return (0); 238276533Sbr} 239276533Sbr 240276533Sbrstatic int 241276533Sbrsocfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 242276533Sbr{ 243276533Sbr struct socfpga_gpio_softc *sc; 244276533Sbr int i; 245276533Sbr 246276533Sbr sc = device_get_softc(dev); 247276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 248276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 249276533Sbr break; 250276533Sbr } 251276533Sbr 252276533Sbr if (i >= sc->gpio_npins) 253276533Sbr return (EINVAL); 254276533Sbr 255276533Sbr GPIO_LOCK(sc); 256276533Sbr *caps = sc->gpio_pins[i].gp_caps; 257276533Sbr GPIO_UNLOCK(sc); 258276533Sbr 259276533Sbr return (0); 260276533Sbr} 261276533Sbr 262276533Sbrstatic int 263276533Sbrsocfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 264276533Sbr{ 265276533Sbr struct socfpga_gpio_softc *sc; 266276533Sbr int i; 267276533Sbr 268276533Sbr sc = device_get_softc(dev); 269276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 270276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 271276533Sbr break; 272276533Sbr } 273276533Sbr 274276533Sbr if (i >= sc->gpio_npins) 275276533Sbr return (EINVAL); 276276533Sbr 277276533Sbr GPIO_LOCK(sc); 278276533Sbr *flags = sc->gpio_pins[i].gp_flags; 279276533Sbr GPIO_UNLOCK(sc); 280276533Sbr 281276533Sbr return (0); 282276533Sbr} 283276533Sbr 284276533Sbrstatic int 285276533Sbrsocfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 286276533Sbr{ 287276533Sbr struct socfpga_gpio_softc *sc; 288276533Sbr int i; 289276533Sbr 290276533Sbr sc = device_get_softc(dev); 291276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 292276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 293276533Sbr break; 294276533Sbr } 295276533Sbr 296276533Sbr if (i >= sc->gpio_npins) 297276533Sbr return (EINVAL); 298276533Sbr 299276533Sbr GPIO_LOCK(sc); 300276533Sbr *val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0; 301276533Sbr GPIO_UNLOCK(sc); 302276533Sbr 303276533Sbr return (0); 304276533Sbr} 305276533Sbr 306276533Sbrstatic int 307276533Sbrsocfpga_gpio_pin_toggle(device_t dev, uint32_t pin) 308276533Sbr{ 309276533Sbr struct socfpga_gpio_softc *sc; 310276533Sbr int reg; 311276533Sbr int i; 312276533Sbr 313276533Sbr sc = device_get_softc(dev); 314276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 315276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 316276533Sbr break; 317276533Sbr } 318276533Sbr 319276533Sbr if (i >= sc->gpio_npins) 320276533Sbr return (EINVAL); 321276533Sbr 322276533Sbr GPIO_LOCK(sc); 323276533Sbr reg = READ4(sc, GPIO_SWPORTA_DR); 324276533Sbr if (reg & (1 << i)) 325276533Sbr reg &= ~(1 << i); 326276533Sbr else 327276533Sbr reg |= (1 << i); 328276533Sbr WRITE4(sc, GPIO_SWPORTA_DR, reg); 329276533Sbr GPIO_UNLOCK(sc); 330276533Sbr 331276533Sbr return (0); 332276533Sbr} 333276533Sbr 334276533Sbr 335276533Sbrstatic void 336276533Sbrsocfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc, 337276533Sbr struct gpio_pin *pin, unsigned int flags) 338276533Sbr{ 339276533Sbr int reg; 340276533Sbr 341276533Sbr GPIO_LOCK(sc); 342276533Sbr 343276533Sbr /* 344276533Sbr * Manage input/output 345276533Sbr */ 346276533Sbr 347276533Sbr reg = READ4(sc, GPIO_SWPORTA_DDR); 348276533Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 349276533Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 350276533Sbr if (flags & GPIO_PIN_OUTPUT) { 351276533Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 352276533Sbr reg |= (1 << pin->gp_pin); 353276533Sbr } else { 354276533Sbr pin->gp_flags |= GPIO_PIN_INPUT; 355276533Sbr reg &= ~(1 << pin->gp_pin); 356276533Sbr } 357276533Sbr } 358276533Sbr 359276533Sbr WRITE4(sc, GPIO_SWPORTA_DDR, reg); 360276533Sbr GPIO_UNLOCK(sc); 361276533Sbr} 362276533Sbr 363276533Sbr 364276533Sbrstatic int 365276533Sbrsocfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 366276533Sbr{ 367276533Sbr struct socfpga_gpio_softc *sc; 368276533Sbr int i; 369276533Sbr 370276533Sbr sc = device_get_softc(dev); 371276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 372276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 373276533Sbr break; 374276533Sbr } 375276533Sbr 376276533Sbr if (i >= sc->gpio_npins) 377276533Sbr return (EINVAL); 378276533Sbr 379276533Sbr socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 380276533Sbr 381276533Sbr return (0); 382276533Sbr} 383276533Sbr 384276533Sbrstatic int 385276533Sbrsocfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 386276533Sbr{ 387276533Sbr struct socfpga_gpio_softc *sc; 388276533Sbr int reg; 389276533Sbr int i; 390276533Sbr 391276533Sbr sc = device_get_softc(dev); 392276533Sbr 393276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 394276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 395276533Sbr break; 396276533Sbr } 397276533Sbr 398276533Sbr if (i >= sc->gpio_npins) 399276533Sbr return (EINVAL); 400276533Sbr 401276533Sbr GPIO_LOCK(sc); 402276533Sbr reg = READ4(sc, GPIO_SWPORTA_DR); 403276533Sbr if (value) 404276533Sbr reg |= (1 << i); 405276533Sbr else 406276533Sbr reg &= ~(1 << i); 407276533Sbr WRITE4(sc, GPIO_SWPORTA_DR, reg); 408276533Sbr GPIO_UNLOCK(sc); 409276533Sbr 410276533Sbr return (0); 411276533Sbr} 412276533Sbr 413276533Sbrstatic device_method_t socfpga_gpio_methods[] = { 414276533Sbr DEVMETHOD(device_probe, socfpga_gpio_probe), 415276533Sbr DEVMETHOD(device_attach, socfpga_gpio_attach), 416276533Sbr 417276533Sbr /* GPIO protocol */ 418276533Sbr DEVMETHOD(gpio_pin_max, socfpga_gpio_pin_max), 419276533Sbr DEVMETHOD(gpio_pin_getname, socfpga_gpio_pin_getname), 420276533Sbr DEVMETHOD(gpio_pin_getcaps, socfpga_gpio_pin_getcaps), 421276533Sbr DEVMETHOD(gpio_pin_getflags, socfpga_gpio_pin_getflags), 422276533Sbr DEVMETHOD(gpio_pin_get, socfpga_gpio_pin_get), 423276533Sbr DEVMETHOD(gpio_pin_toggle, socfpga_gpio_pin_toggle), 424276533Sbr DEVMETHOD(gpio_pin_setflags, socfpga_gpio_pin_setflags), 425276533Sbr DEVMETHOD(gpio_pin_set, socfpga_gpio_pin_set), 426276533Sbr { 0, 0 } 427276533Sbr}; 428276533Sbr 429276533Sbrstatic driver_t socfpga_gpio_driver = { 430276533Sbr "gpio", 431276533Sbr socfpga_gpio_methods, 432276533Sbr sizeof(struct socfpga_gpio_softc), 433276533Sbr}; 434276533Sbr 435276533Sbrstatic devclass_t socfpga_gpio_devclass; 436276533Sbr 437276533SbrDRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver, 438276533Sbr socfpga_gpio_devclass, 0, 0); 439