1296936Smmel/*- 2296936Smmel * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3296936Smmel * All rights reserved. 4296936Smmel * 5296936Smmel * Redistribution and use in source and binary forms, with or without 6296936Smmel * modification, are permitted provided that the following conditions 7296936Smmel * are met: 8296936Smmel * 1. Redistributions of source code must retain the above copyright 9296936Smmel * notice, this list of conditions and the following disclaimer. 10296936Smmel * 2. Redistributions in binary form must reproduce the above copyright 11296936Smmel * notice, this list of conditions and the following disclaimer in the 12296936Smmel * documentation and/or other materials provided with the distribution. 13296936Smmel * 14296936Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15296936Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16296936Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17296936Smmel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18296936Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19296936Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20296936Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21296936Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22296936Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23296936Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24296936Smmel * SUCH DAMAGE. 25296936Smmel */ 26296936Smmel 27296936Smmel#include <sys/cdefs.h> 28296936Smmel__FBSDID("$FreeBSD: stable/11/sys/arm/nvidia/tegra_gpio.c 308335 2016-11-05 10:56:32Z mmel $"); 29296936Smmel 30296936Smmel/* 31296936Smmel * Tegra GPIO driver. 32296936Smmel */ 33298742Smmel#include "opt_platform.h" 34296936Smmel#include <sys/param.h> 35296936Smmel#include <sys/systm.h> 36296936Smmel#include <sys/bus.h> 37298742Smmel#include <sys/gpio.h> 38296936Smmel#include <sys/kernel.h> 39298742Smmel#include <sys/proc.h> 40296936Smmel#include <sys/rman.h> 41296936Smmel#include <sys/lock.h> 42298742Smmel#include <sys/module.h> 43296936Smmel#include <sys/mutex.h> 44296936Smmel 45296936Smmel#include <machine/bus.h> 46298742Smmel#include <machine/intr.h> 47296936Smmel#include <machine/resource.h> 48296936Smmel 49296936Smmel#include <dev/fdt/fdt_common.h> 50296936Smmel#include <dev/gpio/gpiobusvar.h> 51296936Smmel#include <dev/ofw/openfirm.h> 52296936Smmel#include <dev/ofw/ofw_bus.h> 53296936Smmel#include <dev/ofw/ofw_bus_subr.h> 54296936Smmel 55298742Smmel#include "pic_if.h" 56296936Smmel 57298742Smmel#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) 58298742Smmel#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 59298742Smmel#define GPIO_LOCK_INIT(_sc) mtx_init(&_sc->mtx, \ 60298742Smmel device_get_nameunit(_sc->dev), "tegra_gpio", MTX_DEF) 61298742Smmel#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx); 62298742Smmel#define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED); 63298742Smmel#define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED); 64296936Smmel 65296936Smmel#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) 66296936Smmel#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) 67296936Smmel 68296936Smmel#define GPIO_BANK_OFFS 0x100 /* Bank offset */ 69296936Smmel#define GPIO_NUM_BANKS 8 /* Total number per bank */ 70296936Smmel#define GPIO_REGS_IN_BANK 4 /* Total registers in bank */ 71296936Smmel#define GPIO_PINS_IN_REG 8 /* Total pin in register */ 72296936Smmel 73296936Smmel#define GPIO_BANKNUM(n) ((n) / (GPIO_REGS_IN_BANK * GPIO_PINS_IN_REG)) 74296936Smmel#define GPIO_PORTNUM(n) (((n) / GPIO_PINS_IN_REG) % GPIO_REGS_IN_BANK) 75296936Smmel#define GPIO_BIT(n) ((n) % GPIO_PINS_IN_REG) 76296936Smmel 77296936Smmel#define GPIO_REGNUM(n) (GPIO_BANKNUM(n) * GPIO_BANK_OFFS + \ 78296936Smmel GPIO_PORTNUM(n) * 4) 79296936Smmel 80296936Smmel#define NGPIO ((GPIO_NUM_BANKS * GPIO_REGS_IN_BANK * GPIO_PINS_IN_REG) - 8) 81296936Smmel 82296936Smmel/* Register offsets */ 83296936Smmel#define GPIO_CNF 0x00 84296936Smmel#define GPIO_OE 0x10 85296936Smmel#define GPIO_OUT 0x20 86296936Smmel#define GPIO_IN 0x30 87296936Smmel#define GPIO_INT_STA 0x40 88296936Smmel#define GPIO_INT_ENB 0x50 89296936Smmel#define GPIO_INT_LVL 0x60 90298742Smmel#define GPIO_INT_LVL_DELTA (1 << 16) 91298742Smmel#define GPIO_INT_LVL_EDGE (1 << 8) 92298742Smmel#define GPIO_INT_LVL_HIGH (1 << 0) 93298742Smmel#define GPIO_INT_LVL_MASK (GPIO_INT_LVL_DELTA | \ 94298742Smmel GPIO_INT_LVL_EDGE | GPIO_INT_LVL_HIGH) 95296936Smmel#define GPIO_INT_CLR 0x70 96296936Smmel#define GPIO_MSK_CNF 0x80 97296936Smmel#define GPIO_MSK_OE 0x90 98296936Smmel#define GPIO_MSK_OUT 0xA0 99296936Smmel#define GPIO_MSK_INT_STA 0xC0 100296936Smmel#define GPIO_MSK_INT_ENB 0xD0 101296936Smmel#define GPIO_MSK_INT_LVL 0xE0 102296936Smmel 103296936Smmelchar *tegra_gpio_port_names[] = { 104296936Smmel "A", "B", "C", "D", /* Bank 0 */ 105296936Smmel "E", "F", "G", "H", /* Bank 1 */ 106296936Smmel "I", "J", "K", "L", /* Bank 2 */ 107296936Smmel "M", "N", "O", "P", /* Bank 3 */ 108296936Smmel "Q", "R", "S", "T", /* Bank 4 */ 109296936Smmel "U", "V", "W", "X", /* Bank 5 */ 110298742Smmel "Y", "Z", "AA", "BB", /* Bank 6 */ 111298742Smmel "CC", "DD", "EE" /* Bank 7 */ 112296936Smmel}; 113296936Smmel 114298742Smmelstruct tegra_gpio_irqsrc { 115298742Smmel struct intr_irqsrc isrc; 116298742Smmel u_int irq; 117298742Smmel uint32_t cfgreg; 118298742Smmel}; 119298742Smmel 120298742Smmelstruct tegra_gpio_softc; 121298742Smmelstruct tegra_gpio_irq_cookie { 122298742Smmel struct tegra_gpio_softc *sc; 123298742Smmel int bank_num; 124298742Smmel}; 125298742Smmel 126296936Smmelstruct tegra_gpio_softc { 127296936Smmel device_t dev; 128298742Smmel device_t busdev; 129298742Smmel struct mtx mtx; 130296936Smmel struct resource *mem_res; 131298742Smmel struct resource *irq_res[GPIO_NUM_BANKS]; 132298742Smmel void *irq_ih[GPIO_NUM_BANKS]; 133298742Smmel struct tegra_gpio_irq_cookie irq_cookies[GPIO_NUM_BANKS]; 134296936Smmel int gpio_npins; 135296936Smmel struct gpio_pin gpio_pins[NGPIO]; 136298742Smmel struct tegra_gpio_irqsrc *isrcs; 137296936Smmel}; 138296936Smmel 139296936Smmelstatic struct ofw_compat_data compat_data[] = { 140296936Smmel {"nvidia,tegra124-gpio", 1}, 141296936Smmel {NULL, 0} 142296936Smmel}; 143296936Smmel 144298742Smmel/* -------------------------------------------------------------------------- 145298742Smmel * 146298742Smmel * GPIO 147298742Smmel * 148298742Smmel */ 149296936Smmelstatic inline void 150296936Smmelgpio_write_masked(struct tegra_gpio_softc *sc, bus_size_t reg, 151296936Smmel struct gpio_pin *pin, uint32_t val) 152296936Smmel{ 153296936Smmel uint32_t tmp; 154296936Smmel int bit; 155296936Smmel 156296936Smmel bit = GPIO_BIT(pin->gp_pin); 157296936Smmel tmp = 0x100 << bit; /* mask */ 158296936Smmel tmp |= (val & 1) << bit; /* value */ 159296936Smmel bus_write_4(sc->mem_res, reg + GPIO_REGNUM(pin->gp_pin), tmp); 160296936Smmel} 161298742Smmel 162296936Smmelstatic inline uint32_t 163296936Smmelgpio_read(struct tegra_gpio_softc *sc, bus_size_t reg, struct gpio_pin *pin) 164296936Smmel{ 165296936Smmel int bit; 166296936Smmel uint32_t val; 167296936Smmel 168296936Smmel bit = GPIO_BIT(pin->gp_pin); 169296936Smmel val = bus_read_4(sc->mem_res, reg + GPIO_REGNUM(pin->gp_pin)); 170296936Smmel return (val >> bit) & 1; 171296936Smmel} 172296936Smmel 173296936Smmelstatic void 174296936Smmeltegra_gpio_pin_configure(struct tegra_gpio_softc *sc, struct gpio_pin *pin, 175296936Smmel unsigned int flags) 176296936Smmel{ 177296936Smmel 178296936Smmel if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 0) 179296936Smmel return; 180296936Smmel 181296936Smmel /* Manage input/output */ 182296936Smmel pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); 183296936Smmel if (flags & GPIO_PIN_OUTPUT) { 184296936Smmel pin->gp_flags |= GPIO_PIN_OUTPUT; 185296936Smmel gpio_write_masked(sc, GPIO_MSK_OE, pin, 1); 186296936Smmel } else { 187296936Smmel pin->gp_flags |= GPIO_PIN_INPUT; 188296936Smmel gpio_write_masked(sc, GPIO_MSK_OE, pin, 0); 189296936Smmel } 190296936Smmel} 191296936Smmel 192296936Smmelstatic device_t 193296936Smmeltegra_gpio_get_bus(device_t dev) 194296936Smmel{ 195296936Smmel struct tegra_gpio_softc *sc; 196296936Smmel 197296936Smmel sc = device_get_softc(dev); 198298742Smmel return (sc->busdev); 199296936Smmel} 200296936Smmel 201296936Smmelstatic int 202296936Smmeltegra_gpio_pin_max(device_t dev, int *maxpin) 203296936Smmel{ 204296936Smmel 205296936Smmel *maxpin = NGPIO - 1; 206296936Smmel return (0); 207296936Smmel} 208296936Smmel 209296936Smmelstatic int 210296936Smmeltegra_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 211296936Smmel{ 212296936Smmel struct tegra_gpio_softc *sc; 213296936Smmel 214296936Smmel sc = device_get_softc(dev); 215296936Smmel if (pin >= sc->gpio_npins) 216296936Smmel return (EINVAL); 217296936Smmel 218296936Smmel GPIO_LOCK(sc); 219296936Smmel *caps = sc->gpio_pins[pin].gp_caps; 220296936Smmel GPIO_UNLOCK(sc); 221296936Smmel 222296936Smmel return (0); 223296936Smmel} 224296936Smmel 225296936Smmelstatic int 226296936Smmeltegra_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 227296936Smmel{ 228296936Smmel struct tegra_gpio_softc *sc; 229296936Smmel int cnf; 230296936Smmel 231296936Smmel sc = device_get_softc(dev); 232296936Smmel if (pin >= sc->gpio_npins) 233296936Smmel return (EINVAL); 234296936Smmel 235296936Smmel GPIO_LOCK(sc); 236296936Smmel cnf = gpio_read(sc, GPIO_CNF, &sc->gpio_pins[pin]); 237296936Smmel if (cnf == 0) { 238296936Smmel GPIO_UNLOCK(sc); 239296936Smmel return (ENXIO); 240296936Smmel } 241296936Smmel *flags = sc->gpio_pins[pin].gp_flags; 242296936Smmel GPIO_UNLOCK(sc); 243296936Smmel 244296936Smmel return (0); 245296936Smmel} 246296936Smmel 247296936Smmelstatic int 248296936Smmeltegra_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 249296936Smmel{ 250296936Smmel struct tegra_gpio_softc *sc; 251296936Smmel 252296936Smmel sc = device_get_softc(dev); 253296936Smmel if (pin >= sc->gpio_npins) 254296936Smmel return (EINVAL); 255296936Smmel 256296936Smmel GPIO_LOCK(sc); 257296936Smmel memcpy(name, sc->gpio_pins[pin].gp_name, GPIOMAXNAME); 258296936Smmel GPIO_UNLOCK(sc); 259296936Smmel 260296936Smmel return (0); 261296936Smmel} 262296936Smmel 263296936Smmelstatic int 264296936Smmeltegra_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 265296936Smmel{ 266296936Smmel struct tegra_gpio_softc *sc; 267296936Smmel int cnf; 268296936Smmel 269296936Smmel sc = device_get_softc(dev); 270296936Smmel if (pin >= sc->gpio_npins) 271296936Smmel return (EINVAL); 272296936Smmel 273296936Smmel GPIO_LOCK(sc); 274296936Smmel cnf = gpio_read(sc, GPIO_CNF, &sc->gpio_pins[pin]); 275296936Smmel if (cnf == 0) { 276296936Smmel /* XXX - allow this for while .... 277296936Smmel GPIO_UNLOCK(sc); 278296936Smmel return (ENXIO); 279296936Smmel */ 280296936Smmel gpio_write_masked(sc, GPIO_MSK_CNF, &sc->gpio_pins[pin], 1); 281296936Smmel } 282296936Smmel tegra_gpio_pin_configure(sc, &sc->gpio_pins[pin], flags); 283296936Smmel GPIO_UNLOCK(sc); 284296936Smmel 285296936Smmel return (0); 286296936Smmel} 287296936Smmel 288296936Smmelstatic int 289296936Smmeltegra_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 290296936Smmel{ 291296936Smmel struct tegra_gpio_softc *sc; 292296936Smmel 293296936Smmel sc = device_get_softc(dev); 294296936Smmel if (pin >= sc->gpio_npins) 295296936Smmel return (EINVAL); 296296936Smmel GPIO_LOCK(sc); 297296936Smmel gpio_write_masked(sc, GPIO_MSK_OUT, &sc->gpio_pins[pin], value); 298296936Smmel GPIO_UNLOCK(sc); 299296936Smmel 300296936Smmel return (0); 301296936Smmel} 302296936Smmel 303296936Smmelstatic int 304296936Smmeltegra_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 305296936Smmel{ 306296936Smmel struct tegra_gpio_softc *sc; 307296936Smmel 308296936Smmel sc = device_get_softc(dev); 309296936Smmel if (pin >= sc->gpio_npins) 310296936Smmel return (EINVAL); 311296936Smmel 312296936Smmel GPIO_LOCK(sc); 313296936Smmel *val = gpio_read(sc, GPIO_IN, &sc->gpio_pins[pin]); 314296936Smmel GPIO_UNLOCK(sc); 315296936Smmel 316296936Smmel return (0); 317296936Smmel} 318296936Smmel 319296936Smmelstatic int 320296936Smmeltegra_gpio_pin_toggle(device_t dev, uint32_t pin) 321296936Smmel{ 322296936Smmel struct tegra_gpio_softc *sc; 323296936Smmel 324296936Smmel sc = device_get_softc(dev); 325296936Smmel if (pin >= sc->gpio_npins) 326296936Smmel return (EINVAL); 327296936Smmel 328296936Smmel GPIO_LOCK(sc); 329296936Smmel gpio_write_masked(sc, GPIO_MSK_OE, &sc->gpio_pins[pin], 330296936Smmel gpio_read(sc, GPIO_IN, &sc->gpio_pins[pin]) ^ 1); 331296936Smmel GPIO_UNLOCK(sc); 332296936Smmel 333296936Smmel return (0); 334296936Smmel} 335296936Smmel 336298742Smmel/* -------------------------------------------------------------------------- 337298742Smmel * 338298742Smmel * Interrupts 339298742Smmel * 340298742Smmel */ 341298742Smmelstatic inline void 342298742Smmelintr_write_masked(struct tegra_gpio_softc *sc, bus_addr_t reg, 343298742Smmel struct tegra_gpio_irqsrc *tgi, uint32_t val) 344298742Smmel{ 345298742Smmel uint32_t tmp; 346298742Smmel int bit; 347298742Smmel 348298742Smmel bit = GPIO_BIT(tgi->irq); 349298742Smmel tmp = 0x100 << bit; /* mask */ 350298742Smmel tmp |= (val & 1) << bit; /* value */ 351298742Smmel bus_write_4(sc->mem_res, reg + GPIO_REGNUM(tgi->irq), tmp); 352298742Smmel} 353298742Smmel 354298742Smmelstatic inline void 355298742Smmelintr_write_modify(struct tegra_gpio_softc *sc, bus_addr_t reg, 356298742Smmel struct tegra_gpio_irqsrc *tgi, uint32_t val, uint32_t mask) 357298742Smmel{ 358298742Smmel uint32_t tmp; 359298742Smmel int bit; 360298742Smmel 361298742Smmel bit = GPIO_BIT(tgi->irq); 362298742Smmel GPIO_LOCK(sc); 363298742Smmel tmp = bus_read_4(sc->mem_res, reg + GPIO_REGNUM(tgi->irq)); 364298742Smmel tmp &= ~(mask << bit); 365298742Smmel tmp |= val << bit; 366298742Smmel bus_write_4(sc->mem_res, reg + GPIO_REGNUM(tgi->irq), tmp); 367298742Smmel GPIO_UNLOCK(sc); 368298742Smmel} 369298742Smmel 370298742Smmelstatic inline void 371298742Smmeltegra_gpio_isrc_mask(struct tegra_gpio_softc *sc, 372298742Smmel struct tegra_gpio_irqsrc *tgi, uint32_t val) 373298742Smmel{ 374298742Smmel 375298742Smmel intr_write_masked(sc, GPIO_MSK_INT_ENB, tgi, val); 376298742Smmel} 377298742Smmel 378298742Smmelstatic inline void 379298742Smmeltegra_gpio_isrc_eoi(struct tegra_gpio_softc *sc, 380298742Smmel struct tegra_gpio_irqsrc *tgi) 381298742Smmel{ 382298742Smmel 383298742Smmel intr_write_masked(sc, GPIO_INT_CLR, tgi, 1); 384298742Smmel} 385298742Smmel 386298742Smmelstatic inline bool 387298742Smmeltegra_gpio_isrc_is_level(struct tegra_gpio_irqsrc *tgi) 388298742Smmel{ 389298742Smmel 390298742Smmel return (tgi->cfgreg & GPIO_INT_LVL_EDGE); 391298742Smmel} 392298742Smmel 393296936Smmelstatic int 394296936Smmeltegra_gpio_intr(void *arg) 395296936Smmel{ 396298742Smmel u_int irq, i, j, val, basepin; 397296936Smmel struct tegra_gpio_softc *sc; 398298742Smmel struct trapframe *tf; 399298742Smmel struct tegra_gpio_irqsrc *tgi; 400298742Smmel struct tegra_gpio_irq_cookie *cookie; 401296936Smmel 402298742Smmel cookie = (struct tegra_gpio_irq_cookie *)arg; 403298742Smmel sc = cookie->sc; 404298742Smmel tf = curthread->td_intr_frame; 405298742Smmel 406298742Smmel for (i = 0; i < GPIO_REGS_IN_BANK; i++) { 407298742Smmel basepin = cookie->bank_num * GPIO_REGS_IN_BANK * 408298742Smmel GPIO_PINS_IN_REG + i * GPIO_PINS_IN_REG; 409298742Smmel 410298742Smmel val = bus_read_4(sc->mem_res, GPIO_INT_STA + 411298742Smmel GPIO_REGNUM(basepin)); 412298742Smmel val &= bus_read_4(sc->mem_res, GPIO_INT_ENB + 413298742Smmel GPIO_REGNUM(basepin)); 414296936Smmel /* Interrupt handling */ 415296936Smmel for (j = 0; j < GPIO_PINS_IN_REG; j++) { 416298742Smmel if ((val & (1 << j)) == 0) 417298742Smmel continue; 418298742Smmel irq = basepin + j; 419298742Smmel tgi = &sc->isrcs[irq]; 420298742Smmel if (!tegra_gpio_isrc_is_level(tgi)) 421298742Smmel tegra_gpio_isrc_eoi(sc, tgi); 422298742Smmel if (intr_isrc_dispatch(&tgi->isrc, tf) != 0) { 423298742Smmel tegra_gpio_isrc_mask(sc, tgi, 0); 424298742Smmel if (tegra_gpio_isrc_is_level(tgi)) 425298742Smmel tegra_gpio_isrc_eoi(sc, tgi); 426298742Smmel device_printf(sc->dev, 427298742Smmel "Stray irq %u disabled\n", irq); 428298742Smmel } 429298742Smmel 430296936Smmel } 431296936Smmel } 432298742Smmel 433296936Smmel return (FILTER_HANDLED); 434296936Smmel} 435296936Smmel 436296936Smmelstatic int 437298742Smmeltegra_gpio_pic_attach(struct tegra_gpio_softc *sc) 438298742Smmel{ 439298742Smmel int error; 440298742Smmel uint32_t irq; 441298742Smmel const char *name; 442298742Smmel 443298742Smmel sc->isrcs = malloc(sizeof(*sc->isrcs) * sc->gpio_npins, M_DEVBUF, 444298742Smmel M_WAITOK | M_ZERO); 445298742Smmel 446298742Smmel name = device_get_nameunit(sc->dev); 447298742Smmel for (irq = 0; irq < sc->gpio_npins; irq++) { 448298742Smmel sc->isrcs[irq].irq = irq; 449298742Smmel sc->isrcs[irq].cfgreg = 0; 450298742Smmel error = intr_isrc_register(&sc->isrcs[irq].isrc, 451298742Smmel sc->dev, 0, "%s,%u", name, irq); 452298742Smmel if (error != 0) 453298742Smmel return (error); /* XXX deregister ISRCs */ 454298742Smmel } 455300149Sandrew if (intr_pic_register(sc->dev, 456300149Sandrew OF_xref_from_node(ofw_bus_get_node(sc->dev))) == NULL) 457300149Sandrew return (ENXIO); 458300149Sandrew 459300149Sandrew return (0); 460298742Smmel} 461298742Smmel 462298742Smmelstatic int 463298742Smmeltegra_gpio_pic_detach(struct tegra_gpio_softc *sc) 464298742Smmel{ 465298742Smmel 466298742Smmel /* 467298742Smmel * There has not been established any procedure yet 468298742Smmel * how to detach PIC from living system correctly. 469298742Smmel */ 470298742Smmel device_printf(sc->dev, "%s: not implemented yet\n", __func__); 471298742Smmel return (EBUSY); 472298742Smmel} 473298742Smmel 474298742Smmel 475298742Smmelstatic void 476298742Smmeltegra_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 477298742Smmel{ 478298742Smmel struct tegra_gpio_softc *sc; 479298742Smmel struct tegra_gpio_irqsrc *tgi; 480298742Smmel 481298742Smmel sc = device_get_softc(dev); 482298742Smmel tgi = (struct tegra_gpio_irqsrc *)isrc; 483298742Smmel tegra_gpio_isrc_mask(sc, tgi, 0); 484298742Smmel} 485298742Smmel 486298742Smmelstatic void 487298742Smmeltegra_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 488298742Smmel{ 489298742Smmel struct tegra_gpio_softc *sc; 490298742Smmel struct tegra_gpio_irqsrc *tgi; 491298742Smmel 492298742Smmel sc = device_get_softc(dev); 493298742Smmel tgi = (struct tegra_gpio_irqsrc *)isrc; 494298742Smmel tegra_gpio_isrc_mask(sc, tgi, 1); 495298742Smmel} 496298742Smmel 497298742Smmelstatic int 498298742Smmeltegra_gpio_pic_map_fdt(struct tegra_gpio_softc *sc, u_int ncells, 499298742Smmel pcell_t *cells, u_int *irqp, uint32_t *regp) 500298742Smmel{ 501298742Smmel uint32_t reg; 502298742Smmel 503298742Smmel /* 504298742Smmel * The first cell is the interrupt number. 505298742Smmel * The second cell is used to specify flags: 506298742Smmel * bits[3:0] trigger type and level flags: 507298742Smmel * 1 = low-to-high edge triggered. 508298742Smmel * 2 = high-to-low edge triggered. 509298742Smmel * 4 = active high level-sensitive. 510298742Smmel * 8 = active low level-sensitive. 511298742Smmel */ 512298742Smmel if (ncells != 2 || cells[0] >= sc->gpio_npins) 513298742Smmel return (EINVAL); 514298742Smmel 515298742Smmel /* 516298742Smmel * All interrupt types could be set for an interrupt at one moment. 517298742Smmel * At least, the combination of 'low-to-high' and 'high-to-low' edge 518298742Smmel * triggered interrupt types can make a sense. 519298742Smmel */ 520298742Smmel if (cells[1] == 1) 521298742Smmel reg = GPIO_INT_LVL_EDGE | GPIO_INT_LVL_HIGH; 522298742Smmel else if (cells[1] == 2) 523298742Smmel reg = GPIO_INT_LVL_EDGE; 524298742Smmel else if (cells[1] == 3) 525298742Smmel reg = GPIO_INT_LVL_EDGE | GPIO_INT_LVL_DELTA; 526298742Smmel else if (cells[1] == 4) 527298742Smmel reg = GPIO_INT_LVL_HIGH; 528298742Smmel else if (cells[1] == 8) 529298742Smmel reg = 0; 530298742Smmel else 531298742Smmel return (EINVAL); 532298742Smmel 533298742Smmel *irqp = cells[0]; 534298742Smmel if (regp != NULL) 535298742Smmel *regp = reg; 536298742Smmel return (0); 537298742Smmel} 538298742Smmel 539298742Smmel 540298742Smmelstatic int 541298742Smmeltegra_gpio_pic_map_gpio(struct tegra_gpio_softc *sc, u_int gpio_pin_num, 542298742Smmel u_int gpio_pin_flags, u_int intr_mode, u_int *irqp, uint32_t *regp) 543298742Smmel{ 544298742Smmel 545298742Smmel uint32_t reg; 546298742Smmel 547298742Smmel if (gpio_pin_num >= sc->gpio_npins) 548298742Smmel return (EINVAL); 549298742Smmel switch (intr_mode) { 550298742Smmel case GPIO_INTR_CONFORM: 551298742Smmel case GPIO_INTR_LEVEL_LOW: 552298742Smmel reg = 0; 553298742Smmel break; 554298742Smmel case GPIO_INTR_LEVEL_HIGH: 555298742Smmel reg = GPIO_INT_LVL_HIGH; 556298742Smmel break; 557298742Smmel case GPIO_INTR_EDGE_RISING: 558298742Smmel reg = GPIO_INT_LVL_EDGE | GPIO_INT_LVL_HIGH; 559298742Smmel break; 560298742Smmel case GPIO_INTR_EDGE_FALLING: 561298742Smmel reg = GPIO_INT_LVL_EDGE; 562298742Smmel break; 563298742Smmel case GPIO_INTR_EDGE_BOTH: 564298742Smmel reg = GPIO_INT_LVL_EDGE | GPIO_INT_LVL_DELTA; 565298742Smmel break; 566298742Smmel default: 567298742Smmel return (EINVAL); 568298742Smmel } 569298742Smmel *irqp = gpio_pin_num; 570298742Smmel if (regp != NULL) 571298742Smmel *regp = reg; 572298742Smmel return (0); 573298742Smmel} 574298742Smmel 575298742Smmelstatic int 576298742Smmeltegra_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, 577298742Smmel struct intr_irqsrc **isrcp) 578298742Smmel{ 579298742Smmel int rv; 580298742Smmel u_int irq; 581298742Smmel struct tegra_gpio_softc *sc; 582298742Smmel 583298742Smmel sc = device_get_softc(dev); 584298742Smmel 585299117Sskra if (data->type == INTR_MAP_DATA_FDT) { 586299117Sskra struct intr_map_data_fdt *daf; 587299117Sskra 588299117Sskra daf = (struct intr_map_data_fdt *)data; 589299117Sskra rv = tegra_gpio_pic_map_fdt(sc, daf->ncells, daf->cells, &irq, 590299117Sskra NULL); 591299117Sskra } else if (data->type == INTR_MAP_DATA_GPIO) { 592299117Sskra struct intr_map_data_gpio *dag; 593299117Sskra 594299117Sskra dag = (struct intr_map_data_gpio *)data; 595299117Sskra rv = tegra_gpio_pic_map_gpio(sc, dag->gpio_pin_num, 596299117Sskra dag->gpio_pin_flags, dag->gpio_intr_mode, &irq, NULL); 597299117Sskra } else 598298742Smmel return (ENOTSUP); 599298742Smmel 600298742Smmel if (rv == 0) 601298742Smmel *isrcp = &sc->isrcs[irq].isrc; 602298742Smmel return (rv); 603298742Smmel} 604298742Smmel 605298742Smmelstatic void 606298742Smmeltegra_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) 607298742Smmel{ 608298742Smmel struct tegra_gpio_softc *sc; 609298742Smmel struct tegra_gpio_irqsrc *tgi; 610298742Smmel 611298742Smmel sc = device_get_softc(dev); 612298742Smmel tgi = (struct tegra_gpio_irqsrc *)isrc; 613298742Smmel if (tegra_gpio_isrc_is_level(tgi)) 614298742Smmel tegra_gpio_isrc_eoi(sc, tgi); 615298742Smmel} 616298742Smmel 617298742Smmelstatic void 618298742Smmeltegra_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 619298742Smmel{ 620298742Smmel struct tegra_gpio_softc *sc; 621298742Smmel struct tegra_gpio_irqsrc *tgi; 622298742Smmel 623298742Smmel sc = device_get_softc(dev); 624298742Smmel tgi = (struct tegra_gpio_irqsrc *)isrc; 625298742Smmel tegra_gpio_isrc_mask(sc, tgi, 1); 626298742Smmel} 627298742Smmel 628298742Smmelstatic void 629298742Smmeltegra_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 630298742Smmel{ 631298742Smmel struct tegra_gpio_softc *sc; 632298742Smmel struct tegra_gpio_irqsrc *tgi; 633298742Smmel 634298742Smmel sc = device_get_softc(dev); 635298742Smmel tgi = (struct tegra_gpio_irqsrc *)isrc; 636298742Smmel 637298742Smmel tegra_gpio_isrc_mask(sc, tgi, 0); 638298742Smmel if (tegra_gpio_isrc_is_level(tgi)) 639298742Smmel tegra_gpio_isrc_eoi(sc, tgi); 640298742Smmel} 641298742Smmel 642298742Smmelstatic int 643298742Smmeltegra_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, 644298742Smmel struct resource *res, struct intr_map_data *data) 645298742Smmel{ 646298742Smmel u_int irq; 647298742Smmel uint32_t cfgreg; 648298742Smmel int rv; 649298742Smmel struct tegra_gpio_softc *sc; 650298742Smmel struct tegra_gpio_irqsrc *tgi; 651298742Smmel 652298742Smmel sc = device_get_softc(dev); 653298742Smmel tgi = (struct tegra_gpio_irqsrc *)isrc; 654298742Smmel 655298742Smmel if (data == NULL) 656298742Smmel return (ENOTSUP); 657298742Smmel 658298742Smmel /* Get and check config for an interrupt. */ 659299117Sskra if (data->type == INTR_MAP_DATA_FDT) { 660299117Sskra struct intr_map_data_fdt *daf; 661299117Sskra 662299117Sskra daf = (struct intr_map_data_fdt *)data; 663299117Sskra rv = tegra_gpio_pic_map_fdt(sc, daf->ncells, daf->cells, &irq, 664299117Sskra &cfgreg); 665299117Sskra } else if (data->type == INTR_MAP_DATA_GPIO) { 666299117Sskra struct intr_map_data_gpio *dag; 667299117Sskra 668299117Sskra dag = (struct intr_map_data_gpio *)data; 669299117Sskra rv = tegra_gpio_pic_map_gpio(sc, dag->gpio_pin_num, 670299117Sskra dag->gpio_pin_flags, dag->gpio_intr_mode, &irq, &cfgreg); 671299117Sskra } else 672298742Smmel return (ENOTSUP); 673298742Smmel if (rv != 0) 674298742Smmel return (EINVAL); 675298742Smmel 676298742Smmel /* 677298742Smmel * If this is a setup for another handler, 678298742Smmel * only check that its configuration match. 679298742Smmel */ 680298742Smmel if (isrc->isrc_handlers != 0) 681298742Smmel return (tgi->cfgreg == cfgreg ? 0 : EINVAL); 682298742Smmel 683298742Smmel tgi->cfgreg = cfgreg; 684298742Smmel intr_write_modify(sc, GPIO_INT_LVL, tgi, cfgreg, GPIO_INT_LVL_MASK); 685298742Smmel tegra_gpio_pic_enable_intr(dev, isrc); 686298742Smmel 687298742Smmel return (0); 688298742Smmel} 689298742Smmel 690298742Smmelstatic int 691298742Smmeltegra_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 692298742Smmel struct resource *res, struct intr_map_data *data) 693298742Smmel{ 694298742Smmel struct tegra_gpio_softc *sc; 695298742Smmel struct tegra_gpio_irqsrc *tgi; 696298742Smmel 697298742Smmel sc = device_get_softc(dev); 698298742Smmel tgi = (struct tegra_gpio_irqsrc *)isrc; 699298742Smmel 700298742Smmel if (isrc->isrc_handlers == 0) 701298742Smmel tegra_gpio_isrc_mask(sc, tgi, 0); 702298742Smmel return (0); 703298742Smmel} 704298742Smmel 705298742Smmelstatic int 706296936Smmeltegra_gpio_probe(device_t dev) 707296936Smmel{ 708296936Smmel 709296936Smmel if (!ofw_bus_status_okay(dev)) 710296936Smmel return (ENXIO); 711296936Smmel if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 712296936Smmel device_set_desc(dev, "Tegra GPIO Controller"); 713296936Smmel return (BUS_PROBE_DEFAULT); 714296936Smmel } 715296936Smmel 716296936Smmel return (ENXIO); 717296936Smmel} 718296936Smmel 719298742Smmel/* -------------------------------------------------------------------------- 720298742Smmel * 721298742Smmel * Bus 722298742Smmel * 723298742Smmel */ 724296936Smmelstatic int 725296936Smmeltegra_gpio_detach(device_t dev) 726296936Smmel{ 727296936Smmel struct tegra_gpio_softc *sc; 728298742Smmel int i; 729296936Smmel 730296936Smmel sc = device_get_softc(dev); 731296936Smmel 732298742Smmel KASSERT(mtx_initialized(&sc->mtx), ("gpio mutex not initialized")); 733296936Smmel 734298742Smmel for (i = 0; i < GPIO_NUM_BANKS; i++) { 735298742Smmel if (sc->irq_ih[i] != NULL) 736298742Smmel bus_teardown_intr(dev, sc->irq_res[i], sc->irq_ih[i]); 737298742Smmel } 738298742Smmel 739298742Smmel if (sc->isrcs != NULL) 740298742Smmel tegra_gpio_pic_detach(sc); 741298742Smmel 742296936Smmel gpiobus_detach_bus(dev); 743298742Smmel 744298742Smmel for (i = 0; i < GPIO_NUM_BANKS; i++) { 745298742Smmel if (sc->irq_res[i] != NULL) 746298742Smmel bus_release_resource(dev, SYS_RES_IRQ, 0, 747298742Smmel sc->irq_res[i]); 748298742Smmel } 749296936Smmel if (sc->mem_res != NULL) 750296936Smmel bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 751298742Smmel GPIO_LOCK_DESTROY(sc); 752296936Smmel 753296936Smmel return(0); 754296936Smmel} 755296936Smmel 756296936Smmelstatic int 757296936Smmeltegra_gpio_attach(device_t dev) 758296936Smmel{ 759296936Smmel struct tegra_gpio_softc *sc; 760296936Smmel int i, rid; 761296936Smmel 762296936Smmel sc = device_get_softc(dev); 763298742Smmel sc->dev = dev; 764298742Smmel GPIO_LOCK_INIT(sc); 765296936Smmel 766296936Smmel /* Allocate bus_space resources. */ 767296936Smmel rid = 0; 768296936Smmel sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 769296936Smmel RF_ACTIVE); 770296936Smmel if (sc->mem_res == NULL) { 771296936Smmel device_printf(dev, "Cannot allocate memory resources\n"); 772296936Smmel tegra_gpio_detach(dev); 773296936Smmel return (ENXIO); 774296936Smmel } 775296936Smmel 776296936Smmel sc->gpio_npins = NGPIO; 777296936Smmel for (i = 0; i < sc->gpio_npins; i++) { 778296936Smmel sc->gpio_pins[i].gp_pin = i; 779298742Smmel sc->gpio_pins[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | 780298742Smmel GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH | 781298742Smmel GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | 782298742Smmel GPIO_INTR_EDGE_BOTH; 783296936Smmel snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "gpio_%s.%d", 784296936Smmel tegra_gpio_port_names[ i / GPIO_PINS_IN_REG], 785296936Smmel i % GPIO_PINS_IN_REG); 786296936Smmel sc->gpio_pins[i].gp_flags = 787296936Smmel gpio_read(sc, GPIO_OE, &sc->gpio_pins[i]) != 0 ? 788296936Smmel GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; 789296936Smmel } 790296936Smmel 791298742Smmel /* Init interrupt related registes. */ 792298742Smmel for (i = 0; i < sc->gpio_npins; i += GPIO_PINS_IN_REG) { 793298742Smmel bus_write_4(sc->mem_res, GPIO_INT_ENB + GPIO_REGNUM(i), 0); 794298742Smmel bus_write_4(sc->mem_res, GPIO_INT_STA + GPIO_REGNUM(i), 0xFF); 795298742Smmel bus_write_4(sc->mem_res, GPIO_INT_CLR + GPIO_REGNUM(i), 0xFF); 796298742Smmel } 797298742Smmel 798298742Smmel /* Allocate interrupts. */ 799298742Smmel for (i = 0; i < GPIO_NUM_BANKS; i++) { 800298742Smmel sc->irq_cookies[i].sc = sc; 801298742Smmel sc->irq_cookies[i].bank_num = i; 802298742Smmel rid = i; 803298742Smmel sc->irq_res[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ, 804298742Smmel &rid, RF_ACTIVE); 805298742Smmel if (sc->irq_res[i] == NULL) { 806298742Smmel device_printf(dev, "Cannot allocate IRQ resources\n"); 807298742Smmel tegra_gpio_detach(dev); 808298742Smmel return (ENXIO); 809298742Smmel } 810298742Smmel if ((bus_setup_intr(dev, sc->irq_res[i], 811298742Smmel INTR_TYPE_MISC | INTR_MPSAFE, tegra_gpio_intr, NULL, 812298742Smmel &sc->irq_cookies[i], &sc->irq_ih[i]))) { 813298742Smmel device_printf(dev, 814298742Smmel "WARNING: unable to register interrupt handler\n"); 815298742Smmel tegra_gpio_detach(dev); 816298742Smmel return (ENXIO); 817298742Smmel } 818298742Smmel } 819298742Smmel 820298742Smmel if (tegra_gpio_pic_attach(sc) != 0) { 821298742Smmel device_printf(dev, "WARNING: unable to attach PIC\n"); 822296936Smmel tegra_gpio_detach(dev); 823296936Smmel return (ENXIO); 824296936Smmel } 825296936Smmel 826298742Smmel sc->busdev = gpiobus_attach_bus(dev); 827298742Smmel if (sc->busdev == NULL) { 828298742Smmel tegra_gpio_detach(dev); 829298742Smmel return (ENXIO); 830298742Smmel } 831298742Smmel 832296936Smmel return (bus_generic_attach(dev)); 833296936Smmel} 834296936Smmel 835296936Smmelstatic int 836296936Smmeltegra_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent, 837296936Smmel int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) 838296936Smmel{ 839296936Smmel 840296936Smmel if (gcells != 2) 841296936Smmel return (ERANGE); 842296936Smmel *pin = gpios[0]; 843296936Smmel *flags= gpios[1]; 844296936Smmel return (0); 845296936Smmel} 846296936Smmel 847296936Smmelstatic phandle_t 848296936Smmeltegra_gpio_get_node(device_t bus, device_t dev) 849296936Smmel{ 850296936Smmel 851296936Smmel /* We only have one child, the GPIO bus, which needs our own node. */ 852296936Smmel return (ofw_bus_get_node(bus)); 853296936Smmel} 854296936Smmel 855296936Smmelstatic device_method_t tegra_gpio_methods[] = { 856296936Smmel DEVMETHOD(device_probe, tegra_gpio_probe), 857296936Smmel DEVMETHOD(device_attach, tegra_gpio_attach), 858296936Smmel DEVMETHOD(device_detach, tegra_gpio_detach), 859296936Smmel 860298742Smmel /* Interrupt controller interface */ 861298742Smmel DEVMETHOD(pic_disable_intr, tegra_gpio_pic_disable_intr), 862298742Smmel DEVMETHOD(pic_enable_intr, tegra_gpio_pic_enable_intr), 863298742Smmel DEVMETHOD(pic_map_intr, tegra_gpio_pic_map_intr), 864298742Smmel DEVMETHOD(pic_setup_intr, tegra_gpio_pic_setup_intr), 865298742Smmel DEVMETHOD(pic_teardown_intr, tegra_gpio_pic_teardown_intr), 866298742Smmel DEVMETHOD(pic_post_filter, tegra_gpio_pic_post_filter), 867298742Smmel DEVMETHOD(pic_post_ithread, tegra_gpio_pic_post_ithread), 868298742Smmel DEVMETHOD(pic_pre_ithread, tegra_gpio_pic_pre_ithread), 869298742Smmel 870296936Smmel /* GPIO protocol */ 871296936Smmel DEVMETHOD(gpio_get_bus, tegra_gpio_get_bus), 872296936Smmel DEVMETHOD(gpio_pin_max, tegra_gpio_pin_max), 873296936Smmel DEVMETHOD(gpio_pin_getname, tegra_gpio_pin_getname), 874296936Smmel DEVMETHOD(gpio_pin_getflags, tegra_gpio_pin_getflags), 875296936Smmel DEVMETHOD(gpio_pin_getcaps, tegra_gpio_pin_getcaps), 876296936Smmel DEVMETHOD(gpio_pin_setflags, tegra_gpio_pin_setflags), 877296936Smmel DEVMETHOD(gpio_pin_get, tegra_gpio_pin_get), 878296936Smmel DEVMETHOD(gpio_pin_set, tegra_gpio_pin_set), 879296936Smmel DEVMETHOD(gpio_pin_toggle, tegra_gpio_pin_toggle), 880296936Smmel DEVMETHOD(gpio_map_gpios, tegra_map_gpios), 881296936Smmel 882296936Smmel /* ofw_bus interface */ 883296936Smmel DEVMETHOD(ofw_bus_get_node, tegra_gpio_get_node), 884296936Smmel 885296936Smmel DEVMETHOD_END 886296936Smmel}; 887296936Smmel 888296936Smmelstatic devclass_t tegra_gpio_devclass; 889308335Smmelstatic DEFINE_CLASS_0(gpio, tegra_gpio_driver, tegra_gpio_methods, 890308335Smmel sizeof(struct tegra_gpio_softc)); 891296936SmmelEARLY_DRIVER_MODULE(tegra_gpio, simplebus, tegra_gpio_driver, 892308335Smmel tegra_gpio_devclass, NULL, NULL, 70); 893