zy7_gpio.c revision 249997
1/*- 2 * Copyright (C) 2013, Thomas Skibo. 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 are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * The names of contributors may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND 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 AUTHORS OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * 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 SUCH 25 * DAMAGE. 26 * 27 */ 28 29/* A GPIO driver for Xilinx Zynq-7000. 30 * 31 * The GPIO peripheral on Zynq allows controlling 114 general purpose I/Os. 32 * 33 * Pins 53-0 are sent to the MIO. Any MIO pins not used by a PS peripheral are 34 * available as a GPIO pin. Pins 64-127 are sent to the PL (FPGA) section of 35 * Zynq as EMIO signals. 36 * 37 * The hardware provides a way to use IOs as interrupt sources but the 38 * gpio framework doesn't seem to have hooks for this. 39 * 40 * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual. 41 * (v1.4) November 16, 2012. Xilinx doc UG585. GPIO is covered in 42 * chater 14. Register definitions are in appendix B.19. 43 */ 44 45#include <sys/cdefs.h> 46__FBSDID("$FreeBSD: head/sys/arm/xilinx/zy7_gpio.c 249997 2013-04-27 22:38:29Z wkoszek $"); 47 48#include <sys/param.h> 49#include <sys/systm.h> 50#include <sys/conf.h> 51#include <sys/bus.h> 52#include <sys/kernel.h> 53#include <sys/module.h> 54#include <sys/lock.h> 55#include <sys/mutex.h> 56#include <sys/resource.h> 57#include <sys/rman.h> 58#include <sys/gpio.h> 59 60#include <machine/bus.h> 61#include <machine/resource.h> 62#include <machine/stdarg.h> 63 64#include <dev/fdt/fdt_common.h> 65#include <dev/ofw/ofw_bus.h> 66#include <dev/ofw/ofw_bus_subr.h> 67 68#include "gpio_if.h" 69 70#define NUMBANKS 4 71#define MAXPIN (32*NUMBANKS) 72 73#define MIO_PIN 0 /* pins 0-53 go to MIO */ 74#define NUM_MIO_PINS 54 75#define EMIO_PIN 64 /* pins 64-127 go to PL */ 76#define NUM_EMIO_PINS 64 77 78#define VALID_PIN(u) (((u) >= MIO_PIN && (u) < MIO_PIN + NUM_MIO_PINS) || \ 79 ((u) >= EMIO_PIN && (u) < EMIO_PIN + NUM_EMIO_PINS)) 80 81#define ZGPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 82#define ZGPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 83#define ZGPIO_LOCK_INIT(sc) \ 84 mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ 85 "gpio", MTX_DEF) 86#define ZGPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 87 88struct zy7_gpio_softc { 89 device_t dev; 90 struct mtx sc_mtx; 91 struct resource *mem_res; /* Memory resource */ 92}; 93 94#define WR4(sc, off, val) bus_write_4((sc)->mem_res, (off), (val)) 95#define RD4(sc, off) bus_read_4((sc)->mem_res, (off)) 96 97 98/* Xilinx Zynq-7000 GPIO register definitions: 99 */ 100#define ZY7_GPIO_MASK_DATA_LSW(b) (0x0000+8*(b)) /* maskable wr lo */ 101#define ZY7_GPIO_MASK_DATA_MSW(b) (0x0004+8*(b)) /* maskable wr hi */ 102#define ZY7_GPIO_DATA(b) (0x0040+4*(b)) /* in/out data */ 103#define ZY7_GPIO_DATA_RO(b) (0x0060+4*(b)) /* input data */ 104 105#define ZY7_GPIO_DIRM(b) (0x0204+0x40*(b)) /* direction mode */ 106#define ZY7_GPIO_OEN(b) (0x0208+0x40*(b)) /* output enable */ 107#define ZY7_GPIO_INT_MASK(b) (0x020c+0x40*(b)) /* int mask */ 108#define ZY7_GPIO_INT_EN(b) (0x0210+0x40*(b)) /* int enable */ 109#define ZY7_GPIO_INT_DIS(b) (0x0214+0x40*(b)) /* int disable */ 110#define ZY7_GPIO_INT_STAT(b) (0x0218+0x40*(b)) /* int status */ 111#define ZY7_GPIO_INT_TYPE(b) (0x021c+0x40*(b)) /* int type */ 112#define ZY7_GPIO_INT_POLARITY(b) (0x0220+0x40*(b)) /* int polarity */ 113#define ZY7_GPIO_INT_ANY(b) (0x0224+0x40*(b)) /* any edge */ 114 115 116static int 117zy7_gpio_pin_max(device_t dev, int *maxpin) 118{ 119 120 *maxpin = MAXPIN; 121 return (0); 122} 123 124/* Get a specific pin's capabilities. */ 125static int 126zy7_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 127{ 128 129 if (!VALID_PIN(pin)) 130 return (EINVAL); 131 132 *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 133 134 return (0); 135} 136 137/* Get a specific pin's name. */ 138static int 139zy7_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 140{ 141 142 if (!VALID_PIN(pin)) 143 return (EINVAL); 144 145 if (pin < NUM_MIO_PINS) { 146 snprintf(name, GPIOMAXNAME, "MIO_%d", pin); 147 name[GPIOMAXNAME - 1] = '\0'; 148 } else { 149 snprintf(name, GPIOMAXNAME, "EMIO_%d", pin - EMIO_PIN); 150 name[GPIOMAXNAME - 1] = '\0'; 151 } 152 153 return (0); 154} 155 156/* Get a specific pin's current in/out/tri state. */ 157static int 158zy7_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 159{ 160 struct zy7_gpio_softc *sc = device_get_softc(dev); 161 162 if (!VALID_PIN(pin)) 163 return (EINVAL); 164 165 ZGPIO_LOCK(sc); 166 167 if ((RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) & (1 << (pin & 31))) != 0) { 168 /* output */ 169 if ((RD4(sc, ZY7_GPIO_OEN(pin >> 5)) & (1 << (pin & 31))) == 0) 170 *flags = (GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 171 else 172 *flags = GPIO_PIN_OUTPUT; 173 } else 174 /* input */ 175 *flags = GPIO_PIN_INPUT; 176 177 ZGPIO_UNLOCK(sc); 178 179 return (0); 180} 181 182/* Set a specific pin's in/out/tri state. */ 183static int 184zy7_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 185{ 186 struct zy7_gpio_softc *sc = device_get_softc(dev); 187 188 if (!VALID_PIN(pin)) 189 return (EINVAL); 190 191 ZGPIO_LOCK(sc); 192 193 if ((flags & GPIO_PIN_OUTPUT) != 0) { 194 /* Output. Set or reset OEN too. */ 195 WR4(sc, ZY7_GPIO_DIRM(pin >> 5), 196 RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) | (1 << (pin & 31))); 197 198 if ((flags & GPIO_PIN_TRISTATE) != 0) 199 WR4(sc, ZY7_GPIO_OEN(pin >> 5), 200 RD4(sc, ZY7_GPIO_OEN(pin >> 5)) & 201 ~(1 << (pin & 31))); 202 else 203 WR4(sc, ZY7_GPIO_OEN(pin >> 5), 204 RD4(sc, ZY7_GPIO_OEN(pin >> 5)) | 205 (1 << (pin & 31))); 206 } else { 207 /* Input. Turn off OEN. */ 208 WR4(sc, ZY7_GPIO_DIRM(pin >> 5), 209 RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) & ~(1 << (pin & 31))); 210 WR4(sc, ZY7_GPIO_OEN(pin >> 5), 211 RD4(sc, ZY7_GPIO_OEN(pin >> 5)) & ~(1 << (pin & 31))); 212 } 213 214 ZGPIO_UNLOCK(sc); 215 216 return (0); 217} 218 219/* Set a specific output pin's value. */ 220static int 221zy7_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 222{ 223 struct zy7_gpio_softc *sc = device_get_softc(dev); 224 225 if (!VALID_PIN(pin) || value > 1) 226 return (EINVAL); 227 228 /* Fancy register tricks allow atomic set or reset. */ 229 if ((pin & 16) != 0) 230 WR4(sc, ZY7_GPIO_MASK_DATA_MSW(pin >> 5), 231 (0xffff0000 ^ (0x10000 << (pin & 15))) | 232 (value << (pin & 15))); 233 else 234 WR4(sc, ZY7_GPIO_MASK_DATA_LSW(pin >> 5), 235 (0xffff0000 ^ (0x10000 << (pin & 15))) | 236 (value << (pin & 15))); 237 238 return (0); 239} 240 241/* Get a specific pin's input value. */ 242static int 243zy7_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 244{ 245 struct zy7_gpio_softc *sc = device_get_softc(dev); 246 247 if (!VALID_PIN(pin)) 248 return (EINVAL); 249 250 *value = (RD4(sc, ZY7_GPIO_DATA_RO(pin >> 5)) >> (pin & 31)) & 1; 251 252 return (0); 253} 254 255/* Toggle a pin's output value. */ 256static int 257zy7_gpio_pin_toggle(device_t dev, uint32_t pin) 258{ 259 struct zy7_gpio_softc *sc = device_get_softc(dev); 260 261 if (!VALID_PIN(pin)) 262 return (EINVAL); 263 264 ZGPIO_LOCK(sc); 265 266 WR4(sc, ZY7_GPIO_DATA(pin >> 5), 267 RD4(sc, ZY7_GPIO_DATA(pin >> 5)) ^ (1 << (pin & 31))); 268 269 ZGPIO_UNLOCK(sc); 270 271 return (0); 272} 273 274static int 275zy7_gpio_probe(device_t dev) 276{ 277 278 if (!ofw_bus_is_compatible(dev, "xlnx,zy7_gpio")) 279 return (ENXIO); 280 281 device_set_desc(dev, "Zynq-7000 GPIO driver"); 282 return (0); 283} 284 285static void 286zy7_gpio_hw_reset(struct zy7_gpio_softc *sc) 287{ 288 int i; 289 290 for (i = 0; i < NUMBANKS; i++) { 291 WR4(sc, ZY7_GPIO_DATA(i), 0); 292 WR4(sc, ZY7_GPIO_DIRM(i), 0); 293 WR4(sc, ZY7_GPIO_OEN(i), 0); 294 WR4(sc, ZY7_GPIO_INT_DIS(i), 0xffffffff); 295 WR4(sc, ZY7_GPIO_INT_POLARITY(i), 0); 296 WR4(sc, ZY7_GPIO_INT_TYPE(i), 297 i == 1 ? 0x003fffff : 0xffffffff); 298 WR4(sc, ZY7_GPIO_INT_ANY(i), 0); 299 WR4(sc, ZY7_GPIO_INT_STAT(i), 0xffffffff); 300 } 301} 302 303static int zy7_gpio_detach(device_t dev); 304 305static int 306zy7_gpio_attach(device_t dev) 307{ 308 struct zy7_gpio_softc *sc = device_get_softc(dev); 309 int rid; 310 311 sc->dev = dev; 312 313 ZGPIO_LOCK_INIT(sc); 314 315 /* Allocate memory. */ 316 rid = 0; 317 sc->mem_res = bus_alloc_resource_any(dev, 318 SYS_RES_MEMORY, &rid, RF_ACTIVE); 319 if (sc->mem_res == NULL) { 320 device_printf(dev, "Can't allocate memory for device"); 321 zy7_gpio_detach(dev); 322 return (ENOMEM); 323 } 324 325 /* Completely reset. */ 326 zy7_gpio_hw_reset(sc); 327 328 device_add_child(dev, "gpioc", device_get_unit(dev)); 329 device_add_child(dev, "gpiobus", device_get_unit(dev)); 330 331 return (bus_generic_attach(dev)); 332} 333 334static int 335zy7_gpio_detach(device_t dev) 336{ 337 struct zy7_gpio_softc *sc = device_get_softc(dev); 338 339 bus_generic_detach(dev); 340 341 if (sc->mem_res != NULL) { 342 /* Release memory resource. */ 343 bus_release_resource(dev, SYS_RES_MEMORY, 344 rman_get_rid(sc->mem_res), sc->mem_res); 345 } 346 347 ZGPIO_LOCK_DESTROY(sc); 348 349 return (0); 350} 351 352static device_method_t zy7_gpio_methods[] = { 353 /* device_if */ 354 DEVMETHOD(device_probe, zy7_gpio_probe), 355 DEVMETHOD(device_attach, zy7_gpio_attach), 356 DEVMETHOD(device_detach, zy7_gpio_detach), 357 358 /* GPIO protocol */ 359 DEVMETHOD(gpio_pin_max, zy7_gpio_pin_max), 360 DEVMETHOD(gpio_pin_getname, zy7_gpio_pin_getname), 361 DEVMETHOD(gpio_pin_getflags, zy7_gpio_pin_getflags), 362 DEVMETHOD(gpio_pin_getcaps, zy7_gpio_pin_getcaps), 363 DEVMETHOD(gpio_pin_setflags, zy7_gpio_pin_setflags), 364 DEVMETHOD(gpio_pin_get, zy7_gpio_pin_get), 365 DEVMETHOD(gpio_pin_set, zy7_gpio_pin_set), 366 DEVMETHOD(gpio_pin_toggle, zy7_gpio_pin_toggle), 367 368 DEVMETHOD_END 369}; 370 371static driver_t zy7_gpio_driver = { 372 "zy7_gpio", 373 zy7_gpio_methods, 374 sizeof(struct zy7_gpio_softc), 375}; 376static devclass_t zy7_gpio_devclass; 377 378extern devclass_t gpiobus_devclass, gpioc_devclass; 379extern driver_t gpiobus_driver, gpioc_driver; 380 381DRIVER_MODULE(zy7_gpio, simplebus, zy7_gpio_driver, zy7_gpio_devclass, \ 382 NULL, NULL); 383DRIVER_MODULE(gpiobus, zy7_gpio, gpiobus_driver, gpiobus_devclass, 0, 0); 384DRIVER_MODULE(gpioc, zy7_gpio, gpioc_driver, gpioc_devclass, 0, 0); 385