Index: sys/dev/amdgpio/amdgpio.h =================================================================== --- sys/dev/amdgpio/amdgpio.h +++ sys/dev/amdgpio/amdgpio.h @@ -0,0 +1,328 @@ +/*- + * Copyright (c) 2018 Advanced Micro Devices + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef DEBUG +#define dprintf(fmt, args...) do { \ + printf("%s(): ", __func__); \ + printf(fmt,##args); \ +} while (0) +#else +#define dprintf(fmt, args...) +#endif + +#define AMD_GPIO_PREFIX "AMDGPIO" + +#define AMD_GPIO_NUM_PIN_BANK 4 +#define AMD_GPIO_PINS_PER_BANK 64 +#define AMD_GPIO_PINS_MAX 256 /* 4 banks * 64 pins */ + +/* Number of pins in each bank */ +#define AMD_GPIO_PINS_BANK0 63 +#define AMD_GPIO_PINS_BANK1 64 +#define AMD_GPIO_PINS_BANK2 56 +#define AMD_GPIO_PINS_BANK3 32 +#define AMD_GPIO_PIN_PRESENT (AMD_GPIO_PINS_BANK0 + \ + AMD_GPIO_PINS_BANK1 + \ + AMD_GPIO_PINS_BANK2 + \ + AMD_GPIO_PINS_BANK3) +#define AMDGPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) + +/* Register related macros */ +#define AMDGPIO_PIN_REGISTER(pin) (pin * 4) + +#define WAKE_INT_MASTER_REG 0xfc +#define EOI_MASK (1 << 29) +#define WAKE_INT_STATUS_REG0 0x2f8 +#define WAKE_INT_STATUS_REG1 0x2fc + +/* Bit definition of 32 bits of each pin register */ +#define DB_TMR_OUT_OFF 0 +#define DB_TMR_OUT_UNIT_OFF 4 +#define DB_CNTRL_OFF 5 +#define DB_TMR_LARGE_OFF 7 +#define LEVEL_TRIG_OFF 8 +#define ACTIVE_LEVEL_OFF 9 +#define INTERRUPT_ENABLE_OFF 11 +#define INTERRUPT_MASK_OFF 12 +#define WAKE_CNTRL_OFF_S0I3 13 +#define WAKE_CNTRL_OFF_S3 14 +#define WAKE_CNTRL_OFF_S4 15 +#define PIN_STS_OFF 16 +#define DRV_STRENGTH_SEL_OFF 17 +#define PULL_UP_SEL_OFF 19 +#define PULL_UP_ENABLE_OFF 20 +#define PULL_DOWN_ENABLE_OFF 21 +#define OUTPUT_VALUE_OFF 22 +#define OUTPUT_ENABLE_OFF 23 +#define SW_CNTRL_IN_OFF 24 +#define SW_CNTRL_EN_OFF 25 +#define INTERRUPT_STS_OFF 28 +#define WAKE_STS_OFF 29 + +#define DB_TMR_OUT_MASK 0xFUL +#define DB_CNTRL_MASK 0x3UL +#define ACTIVE_LEVEL_MASK 0x3UL +#define DRV_STRENGTH_SEL_MASK 0x3UL + +#define DB_TYPE_NO_DEBOUNCE 0x0UL +#define DB_TYPE_PRESERVE_LOW_GLITCH 0x1UL +#define DB_TYPE_PRESERVE_HIGH_GLITCH 0x2UL +#define DB_TYPE_REMOVE_GLITCH 0x3UL + +#define EDGE_TRIGGER 0x0UL +#define LEVEL_TRIGGER 0x1UL + +#define ACTIVE_HIGH 0x0UL +#define ACTIVE_LOW 0x1UL +#define BOTH_EDGE 0x2UL + +#define ENABLE_INTERRUPT 0x1UL +#define DISABLE_INTERRUPT 0x0UL + +#define ENABLE_INTERRUPT_MASK 0x0UL +#define DISABLE_INTERRUPT_MASK 0x1UL +#define CLR_INTR_STAT 0x1UL + +#define BIT(bit) (1 << bit) +#define GPIO_PIN_INFO(p, n) { .pin_num = (p), .pin_name = (n) } + +struct pin_info { + int pin_num; + char *pin_name; +}; + +/* Pins exposed to drivers */ +static const struct pin_info kernzp_pins[] = { + GPIO_PIN_INFO(0, "PIN_0"), + GPIO_PIN_INFO(1, "PIN_1"), + GPIO_PIN_INFO(2, "PIN_2"), + GPIO_PIN_INFO(3, "PIN_3"), + GPIO_PIN_INFO(4, "PIN_4"), + GPIO_PIN_INFO(5, "PIN_5"), + GPIO_PIN_INFO(6, "PIN_6"), + GPIO_PIN_INFO(7, "PIN_7"), + GPIO_PIN_INFO(8, "PIN_8"), + GPIO_PIN_INFO(9, "PIN_9"), + GPIO_PIN_INFO(10, "PIN_10"), + GPIO_PIN_INFO(11, "PIN_11"), + GPIO_PIN_INFO(12, "PIN_12"), + GPIO_PIN_INFO(13, "PIN_13"), + GPIO_PIN_INFO(14, "PIN_14"), + GPIO_PIN_INFO(15, "PIN_15"), + GPIO_PIN_INFO(16, "PIN_16"), + GPIO_PIN_INFO(17, "PIN_17"), + GPIO_PIN_INFO(18, "PIN_18"), + GPIO_PIN_INFO(19, "PIN_19"), + GPIO_PIN_INFO(20, "PIN_20"), + GPIO_PIN_INFO(23, "PIN_23"), + GPIO_PIN_INFO(24, "PIN_24"), + GPIO_PIN_INFO(25, "PIN_25"), + GPIO_PIN_INFO(26, "PIN_26"), + GPIO_PIN_INFO(39, "PIN_39"), + GPIO_PIN_INFO(40, "PIN_40"), + GPIO_PIN_INFO(43, "PIN_43"), + GPIO_PIN_INFO(46, "PIN_46"), + GPIO_PIN_INFO(47, "PIN_47"), + GPIO_PIN_INFO(48, "PIN_48"), + GPIO_PIN_INFO(49, "PIN_49"), + GPIO_PIN_INFO(50, "PIN_50"), + GPIO_PIN_INFO(51, "PIN_51"), + GPIO_PIN_INFO(52, "PIN_52"), + GPIO_PIN_INFO(53, "PIN_53"), + GPIO_PIN_INFO(54, "PIN_54"), + GPIO_PIN_INFO(55, "PIN_55"), + GPIO_PIN_INFO(56, "PIN_56"), + GPIO_PIN_INFO(57, "PIN_57"), + GPIO_PIN_INFO(58, "PIN_58"), + GPIO_PIN_INFO(59, "PIN_59"), + GPIO_PIN_INFO(60, "PIN_60"), + GPIO_PIN_INFO(61, "PIN_61"), + GPIO_PIN_INFO(62, "PIN_62"), + GPIO_PIN_INFO(64, "PIN_64"), + GPIO_PIN_INFO(65, "PIN_65"), + GPIO_PIN_INFO(66, "PIN_66"), + GPIO_PIN_INFO(68, "PIN_68"), + GPIO_PIN_INFO(69, "PIN_69"), + GPIO_PIN_INFO(70, "PIN_70"), + GPIO_PIN_INFO(71, "PIN_71"), + GPIO_PIN_INFO(72, "PIN_72"), + GPIO_PIN_INFO(74, "PIN_74"), + GPIO_PIN_INFO(75, "PIN_75"), + GPIO_PIN_INFO(76, "PIN_76"), + GPIO_PIN_INFO(84, "PIN_84"), + GPIO_PIN_INFO(85, "PIN_85"), + GPIO_PIN_INFO(86, "PIN_86"), + GPIO_PIN_INFO(87, "PIN_87"), + GPIO_PIN_INFO(88, "PIN_88"), + GPIO_PIN_INFO(89, "PIN_89"), + GPIO_PIN_INFO(90, "PIN_90"), + GPIO_PIN_INFO(91, "PIN_91"), + GPIO_PIN_INFO(92, "PIN_92"), + GPIO_PIN_INFO(93, "PIN_93"), + GPIO_PIN_INFO(95, "PIN_95"), + GPIO_PIN_INFO(96, "PIN_96"), + GPIO_PIN_INFO(97, "PIN_97"), + GPIO_PIN_INFO(98, "PIN_98"), + GPIO_PIN_INFO(99, "PIN_99"), + GPIO_PIN_INFO(100, "PIN_100"), + GPIO_PIN_INFO(101, "PIN_101"), + GPIO_PIN_INFO(102, "PIN_102"), + GPIO_PIN_INFO(113, "PIN_113"), + GPIO_PIN_INFO(114, "PIN_114"), + GPIO_PIN_INFO(115, "PIN_115"), + GPIO_PIN_INFO(116, "PIN_116"), + GPIO_PIN_INFO(117, "PIN_117"), + GPIO_PIN_INFO(118, "PIN_118"), + GPIO_PIN_INFO(119, "PIN_119"), + GPIO_PIN_INFO(120, "PIN_120"), + GPIO_PIN_INFO(121, "PIN_121"), + GPIO_PIN_INFO(122, "PIN_122"), + GPIO_PIN_INFO(126, "PIN_126"), + GPIO_PIN_INFO(129, "PIN_129"), + GPIO_PIN_INFO(130, "PIN_130"), + GPIO_PIN_INFO(131, "PIN_131"), + GPIO_PIN_INFO(132, "PIN_132"), + GPIO_PIN_INFO(133, "PIN_133"), + GPIO_PIN_INFO(135, "PIN_135"), + GPIO_PIN_INFO(136, "PIN_136"), + GPIO_PIN_INFO(137, "PIN_137"), + GPIO_PIN_INFO(138, "PIN_138"), + GPIO_PIN_INFO(139, "PIN_139"), + GPIO_PIN_INFO(140, "PIN_140"), + GPIO_PIN_INFO(141, "PIN_141"), + GPIO_PIN_INFO(142, "PIN_142"), + GPIO_PIN_INFO(143, "PIN_143"), + GPIO_PIN_INFO(144, "PIN_144"), + GPIO_PIN_INFO(145, "PIN_145"), + GPIO_PIN_INFO(146, "PIN_146"), + GPIO_PIN_INFO(147, "PIN_147"), + GPIO_PIN_INFO(148, "PIN_148"), + GPIO_PIN_INFO(166, "PIN_166"), + GPIO_PIN_INFO(167, "PIN_167"), + GPIO_PIN_INFO(168, "PIN_168"), + GPIO_PIN_INFO(169, "PIN_169"), + GPIO_PIN_INFO(170, "PIN_170"), + GPIO_PIN_INFO(171, "PIN_171"), + GPIO_PIN_INFO(172, "PIN_172"), + GPIO_PIN_INFO(173, "PIN_173"), + GPIO_PIN_INFO(174, "PIN_174"), + GPIO_PIN_INFO(175, "PIN_175"), + GPIO_PIN_INFO(176, "PIN_176"), + GPIO_PIN_INFO(177, "PIN_177"), +}; + +#define AMD_GPIO_PINS_EXPOSED nitems(kernzp_pins) + +static const unsigned i2c0_pins[] = {145, 146}; +static const unsigned i2c1_pins[] = {147, 148}; +static const unsigned i2c2_pins[] = {113, 114}; +static const unsigned i2c3_pins[] = {19, 20}; +static const unsigned i2c4_pins[] = {149, 150}; +static const unsigned i2c5_pins[] = {151, 152}; + +static const unsigned uart0_pins[] = {135, 136, 137, 138, 139}; +static const unsigned uart1_pins[] = {140, 141, 142, 143, 144}; + +struct amd_pingroup { + const char *name; + const unsigned *pins; + unsigned npins; +}; + +static const struct amd_pingroup kernzp_groups[] = { + { + .name = "i2c0", + .pins = i2c0_pins, + .npins = 2, + }, + { + .name = "i2c1", + .pins = i2c1_pins, + .npins = 2, + }, + { + .name = "i2c2", + .pins = i2c2_pins, + .npins = 2, + }, + { + .name = "i2c3", + .pins = i2c3_pins, + .npins = 2, + }, + { + .name = "i2c4", + .pins = i2c4_pins, + .npins = 2, + }, + { + .name = "i2c5", + .pins = i2c5_pins, + .npins = 2, + }, + { + .name = "uart0", + .pins = uart0_pins, + .npins = 5, + }, + { + .name = "uart1", + .pins = uart1_pins, + .npins = 5, + }, +}; + +/* Macros for driver mutex locking */ +#define AMDGPIO_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ + "amdgpio", MTX_SPIN) +#define AMDGPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) +#define AMDGPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) +#define AMDGPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) +#define AMDGPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) +#define AMDGPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED) + +struct amdgpio_softc { + ACPI_HANDLE sc_handle; + device_t sc_dev; + device_t sc_busdev; + const char* sc_bank_prefix; + int sc_nbanks; + int sc_npins; + int sc_ngroups; + struct mtx sc_mtx; + struct resource *sc_res[AMD_GPIO_NUM_PIN_BANK + 1]; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + struct gpio_pin sc_gpio_pins[AMD_GPIO_PINS_MAX]; + const struct pin_info *sc_pin_info; + const struct amd_pingroup *sc_groups; +}; + +struct amdgpio_sysctl { + struct amdgpio_softc *sc; + uint32_t pin; +}; Index: sys/dev/amdgpio/amdgpio.c =================================================================== --- sys/dev/amdgpio/amdgpio.c +++ sys/dev/amdgpio/amdgpio.c @@ -0,0 +1,463 @@ +/*- + * Copyright (c) 2018 Advanced Micro Devices + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_acpi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "gpio_if.h" +#include "amdgpio.h" + +static struct resource_spec amdgpio_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0, 0 } +}; + +static inline uint32_t +amdgpio_read_4(struct amdgpio_softc *sc, bus_size_t off) +{ + return (bus_read_4(sc->sc_res[0], off)); +} + +static inline void +amdgpio_write_4(struct amdgpio_softc *sc, bus_size_t off, + uint32_t val) +{ + bus_write_4(sc->sc_res[0], off, val); +} + +static bool +amdgpio_is_pin_output(struct amdgpio_softc *sc, uint32_t pin) +{ + uint32_t reg, val; + bool ret; + + /* Get the current pin state */ + AMDGPIO_LOCK(sc); + + reg = AMDGPIO_PIN_REGISTER(pin); + val = amdgpio_read_4(sc, reg); + + if (val & BIT(OUTPUT_ENABLE_OFF)) + ret = true; + else + ret = false; + + AMDGPIO_UNLOCK(sc); + + return (ret); +} + +static device_t +amdgpio_get_bus(device_t dev) +{ + struct amdgpio_softc *sc; + + sc = device_get_softc(dev); + + dprintf("busdev %p\n", sc->sc_busdev); + return (sc->sc_busdev); +} + +static int +amdgpio_pin_max(device_t dev, int *maxpin) +{ + struct amdgpio_softc *sc; + + sc = device_get_softc(dev); + + *maxpin = sc->sc_npins - 1; + dprintf("npins %d maxpin %d\n", sc->sc_npins, *maxpin); + + return (0); +} + +static bool +amdgpio_valid_pin(struct amdgpio_softc *sc, int pin) +{ + dprintf("pin %d\n", pin); + if (sc->sc_res[0] == NULL) + return (false); + + if ((sc->sc_gpio_pins[pin].gp_pin == pin) && + (sc->sc_gpio_pins[pin].gp_caps != 0)) + return (true); + + return (false); +} + +static int +amdgpio_pin_getname(device_t dev, uint32_t pin, char *name) +{ + struct amdgpio_softc *sc; + + dprintf("pin %d\n", pin); + sc = device_get_softc(dev); + + if (!amdgpio_valid_pin(sc, pin)) + return (EINVAL); + + /* Set a very simple name */ + snprintf(name, GPIOMAXNAME, "%s", sc->sc_gpio_pins[pin].gp_name); + name[GPIOMAXNAME - 1] = '\0'; + + dprintf("pin %d name %s\n", pin, name); + + return (0); +} + +static int +amdgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + struct amdgpio_softc *sc; + + sc = device_get_softc(dev); + + dprintf("pin %d\n", pin); + if (!amdgpio_valid_pin(sc, pin)) + return (EINVAL); + + *caps = sc->sc_gpio_pins[pin].gp_caps; + + dprintf("pin %d caps 0x%x\n", pin, *caps); + + return (0); +} + +static int +amdgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct amdgpio_softc *sc; + + sc = device_get_softc(dev); + + + dprintf("pin %d\n", pin); + if (!amdgpio_valid_pin(sc, pin)) + return (EINVAL); + + AMDGPIO_LOCK(sc); + + *flags = sc->sc_gpio_pins[pin].gp_flags; + + dprintf("pin %d flags 0x%x\n", pin, *flags); + + AMDGPIO_UNLOCK(sc); + + return (0); +} + +static int +amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) +{ + struct amdgpio_softc *sc; + uint32_t reg, val, allowed; + + sc = device_get_softc(dev); + + dprintf("pin %d flags 0x%x\n", pin, flags); + if (!amdgpio_valid_pin(sc, pin)) + return (EINVAL); + + allowed = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; + + /* + * Only directtion flag allowed + */ + if (flags & ~allowed) + return (EINVAL); + + /* + * Not both directions simultaneously + */ + if ((flags & allowed) == allowed) + return (EINVAL); + + /* Set the GPIO mode and state */ + AMDGPIO_LOCK(sc); + + reg = AMDGPIO_PIN_REGISTER(pin); + val = amdgpio_read_4(sc, reg); + + if (flags & GPIO_PIN_INPUT) { + val &= ~BIT(OUTPUT_ENABLE_OFF); + sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_INPUT; + } else { + val |= BIT(OUTPUT_ENABLE_OFF); + sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_OUTPUT; + } + + amdgpio_write_4(sc, reg, val); + + dprintf("pin %d flags 0x%x val 0x%x gp_flags 0x%x\n", + pin, flags, val, sc->sc_gpio_pins[pin].gp_flags); + + AMDGPIO_UNLOCK(sc); + + return (0); +} + +static int +amdgpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) +{ + struct amdgpio_softc *sc; + uint32_t reg, val; + + sc = device_get_softc(dev); + + dprintf("pin %d\n", pin); + if (!amdgpio_valid_pin(sc, pin)) + return (EINVAL); + + *value = 0; + + AMDGPIO_LOCK(sc); + + reg = AMDGPIO_PIN_REGISTER(pin); + val = amdgpio_read_4(sc, reg); + + if (val & BIT(OUTPUT_VALUE_OFF)) + *value = GPIO_PIN_HIGH; + else + *value = GPIO_PIN_LOW; + + dprintf("pin %d value 0x%x\n", pin, *value); + + AMDGPIO_UNLOCK(sc); + + return (0); +} + +static int +amdgpio_pin_set(device_t dev, uint32_t pin, unsigned int value) +{ + struct amdgpio_softc *sc; + uint32_t reg, val; + + sc = device_get_softc(dev); + + dprintf("pin %d value 0x%x\n", pin, value); + if (!amdgpio_valid_pin(sc, pin)) + return (EINVAL); + + AMDGPIO_LOCK(sc); + + reg = AMDGPIO_PIN_REGISTER(pin); + val = amdgpio_read_4(sc, reg); + + if (value == GPIO_PIN_LOW) + val &= ~BIT(OUTPUT_VALUE_OFF); + else + val |= BIT(OUTPUT_VALUE_OFF); + + amdgpio_write_4(sc, reg, val); + + dprintf("pin %d value 0x%x val 0x%x\n", pin, value, val); + + AMDGPIO_UNLOCK(sc); + + return (0); +} + +static int +amdgpio_pin_toggle(device_t dev, uint32_t pin) +{ + struct amdgpio_softc *sc; + uint32_t reg, val; + + sc = device_get_softc(dev); + + dprintf("pin %d\n", pin); + if (!amdgpio_valid_pin(sc, pin)) + return (EINVAL); + + /* Toggle the pin */ + AMDGPIO_LOCK(sc); + + reg = AMDGPIO_PIN_REGISTER(pin); + val = amdgpio_read_4(sc, reg); + dprintf("pin %d value before 0x%x\n", pin, val); + val = val ^ BIT(OUTPUT_VALUE_OFF); + dprintf("pin %d value after 0x%x\n", pin, val); + amdgpio_write_4(sc, reg, val); + + AMDGPIO_UNLOCK(sc); + + return (0); +} + +static int +amdgpio_probe(device_t dev) +{ + static char *gpio_ids[] = { "AMD0030", "AMDI0030", NULL }; + + if (acpi_disabled("gpio") || + ACPI_ID_PROBE(device_get_parent(dev), dev, gpio_ids) == NULL) + return (ENXIO); + + device_set_desc(dev, "AMD GPIO Controller"); + return (0); +} + +static int +amdgpio_attach(device_t dev) +{ + struct amdgpio_softc *sc; + int i, pin, unit; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_handle = acpi_get_handle(dev); + + AMDGPIO_LOCK_INIT(sc); + + sc->sc_nbanks = AMD_GPIO_NUM_PIN_BANK; + sc->sc_npins = AMD_GPIO_PINS_MAX; + sc->sc_bank_prefix = AMD_GPIO_PREFIX; + sc->sc_pin_info = kernzp_pins; + sc->sc_ngroups = nitems(kernzp_groups); + sc->sc_groups = kernzp_groups; + + if (bus_alloc_resources(dev, amdgpio_spec, sc->sc_res)) { + device_printf(dev, "could not allocate resources\n"); + goto err_rsrc; + } + + sc->sc_bst = rman_get_bustag(sc->sc_res[0]); + sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); + + /* Initialize all possible pins to be Invalid */ + for (i = 0; i < AMD_GPIO_PINS_MAX ; i++) { + snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME, + "Unexposed PIN %d\n", i); + sc->sc_gpio_pins[i].gp_pin = -1; + sc->sc_gpio_pins[i].gp_caps = 0; + sc->sc_gpio_pins[i].gp_flags = 0; + } + + /* Initialize only driver exposed pins with appropriate capabilities */ + unit = device_get_unit(dev); + for (i = 0; i < AMD_GPIO_PINS_EXPOSED ; i++) { + pin = kernzp_pins[i].pin_num; + snprintf(sc->sc_gpio_pins[pin].gp_name, GPIOMAXNAME, "%s%d_%s\n", + AMD_GPIO_PREFIX, unit, kernzp_pins[i].pin_name); + sc->sc_gpio_pins[pin].gp_pin = pin; + sc->sc_gpio_pins[pin].gp_caps = AMDGPIO_DEFAULT_CAPS; + sc->sc_gpio_pins[pin].gp_flags = (amdgpio_is_pin_output(sc, pin)? + GPIO_PIN_OUTPUT : GPIO_PIN_INPUT); + } + + sc->sc_busdev = gpiobus_attach_bus(dev); + if (sc->sc_busdev == NULL) { + device_printf(dev, "could not attach gpiobus\n"); + goto err_bus; + } + + return (0); + +err_bus: + bus_release_resources(dev, amdgpio_spec, sc->sc_res); + +err_rsrc: + AMDGPIO_LOCK_DESTROY(sc); + + return (ENXIO); +} + + +static int +amdgpio_detach(device_t dev) +{ + struct amdgpio_softc *sc; + sc = device_get_softc(dev); + + if (sc->sc_busdev) + gpiobus_detach_bus(dev); + + bus_release_resources(dev, amdgpio_spec, sc->sc_res); + + AMDGPIO_LOCK_DESTROY(sc); + + return (0); +} + +static device_method_t amdgpio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, amdgpio_probe), + DEVMETHOD(device_attach, amdgpio_attach), + DEVMETHOD(device_detach, amdgpio_detach), + + /* GPIO protocol */ + DEVMETHOD(gpio_get_bus, amdgpio_get_bus), + DEVMETHOD(gpio_pin_max, amdgpio_pin_max), + DEVMETHOD(gpio_pin_getname, amdgpio_pin_getname), + DEVMETHOD(gpio_pin_getcaps, amdgpio_pin_getcaps), + DEVMETHOD(gpio_pin_getflags, amdgpio_pin_getflags), + DEVMETHOD(gpio_pin_setflags, amdgpio_pin_setflags), + DEVMETHOD(gpio_pin_get, amdgpio_pin_get), + DEVMETHOD(gpio_pin_set, amdgpio_pin_set), + DEVMETHOD(gpio_pin_toggle, amdgpio_pin_toggle), + + DEVMETHOD_END +}; + +static driver_t amdgpio_driver = { + "gpio", + amdgpio_methods, + sizeof(struct amdgpio_softc), +}; + +static devclass_t amdgpio_devclass; +DRIVER_MODULE(amdgpio, acpi, amdgpio_driver, amdgpio_devclass, 0, 0); +MODULE_DEPEND(amdgpio, acpi, 1, 1, 1); +MODULE_DEPEND(amdgpio, gpiobus, 1, 1, 1); +MODULE_VERSION(amdgpio, 1); Index: sys/modules/amdgpio/Makefile =================================================================== --- sys/modules/amdgpio/Makefile +++ sys/modules/amdgpio/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/amdgpio +KMOD= amdgpio +SRCS= amdgpio.c +SRCS+= acpi_if.h device_if.h bus_if.h ofw_bus_if.h gpio_if.h pic_if.h opt_acpi.h opt_platform.h + +.include