1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2026 Beckhoff Automation GmbH & Co. KG 5 */ 6 7 #include <sys/param.h> 8 #include <sys/systm.h> 9 #include <sys/bus.h> 10 #include <sys/gpio.h> 11 #include <sys/kernel.h> 12 #include <sys/module.h> 13 #include <sys/rman.h> 14 15 #include <machine/bus.h> 16 #include <machine/resource.h> 17 18 #include <contrib/dev/acpica/include/acpi.h> 19 #include <contrib/dev/acpica/include/accommon.h> 20 21 #include <dev/acpica/acpivar.h> 22 #include <dev/gpio/gpiobusvar.h> 23 24 #include "intelgpio.h" 25 26 #include "gpio_if.h" 27 #include "opt_acpi.h" 28 29 #define INTELGPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) 30 #define INTELGPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) 31 #define INTELGPIO_LOCK_INIT(_sc) \ 32 mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ 33 "intelgpio", MTX_SPIN) 34 #define INTELGPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 35 36 static int 37 intelgpio_gpio_to_pad(struct intelgpio_softc *sc, uint32_t pin, 38 struct resource **res, bus_size_t *pad_off, 39 const struct intelgpio_padgroup **pgp) 40 { 41 const struct intelgpio_platform *plat = sc->sc_plat; 42 const struct intelgpio_community *com; 43 const struct intelgpio_padgroup *pg; 44 int i, j, offset, local_pad; 45 46 for (i = 0; i < plat->ncommunities; i++) { 47 com = &plat->communities[i]; 48 for (j = 0; j < com->ngroups; j++) { 49 pg = &com->groups[j]; 50 if (pg->gpio_base == INTELGPIO_GPIO_NOMAP) 51 continue; 52 if (pin >= pg->gpio_base && 53 pin < pg->gpio_base + pg->npads) { 54 if (res != NULL) 55 *res = sc->sc_mem_res[i]; 56 if (pad_off != NULL) { 57 offset = pin - pg->gpio_base; 58 local_pad = (pg->first_pad + offset) - 59 com->groups[0].first_pad; 60 *pad_off = sc->sc_padbar[i] + 61 (local_pad * INTELGPIO_PAD_SIZE); 62 } 63 if (pgp != NULL) 64 *pgp = pg; 65 return (0); 66 } 67 } 68 } 69 return (-1); 70 } 71 72 static device_t 73 intelgpio_get_bus(device_t dev) 74 { 75 struct intelgpio_softc *sc; 76 77 sc = device_get_softc(dev); 78 return (sc->sc_busdev); 79 } 80 81 static int 82 intelgpio_pin_max(device_t dev, int *maxpin) 83 { 84 struct intelgpio_softc *sc; 85 const struct intelgpio_platform *plat; 86 const struct intelgpio_community *com; 87 const struct intelgpio_padgroup *pg; 88 int i, j; 89 90 if (maxpin == NULL) 91 return (EINVAL); 92 93 sc = device_get_softc(dev); 94 plat = sc->sc_plat; 95 96 /* Find the last group with a valid gpio_base, skipping NOMAP */ 97 *maxpin = 0; 98 for (i = 0; i < plat->ncommunities; i++) { 99 com = &plat->communities[i]; 100 for (j = 0; j < com->ngroups; j++) { 101 pg = &com->groups[j]; 102 if (pg->gpio_base == INTELGPIO_GPIO_NOMAP) 103 continue; 104 *maxpin = pg->gpio_base + (pg->npads - 1); 105 } 106 } 107 return (0); 108 } 109 110 static int 111 intelgpio_pin_getname(device_t dev, uint32_t pin, char *name) 112 { 113 struct intelgpio_softc *sc; 114 const struct intelgpio_padgroup *pg; 115 int offset; 116 117 sc = device_get_softc(dev); 118 if (intelgpio_gpio_to_pad(sc, pin, NULL, NULL, &pg) != 0) 119 return (EINVAL); 120 121 offset = pin - pg->gpio_base; 122 snprintf(name, GPIOMAXNAME, "%s%d", pg->name, offset); 123 return (0); 124 } 125 126 static int 127 intelgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 128 { 129 struct intelgpio_softc *sc; 130 131 sc = device_get_softc(dev); 132 133 /* 134 * The getcaps function is expected to return the capabilities 135 * of the pin. Validate that the pin number maps to an existing 136 * pad first. 137 */ 138 if (intelgpio_gpio_to_pad(sc, pin, NULL, NULL, NULL) != 0) 139 return (EINVAL); 140 141 *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 142 return (0); 143 } 144 145 static int 146 intelgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 147 { 148 struct intelgpio_softc *sc; 149 struct resource *res; 150 bus_size_t pad_off; 151 uint32_t val; 152 153 sc = device_get_softc(dev); 154 if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0) 155 return (EINVAL); 156 if (res == NULL) 157 return (EINVAL); 158 159 *flags = 0; 160 161 INTELGPIO_LOCK(sc); 162 val = bus_read_4(res, pad_off); 163 INTELGPIO_UNLOCK(sc); 164 165 /* 166 * If the pad is not in GPIO mode (i.e. configured for a native 167 * function like PCIe, UART, I2C, etc.), report no flags. The pin 168 * cannot be used as GPIO without first switching it via setflags. 169 */ 170 if ((val & INTELGPIO_PADCFG0_PMODE_MASK) != 171 INTELGPIO_PADCFG0_PMODE_GPIO) 172 return (0); 173 174 /* 175 * Report OUTPUT only if TX is explicitly enabled. Default to INPUT 176 * otherwise: a non-driving pin is considered an input from the user's 177 * perspective. 178 */ 179 if (!(val & INTELGPIO_PADCFG0_GPIOTXDIS)) 180 *flags = GPIO_PIN_OUTPUT; 181 else 182 *flags = GPIO_PIN_INPUT; 183 184 return (0); 185 } 186 187 static int 188 intelgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 189 { 190 struct intelgpio_softc *sc; 191 struct resource *res; 192 bus_size_t pad_off; 193 uint32_t val; 194 195 sc = device_get_softc(dev); 196 if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0) 197 return (EINVAL); 198 if (res == NULL) 199 return (EINVAL); 200 201 /* 202 * We currently only support input and output, not both simultaneously 203 */ 204 if (flags & ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) 205 return (EINVAL); 206 if ((flags & GPIO_PIN_INPUT) && (flags & GPIO_PIN_OUTPUT)) 207 return (EINVAL); 208 209 INTELGPIO_LOCK(sc); 210 val = bus_read_4(res, pad_off); 211 212 /* 213 * Switch the pad to GPIO mode. Intel pads can operate in different 214 * modes (native function 1-15 or GPIO). Since setflags is only called 215 * when userspace or a consumer explicitly wants to use the pin as a 216 * GPIO, we force the pad into GPIO mode here so the direction bits 217 * (TXDIS/RXDIS) below take effect. 218 */ 219 val &= ~INTELGPIO_PADCFG0_PMODE_MASK; 220 val |= INTELGPIO_PADCFG0_PMODE_GPIO; 221 222 if (flags & GPIO_PIN_INPUT) 223 val &= ~INTELGPIO_PADCFG0_GPIORXDIS; 224 else 225 val |= INTELGPIO_PADCFG0_GPIORXDIS; 226 227 if (flags & GPIO_PIN_OUTPUT) 228 val &= ~INTELGPIO_PADCFG0_GPIOTXDIS; 229 else 230 val |= INTELGPIO_PADCFG0_GPIOTXDIS; 231 232 bus_write_4(res, pad_off, val); 233 INTELGPIO_UNLOCK(sc); 234 235 return (0); 236 } 237 238 static int 239 intelgpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 240 { 241 struct intelgpio_softc *sc; 242 struct resource *res; 243 bus_size_t pad_off; 244 uint32_t val; 245 246 sc = device_get_softc(dev); 247 if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0) 248 return (EINVAL); 249 if (res == NULL) 250 return (EINVAL); 251 252 INTELGPIO_LOCK(sc); 253 val = bus_read_4(res, pad_off); 254 INTELGPIO_UNLOCK(sc); 255 256 *value = (val & INTELGPIO_PADCFG0_GPIORXSTATE) ? 257 GPIO_PIN_HIGH : GPIO_PIN_LOW; 258 259 return (0); 260 } 261 262 static int 263 intelgpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 264 { 265 struct intelgpio_softc *sc; 266 struct resource *res; 267 bus_size_t pad_off; 268 uint32_t val; 269 270 sc = device_get_softc(dev); 271 if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0) 272 return (EINVAL); 273 if (res == NULL) 274 return (EINVAL); 275 276 INTELGPIO_LOCK(sc); 277 val = bus_read_4(res, pad_off); 278 if (value == GPIO_PIN_LOW) 279 val &= ~INTELGPIO_PADCFG0_GPIOTXSTATE; 280 else 281 val |= INTELGPIO_PADCFG0_GPIOTXSTATE; 282 bus_write_4(res, pad_off, val); 283 INTELGPIO_UNLOCK(sc); 284 285 return (0); 286 } 287 288 static int 289 intelgpio_pin_toggle(device_t dev, uint32_t pin) 290 { 291 struct intelgpio_softc *sc; 292 struct resource *res; 293 bus_size_t pad_off; 294 uint32_t val; 295 296 sc = device_get_softc(dev); 297 if (intelgpio_gpio_to_pad(sc, pin, &res, &pad_off, NULL) != 0) 298 return (EINVAL); 299 if (res == NULL) 300 return (EINVAL); 301 302 INTELGPIO_LOCK(sc); 303 val = bus_read_4(res, pad_off); 304 val ^= INTELGPIO_PADCFG0_GPIOTXSTATE; 305 bus_write_4(res, pad_off, val); 306 INTELGPIO_UNLOCK(sc); 307 308 return (0); 309 } 310 311 int 312 intelgpio_probe(device_t dev, const struct intelgpio_platform *plat) 313 { 314 int rv; 315 316 if (acpi_disabled("intelgpio")) 317 return (ENXIO); 318 319 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, plat->hids, NULL); 320 if (rv <= 0) 321 device_set_desc(dev, plat->desc); 322 return (rv); 323 } 324 325 static int 326 intelgpio_detach(device_t dev) 327 { 328 struct intelgpio_softc *sc; 329 int i; 330 331 sc = device_get_softc(dev); 332 333 if (sc->sc_busdev != NULL) 334 gpiobus_detach_bus(dev); 335 336 for (i = 0; i < sc->sc_plat->ncommunities; i++) { 337 if (sc->sc_mem_res[i] != NULL) 338 bus_release_resource(dev, SYS_RES_MEMORY, i, 339 sc->sc_mem_res[i]); 340 } 341 342 INTELGPIO_LOCK_DESTROY(sc); 343 return (0); 344 } 345 346 int 347 intelgpio_attach(device_t dev, const struct intelgpio_platform *plat) 348 { 349 struct intelgpio_softc *sc; 350 bool have_res; 351 int i; 352 353 sc = device_get_softc(dev); 354 sc->sc_dev = dev; 355 sc->sc_plat = plat; 356 357 KASSERT(plat->ncommunities <= INTELGPIO_MAX_COMMUNITIES, 358 ("too many communities: %d > %d", plat->ncommunities, 359 INTELGPIO_MAX_COMMUNITIES)); 360 361 INTELGPIO_LOCK_INIT(sc); 362 363 have_res = false; 364 for (i = 0; i < plat->ncommunities; i++) { 365 sc->sc_mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 366 &i, RF_ACTIVE); 367 if (sc->sc_mem_res[i] == NULL) { 368 device_printf(dev, 369 "failed to allocate memory resource " 370 "for community %d\n", 371 i); 372 continue; 373 } 374 sc->sc_padbar[i] = bus_read_4(sc->sc_mem_res[i], 375 INTELGPIO_PADBAR_REG); 376 have_res = true; 377 } 378 379 if (!have_res) { 380 device_printf(dev, "no memory resources found\n"); 381 INTELGPIO_LOCK_DESTROY(sc); 382 return (ENXIO); 383 } 384 385 sc->sc_busdev = gpiobus_add_bus(dev); 386 if (sc->sc_busdev == NULL) { 387 device_printf(dev, "failed to add gpiobus\n"); 388 intelgpio_detach(dev); 389 return (ENXIO); 390 } 391 392 bus_attach_children(dev); 393 394 return (0); 395 } 396 397 398 static device_method_t intelgpio_methods[] = { 399 DEVMETHOD(device_detach, intelgpio_detach), 400 401 DEVMETHOD(gpio_get_bus, intelgpio_get_bus), 402 DEVMETHOD(gpio_pin_max, intelgpio_pin_max), 403 DEVMETHOD(gpio_pin_getname, intelgpio_pin_getname), 404 DEVMETHOD(gpio_pin_getcaps, intelgpio_pin_getcaps), 405 DEVMETHOD(gpio_pin_getflags, intelgpio_pin_getflags), 406 DEVMETHOD(gpio_pin_setflags, intelgpio_pin_setflags), 407 DEVMETHOD(gpio_pin_get, intelgpio_pin_get), 408 DEVMETHOD(gpio_pin_set, intelgpio_pin_set), 409 DEVMETHOD(gpio_pin_toggle, intelgpio_pin_toggle), 410 411 DEVMETHOD_END 412 }; 413 414 DEFINE_CLASS_0(intelgpio, intelgpio_driver, intelgpio_methods, 415 sizeof(struct intelgpio_softc)); 416