18ce574deSOleksandr Tymoshenko /*- 28ce574deSOleksandr Tymoshenko * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38ce574deSOleksandr Tymoshenko * 48ce574deSOleksandr Tymoshenko * Copyright (c) 2018 Advanced Micro Devices 58ce574deSOleksandr Tymoshenko * All rights reserved. 68ce574deSOleksandr Tymoshenko * 78ce574deSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 88ce574deSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 98ce574deSOleksandr Tymoshenko * are met: 108ce574deSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 118ce574deSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 128ce574deSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 138ce574deSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 148ce574deSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 158ce574deSOleksandr Tymoshenko * 168ce574deSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 178ce574deSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188ce574deSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198ce574deSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 208ce574deSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 218ce574deSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228ce574deSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 238ce574deSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 248ce574deSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258ce574deSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268ce574deSOleksandr Tymoshenko * SUCH DAMAGE. 278ce574deSOleksandr Tymoshenko */ 288ce574deSOleksandr Tymoshenko 298ce574deSOleksandr Tymoshenko #include <sys/cdefs.h> 308ce574deSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 318ce574deSOleksandr Tymoshenko 328ce574deSOleksandr Tymoshenko #include "opt_acpi.h" 338ce574deSOleksandr Tymoshenko 348ce574deSOleksandr Tymoshenko #include <sys/param.h> 358ce574deSOleksandr Tymoshenko #include <sys/systm.h> 368ce574deSOleksandr Tymoshenko #include <sys/bus.h> 378ce574deSOleksandr Tymoshenko #include <sys/gpio.h> 388ce574deSOleksandr Tymoshenko #include <sys/interrupt.h> 398ce574deSOleksandr Tymoshenko #include <sys/kernel.h> 408ce574deSOleksandr Tymoshenko #include <sys/lock.h> 418ce574deSOleksandr Tymoshenko #include <sys/module.h> 428ce574deSOleksandr Tymoshenko #include <sys/mutex.h> 438ce574deSOleksandr Tymoshenko #include <sys/proc.h> 448ce574deSOleksandr Tymoshenko #include <sys/rman.h> 458ce574deSOleksandr Tymoshenko #include <sys/sysctl.h> 468ce574deSOleksandr Tymoshenko 478ce574deSOleksandr Tymoshenko #include <machine/bus.h> 488ce574deSOleksandr Tymoshenko #include <machine/resource.h> 498ce574deSOleksandr Tymoshenko 508ce574deSOleksandr Tymoshenko #include <contrib/dev/acpica/include/acpi.h> 518ce574deSOleksandr Tymoshenko #include <contrib/dev/acpica/include/accommon.h> 528ce574deSOleksandr Tymoshenko 538ce574deSOleksandr Tymoshenko #include <dev/acpica/acpivar.h> 548ce574deSOleksandr Tymoshenko #include <dev/gpio/gpiobusvar.h> 558ce574deSOleksandr Tymoshenko 568ce574deSOleksandr Tymoshenko #include "gpio_if.h" 578ce574deSOleksandr Tymoshenko #include "amdgpio.h" 588ce574deSOleksandr Tymoshenko 598ce574deSOleksandr Tymoshenko static struct resource_spec amdgpio_spec[] = { 608ce574deSOleksandr Tymoshenko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 618ce574deSOleksandr Tymoshenko { -1, 0, 0 } 628ce574deSOleksandr Tymoshenko }; 638ce574deSOleksandr Tymoshenko 648ce574deSOleksandr Tymoshenko static inline uint32_t 658ce574deSOleksandr Tymoshenko amdgpio_read_4(struct amdgpio_softc *sc, bus_size_t off) 668ce574deSOleksandr Tymoshenko { 678ce574deSOleksandr Tymoshenko return (bus_read_4(sc->sc_res[0], off)); 688ce574deSOleksandr Tymoshenko } 698ce574deSOleksandr Tymoshenko 708ce574deSOleksandr Tymoshenko static inline void 718ce574deSOleksandr Tymoshenko amdgpio_write_4(struct amdgpio_softc *sc, bus_size_t off, 728ce574deSOleksandr Tymoshenko uint32_t val) 738ce574deSOleksandr Tymoshenko { 748ce574deSOleksandr Tymoshenko bus_write_4(sc->sc_res[0], off, val); 758ce574deSOleksandr Tymoshenko } 768ce574deSOleksandr Tymoshenko 778ce574deSOleksandr Tymoshenko static bool 788ce574deSOleksandr Tymoshenko amdgpio_is_pin_output(struct amdgpio_softc *sc, uint32_t pin) 798ce574deSOleksandr Tymoshenko { 808ce574deSOleksandr Tymoshenko uint32_t reg, val; 818ce574deSOleksandr Tymoshenko bool ret; 828ce574deSOleksandr Tymoshenko 838ce574deSOleksandr Tymoshenko /* Get the current pin state */ 848ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 858ce574deSOleksandr Tymoshenko 868ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 878ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 888ce574deSOleksandr Tymoshenko 898ce574deSOleksandr Tymoshenko if (val & BIT(OUTPUT_ENABLE_OFF)) 908ce574deSOleksandr Tymoshenko ret = true; 918ce574deSOleksandr Tymoshenko else 928ce574deSOleksandr Tymoshenko ret = false; 938ce574deSOleksandr Tymoshenko 948ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 958ce574deSOleksandr Tymoshenko 968ce574deSOleksandr Tymoshenko return (ret); 978ce574deSOleksandr Tymoshenko } 988ce574deSOleksandr Tymoshenko 998ce574deSOleksandr Tymoshenko static device_t 1008ce574deSOleksandr Tymoshenko amdgpio_get_bus(device_t dev) 1018ce574deSOleksandr Tymoshenko { 1028ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 1038ce574deSOleksandr Tymoshenko 1048ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 1058ce574deSOleksandr Tymoshenko 1068ce574deSOleksandr Tymoshenko dprintf("busdev %p\n", sc->sc_busdev); 1078ce574deSOleksandr Tymoshenko return (sc->sc_busdev); 1088ce574deSOleksandr Tymoshenko } 1098ce574deSOleksandr Tymoshenko 1108ce574deSOleksandr Tymoshenko static int 1118ce574deSOleksandr Tymoshenko amdgpio_pin_max(device_t dev, int *maxpin) 1128ce574deSOleksandr Tymoshenko { 1138ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 1148ce574deSOleksandr Tymoshenko 1158ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 1168ce574deSOleksandr Tymoshenko 1178ce574deSOleksandr Tymoshenko *maxpin = sc->sc_npins - 1; 1188ce574deSOleksandr Tymoshenko dprintf("npins %d maxpin %d\n", sc->sc_npins, *maxpin); 1198ce574deSOleksandr Tymoshenko 1208ce574deSOleksandr Tymoshenko return (0); 1218ce574deSOleksandr Tymoshenko } 1228ce574deSOleksandr Tymoshenko 1238ce574deSOleksandr Tymoshenko static bool 1248ce574deSOleksandr Tymoshenko amdgpio_valid_pin(struct amdgpio_softc *sc, int pin) 1258ce574deSOleksandr Tymoshenko { 1268ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 1278ce574deSOleksandr Tymoshenko if (sc->sc_res[0] == NULL) 1288ce574deSOleksandr Tymoshenko return (false); 1298ce574deSOleksandr Tymoshenko 1308ce574deSOleksandr Tymoshenko if ((sc->sc_gpio_pins[pin].gp_pin == pin) && 1318ce574deSOleksandr Tymoshenko (sc->sc_gpio_pins[pin].gp_caps != 0)) 1328ce574deSOleksandr Tymoshenko return (true); 1338ce574deSOleksandr Tymoshenko 1348ce574deSOleksandr Tymoshenko return (false); 1358ce574deSOleksandr Tymoshenko } 1368ce574deSOleksandr Tymoshenko 1378ce574deSOleksandr Tymoshenko static int 1388ce574deSOleksandr Tymoshenko amdgpio_pin_getname(device_t dev, uint32_t pin, char *name) 1398ce574deSOleksandr Tymoshenko { 1408ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 1418ce574deSOleksandr Tymoshenko 1428ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 1438ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 1448ce574deSOleksandr Tymoshenko 1458ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 1468ce574deSOleksandr Tymoshenko return (EINVAL); 1478ce574deSOleksandr Tymoshenko 1488ce574deSOleksandr Tymoshenko /* Set a very simple name */ 1498ce574deSOleksandr Tymoshenko snprintf(name, GPIOMAXNAME, "%s", sc->sc_gpio_pins[pin].gp_name); 1508ce574deSOleksandr Tymoshenko name[GPIOMAXNAME - 1] = '\0'; 1518ce574deSOleksandr Tymoshenko 1528ce574deSOleksandr Tymoshenko dprintf("pin %d name %s\n", pin, name); 1538ce574deSOleksandr Tymoshenko 1548ce574deSOleksandr Tymoshenko return (0); 1558ce574deSOleksandr Tymoshenko } 1568ce574deSOleksandr Tymoshenko 1578ce574deSOleksandr Tymoshenko static int 1588ce574deSOleksandr Tymoshenko amdgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 1598ce574deSOleksandr Tymoshenko { 1608ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 1618ce574deSOleksandr Tymoshenko 1628ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 1638ce574deSOleksandr Tymoshenko 1648ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 1658ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 1668ce574deSOleksandr Tymoshenko return (EINVAL); 1678ce574deSOleksandr Tymoshenko 1688ce574deSOleksandr Tymoshenko *caps = sc->sc_gpio_pins[pin].gp_caps; 1698ce574deSOleksandr Tymoshenko 1708ce574deSOleksandr Tymoshenko dprintf("pin %d caps 0x%x\n", pin, *caps); 1718ce574deSOleksandr Tymoshenko 1728ce574deSOleksandr Tymoshenko return (0); 1738ce574deSOleksandr Tymoshenko } 1748ce574deSOleksandr Tymoshenko 1758ce574deSOleksandr Tymoshenko static int 1768ce574deSOleksandr Tymoshenko amdgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 1778ce574deSOleksandr Tymoshenko { 1788ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 1798ce574deSOleksandr Tymoshenko 1808ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 1818ce574deSOleksandr Tymoshenko 1828ce574deSOleksandr Tymoshenko 1838ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 1848ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 1858ce574deSOleksandr Tymoshenko return (EINVAL); 1868ce574deSOleksandr Tymoshenko 1878ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 1888ce574deSOleksandr Tymoshenko 1898ce574deSOleksandr Tymoshenko *flags = sc->sc_gpio_pins[pin].gp_flags; 1908ce574deSOleksandr Tymoshenko 1918ce574deSOleksandr Tymoshenko dprintf("pin %d flags 0x%x\n", pin, *flags); 1928ce574deSOleksandr Tymoshenko 1938ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 1948ce574deSOleksandr Tymoshenko 1958ce574deSOleksandr Tymoshenko return (0); 1968ce574deSOleksandr Tymoshenko } 1978ce574deSOleksandr Tymoshenko 1988ce574deSOleksandr Tymoshenko static int 1998ce574deSOleksandr Tymoshenko amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 2008ce574deSOleksandr Tymoshenko { 2018ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 2028ce574deSOleksandr Tymoshenko uint32_t reg, val, allowed; 2038ce574deSOleksandr Tymoshenko 2048ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 2058ce574deSOleksandr Tymoshenko 2068ce574deSOleksandr Tymoshenko dprintf("pin %d flags 0x%x\n", pin, flags); 2078ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 2088ce574deSOleksandr Tymoshenko return (EINVAL); 2098ce574deSOleksandr Tymoshenko 2108ce574deSOleksandr Tymoshenko allowed = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 2118ce574deSOleksandr Tymoshenko 2128ce574deSOleksandr Tymoshenko /* 2138ce574deSOleksandr Tymoshenko * Only directtion flag allowed 2148ce574deSOleksandr Tymoshenko */ 2158ce574deSOleksandr Tymoshenko if (flags & ~allowed) 2168ce574deSOleksandr Tymoshenko return (EINVAL); 2178ce574deSOleksandr Tymoshenko 2188ce574deSOleksandr Tymoshenko /* 2198ce574deSOleksandr Tymoshenko * Not both directions simultaneously 2208ce574deSOleksandr Tymoshenko */ 2218ce574deSOleksandr Tymoshenko if ((flags & allowed) == allowed) 2228ce574deSOleksandr Tymoshenko return (EINVAL); 2238ce574deSOleksandr Tymoshenko 2248ce574deSOleksandr Tymoshenko /* Set the GPIO mode and state */ 2258ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 2268ce574deSOleksandr Tymoshenko 2278ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 2288ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 2298ce574deSOleksandr Tymoshenko 2308ce574deSOleksandr Tymoshenko if (flags & GPIO_PIN_INPUT) { 2318ce574deSOleksandr Tymoshenko val &= ~BIT(OUTPUT_ENABLE_OFF); 2328ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_INPUT; 2338ce574deSOleksandr Tymoshenko } else { 2348ce574deSOleksandr Tymoshenko val |= BIT(OUTPUT_ENABLE_OFF); 2358ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_OUTPUT; 2368ce574deSOleksandr Tymoshenko } 2378ce574deSOleksandr Tymoshenko 2388ce574deSOleksandr Tymoshenko amdgpio_write_4(sc, reg, val); 2398ce574deSOleksandr Tymoshenko 2408ce574deSOleksandr Tymoshenko dprintf("pin %d flags 0x%x val 0x%x gp_flags 0x%x\n", 2418ce574deSOleksandr Tymoshenko pin, flags, val, sc->sc_gpio_pins[pin].gp_flags); 2428ce574deSOleksandr Tymoshenko 2438ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 2448ce574deSOleksandr Tymoshenko 2458ce574deSOleksandr Tymoshenko return (0); 2468ce574deSOleksandr Tymoshenko } 2478ce574deSOleksandr Tymoshenko 2488ce574deSOleksandr Tymoshenko static int 2498ce574deSOleksandr Tymoshenko amdgpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 2508ce574deSOleksandr Tymoshenko { 2518ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 2528ce574deSOleksandr Tymoshenko uint32_t reg, val; 2538ce574deSOleksandr Tymoshenko 2548ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 2558ce574deSOleksandr Tymoshenko 2568ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 2578ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 2588ce574deSOleksandr Tymoshenko return (EINVAL); 2598ce574deSOleksandr Tymoshenko 2608ce574deSOleksandr Tymoshenko *value = 0; 2618ce574deSOleksandr Tymoshenko 2628ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 2638ce574deSOleksandr Tymoshenko 2648ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 2658ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 2668ce574deSOleksandr Tymoshenko 2678ce574deSOleksandr Tymoshenko if (val & BIT(OUTPUT_VALUE_OFF)) 2688ce574deSOleksandr Tymoshenko *value = GPIO_PIN_HIGH; 2698ce574deSOleksandr Tymoshenko else 2708ce574deSOleksandr Tymoshenko *value = GPIO_PIN_LOW; 2718ce574deSOleksandr Tymoshenko 2728ce574deSOleksandr Tymoshenko dprintf("pin %d value 0x%x\n", pin, *value); 2738ce574deSOleksandr Tymoshenko 2748ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 2758ce574deSOleksandr Tymoshenko 2768ce574deSOleksandr Tymoshenko return (0); 2778ce574deSOleksandr Tymoshenko } 2788ce574deSOleksandr Tymoshenko 2798ce574deSOleksandr Tymoshenko static int 2808ce574deSOleksandr Tymoshenko amdgpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 2818ce574deSOleksandr Tymoshenko { 2828ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 2838ce574deSOleksandr Tymoshenko uint32_t reg, val; 2848ce574deSOleksandr Tymoshenko 2858ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 2868ce574deSOleksandr Tymoshenko 2878ce574deSOleksandr Tymoshenko dprintf("pin %d value 0x%x\n", pin, value); 2888ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 2898ce574deSOleksandr Tymoshenko return (EINVAL); 2908ce574deSOleksandr Tymoshenko 2918ce574deSOleksandr Tymoshenko if (!amdgpio_is_pin_output(sc, pin)) 2928ce574deSOleksandr Tymoshenko return (EINVAL); 2938ce574deSOleksandr Tymoshenko 2948ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 2958ce574deSOleksandr Tymoshenko 2968ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 2978ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 2988ce574deSOleksandr Tymoshenko 2998ce574deSOleksandr Tymoshenko if (value == GPIO_PIN_LOW) 3008ce574deSOleksandr Tymoshenko val &= ~BIT(OUTPUT_VALUE_OFF); 3018ce574deSOleksandr Tymoshenko else 3028ce574deSOleksandr Tymoshenko val |= BIT(OUTPUT_VALUE_OFF); 3038ce574deSOleksandr Tymoshenko 3048ce574deSOleksandr Tymoshenko amdgpio_write_4(sc, reg, val); 3058ce574deSOleksandr Tymoshenko 3068ce574deSOleksandr Tymoshenko dprintf("pin %d value 0x%x val 0x%x\n", pin, value, val); 3078ce574deSOleksandr Tymoshenko 3088ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 3098ce574deSOleksandr Tymoshenko 3108ce574deSOleksandr Tymoshenko return (0); 3118ce574deSOleksandr Tymoshenko } 3128ce574deSOleksandr Tymoshenko 3138ce574deSOleksandr Tymoshenko static int 3148ce574deSOleksandr Tymoshenko amdgpio_pin_toggle(device_t dev, uint32_t pin) 3158ce574deSOleksandr Tymoshenko { 3168ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 3178ce574deSOleksandr Tymoshenko uint32_t reg, val; 3188ce574deSOleksandr Tymoshenko 3198ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 3208ce574deSOleksandr Tymoshenko 3218ce574deSOleksandr Tymoshenko dprintf("pin %d\n", pin); 3228ce574deSOleksandr Tymoshenko if (!amdgpio_valid_pin(sc, pin)) 3238ce574deSOleksandr Tymoshenko return (EINVAL); 3248ce574deSOleksandr Tymoshenko 3258ce574deSOleksandr Tymoshenko if (!amdgpio_is_pin_output(sc, pin)) 3268ce574deSOleksandr Tymoshenko return (EINVAL); 3278ce574deSOleksandr Tymoshenko 3288ce574deSOleksandr Tymoshenko /* Toggle the pin */ 3298ce574deSOleksandr Tymoshenko AMDGPIO_LOCK(sc); 3308ce574deSOleksandr Tymoshenko 3318ce574deSOleksandr Tymoshenko reg = AMDGPIO_PIN_REGISTER(pin); 3328ce574deSOleksandr Tymoshenko val = amdgpio_read_4(sc, reg); 3338ce574deSOleksandr Tymoshenko dprintf("pin %d value before 0x%x\n", pin, val); 3348ce574deSOleksandr Tymoshenko val = val ^ BIT(OUTPUT_VALUE_OFF); 3358ce574deSOleksandr Tymoshenko dprintf("pin %d value after 0x%x\n", pin, val); 3368ce574deSOleksandr Tymoshenko amdgpio_write_4(sc, reg, val); 3378ce574deSOleksandr Tymoshenko 3388ce574deSOleksandr Tymoshenko AMDGPIO_UNLOCK(sc); 3398ce574deSOleksandr Tymoshenko 3408ce574deSOleksandr Tymoshenko return (0); 3418ce574deSOleksandr Tymoshenko } 3428ce574deSOleksandr Tymoshenko 3438ce574deSOleksandr Tymoshenko static int 3448ce574deSOleksandr Tymoshenko amdgpio_probe(device_t dev) 3458ce574deSOleksandr Tymoshenko { 3468ce574deSOleksandr Tymoshenko static char *gpio_ids[] = { "AMD0030", "AMDI0030", NULL }; 3475efca36fSTakanori Watanabe int rv; 3488ce574deSOleksandr Tymoshenko 3495efca36fSTakanori Watanabe if (acpi_disabled("gpio")) 3508ce574deSOleksandr Tymoshenko return (ENXIO); 3515efca36fSTakanori Watanabe rv = ACPI_ID_PROBE(device_get_parent(dev), dev, gpio_ids, NULL); 3528ce574deSOleksandr Tymoshenko 3535efca36fSTakanori Watanabe if (rv <= 0) 3548ce574deSOleksandr Tymoshenko device_set_desc(dev, "AMD GPIO Controller"); 3555efca36fSTakanori Watanabe 3565efca36fSTakanori Watanabe return (rv); 3578ce574deSOleksandr Tymoshenko } 3588ce574deSOleksandr Tymoshenko 3598ce574deSOleksandr Tymoshenko static int 3608ce574deSOleksandr Tymoshenko amdgpio_attach(device_t dev) 3618ce574deSOleksandr Tymoshenko { 3628ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 3638ce574deSOleksandr Tymoshenko int i, pin, bank; 3648ce574deSOleksandr Tymoshenko 3658ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 3668ce574deSOleksandr Tymoshenko sc->sc_dev = dev; 3678ce574deSOleksandr Tymoshenko sc->sc_handle = acpi_get_handle(dev); 3688ce574deSOleksandr Tymoshenko 3698ce574deSOleksandr Tymoshenko AMDGPIO_LOCK_INIT(sc); 3708ce574deSOleksandr Tymoshenko 3718ce574deSOleksandr Tymoshenko sc->sc_nbanks = AMD_GPIO_NUM_PIN_BANK; 3728ce574deSOleksandr Tymoshenko sc->sc_npins = AMD_GPIO_PINS_MAX; 3738ce574deSOleksandr Tymoshenko sc->sc_bank_prefix = AMD_GPIO_PREFIX; 3748ce574deSOleksandr Tymoshenko sc->sc_pin_info = kernzp_pins; 3758ce574deSOleksandr Tymoshenko sc->sc_ngroups = nitems(kernzp_groups); 3768ce574deSOleksandr Tymoshenko sc->sc_groups = kernzp_groups; 3778ce574deSOleksandr Tymoshenko 3788ce574deSOleksandr Tymoshenko if (bus_alloc_resources(dev, amdgpio_spec, sc->sc_res)) { 3798ce574deSOleksandr Tymoshenko device_printf(dev, "could not allocate resources\n"); 3808ce574deSOleksandr Tymoshenko goto err_rsrc; 3818ce574deSOleksandr Tymoshenko } 3828ce574deSOleksandr Tymoshenko 3838ce574deSOleksandr Tymoshenko sc->sc_bst = rman_get_bustag(sc->sc_res[0]); 3848ce574deSOleksandr Tymoshenko sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); 3858ce574deSOleksandr Tymoshenko 3868ce574deSOleksandr Tymoshenko /* Initialize all possible pins to be Invalid */ 3878ce574deSOleksandr Tymoshenko for (i = 0; i < AMD_GPIO_PINS_MAX ; i++) { 3888ce574deSOleksandr Tymoshenko snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME, 389*cfdb42f8SAndriy Gapon "Unexposed PIN %d", i); 3908ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[i].gp_pin = -1; 3918ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[i].gp_caps = 0; 3928ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[i].gp_flags = 0; 3938ce574deSOleksandr Tymoshenko } 3948ce574deSOleksandr Tymoshenko 3958ce574deSOleksandr Tymoshenko /* Initialize only driver exposed pins with appropriate capabilities */ 3968ce574deSOleksandr Tymoshenko for (i = 0; i < AMD_GPIO_PINS_EXPOSED ; i++) { 3978ce574deSOleksandr Tymoshenko pin = kernzp_pins[i].pin_num; 3988ce574deSOleksandr Tymoshenko bank = pin/AMD_GPIO_PINS_PER_BANK; 399*cfdb42f8SAndriy Gapon snprintf(sc->sc_gpio_pins[pin].gp_name, GPIOMAXNAME, "%s%d_%s", 4008ce574deSOleksandr Tymoshenko AMD_GPIO_PREFIX, bank, kernzp_pins[i].pin_name); 4018ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_pin = pin; 4028ce574deSOleksandr Tymoshenko sc->sc_gpio_pins[pin].gp_caps = AMDGPIO_DEFAULT_CAPS; 403*cfdb42f8SAndriy Gapon sc->sc_gpio_pins[pin].gp_flags = 404*cfdb42f8SAndriy Gapon amdgpio_is_pin_output(sc, pin) ? 405*cfdb42f8SAndriy Gapon GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; 4068ce574deSOleksandr Tymoshenko } 4078ce574deSOleksandr Tymoshenko 4088ce574deSOleksandr Tymoshenko sc->sc_busdev = gpiobus_attach_bus(dev); 4098ce574deSOleksandr Tymoshenko if (sc->sc_busdev == NULL) { 4108ce574deSOleksandr Tymoshenko device_printf(dev, "could not attach gpiobus\n"); 4118ce574deSOleksandr Tymoshenko goto err_bus; 4128ce574deSOleksandr Tymoshenko } 4138ce574deSOleksandr Tymoshenko 4148ce574deSOleksandr Tymoshenko return (0); 4158ce574deSOleksandr Tymoshenko 4168ce574deSOleksandr Tymoshenko err_bus: 4178ce574deSOleksandr Tymoshenko bus_release_resources(dev, amdgpio_spec, sc->sc_res); 4188ce574deSOleksandr Tymoshenko 4198ce574deSOleksandr Tymoshenko err_rsrc: 4208ce574deSOleksandr Tymoshenko AMDGPIO_LOCK_DESTROY(sc); 4218ce574deSOleksandr Tymoshenko 4228ce574deSOleksandr Tymoshenko return (ENXIO); 4238ce574deSOleksandr Tymoshenko } 4248ce574deSOleksandr Tymoshenko 4258ce574deSOleksandr Tymoshenko 4268ce574deSOleksandr Tymoshenko static int 4278ce574deSOleksandr Tymoshenko amdgpio_detach(device_t dev) 4288ce574deSOleksandr Tymoshenko { 4298ce574deSOleksandr Tymoshenko struct amdgpio_softc *sc; 4308ce574deSOleksandr Tymoshenko sc = device_get_softc(dev); 4318ce574deSOleksandr Tymoshenko 4328ce574deSOleksandr Tymoshenko if (sc->sc_busdev) 4338ce574deSOleksandr Tymoshenko gpiobus_detach_bus(dev); 4348ce574deSOleksandr Tymoshenko 4358ce574deSOleksandr Tymoshenko bus_release_resources(dev, amdgpio_spec, sc->sc_res); 4368ce574deSOleksandr Tymoshenko 4378ce574deSOleksandr Tymoshenko AMDGPIO_LOCK_DESTROY(sc); 4388ce574deSOleksandr Tymoshenko 4398ce574deSOleksandr Tymoshenko return (0); 4408ce574deSOleksandr Tymoshenko } 4418ce574deSOleksandr Tymoshenko 4428ce574deSOleksandr Tymoshenko static device_method_t amdgpio_methods[] = { 4438ce574deSOleksandr Tymoshenko /* Device interface */ 4448ce574deSOleksandr Tymoshenko DEVMETHOD(device_probe, amdgpio_probe), 4458ce574deSOleksandr Tymoshenko DEVMETHOD(device_attach, amdgpio_attach), 4468ce574deSOleksandr Tymoshenko DEVMETHOD(device_detach, amdgpio_detach), 4478ce574deSOleksandr Tymoshenko 4488ce574deSOleksandr Tymoshenko /* GPIO protocol */ 4498ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_get_bus, amdgpio_get_bus), 4508ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_max, amdgpio_pin_max), 4518ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getname, amdgpio_pin_getname), 4528ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getcaps, amdgpio_pin_getcaps), 4538ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_getflags, amdgpio_pin_getflags), 4548ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_setflags, amdgpio_pin_setflags), 4558ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_get, amdgpio_pin_get), 4568ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_set, amdgpio_pin_set), 4578ce574deSOleksandr Tymoshenko DEVMETHOD(gpio_pin_toggle, amdgpio_pin_toggle), 4588ce574deSOleksandr Tymoshenko 4598ce574deSOleksandr Tymoshenko DEVMETHOD_END 4608ce574deSOleksandr Tymoshenko }; 4618ce574deSOleksandr Tymoshenko 4628ce574deSOleksandr Tymoshenko static driver_t amdgpio_driver = { 4638ce574deSOleksandr Tymoshenko "gpio", 4648ce574deSOleksandr Tymoshenko amdgpio_methods, 4658ce574deSOleksandr Tymoshenko sizeof(struct amdgpio_softc), 4668ce574deSOleksandr Tymoshenko }; 4678ce574deSOleksandr Tymoshenko 4688ce574deSOleksandr Tymoshenko static devclass_t amdgpio_devclass; 4698ce574deSOleksandr Tymoshenko DRIVER_MODULE(amdgpio, acpi, amdgpio_driver, amdgpio_devclass, 0, 0); 4708ce574deSOleksandr Tymoshenko MODULE_DEPEND(amdgpio, acpi, 1, 1, 1); 4718ce574deSOleksandr Tymoshenko MODULE_DEPEND(amdgpio, gpiobus, 1, 1, 1); 4728ce574deSOleksandr Tymoshenko MODULE_VERSION(amdgpio, 1); 473