socfpga_gpio.c revision 277996
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 277996 2015-01-31 19:32:14Z 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> 58277996Sloos#include <dev/gpio/gpiobusvar.h> 59276533Sbr#include <dev/ofw/openfirm.h> 60276533Sbr#include <dev/ofw/ofw_bus.h> 61276533Sbr#include <dev/ofw/ofw_bus_subr.h> 62276533Sbr 63276533Sbr#include <machine/bus.h> 64276533Sbr#include <machine/fdt.h> 65276533Sbr#include <machine/cpu.h> 66276533Sbr#include <machine/intr.h> 67276533Sbr 68276533Sbr#include "gpio_if.h" 69276533Sbr 70276533Sbr#define READ4(_sc, _reg) \ 71276533Sbr bus_read_4((_sc)->res[0], _reg) 72276533Sbr#define WRITE4(_sc, _reg, _val) \ 73276533Sbr bus_write_4((_sc)->res[0], _reg, _val) 74276533Sbr 75276533Sbr#define GPIO_SWPORTA_DR 0x00 /* Port A Data Register */ 76276533Sbr#define GPIO_SWPORTA_DDR 0x04 /* Port A Data Direction Register */ 77276533Sbr#define GPIO_INTEN 0x30 /* Interrupt Enable Register */ 78276533Sbr#define GPIO_INTMASK 0x34 /* Interrupt Mask Register */ 79276533Sbr#define GPIO_INTTYPE_LEVEL 0x38 /* Interrupt Level Register */ 80276533Sbr#define GPIO_INT_POLARITY 0x3C /* Interrupt Polarity Register */ 81276533Sbr#define GPIO_INTSTATUS 0x40 /* Interrupt Status Register */ 82276533Sbr#define GPIO_RAW_INTSTATUS 0x44 /* Raw Interrupt Status Register */ 83276533Sbr#define GPIO_DEBOUNCE 0x48 /* Debounce Enable Register */ 84276533Sbr#define GPIO_PORTA_EOI 0x4C /* Clear Interrupt Register */ 85276533Sbr#define GPIO_EXT_PORTA 0x50 /* External Port A Register */ 86276533Sbr#define GPIO_LS_SYNC 0x60 /* Synchronization Level Register */ 87276533Sbr#define GPIO_ID_CODE 0x64 /* ID Code Register */ 88276533Sbr#define GPIO_VER_ID_CODE 0x6C /* GPIO Version Register */ 89276533Sbr#define GPIO_CONFIG_REG2 0x70 /* Configuration Register 2 */ 90276533Sbr#define ENCODED_ID_PWIDTH_M 0x1f /* Width of GPIO Port N Mask */ 91276533Sbr#define ENCODED_ID_PWIDTH_S(n) (5 * n) /* Width of GPIO Port N Shift */ 92276533Sbr#define GPIO_CONFIG_REG1 0x74 /* Configuration Register 1 */ 93276533Sbr 94276533Sbrenum port_no { 95276533Sbr PORTA, 96276533Sbr PORTB, 97276533Sbr PORTC, 98276533Sbr PORTD, 99276533Sbr}; 100276533Sbr 101276533Sbr#define NR_GPIO_MAX 32 /* Maximum pins per port */ 102276533Sbr 103276533Sbr#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 104276533Sbr#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 105276533Sbr 106276533Sbr#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 107276533Sbr 108276533Sbr/* 109276533Sbr * GPIO interface 110276533Sbr */ 111277996Sloosstatic device_t socfpga_gpio_get_bus(device_t); 112276533Sbrstatic int socfpga_gpio_pin_max(device_t, int *); 113276533Sbrstatic int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); 114276533Sbrstatic int socfpga_gpio_pin_getname(device_t, uint32_t, char *); 115276533Sbrstatic int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *); 116276533Sbrstatic int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t); 117276533Sbrstatic int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int); 118276533Sbrstatic int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *); 119276533Sbrstatic int socfpga_gpio_pin_toggle(device_t, uint32_t pin); 120276533Sbr 121276533Sbrstruct socfpga_gpio_softc { 122276533Sbr struct resource *res[1]; 123276533Sbr bus_space_tag_t bst; 124276533Sbr bus_space_handle_t bsh; 125276533Sbr 126276533Sbr device_t dev; 127277996Sloos device_t busdev; 128276533Sbr struct mtx sc_mtx; 129276533Sbr int gpio_npins; 130276533Sbr struct gpio_pin gpio_pins[NR_GPIO_MAX]; 131276533Sbr}; 132276533Sbr 133276533Sbrstruct socfpga_gpio_softc *gpio_sc; 134276533Sbr 135276533Sbrstatic struct resource_spec socfpga_gpio_spec[] = { 136276533Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 137276533Sbr { -1, 0 } 138276533Sbr}; 139276533Sbr 140276533Sbrstatic int 141276533Sbrsocfpga_gpio_probe(device_t dev) 142276533Sbr{ 143276533Sbr 144276533Sbr if (!ofw_bus_status_okay(dev)) 145276533Sbr return (ENXIO); 146276533Sbr 147276533Sbr if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio")) 148276533Sbr return (ENXIO); 149276533Sbr 150276533Sbr device_set_desc(dev, "DesignWare General-Purpose I/O Interface"); 151276533Sbr return (BUS_PROBE_DEFAULT); 152276533Sbr} 153276533Sbr 154276533Sbrstatic int 155276533Sbrsocfpga_gpio_attach(device_t dev) 156276533Sbr{ 157276533Sbr struct socfpga_gpio_softc *sc; 158276533Sbr int version; 159276533Sbr int nr_pins; 160276533Sbr int cfg2; 161276533Sbr int i; 162276533Sbr 163276533Sbr sc = device_get_softc(dev); 164276533Sbr sc->dev = dev; 165276533Sbr mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 166276533Sbr 167276533Sbr if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) { 168276533Sbr device_printf(dev, "could not allocate resources\n"); 169277968Sloos mtx_destroy(&sc->sc_mtx); 170276533Sbr return (ENXIO); 171276533Sbr } 172276533Sbr 173276533Sbr /* Memory interface */ 174276533Sbr sc->bst = rman_get_bustag(sc->res[0]); 175276533Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 176276533Sbr 177276533Sbr gpio_sc = sc; 178276533Sbr 179276533Sbr version = READ4(sc, GPIO_VER_ID_CODE); 180276533Sbr#if 0 181276533Sbr device_printf(sc->dev, "Version = 0x%08x\n", version); 182276533Sbr#endif 183276533Sbr 184276533Sbr /* 185276533Sbr * Take number of pins from hardware. 186276533Sbr * XXX: Assume we have GPIO port A only. 187276533Sbr */ 188276533Sbr cfg2 = READ4(sc, GPIO_CONFIG_REG2); 189276533Sbr nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \ 190276533Sbr ENCODED_ID_PWIDTH_M; 191276533Sbr sc->gpio_npins = nr_pins + 1; 192276533Sbr 193276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 194276533Sbr sc->gpio_pins[i].gp_pin = i; 195276533Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 196276533Sbr sc->gpio_pins[i].gp_flags = 197276533Sbr (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ? 198276533Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 199276533Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 200276533Sbr "socfpga_gpio%d.%d", device_get_unit(dev), i); 201276533Sbr } 202277996Sloos sc->busdev = gpiobus_attach_bus(dev); 203277996Sloos if (sc->busdev == NULL) { 204277996Sloos bus_release_resources(dev, socfpga_gpio_spec, sc->res); 205277996Sloos mtx_destroy(&sc->sc_mtx); 206277996Sloos return (ENXIO); 207277996Sloos } 208276533Sbr 209277996Sloos return (0); 210277996Sloos} 211276533Sbr 212277996Sloosstatic device_t 213277996Sloossocfpga_gpio_get_bus(device_t dev) 214277996Sloos{ 215277996Sloos struct socfpga_gpio_softc *sc; 216277996Sloos 217277996Sloos sc = device_get_softc(dev); 218277996Sloos 219277996Sloos return (sc->busdev); 220276533Sbr} 221276533Sbr 222276533Sbrstatic int 223276533Sbrsocfpga_gpio_pin_max(device_t dev, int *maxpin) 224276533Sbr{ 225276533Sbr struct socfpga_gpio_softc *sc; 226276533Sbr 227276533Sbr sc = device_get_softc(dev); 228276533Sbr 229276533Sbr *maxpin = sc->gpio_npins - 1; 230276533Sbr 231276533Sbr return (0); 232276533Sbr} 233276533Sbr 234276533Sbrstatic int 235276533Sbrsocfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 236276533Sbr{ 237276533Sbr struct socfpga_gpio_softc *sc; 238276533Sbr int i; 239276533Sbr 240276533Sbr sc = device_get_softc(dev); 241276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 242276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 243276533Sbr break; 244276533Sbr } 245276533Sbr 246276533Sbr if (i >= sc->gpio_npins) 247276533Sbr return (EINVAL); 248276533Sbr 249276533Sbr GPIO_LOCK(sc); 250276533Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 251276533Sbr GPIO_UNLOCK(sc); 252276533Sbr 253276533Sbr return (0); 254276533Sbr} 255276533Sbr 256276533Sbrstatic int 257276533Sbrsocfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 258276533Sbr{ 259276533Sbr struct socfpga_gpio_softc *sc; 260276533Sbr int i; 261276533Sbr 262276533Sbr sc = device_get_softc(dev); 263276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 264276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 265276533Sbr break; 266276533Sbr } 267276533Sbr 268276533Sbr if (i >= sc->gpio_npins) 269276533Sbr return (EINVAL); 270276533Sbr 271276533Sbr GPIO_LOCK(sc); 272276533Sbr *caps = sc->gpio_pins[i].gp_caps; 273276533Sbr GPIO_UNLOCK(sc); 274276533Sbr 275276533Sbr return (0); 276276533Sbr} 277276533Sbr 278276533Sbrstatic int 279276533Sbrsocfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 280276533Sbr{ 281276533Sbr struct socfpga_gpio_softc *sc; 282276533Sbr int i; 283276533Sbr 284276533Sbr sc = device_get_softc(dev); 285276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 286276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 287276533Sbr break; 288276533Sbr } 289276533Sbr 290276533Sbr if (i >= sc->gpio_npins) 291276533Sbr return (EINVAL); 292276533Sbr 293276533Sbr GPIO_LOCK(sc); 294276533Sbr *flags = sc->gpio_pins[i].gp_flags; 295276533Sbr GPIO_UNLOCK(sc); 296276533Sbr 297276533Sbr return (0); 298276533Sbr} 299276533Sbr 300276533Sbrstatic int 301276533Sbrsocfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 302276533Sbr{ 303276533Sbr struct socfpga_gpio_softc *sc; 304276533Sbr int i; 305276533Sbr 306276533Sbr sc = device_get_softc(dev); 307276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 308276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 309276533Sbr break; 310276533Sbr } 311276533Sbr 312276533Sbr if (i >= sc->gpio_npins) 313276533Sbr return (EINVAL); 314276533Sbr 315276533Sbr GPIO_LOCK(sc); 316276533Sbr *val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0; 317276533Sbr GPIO_UNLOCK(sc); 318276533Sbr 319276533Sbr return (0); 320276533Sbr} 321276533Sbr 322276533Sbrstatic int 323276533Sbrsocfpga_gpio_pin_toggle(device_t dev, uint32_t pin) 324276533Sbr{ 325276533Sbr struct socfpga_gpio_softc *sc; 326276533Sbr int reg; 327276533Sbr int i; 328276533Sbr 329276533Sbr sc = device_get_softc(dev); 330276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 331276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 332276533Sbr break; 333276533Sbr } 334276533Sbr 335276533Sbr if (i >= sc->gpio_npins) 336276533Sbr return (EINVAL); 337276533Sbr 338276533Sbr GPIO_LOCK(sc); 339276533Sbr reg = READ4(sc, GPIO_SWPORTA_DR); 340276533Sbr if (reg & (1 << i)) 341276533Sbr reg &= ~(1 << i); 342276533Sbr else 343276533Sbr reg |= (1 << i); 344276533Sbr WRITE4(sc, GPIO_SWPORTA_DR, reg); 345276533Sbr GPIO_UNLOCK(sc); 346276533Sbr 347276533Sbr return (0); 348276533Sbr} 349276533Sbr 350276533Sbr 351276533Sbrstatic void 352276533Sbrsocfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc, 353276533Sbr struct gpio_pin *pin, unsigned int flags) 354276533Sbr{ 355276533Sbr int reg; 356276533Sbr 357276533Sbr GPIO_LOCK(sc); 358276533Sbr 359276533Sbr /* 360276533Sbr * Manage input/output 361276533Sbr */ 362276533Sbr 363276533Sbr reg = READ4(sc, GPIO_SWPORTA_DDR); 364276533Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 365276533Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 366276533Sbr if (flags & GPIO_PIN_OUTPUT) { 367276533Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 368276533Sbr reg |= (1 << pin->gp_pin); 369276533Sbr } else { 370276533Sbr pin->gp_flags |= GPIO_PIN_INPUT; 371276533Sbr reg &= ~(1 << pin->gp_pin); 372276533Sbr } 373276533Sbr } 374276533Sbr 375276533Sbr WRITE4(sc, GPIO_SWPORTA_DDR, reg); 376276533Sbr GPIO_UNLOCK(sc); 377276533Sbr} 378276533Sbr 379276533Sbr 380276533Sbrstatic int 381276533Sbrsocfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 382276533Sbr{ 383276533Sbr struct socfpga_gpio_softc *sc; 384276533Sbr int i; 385276533Sbr 386276533Sbr sc = device_get_softc(dev); 387276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 388276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 389276533Sbr break; 390276533Sbr } 391276533Sbr 392276533Sbr if (i >= sc->gpio_npins) 393276533Sbr return (EINVAL); 394276533Sbr 395276533Sbr socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 396276533Sbr 397276533Sbr return (0); 398276533Sbr} 399276533Sbr 400276533Sbrstatic int 401276533Sbrsocfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 402276533Sbr{ 403276533Sbr struct socfpga_gpio_softc *sc; 404276533Sbr int reg; 405276533Sbr int i; 406276533Sbr 407276533Sbr sc = device_get_softc(dev); 408276533Sbr 409276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 410276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 411276533Sbr break; 412276533Sbr } 413276533Sbr 414276533Sbr if (i >= sc->gpio_npins) 415276533Sbr return (EINVAL); 416276533Sbr 417276533Sbr GPIO_LOCK(sc); 418276533Sbr reg = READ4(sc, GPIO_SWPORTA_DR); 419276533Sbr if (value) 420276533Sbr reg |= (1 << i); 421276533Sbr else 422276533Sbr reg &= ~(1 << i); 423276533Sbr WRITE4(sc, GPIO_SWPORTA_DR, reg); 424276533Sbr GPIO_UNLOCK(sc); 425276533Sbr 426276533Sbr return (0); 427276533Sbr} 428276533Sbr 429276533Sbrstatic device_method_t socfpga_gpio_methods[] = { 430276533Sbr DEVMETHOD(device_probe, socfpga_gpio_probe), 431276533Sbr DEVMETHOD(device_attach, socfpga_gpio_attach), 432276533Sbr 433276533Sbr /* GPIO protocol */ 434277996Sloos DEVMETHOD(gpio_get_bus, socfpga_gpio_get_bus), 435276533Sbr DEVMETHOD(gpio_pin_max, socfpga_gpio_pin_max), 436276533Sbr DEVMETHOD(gpio_pin_getname, socfpga_gpio_pin_getname), 437276533Sbr DEVMETHOD(gpio_pin_getcaps, socfpga_gpio_pin_getcaps), 438276533Sbr DEVMETHOD(gpio_pin_getflags, socfpga_gpio_pin_getflags), 439276533Sbr DEVMETHOD(gpio_pin_get, socfpga_gpio_pin_get), 440276533Sbr DEVMETHOD(gpio_pin_toggle, socfpga_gpio_pin_toggle), 441276533Sbr DEVMETHOD(gpio_pin_setflags, socfpga_gpio_pin_setflags), 442276533Sbr DEVMETHOD(gpio_pin_set, socfpga_gpio_pin_set), 443276533Sbr { 0, 0 } 444276533Sbr}; 445276533Sbr 446276533Sbrstatic driver_t socfpga_gpio_driver = { 447276533Sbr "gpio", 448276533Sbr socfpga_gpio_methods, 449276533Sbr sizeof(struct socfpga_gpio_softc), 450276533Sbr}; 451276533Sbr 452276533Sbrstatic devclass_t socfpga_gpio_devclass; 453276533Sbr 454276533SbrDRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver, 455276533Sbr socfpga_gpio_devclass, 0, 0); 456