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