socfpga_gpio.c revision 303975
1/*- 2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31/* 32 * SOCFPGA General-Purpose I/O Interface. 33 * Chapter 22, Cyclone V Device Handbook (CV-5V2 2014.07.22) 34 */ 35 36/* 37 * The GPIO modules are instances of the Synopsys�� DesignWare�� APB General 38 * Purpose Programming I/O (DW_apb_gpio) peripheral. 39 */ 40 41#include <sys/cdefs.h> 42__FBSDID("$FreeBSD: releng/11.0/sys/arm/altera/socfpga/socfpga_gpio.c 281085 2015-04-04 21:34:26Z andrew $"); 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/bus.h> 47#include <sys/kernel.h> 48#include <sys/module.h> 49#include <sys/malloc.h> 50#include <sys/rman.h> 51#include <sys/timeet.h> 52#include <sys/timetc.h> 53#include <sys/watchdog.h> 54#include <sys/mutex.h> 55#include <sys/gpio.h> 56 57#include <dev/fdt/fdt_common.h> 58#include <dev/gpio/gpiobusvar.h> 59#include <dev/ofw/openfirm.h> 60#include <dev/ofw/ofw_bus.h> 61#include <dev/ofw/ofw_bus_subr.h> 62 63#include <machine/bus.h> 64#include <machine/cpu.h> 65#include <machine/intr.h> 66 67#include "gpio_if.h" 68 69#define READ4(_sc, _reg) \ 70 bus_read_4((_sc)->res[0], _reg) 71#define WRITE4(_sc, _reg, _val) \ 72 bus_write_4((_sc)->res[0], _reg, _val) 73 74#define GPIO_SWPORTA_DR 0x00 /* Port A Data Register */ 75#define GPIO_SWPORTA_DDR 0x04 /* Port A Data Direction Register */ 76#define GPIO_INTEN 0x30 /* Interrupt Enable Register */ 77#define GPIO_INTMASK 0x34 /* Interrupt Mask Register */ 78#define GPIO_INTTYPE_LEVEL 0x38 /* Interrupt Level Register */ 79#define GPIO_INT_POLARITY 0x3C /* Interrupt Polarity Register */ 80#define GPIO_INTSTATUS 0x40 /* Interrupt Status Register */ 81#define GPIO_RAW_INTSTATUS 0x44 /* Raw Interrupt Status Register */ 82#define GPIO_DEBOUNCE 0x48 /* Debounce Enable Register */ 83#define GPIO_PORTA_EOI 0x4C /* Clear Interrupt Register */ 84#define GPIO_EXT_PORTA 0x50 /* External Port A Register */ 85#define GPIO_LS_SYNC 0x60 /* Synchronization Level Register */ 86#define GPIO_ID_CODE 0x64 /* ID Code Register */ 87#define GPIO_VER_ID_CODE 0x6C /* GPIO Version Register */ 88#define GPIO_CONFIG_REG2 0x70 /* Configuration Register 2 */ 89#define ENCODED_ID_PWIDTH_M 0x1f /* Width of GPIO Port N Mask */ 90#define ENCODED_ID_PWIDTH_S(n) (5 * n) /* Width of GPIO Port N Shift */ 91#define GPIO_CONFIG_REG1 0x74 /* Configuration Register 1 */ 92 93enum port_no { 94 PORTA, 95 PORTB, 96 PORTC, 97 PORTD, 98}; 99 100#define NR_GPIO_MAX 32 /* Maximum pins per port */ 101 102#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 103#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 104 105#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 106 107/* 108 * GPIO interface 109 */ 110static device_t socfpga_gpio_get_bus(device_t); 111static int socfpga_gpio_pin_max(device_t, int *); 112static int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); 113static int socfpga_gpio_pin_getname(device_t, uint32_t, char *); 114static int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *); 115static int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t); 116static int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int); 117static int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *); 118static int socfpga_gpio_pin_toggle(device_t, uint32_t pin); 119 120struct socfpga_gpio_softc { 121 struct resource *res[1]; 122 bus_space_tag_t bst; 123 bus_space_handle_t bsh; 124 125 device_t dev; 126 device_t busdev; 127 struct mtx sc_mtx; 128 int gpio_npins; 129 struct gpio_pin gpio_pins[NR_GPIO_MAX]; 130}; 131 132struct socfpga_gpio_softc *gpio_sc; 133 134static struct resource_spec socfpga_gpio_spec[] = { 135 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 136 { -1, 0 } 137}; 138 139static int 140socfpga_gpio_probe(device_t dev) 141{ 142 143 if (!ofw_bus_status_okay(dev)) 144 return (ENXIO); 145 146 if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio")) 147 return (ENXIO); 148 149 device_set_desc(dev, "DesignWare General-Purpose I/O Interface"); 150 return (BUS_PROBE_DEFAULT); 151} 152 153static int 154socfpga_gpio_attach(device_t dev) 155{ 156 struct socfpga_gpio_softc *sc; 157 int version; 158 int nr_pins; 159 int cfg2; 160 int i; 161 162 sc = device_get_softc(dev); 163 sc->dev = dev; 164 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 165 166 if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) { 167 device_printf(dev, "could not allocate resources\n"); 168 mtx_destroy(&sc->sc_mtx); 169 return (ENXIO); 170 } 171 172 /* Memory interface */ 173 sc->bst = rman_get_bustag(sc->res[0]); 174 sc->bsh = rman_get_bushandle(sc->res[0]); 175 176 gpio_sc = sc; 177 178 version = READ4(sc, GPIO_VER_ID_CODE); 179#if 0 180 device_printf(sc->dev, "Version = 0x%08x\n", version); 181#endif 182 183 /* 184 * Take number of pins from hardware. 185 * XXX: Assume we have GPIO port A only. 186 */ 187 cfg2 = READ4(sc, GPIO_CONFIG_REG2); 188 nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \ 189 ENCODED_ID_PWIDTH_M; 190 sc->gpio_npins = nr_pins + 1; 191 192 for (i = 0; i < sc->gpio_npins; i++) { 193 sc->gpio_pins[i].gp_pin = i; 194 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 195 sc->gpio_pins[i].gp_flags = 196 (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ? 197 GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 198 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 199 "socfpga_gpio%d.%d", device_get_unit(dev), i); 200 } 201 sc->busdev = gpiobus_attach_bus(dev); 202 if (sc->busdev == NULL) { 203 bus_release_resources(dev, socfpga_gpio_spec, sc->res); 204 mtx_destroy(&sc->sc_mtx); 205 return (ENXIO); 206 } 207 208 return (0); 209} 210 211static device_t 212socfpga_gpio_get_bus(device_t dev) 213{ 214 struct socfpga_gpio_softc *sc; 215 216 sc = device_get_softc(dev); 217 218 return (sc->busdev); 219} 220 221static int 222socfpga_gpio_pin_max(device_t dev, int *maxpin) 223{ 224 struct socfpga_gpio_softc *sc; 225 226 sc = device_get_softc(dev); 227 228 *maxpin = sc->gpio_npins - 1; 229 230 return (0); 231} 232 233static int 234socfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 235{ 236 struct socfpga_gpio_softc *sc; 237 int i; 238 239 sc = device_get_softc(dev); 240 for (i = 0; i < sc->gpio_npins; i++) { 241 if (sc->gpio_pins[i].gp_pin == pin) 242 break; 243 } 244 245 if (i >= sc->gpio_npins) 246 return (EINVAL); 247 248 GPIO_LOCK(sc); 249 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 250 GPIO_UNLOCK(sc); 251 252 return (0); 253} 254 255static int 256socfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 257{ 258 struct socfpga_gpio_softc *sc; 259 int i; 260 261 sc = device_get_softc(dev); 262 for (i = 0; i < sc->gpio_npins; i++) { 263 if (sc->gpio_pins[i].gp_pin == pin) 264 break; 265 } 266 267 if (i >= sc->gpio_npins) 268 return (EINVAL); 269 270 GPIO_LOCK(sc); 271 *caps = sc->gpio_pins[i].gp_caps; 272 GPIO_UNLOCK(sc); 273 274 return (0); 275} 276 277static int 278socfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 279{ 280 struct socfpga_gpio_softc *sc; 281 int i; 282 283 sc = device_get_softc(dev); 284 for (i = 0; i < sc->gpio_npins; i++) { 285 if (sc->gpio_pins[i].gp_pin == pin) 286 break; 287 } 288 289 if (i >= sc->gpio_npins) 290 return (EINVAL); 291 292 GPIO_LOCK(sc); 293 *flags = sc->gpio_pins[i].gp_flags; 294 GPIO_UNLOCK(sc); 295 296 return (0); 297} 298 299static int 300socfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 301{ 302 struct socfpga_gpio_softc *sc; 303 int i; 304 305 sc = device_get_softc(dev); 306 for (i = 0; i < sc->gpio_npins; i++) { 307 if (sc->gpio_pins[i].gp_pin == pin) 308 break; 309 } 310 311 if (i >= sc->gpio_npins) 312 return (EINVAL); 313 314 GPIO_LOCK(sc); 315 *val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0; 316 GPIO_UNLOCK(sc); 317 318 return (0); 319} 320 321static int 322socfpga_gpio_pin_toggle(device_t dev, uint32_t pin) 323{ 324 struct socfpga_gpio_softc *sc; 325 int reg; 326 int i; 327 328 sc = device_get_softc(dev); 329 for (i = 0; i < sc->gpio_npins; i++) { 330 if (sc->gpio_pins[i].gp_pin == pin) 331 break; 332 } 333 334 if (i >= sc->gpio_npins) 335 return (EINVAL); 336 337 GPIO_LOCK(sc); 338 reg = READ4(sc, GPIO_SWPORTA_DR); 339 if (reg & (1 << i)) 340 reg &= ~(1 << i); 341 else 342 reg |= (1 << i); 343 WRITE4(sc, GPIO_SWPORTA_DR, reg); 344 GPIO_UNLOCK(sc); 345 346 return (0); 347} 348 349 350static void 351socfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc, 352 struct gpio_pin *pin, unsigned int flags) 353{ 354 int reg; 355 356 GPIO_LOCK(sc); 357 358 /* 359 * Manage input/output 360 */ 361 362 reg = READ4(sc, GPIO_SWPORTA_DDR); 363 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 364 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 365 if (flags & GPIO_PIN_OUTPUT) { 366 pin->gp_flags |= GPIO_PIN_OUTPUT; 367 reg |= (1 << pin->gp_pin); 368 } else { 369 pin->gp_flags |= GPIO_PIN_INPUT; 370 reg &= ~(1 << pin->gp_pin); 371 } 372 } 373 374 WRITE4(sc, GPIO_SWPORTA_DDR, reg); 375 GPIO_UNLOCK(sc); 376} 377 378 379static int 380socfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 381{ 382 struct socfpga_gpio_softc *sc; 383 int i; 384 385 sc = device_get_softc(dev); 386 for (i = 0; i < sc->gpio_npins; i++) { 387 if (sc->gpio_pins[i].gp_pin == pin) 388 break; 389 } 390 391 if (i >= sc->gpio_npins) 392 return (EINVAL); 393 394 socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 395 396 return (0); 397} 398 399static int 400socfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 401{ 402 struct socfpga_gpio_softc *sc; 403 int reg; 404 int i; 405 406 sc = device_get_softc(dev); 407 408 for (i = 0; i < sc->gpio_npins; i++) { 409 if (sc->gpio_pins[i].gp_pin == pin) 410 break; 411 } 412 413 if (i >= sc->gpio_npins) 414 return (EINVAL); 415 416 GPIO_LOCK(sc); 417 reg = READ4(sc, GPIO_SWPORTA_DR); 418 if (value) 419 reg |= (1 << i); 420 else 421 reg &= ~(1 << i); 422 WRITE4(sc, GPIO_SWPORTA_DR, reg); 423 GPIO_UNLOCK(sc); 424 425 return (0); 426} 427 428static device_method_t socfpga_gpio_methods[] = { 429 DEVMETHOD(device_probe, socfpga_gpio_probe), 430 DEVMETHOD(device_attach, socfpga_gpio_attach), 431 432 /* GPIO protocol */ 433 DEVMETHOD(gpio_get_bus, socfpga_gpio_get_bus), 434 DEVMETHOD(gpio_pin_max, socfpga_gpio_pin_max), 435 DEVMETHOD(gpio_pin_getname, socfpga_gpio_pin_getname), 436 DEVMETHOD(gpio_pin_getcaps, socfpga_gpio_pin_getcaps), 437 DEVMETHOD(gpio_pin_getflags, socfpga_gpio_pin_getflags), 438 DEVMETHOD(gpio_pin_get, socfpga_gpio_pin_get), 439 DEVMETHOD(gpio_pin_toggle, socfpga_gpio_pin_toggle), 440 DEVMETHOD(gpio_pin_setflags, socfpga_gpio_pin_setflags), 441 DEVMETHOD(gpio_pin_set, socfpga_gpio_pin_set), 442 { 0, 0 } 443}; 444 445static driver_t socfpga_gpio_driver = { 446 "gpio", 447 socfpga_gpio_methods, 448 sizeof(struct socfpga_gpio_softc), 449}; 450 451static devclass_t socfpga_gpio_devclass; 452 453DRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver, 454 socfpga_gpio_devclass, 0, 0); 455