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: releng/11.0/sys/arm/altera/socfpga/socfpga_gpio.c 281085 2015-04-04 21:34:26Z andrew $"); 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/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 */ 110277996Sloosstatic device_t socfpga_gpio_get_bus(device_t); 111276533Sbrstatic int socfpga_gpio_pin_max(device_t, int *); 112276533Sbrstatic int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); 113276533Sbrstatic int socfpga_gpio_pin_getname(device_t, uint32_t, char *); 114276533Sbrstatic int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *); 115276533Sbrstatic int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t); 116276533Sbrstatic int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int); 117276533Sbrstatic int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *); 118276533Sbrstatic int socfpga_gpio_pin_toggle(device_t, uint32_t pin); 119276533Sbr 120276533Sbrstruct socfpga_gpio_softc { 121276533Sbr struct resource *res[1]; 122276533Sbr bus_space_tag_t bst; 123276533Sbr bus_space_handle_t bsh; 124276533Sbr 125276533Sbr device_t dev; 126277996Sloos device_t busdev; 127276533Sbr struct mtx sc_mtx; 128276533Sbr int gpio_npins; 129276533Sbr struct gpio_pin gpio_pins[NR_GPIO_MAX]; 130276533Sbr}; 131276533Sbr 132276533Sbrstruct socfpga_gpio_softc *gpio_sc; 133276533Sbr 134276533Sbrstatic struct resource_spec socfpga_gpio_spec[] = { 135276533Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 136276533Sbr { -1, 0 } 137276533Sbr}; 138276533Sbr 139276533Sbrstatic int 140276533Sbrsocfpga_gpio_probe(device_t dev) 141276533Sbr{ 142276533Sbr 143276533Sbr if (!ofw_bus_status_okay(dev)) 144276533Sbr return (ENXIO); 145276533Sbr 146276533Sbr if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio")) 147276533Sbr return (ENXIO); 148276533Sbr 149276533Sbr device_set_desc(dev, "DesignWare General-Purpose I/O Interface"); 150276533Sbr return (BUS_PROBE_DEFAULT); 151276533Sbr} 152276533Sbr 153276533Sbrstatic int 154276533Sbrsocfpga_gpio_attach(device_t dev) 155276533Sbr{ 156276533Sbr struct socfpga_gpio_softc *sc; 157276533Sbr int version; 158276533Sbr int nr_pins; 159276533Sbr int cfg2; 160276533Sbr int i; 161276533Sbr 162276533Sbr sc = device_get_softc(dev); 163276533Sbr sc->dev = dev; 164276533Sbr mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 165276533Sbr 166276533Sbr if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) { 167276533Sbr device_printf(dev, "could not allocate resources\n"); 168277968Sloos mtx_destroy(&sc->sc_mtx); 169276533Sbr return (ENXIO); 170276533Sbr } 171276533Sbr 172276533Sbr /* Memory interface */ 173276533Sbr sc->bst = rman_get_bustag(sc->res[0]); 174276533Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 175276533Sbr 176276533Sbr gpio_sc = sc; 177276533Sbr 178276533Sbr version = READ4(sc, GPIO_VER_ID_CODE); 179276533Sbr#if 0 180276533Sbr device_printf(sc->dev, "Version = 0x%08x\n", version); 181276533Sbr#endif 182276533Sbr 183276533Sbr /* 184276533Sbr * Take number of pins from hardware. 185276533Sbr * XXX: Assume we have GPIO port A only. 186276533Sbr */ 187276533Sbr cfg2 = READ4(sc, GPIO_CONFIG_REG2); 188276533Sbr nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \ 189276533Sbr ENCODED_ID_PWIDTH_M; 190276533Sbr sc->gpio_npins = nr_pins + 1; 191276533Sbr 192276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 193276533Sbr sc->gpio_pins[i].gp_pin = i; 194276533Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 195276533Sbr sc->gpio_pins[i].gp_flags = 196276533Sbr (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ? 197276533Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 198276533Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 199276533Sbr "socfpga_gpio%d.%d", device_get_unit(dev), i); 200276533Sbr } 201277996Sloos sc->busdev = gpiobus_attach_bus(dev); 202277996Sloos if (sc->busdev == NULL) { 203277996Sloos bus_release_resources(dev, socfpga_gpio_spec, sc->res); 204277996Sloos mtx_destroy(&sc->sc_mtx); 205277996Sloos return (ENXIO); 206277996Sloos } 207276533Sbr 208277996Sloos return (0); 209277996Sloos} 210276533Sbr 211277996Sloosstatic device_t 212277996Sloossocfpga_gpio_get_bus(device_t dev) 213277996Sloos{ 214277996Sloos struct socfpga_gpio_softc *sc; 215277996Sloos 216277996Sloos sc = device_get_softc(dev); 217277996Sloos 218277996Sloos return (sc->busdev); 219276533Sbr} 220276533Sbr 221276533Sbrstatic int 222276533Sbrsocfpga_gpio_pin_max(device_t dev, int *maxpin) 223276533Sbr{ 224276533Sbr struct socfpga_gpio_softc *sc; 225276533Sbr 226276533Sbr sc = device_get_softc(dev); 227276533Sbr 228276533Sbr *maxpin = sc->gpio_npins - 1; 229276533Sbr 230276533Sbr return (0); 231276533Sbr} 232276533Sbr 233276533Sbrstatic int 234276533Sbrsocfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 235276533Sbr{ 236276533Sbr struct socfpga_gpio_softc *sc; 237276533Sbr int i; 238276533Sbr 239276533Sbr sc = device_get_softc(dev); 240276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 241276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 242276533Sbr break; 243276533Sbr } 244276533Sbr 245276533Sbr if (i >= sc->gpio_npins) 246276533Sbr return (EINVAL); 247276533Sbr 248276533Sbr GPIO_LOCK(sc); 249276533Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 250276533Sbr GPIO_UNLOCK(sc); 251276533Sbr 252276533Sbr return (0); 253276533Sbr} 254276533Sbr 255276533Sbrstatic int 256276533Sbrsocfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 257276533Sbr{ 258276533Sbr struct socfpga_gpio_softc *sc; 259276533Sbr int i; 260276533Sbr 261276533Sbr sc = device_get_softc(dev); 262276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 263276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 264276533Sbr break; 265276533Sbr } 266276533Sbr 267276533Sbr if (i >= sc->gpio_npins) 268276533Sbr return (EINVAL); 269276533Sbr 270276533Sbr GPIO_LOCK(sc); 271276533Sbr *caps = sc->gpio_pins[i].gp_caps; 272276533Sbr GPIO_UNLOCK(sc); 273276533Sbr 274276533Sbr return (0); 275276533Sbr} 276276533Sbr 277276533Sbrstatic int 278276533Sbrsocfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 279276533Sbr{ 280276533Sbr struct socfpga_gpio_softc *sc; 281276533Sbr int i; 282276533Sbr 283276533Sbr sc = device_get_softc(dev); 284276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 285276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 286276533Sbr break; 287276533Sbr } 288276533Sbr 289276533Sbr if (i >= sc->gpio_npins) 290276533Sbr return (EINVAL); 291276533Sbr 292276533Sbr GPIO_LOCK(sc); 293276533Sbr *flags = sc->gpio_pins[i].gp_flags; 294276533Sbr GPIO_UNLOCK(sc); 295276533Sbr 296276533Sbr return (0); 297276533Sbr} 298276533Sbr 299276533Sbrstatic int 300276533Sbrsocfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 301276533Sbr{ 302276533Sbr struct socfpga_gpio_softc *sc; 303276533Sbr int i; 304276533Sbr 305276533Sbr sc = device_get_softc(dev); 306276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 307276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 308276533Sbr break; 309276533Sbr } 310276533Sbr 311276533Sbr if (i >= sc->gpio_npins) 312276533Sbr return (EINVAL); 313276533Sbr 314276533Sbr GPIO_LOCK(sc); 315276533Sbr *val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0; 316276533Sbr GPIO_UNLOCK(sc); 317276533Sbr 318276533Sbr return (0); 319276533Sbr} 320276533Sbr 321276533Sbrstatic int 322276533Sbrsocfpga_gpio_pin_toggle(device_t dev, uint32_t pin) 323276533Sbr{ 324276533Sbr struct socfpga_gpio_softc *sc; 325276533Sbr int reg; 326276533Sbr int i; 327276533Sbr 328276533Sbr sc = device_get_softc(dev); 329276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 330276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 331276533Sbr break; 332276533Sbr } 333276533Sbr 334276533Sbr if (i >= sc->gpio_npins) 335276533Sbr return (EINVAL); 336276533Sbr 337276533Sbr GPIO_LOCK(sc); 338276533Sbr reg = READ4(sc, GPIO_SWPORTA_DR); 339276533Sbr if (reg & (1 << i)) 340276533Sbr reg &= ~(1 << i); 341276533Sbr else 342276533Sbr reg |= (1 << i); 343276533Sbr WRITE4(sc, GPIO_SWPORTA_DR, reg); 344276533Sbr GPIO_UNLOCK(sc); 345276533Sbr 346276533Sbr return (0); 347276533Sbr} 348276533Sbr 349276533Sbr 350276533Sbrstatic void 351276533Sbrsocfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc, 352276533Sbr struct gpio_pin *pin, unsigned int flags) 353276533Sbr{ 354276533Sbr int reg; 355276533Sbr 356276533Sbr GPIO_LOCK(sc); 357276533Sbr 358276533Sbr /* 359276533Sbr * Manage input/output 360276533Sbr */ 361276533Sbr 362276533Sbr reg = READ4(sc, GPIO_SWPORTA_DDR); 363276533Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 364276533Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 365276533Sbr if (flags & GPIO_PIN_OUTPUT) { 366276533Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 367276533Sbr reg |= (1 << pin->gp_pin); 368276533Sbr } else { 369276533Sbr pin->gp_flags |= GPIO_PIN_INPUT; 370276533Sbr reg &= ~(1 << pin->gp_pin); 371276533Sbr } 372276533Sbr } 373276533Sbr 374276533Sbr WRITE4(sc, GPIO_SWPORTA_DDR, reg); 375276533Sbr GPIO_UNLOCK(sc); 376276533Sbr} 377276533Sbr 378276533Sbr 379276533Sbrstatic int 380276533Sbrsocfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 381276533Sbr{ 382276533Sbr struct socfpga_gpio_softc *sc; 383276533Sbr int i; 384276533Sbr 385276533Sbr sc = device_get_softc(dev); 386276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 387276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 388276533Sbr break; 389276533Sbr } 390276533Sbr 391276533Sbr if (i >= sc->gpio_npins) 392276533Sbr return (EINVAL); 393276533Sbr 394276533Sbr socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 395276533Sbr 396276533Sbr return (0); 397276533Sbr} 398276533Sbr 399276533Sbrstatic int 400276533Sbrsocfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 401276533Sbr{ 402276533Sbr struct socfpga_gpio_softc *sc; 403276533Sbr int reg; 404276533Sbr int i; 405276533Sbr 406276533Sbr sc = device_get_softc(dev); 407276533Sbr 408276533Sbr for (i = 0; i < sc->gpio_npins; i++) { 409276533Sbr if (sc->gpio_pins[i].gp_pin == pin) 410276533Sbr break; 411276533Sbr } 412276533Sbr 413276533Sbr if (i >= sc->gpio_npins) 414276533Sbr return (EINVAL); 415276533Sbr 416276533Sbr GPIO_LOCK(sc); 417276533Sbr reg = READ4(sc, GPIO_SWPORTA_DR); 418276533Sbr if (value) 419276533Sbr reg |= (1 << i); 420276533Sbr else 421276533Sbr reg &= ~(1 << i); 422276533Sbr WRITE4(sc, GPIO_SWPORTA_DR, reg); 423276533Sbr GPIO_UNLOCK(sc); 424276533Sbr 425276533Sbr return (0); 426276533Sbr} 427276533Sbr 428276533Sbrstatic device_method_t socfpga_gpio_methods[] = { 429276533Sbr DEVMETHOD(device_probe, socfpga_gpio_probe), 430276533Sbr DEVMETHOD(device_attach, socfpga_gpio_attach), 431276533Sbr 432276533Sbr /* GPIO protocol */ 433277996Sloos DEVMETHOD(gpio_get_bus, socfpga_gpio_get_bus), 434276533Sbr DEVMETHOD(gpio_pin_max, socfpga_gpio_pin_max), 435276533Sbr DEVMETHOD(gpio_pin_getname, socfpga_gpio_pin_getname), 436276533Sbr DEVMETHOD(gpio_pin_getcaps, socfpga_gpio_pin_getcaps), 437276533Sbr DEVMETHOD(gpio_pin_getflags, socfpga_gpio_pin_getflags), 438276533Sbr DEVMETHOD(gpio_pin_get, socfpga_gpio_pin_get), 439276533Sbr DEVMETHOD(gpio_pin_toggle, socfpga_gpio_pin_toggle), 440276533Sbr DEVMETHOD(gpio_pin_setflags, socfpga_gpio_pin_setflags), 441276533Sbr DEVMETHOD(gpio_pin_set, socfpga_gpio_pin_set), 442276533Sbr { 0, 0 } 443276533Sbr}; 444276533Sbr 445276533Sbrstatic driver_t socfpga_gpio_driver = { 446276533Sbr "gpio", 447276533Sbr socfpga_gpio_methods, 448276533Sbr sizeof(struct socfpga_gpio_softc), 449276533Sbr}; 450276533Sbr 451276533Sbrstatic devclass_t socfpga_gpio_devclass; 452276533Sbr 453276533SbrDRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver, 454276533Sbr socfpga_gpio_devclass, 0, 0); 455