1*8ce574deSOleksandr Tymoshenko /*- 2*8ce574deSOleksandr Tymoshenko * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*8ce574deSOleksandr Tymoshenko * 4*8ce574deSOleksandr Tymoshenko * Copyright (c) 2018 Advanced Micro Devices 5*8ce574deSOleksandr Tymoshenko * All rights reserved. 6*8ce574deSOleksandr Tymoshenko * 7*8ce574deSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 8*8ce574deSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 9*8ce574deSOleksandr Tymoshenko * are met: 10*8ce574deSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 11*8ce574deSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 12*8ce574deSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 13*8ce574deSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 14*8ce574deSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 15*8ce574deSOleksandr Tymoshenko * 16*8ce574deSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*8ce574deSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*8ce574deSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*8ce574deSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*8ce574deSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*8ce574deSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*8ce574deSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*8ce574deSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*8ce574deSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*8ce574deSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*8ce574deSOleksandr Tymoshenko * SUCH DAMAGE. 27*8ce574deSOleksandr Tymoshenko */ 28*8ce574deSOleksandr Tymoshenko 29*8ce574deSOleksandr Tymoshenko #include <sys/cdefs.h> 30*8ce574deSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 31*8ce574deSOleksandr Tymoshenko 32*8ce574deSOleksandr Tymoshenko #include "opt_acpi.h" 33*8ce574deSOleksandr Tymoshenko 34*8ce574deSOleksandr Tymoshenko #include <sys/param.h> 35*8ce574deSOleksandr Tymoshenko #include <sys/systm.h> 36*8ce574deSOleksandr Tymoshenko #include <sys/bus.h> 37*8ce574deSOleksandr Tymoshenko #include <sys/gpio.h> 38*8ce574deSOleksandr Tymoshenko #include <sys/interrupt.h> 39*8ce574deSOleksandr Tymoshenko #include <sys/kernel.h> 40*8ce574deSOleksandr Tymoshenko #include <sys/lock.h> 41*8ce574deSOleksandr Tymoshenko #include <sys/module.h> 42*8ce574deSOleksandr Tymoshenko #include <sys/mutex.h> 43*8ce574deSOleksandr Tymoshenko #include <sys/proc.h> 44*8ce574deSOleksandr Tymoshenko #include <sys/rman.h> 45*8ce574deSOleksandr Tymoshenko #include <sys/sysctl.h> 46*8ce574deSOleksandr Tymoshenko 47*8ce574deSOleksandr Tymoshenko #include <machine/bus.h> 48*8ce574deSOleksandr Tymoshenko #include <machine/resource.h> 49*8ce574deSOleksandr Tymoshenko 50*8ce574deSOleksandr Tymoshenko #include <contrib/dev/acpica/include/acpi.h> 51*8ce574deSOleksandr Tymoshenko #include <contrib/dev/acpica/include/accommon.h> 52*8ce574deSOleksandr Tymoshenko 53*8ce574deSOleksandr Tymoshenko #include <dev/acpica/acpivar.h> 54*8ce574deSOleksandr Tymoshenko #include <dev/gpio/gpiobusvar.h> 55*8ce574deSOleksandr Tymoshenko 56*8ce574deSOleksandr Tymoshenko #include "gpio_if.h" 57*8ce574deSOleksandr Tymoshenko #include "amdgpio.h" 58*8ce574deSOleksandr Tymoshenko 59*8ce574deSOleksandr Tymoshenko static struct resource_spec amdgpio_spec[] = { 60*8ce574deSOleksandr Tymoshenko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 61*8ce574deSOleksandr Tymoshenko { -1, 0, 0 } 62*8ce574deSOleksandr Tymoshenko }; 63*8ce574deSOleksandr Tymoshenko 64*8ce574deSOleksandr Tymoshenko static inline uint32_t 65*8ce574deSOleksandr Tymoshenko amdgpio_read_4(struct amdgpio_softc *sc, bus_size_t off) 66*8ce574deSOleksandr Tymoshenko { 67*8ce574deSOleksandr Tymoshenko return (bus_read_4(sc->sc_res[0], off)); 68*8ce574deSOleksandr Tymoshenko } 69*8ce574deSOleksandr Tymoshenko 70*8ce574deSOleksandr Tymoshenko static inline void 71*8ce574deSOleksandr Tymoshenko amdgpio_write_4(struct amdgpio_softc *sc, bus_size_t off, 72*8ce574deSOleksandr Tymoshenko uint32_t val) 73*8ce574deSOleksandr Tymoshenko { 74*8ce574deSOleksandr Tymoshenko bus_write_4(sc->sc_res[0], off, val); 75*8ce574deSOleksandr Tymoshenko } 76*8ce574deSOleksandr Tymoshenko 77*8ce574deSOleksandr Tymoshenko static bool 78*8ce574deSOleksandr Tymoshenko amdgpio_is_pin_output(struct amdgpio_softc *sc, uint32_t pin) 79*8ce574deSOleksandr Tymoshenko { 80*8ce574deSOleksandr Tymoshenko uint32_t reg, val; 81*8ce574deSOleksandr Tymoshenko bool ret; 82*8ce574deSOleksandr Tymoshenko 83*8ce574deSOleksandr Tymoshenko /* Get the current pin state */ 84*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 85*8ce574deSOleksandr Tymoshenko 86*8ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 87*8ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 88*8ce574deSOleksandr Tymoshenko 89*8ce574deSOleksandr Tymoshenko if (val & BIT(OUTPUT_ENABLE_OFF)) 90*8ce574deSOleksandr Tymoshenko ret = true; 91*8ce574deSOleksandr Tymoshenko else 92*8ce574deSOleksandr Tymoshenko ret = false; 93*8ce574deSOleksandr Tymoshenko 94*8ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 95*8ce574deSOleksandr Tymoshenko 96*8ce574deSOleksandr Tymoshenko return (ret); 97*8ce574deSOleksandr Tymoshenko } 98*8ce574deSOleksandr Tymoshenko 99*8ce574deSOleksandr Tymoshenko static device_t 100*8ce574deSOleksandr Tymoshenko amdgpio_get_bus(device_t dev) 101*8ce574deSOleksandr Tymoshenko { 102*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 103*8ce574deSOleksandr Tymoshenko 104*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 105*8ce574deSOleksandr Tymoshenko 106*8ce574deSOleksandr Tymoshenko dprintf("busdev %p\n", sc->sc_busdev); 107*8ce574deSOleksandr Tymoshenko return (sc->sc_busdev); 108*8ce574deSOleksandr Tymoshenko } 109*8ce574deSOleksandr Tymoshenko 110*8ce574deSOleksandr Tymoshenko static int 111*8ce574deSOleksandr Tymoshenko amdgpio_pin_max(device_t dev, int *maxpin) 112*8ce574deSOleksandr Tymoshenko { 113*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 114*8ce574deSOleksandr Tymoshenko 115*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 116*8ce574deSOleksandr Tymoshenko 117*8ce574deSOleksandr Tymoshenko *maxpin = sc->sc_npins - 1; 118*8ce574deSOleksandr Tymoshenko dprintf("npins %d maxpin %d\n", sc->sc_npins, *maxpin); 119*8ce574deSOleksandr Tymoshenko 120*8ce574deSOleksandr Tymoshenko return (0); 121*8ce574deSOleksandr Tymoshenko } 122*8ce574deSOleksandr Tymoshenko 123*8ce574deSOleksandr Tymoshenko static bool 124*8ce574deSOleksandr Tymoshenko amdgpio_valid_pin(struct amdgpio_softc *sc, int pin) 125*8ce574deSOleksandr Tymoshenko { 126*8ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 127*8ce574deSOleksandr Tymoshenko if (sc->sc_res[0] == NULL) 128*8ce574deSOleksandr Tymoshenko return (false); 129*8ce574deSOleksandr Tymoshenko 130*8ce574deSOleksandr Tymoshenko if ((sc->sc_gpio_pins[pin].gp_pin == pin) && 131*8ce574deSOleksandr Tymoshenko (sc->sc_gpio_pins[pin].gp_caps != 0)) 132*8ce574deSOleksandr Tymoshenko return (true); 133*8ce574deSOleksandr Tymoshenko 134*8ce574deSOleksandr Tymoshenko return (false); 135*8ce574deSOleksandr Tymoshenko } 136*8ce574deSOleksandr Tymoshenko 137*8ce574deSOleksandr Tymoshenko static int 138*8ce574deSOleksandr Tymoshenko amdgpio_pin_getname(device_t dev, uint32_t pin, char *name) 139*8ce574deSOleksandr Tymoshenko { 140*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 141*8ce574deSOleksandr Tymoshenko 142*8ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 143*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 144*8ce574deSOleksandr Tymoshenko 145*8ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 146*8ce574deSOleksandr Tymoshenko return (EINVAL); 147*8ce574deSOleksandr Tymoshenko 148*8ce574deSOleksandr Tymoshenko /* Set a very simple name */ 149*8ce574deSOleksandr Tymoshenko snprintf(name, GPIOMAXNAME, "%s", sc->sc_gpio_pins[pin].gp_name); 150*8ce574deSOleksandr Tymoshenko name[GPIOMAXNAME - 1] = '\0'; 151*8ce574deSOleksandr Tymoshenko 152*8ce574deSOleksandr Tymoshenko dprintf("pin %d name %s\n", pin, name); 153*8ce574deSOleksandr Tymoshenko 154*8ce574deSOleksandr Tymoshenko return (0); 155*8ce574deSOleksandr Tymoshenko } 156*8ce574deSOleksandr Tymoshenko 157*8ce574deSOleksandr Tymoshenko static int 158*8ce574deSOleksandr Tymoshenko amdgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 159*8ce574deSOleksandr Tymoshenko { 160*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 161*8ce574deSOleksandr Tymoshenko 162*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 163*8ce574deSOleksandr Tymoshenko 164*8ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 165*8ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 166*8ce574deSOleksandr Tymoshenko return (EINVAL); 167*8ce574deSOleksandr Tymoshenko 168*8ce574deSOleksandr Tymoshenko *caps = sc->sc_gpio_pins[pin].gp_caps; 169*8ce574deSOleksandr Tymoshenko 170*8ce574deSOleksandr Tymoshenko dprintf("pin %d caps 0x%x\n", pin, *caps); 171*8ce574deSOleksandr Tymoshenko 172*8ce574deSOleksandr Tymoshenko return (0); 173*8ce574deSOleksandr Tymoshenko } 174*8ce574deSOleksandr Tymoshenko 175*8ce574deSOleksandr Tymoshenko static int 176*8ce574deSOleksandr Tymoshenko amdgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 177*8ce574deSOleksandr Tymoshenko { 178*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 179*8ce574deSOleksandr Tymoshenko 180*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 181*8ce574deSOleksandr Tymoshenko 182*8ce574deSOleksandr Tymoshenko 183*8ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 184*8ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 185*8ce574deSOleksandr Tymoshenko return (EINVAL); 186*8ce574deSOleksandr Tymoshenko 187*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 188*8ce574deSOleksandr Tymoshenko 189*8ce574deSOleksandr Tymoshenko *flags = sc->sc_gpio_pins[pin].gp_flags; 190*8ce574deSOleksandr Tymoshenko 191*8ce574deSOleksandr Tymoshenko dprintf("pin %d flags 0x%x\n", pin, *flags); 192*8ce574deSOleksandr Tymoshenko 193*8ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 194*8ce574deSOleksandr Tymoshenko 195*8ce574deSOleksandr Tymoshenko return (0); 196*8ce574deSOleksandr Tymoshenko } 197*8ce574deSOleksandr Tymoshenko 198*8ce574deSOleksandr Tymoshenko static int 199*8ce574deSOleksandr Tymoshenko amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 200*8ce574deSOleksandr Tymoshenko { 201*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 202*8ce574deSOleksandr Tymoshenko uint32_t reg, val, allowed; 203*8ce574deSOleksandr Tymoshenko 204*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 205*8ce574deSOleksandr Tymoshenko 206*8ce574deSOleksandr Tymoshenko dprintf("pin %d flags 0x%x\n", pin, flags); 207*8ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 208*8ce574deSOleksandr Tymoshenko return (EINVAL); 209*8ce574deSOleksandr Tymoshenko 210*8ce574deSOleksandr Tymoshenko allowed = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 211*8ce574deSOleksandr Tymoshenko 212*8ce574deSOleksandr Tymoshenko /* 213*8ce574deSOleksandr Tymoshenko * Only directtion flag allowed 214*8ce574deSOleksandr Tymoshenko */ 215*8ce574deSOleksandr Tymoshenko if (flags & ~allowed) 216*8ce574deSOleksandr Tymoshenko return (EINVAL); 217*8ce574deSOleksandr Tymoshenko 218*8ce574deSOleksandr Tymoshenko /* 219*8ce574deSOleksandr Tymoshenko * Not both directions simultaneously 220*8ce574deSOleksandr Tymoshenko */ 221*8ce574deSOleksandr Tymoshenko if ((flags & allowed) == allowed) 222*8ce574deSOleksandr Tymoshenko return (EINVAL); 223*8ce574deSOleksandr Tymoshenko 224*8ce574deSOleksandr Tymoshenko /* Set the GPIO mode and state */ 225*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 226*8ce574deSOleksandr Tymoshenko 227*8ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 228*8ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 229*8ce574deSOleksandr Tymoshenko 230*8ce574deSOleksandr Tymoshenko if (flags & GPIO_PIN_INPUT) { 231*8ce574deSOleksandr Tymoshenko val &= ~BIT(OUTPUT_ENABLE_OFF); 232*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_INPUT; 233*8ce574deSOleksandr Tymoshenko } else { 234*8ce574deSOleksandr Tymoshenko val |= BIT(OUTPUT_ENABLE_OFF); 235*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_OUTPUT; 236*8ce574deSOleksandr Tymoshenko } 237*8ce574deSOleksandr Tymoshenko 238*8ce574deSOleksandr Tymoshenko amdgpio_write_4(sc, reg, val); 239*8ce574deSOleksandr Tymoshenko 240*8ce574deSOleksandr Tymoshenko dprintf("pin %d flags 0x%x val 0x%x gp_flags 0x%x\n", 241*8ce574deSOleksandr Tymoshenko pin, flags, val, sc->sc_gpio_pins[pin].gp_flags); 242*8ce574deSOleksandr Tymoshenko 243*8ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 244*8ce574deSOleksandr Tymoshenko 245*8ce574deSOleksandr Tymoshenko return (0); 246*8ce574deSOleksandr Tymoshenko } 247*8ce574deSOleksandr Tymoshenko 248*8ce574deSOleksandr Tymoshenko static int 249*8ce574deSOleksandr Tymoshenko amdgpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 250*8ce574deSOleksandr Tymoshenko { 251*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 252*8ce574deSOleksandr Tymoshenko uint32_t reg, val; 253*8ce574deSOleksandr Tymoshenko 254*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 255*8ce574deSOleksandr Tymoshenko 256*8ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 257*8ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 258*8ce574deSOleksandr Tymoshenko return (EINVAL); 259*8ce574deSOleksandr Tymoshenko 260*8ce574deSOleksandr Tymoshenko *value = 0; 261*8ce574deSOleksandr Tymoshenko 262*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 263*8ce574deSOleksandr Tymoshenko 264*8ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 265*8ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 266*8ce574deSOleksandr Tymoshenko 267*8ce574deSOleksandr Tymoshenko if (val & BIT(OUTPUT_VALUE_OFF)) 268*8ce574deSOleksandr Tymoshenko *value = GPIO_PIN_HIGH; 269*8ce574deSOleksandr Tymoshenko else 270*8ce574deSOleksandr Tymoshenko *value = GPIO_PIN_LOW; 271*8ce574deSOleksandr Tymoshenko 272*8ce574deSOleksandr Tymoshenko dprintf("pin %d value 0x%x\n", pin, *value); 273*8ce574deSOleksandr Tymoshenko 274*8ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 275*8ce574deSOleksandr Tymoshenko 276*8ce574deSOleksandr Tymoshenko return (0); 277*8ce574deSOleksandr Tymoshenko } 278*8ce574deSOleksandr Tymoshenko 279*8ce574deSOleksandr Tymoshenko static int 280*8ce574deSOleksandr Tymoshenko amdgpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 281*8ce574deSOleksandr Tymoshenko { 282*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 283*8ce574deSOleksandr Tymoshenko uint32_t reg, val; 284*8ce574deSOleksandr Tymoshenko 285*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 286*8ce574deSOleksandr Tymoshenko 287*8ce574deSOleksandr Tymoshenko dprintf("pin %d value 0x%x\n", pin, value); 288*8ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 289*8ce574deSOleksandr Tymoshenko return (EINVAL); 290*8ce574deSOleksandr Tymoshenko 291*8ce574deSOleksandr Tymoshenko if (!amdgpio_is_pin_output(sc, pin)) 292*8ce574deSOleksandr Tymoshenko return (EINVAL); 293*8ce574deSOleksandr Tymoshenko 294*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 295*8ce574deSOleksandr Tymoshenko 296*8ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 297*8ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 298*8ce574deSOleksandr Tymoshenko 299*8ce574deSOleksandr Tymoshenko if (value == GPIO_PIN_LOW) 300*8ce574deSOleksandr Tymoshenko val &= ~BIT(OUTPUT_VALUE_OFF); 301*8ce574deSOleksandr Tymoshenko else 302*8ce574deSOleksandr Tymoshenko val |= BIT(OUTPUT_VALUE_OFF); 303*8ce574deSOleksandr Tymoshenko 304*8ce574deSOleksandr Tymoshenko amdgpio_write_4(sc, reg, val); 305*8ce574deSOleksandr Tymoshenko 306*8ce574deSOleksandr Tymoshenko dprintf("pin %d value 0x%x val 0x%x\n", pin, value, val); 307*8ce574deSOleksandr Tymoshenko 308*8ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 309*8ce574deSOleksandr Tymoshenko 310*8ce574deSOleksandr Tymoshenko return (0); 311*8ce574deSOleksandr Tymoshenko } 312*8ce574deSOleksandr Tymoshenko 313*8ce574deSOleksandr Tymoshenko static int 314*8ce574deSOleksandr Tymoshenko amdgpio_pin_toggle(device_t dev, uint32_t pin) 315*8ce574deSOleksandr Tymoshenko { 316*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 317*8ce574deSOleksandr Tymoshenko uint32_t reg, val; 318*8ce574deSOleksandr Tymoshenko 319*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 320*8ce574deSOleksandr Tymoshenko 321*8ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 322*8ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 323*8ce574deSOleksandr Tymoshenko return (EINVAL); 324*8ce574deSOleksandr Tymoshenko 325*8ce574deSOleksandr Tymoshenko if (!amdgpio_is_pin_output(sc, pin)) 326*8ce574deSOleksandr Tymoshenko return (EINVAL); 327*8ce574deSOleksandr Tymoshenko 328*8ce574deSOleksandr Tymoshenko /* Toggle the pin */ 329*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 330*8ce574deSOleksandr Tymoshenko 331*8ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 332*8ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 333*8ce574deSOleksandr Tymoshenko dprintf("pin %d value before 0x%x\n", pin, val); 334*8ce574deSOleksandr Tymoshenko val = val ^ BIT(OUTPUT_VALUE_OFF); 335*8ce574deSOleksandr Tymoshenko dprintf("pin %d value after 0x%x\n", pin, val); 336*8ce574deSOleksandr Tymoshenko amdgpio_write_4(sc, reg, val); 337*8ce574deSOleksandr Tymoshenko 338*8ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 339*8ce574deSOleksandr Tymoshenko 340*8ce574deSOleksandr Tymoshenko return (0); 341*8ce574deSOleksandr Tymoshenko } 342*8ce574deSOleksandr Tymoshenko 343*8ce574deSOleksandr Tymoshenko static int 344*8ce574deSOleksandr Tymoshenko amdgpio_probe(device_t dev) 345*8ce574deSOleksandr Tymoshenko { 346*8ce574deSOleksandr Tymoshenko static char *gpio_ids[] = { "AMD0030", "AMDI0030", NULL }; 347*8ce574deSOleksandr Tymoshenko 348*8ce574deSOleksandr Tymoshenko if (acpi_disabled("gpio") || 349*8ce574deSOleksandr Tymoshenko ACPI_ID_PROBE(device_get_parent(dev), dev, gpio_ids) == NULL) 350*8ce574deSOleksandr Tymoshenko return (ENXIO); 351*8ce574deSOleksandr Tymoshenko 352*8ce574deSOleksandr Tymoshenko device_set_desc(dev, "AMD GPIO Controller"); 353*8ce574deSOleksandr Tymoshenko return (0); 354*8ce574deSOleksandr Tymoshenko } 355*8ce574deSOleksandr Tymoshenko 356*8ce574deSOleksandr Tymoshenko static int 357*8ce574deSOleksandr Tymoshenko amdgpio_attach(device_t dev) 358*8ce574deSOleksandr Tymoshenko { 359*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 360*8ce574deSOleksandr Tymoshenko int i, pin, bank; 361*8ce574deSOleksandr Tymoshenko 362*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 363*8ce574deSOleksandr Tymoshenko sc->sc_dev = dev; 364*8ce574deSOleksandr Tymoshenko sc->sc_handle = acpi_get_handle(dev); 365*8ce574deSOleksandr Tymoshenko 366*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK_INIT(sc); 367*8ce574deSOleksandr Tymoshenko 368*8ce574deSOleksandr Tymoshenko sc->sc_nbanks = AMD_GPIO_NUM_PIN_BANK; 369*8ce574deSOleksandr Tymoshenko sc->sc_npins = AMD_GPIO_PINS_MAX; 370*8ce574deSOleksandr Tymoshenko sc->sc_bank_prefix = AMD_GPIO_PREFIX; 371*8ce574deSOleksandr Tymoshenko sc->sc_pin_info = kernzp_pins; 372*8ce574deSOleksandr Tymoshenko sc->sc_ngroups = nitems(kernzp_groups); 373*8ce574deSOleksandr Tymoshenko sc->sc_groups = kernzp_groups; 374*8ce574deSOleksandr Tymoshenko 375*8ce574deSOleksandr Tymoshenko if (bus_alloc_resources(dev, amdgpio_spec, sc->sc_res)) { 376*8ce574deSOleksandr Tymoshenko device_printf(dev, "could not allocate resources\n"); 377*8ce574deSOleksandr Tymoshenko goto err_rsrc; 378*8ce574deSOleksandr Tymoshenko } 379*8ce574deSOleksandr Tymoshenko 380*8ce574deSOleksandr Tymoshenko sc->sc_bst = rman_get_bustag(sc->sc_res[0]); 381*8ce574deSOleksandr Tymoshenko sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); 382*8ce574deSOleksandr Tymoshenko 383*8ce574deSOleksandr Tymoshenko /* Initialize all possible pins to be Invalid */ 384*8ce574deSOleksandr Tymoshenko for (i = 0; i < AMD_GPIO_PINS_MAX ; i++) { 385*8ce574deSOleksandr Tymoshenko snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME, 386*8ce574deSOleksandr Tymoshenko "Unexposed PIN %d\n", i); 387*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[i].gp_pin = -1; 388*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[i].gp_caps = 0; 389*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[i].gp_flags = 0; 390*8ce574deSOleksandr Tymoshenko } 391*8ce574deSOleksandr Tymoshenko 392*8ce574deSOleksandr Tymoshenko /* Initialize only driver exposed pins with appropriate capabilities */ 393*8ce574deSOleksandr Tymoshenko for (i = 0; i < AMD_GPIO_PINS_EXPOSED ; i++) { 394*8ce574deSOleksandr Tymoshenko pin = kernzp_pins[i].pin_num; 395*8ce574deSOleksandr Tymoshenko bank = pin/AMD_GPIO_PINS_PER_BANK; 396*8ce574deSOleksandr Tymoshenko snprintf(sc->sc_gpio_pins[pin].gp_name, GPIOMAXNAME, "%s%d_%s\n", 397*8ce574deSOleksandr Tymoshenko AMD_GPIO_PREFIX, bank, kernzp_pins[i].pin_name); 398*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_pin = pin; 399*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_caps = AMDGPIO_DEFAULT_CAPS; 400*8ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_flags = (amdgpio_is_pin_output(sc, pin)? 401*8ce574deSOleksandr Tymoshenko GPIO_PIN_OUTPUT : GPIO_PIN_INPUT); 402*8ce574deSOleksandr Tymoshenko } 403*8ce574deSOleksandr Tymoshenko 404*8ce574deSOleksandr Tymoshenko sc->sc_busdev = gpiobus_attach_bus(dev); 405*8ce574deSOleksandr Tymoshenko if (sc->sc_busdev == NULL) { 406*8ce574deSOleksandr Tymoshenko device_printf(dev, "could not attach gpiobus\n"); 407*8ce574deSOleksandr Tymoshenko goto err_bus; 408*8ce574deSOleksandr Tymoshenko } 409*8ce574deSOleksandr Tymoshenko 410*8ce574deSOleksandr Tymoshenko return (0); 411*8ce574deSOleksandr Tymoshenko 412*8ce574deSOleksandr Tymoshenko err_bus: 413*8ce574deSOleksandr Tymoshenko bus_release_resources(dev, amdgpio_spec, sc->sc_res); 414*8ce574deSOleksandr Tymoshenko 415*8ce574deSOleksandr Tymoshenko err_rsrc: 416*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK_DESTROY(sc); 417*8ce574deSOleksandr Tymoshenko 418*8ce574deSOleksandr Tymoshenko return (ENXIO); 419*8ce574deSOleksandr Tymoshenko } 420*8ce574deSOleksandr Tymoshenko 421*8ce574deSOleksandr Tymoshenko 422*8ce574deSOleksandr Tymoshenko static int 423*8ce574deSOleksandr Tymoshenko amdgpio_detach(device_t dev) 424*8ce574deSOleksandr Tymoshenko { 425*8ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 426*8ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 427*8ce574deSOleksandr Tymoshenko 428*8ce574deSOleksandr Tymoshenko if (sc->sc_busdev) 429*8ce574deSOleksandr Tymoshenko gpiobus_detach_bus(dev); 430*8ce574deSOleksandr Tymoshenko 431*8ce574deSOleksandr Tymoshenko bus_release_resources(dev, amdgpio_spec, sc->sc_res); 432*8ce574deSOleksandr Tymoshenko 433*8ce574deSOleksandr Tymoshenko AMDGPIO_LOCK_DESTROY(sc); 434*8ce574deSOleksandr Tymoshenko 435*8ce574deSOleksandr Tymoshenko return (0); 436*8ce574deSOleksandr Tymoshenko } 437*8ce574deSOleksandr Tymoshenko 438*8ce574deSOleksandr Tymoshenko static device_method_t amdgpio_methods[] = { 439*8ce574deSOleksandr Tymoshenko /* Device interface */ 440*8ce574deSOleksandr Tymoshenko DEVMETHOD(device_probe, amdgpio_probe), 441*8ce574deSOleksandr Tymoshenko DEVMETHOD(device_attach, amdgpio_attach), 442*8ce574deSOleksandr Tymoshenko DEVMETHOD(device_detach, amdgpio_detach), 443*8ce574deSOleksandr Tymoshenko 444*8ce574deSOleksandr Tymoshenko /* GPIO protocol */ 445*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_get_bus, amdgpio_get_bus), 446*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_max, amdgpio_pin_max), 447*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getname, amdgpio_pin_getname), 448*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getcaps, amdgpio_pin_getcaps), 449*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getflags, amdgpio_pin_getflags), 450*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_setflags, amdgpio_pin_setflags), 451*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_get, amdgpio_pin_get), 452*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_set, amdgpio_pin_set), 453*8ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_toggle, amdgpio_pin_toggle), 454*8ce574deSOleksandr Tymoshenko 455*8ce574deSOleksandr Tymoshenko DEVMETHOD_END 456*8ce574deSOleksandr Tymoshenko }; 457*8ce574deSOleksandr Tymoshenko 458*8ce574deSOleksandr Tymoshenko static driver_t amdgpio_driver = { 459*8ce574deSOleksandr Tymoshenko "gpio", 460*8ce574deSOleksandr Tymoshenko amdgpio_methods, 461*8ce574deSOleksandr Tymoshenko sizeof(struct amdgpio_softc), 462*8ce574deSOleksandr Tymoshenko }; 463*8ce574deSOleksandr Tymoshenko 464*8ce574deSOleksandr Tymoshenko static devclass_t amdgpio_devclass; 465*8ce574deSOleksandr Tymoshenko DRIVER_MODULE(amdgpio, acpi, amdgpio_driver, amdgpio_devclass, 0, 0); 466*8ce574deSOleksandr Tymoshenko MODULE_DEPEND(amdgpio, acpi, 1, 1, 1); 467*8ce574deSOleksandr Tymoshenko MODULE_DEPEND(amdgpio, gpiobus, 1, 1, 1); 468*8ce574deSOleksandr Tymoshenko MODULE_VERSION(amdgpio, 1); 469