1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2024 Ahmad Khalifa <ahmadkhalifa570@gmail.com> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/bus.h> 30 #include <sys/kernel.h> 31 #include <sys/module.h> 32 #include <sys/gpio.h> 33 34 #include <contrib/dev/acpica/include/acpi.h> 35 #include <dev/acpica/acpivar.h> 36 37 #include <dev/gpio/gpiobusvar.h> 38 #include <dev/gpio/acpi_gpiobusvar.h> 39 #include <dev/gpio/gpiobus_internal.h> 40 #include <sys/sbuf.h> 41 42 #include "gpiobus_if.h" 43 44 struct acpi_gpiobus_softc { 45 struct gpiobus_softc super_sc; 46 ACPI_CONNECTION_INFO handler_info; 47 }; 48 49 struct acpi_gpiobus_ctx { 50 struct gpiobus_softc *sc; 51 ACPI_HANDLE dev_handle; 52 }; 53 54 struct acpi_gpiobus_ivar 55 { 56 struct gpiobus_ivar gpiobus; 57 ACPI_HANDLE handle; 58 }; 59 60 uint32_t 61 acpi_gpiobus_convflags(ACPI_RESOURCE_GPIO *gpio_res) 62 { 63 uint32_t flags = 0; 64 65 /* Figure out pin flags */ 66 if (gpio_res->ConnectionType == ACPI_RESOURCE_GPIO_TYPE_INT) { 67 switch (gpio_res->Polarity) { 68 case ACPI_ACTIVE_HIGH: 69 flags = gpio_res->Triggering == ACPI_LEVEL_SENSITIVE ? 70 GPIO_INTR_LEVEL_HIGH : GPIO_INTR_EDGE_RISING; 71 break; 72 case ACPI_ACTIVE_LOW: 73 flags = gpio_res->Triggering == ACPI_LEVEL_SENSITIVE ? 74 GPIO_INTR_LEVEL_LOW : GPIO_INTR_EDGE_FALLING; 75 break; 76 case ACPI_ACTIVE_BOTH: 77 flags = GPIO_INTR_EDGE_BOTH; 78 break; 79 } 80 81 flags |= GPIO_PIN_INPUT; 82 #ifdef NOT_YET 83 /* This is not currently implemented. */ 84 if (gpio_res->Shareable == ACPI_SHARED) 85 flags |= GPIO_INTR_SHAREABLE; 86 #endif 87 } 88 if (gpio_res->ConnectionType == ACPI_RESOURCE_GPIO_TYPE_IO) { 89 switch (gpio_res->IoRestriction) { 90 case ACPI_IO_RESTRICT_INPUT: 91 flags |= GPIO_PIN_INPUT; 92 break; 93 case ACPI_IO_RESTRICT_OUTPUT: 94 flags |= GPIO_PIN_OUTPUT; 95 break; 96 } 97 } 98 99 switch (gpio_res->PinConfig) { 100 case ACPI_PIN_CONFIG_PULLUP: 101 flags |= GPIO_PIN_PULLUP; 102 break; 103 case ACPI_PIN_CONFIG_PULLDOWN: 104 flags |= GPIO_PIN_PULLDOWN; 105 break; 106 } 107 108 return (flags); 109 } 110 111 static ACPI_STATUS 112 acpi_gpiobus_enumerate_res(ACPI_RESOURCE *res, void *context) 113 { 114 ACPI_RESOURCE_GPIO *gpio_res = &res->Data.Gpio; 115 struct acpi_gpiobus_ctx *ctx = context; 116 struct gpiobus_softc *super_sc = ctx->sc; 117 ACPI_HANDLE handle; 118 uint32_t flags, i; 119 120 if (res->Type != ACPI_RESOURCE_TYPE_GPIO) 121 return (AE_OK); 122 123 if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, 124 gpio_res->ResourceSource.StringPtr, &handle)) || 125 handle != ctx->dev_handle) 126 return (AE_OK); 127 128 if (__predict_false(gpio_res->PinTableLength > super_sc->sc_npins)) { 129 device_printf(super_sc->sc_busdev, 130 "invalid pin table length %hu, max: %d (bad ACPI tables?)\n", 131 gpio_res->PinTableLength, super_sc->sc_npins); 132 return (AE_LIMIT); 133 } 134 135 flags = acpi_gpiobus_convflags(gpio_res); 136 for (i = 0; i < gpio_res->PinTableLength; i++) { 137 UINT16 pin = gpio_res->PinTable[i]; 138 139 if (__predict_false(pin >= super_sc->sc_npins)) { 140 device_printf(super_sc->sc_busdev, 141 "invalid pin 0x%x, max: 0x%x (bad ACPI tables?)\n", 142 pin, super_sc->sc_npins - 1); 143 return (AE_LIMIT); 144 } 145 146 GPIO_PIN_SETFLAGS(super_sc->sc_dev, pin, flags & 147 ~GPIO_INTR_MASK); 148 } 149 150 return (AE_OK); 151 } 152 153 static ACPI_STATUS 154 acpi_gpiobus_enumerate_aei(ACPI_RESOURCE *res, void *context) 155 { 156 ACPI_RESOURCE_GPIO *gpio_res = &res->Data.Gpio; 157 uint32_t *npins = context, *pins = npins + 1; 158 159 /* 160 * Check that we have a GpioInt object. 161 * Note that according to the spec this 162 * should always be the case. 163 */ 164 if (res->Type != ACPI_RESOURCE_TYPE_GPIO) 165 return (AE_OK); 166 if (gpio_res->ConnectionType != ACPI_RESOURCE_GPIO_TYPE_INT) 167 return (AE_OK); 168 169 for (int i = 0; i < gpio_res->PinTableLength; i++) 170 pins[(*npins)++] = gpio_res->PinTable[i]; 171 return (AE_OK); 172 } 173 174 static ACPI_STATUS 175 acpi_gpiobus_enumerate(ACPI_HANDLE handle, UINT32 depth, void *context, 176 void **result) 177 { 178 UINT32 sta; 179 180 /* 181 * If no _STA method or if it failed, then assume that 182 * the device is present. 183 */ 184 if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) && 185 !ACPI_DEVICE_PRESENT(sta)) 186 return (AE_OK); 187 188 if (!acpi_has_hid(handle)) 189 return (AE_OK); 190 191 /* Look for GPIO resources */ 192 AcpiWalkResources(handle, "_CRS", acpi_gpiobus_enumerate_res, context); 193 194 return (AE_OK); 195 } 196 197 static ACPI_STATUS 198 acpi_gpiobus_space_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address, 199 UINT32 length, UINT64 *value, void *context, void *region_context) 200 { 201 ACPI_CONNECTION_INFO *info = context; 202 ACPI_RESOURCE_GPIO *gpio_res; 203 device_t controller; 204 ACPI_RESOURCE *res; 205 ACPI_STATUS status; 206 207 status = AcpiBufferToResource(info->Connection, info->Length, &res); 208 if (ACPI_FAILURE(status) || res->Type != ACPI_RESOURCE_TYPE_GPIO) 209 goto err; 210 211 gpio_res = &res->Data.Gpio; 212 controller = __containerof(info, struct acpi_gpiobus_softc, 213 handler_info)->super_sc.sc_dev; 214 215 switch (function) { 216 case ACPI_WRITE: 217 if (__predict_false( 218 gpio_res->IoRestriction == ACPI_IO_RESTRICT_INPUT)) 219 goto err; 220 221 for (int i = 0; i < length; i++) 222 if (GPIO_PIN_SET(controller, 223 gpio_res->PinTable[address + i], (*value & 1 << i) ? 224 GPIO_PIN_HIGH : GPIO_PIN_LOW) != 0) 225 goto err; 226 break; 227 case ACPI_READ: 228 if (__predict_false( 229 gpio_res->IoRestriction == ACPI_IO_RESTRICT_OUTPUT)) 230 goto err; 231 232 for (int i = 0; i < length; i++) { 233 uint32_t v; 234 235 if (GPIO_PIN_GET(controller, 236 gpio_res->PinTable[address + i], &v) != 0) 237 goto err; 238 *value |= v << i; 239 } 240 break; 241 default: 242 goto err; 243 } 244 245 ACPI_FREE(res); 246 return (AE_OK); 247 248 err: 249 ACPI_FREE(res); 250 return (AE_BAD_PARAMETER); 251 } 252 253 static void 254 acpi_gpiobus_attach_aei(struct acpi_gpiobus_softc *sc, ACPI_HANDLE handle) 255 { 256 struct acpi_gpiobus_ivar *devi; 257 ACPI_HANDLE aei_handle; 258 device_t child; 259 uint32_t *pins; 260 ACPI_STATUS status; 261 int err; 262 263 status = AcpiGetHandle(handle, "_AEI", &aei_handle); 264 if (ACPI_FAILURE(status)) 265 return; 266 267 /* pins[0] specifies the length of the array. */ 268 pins = mallocarray(sc->super_sc.sc_npins + 1, 269 sizeof(uint32_t), M_DEVBUF, M_WAITOK); 270 pins[0] = 0; 271 272 status = AcpiWalkResources(handle, "_AEI", 273 acpi_gpiobus_enumerate_aei, pins); 274 if (ACPI_FAILURE(status)) { 275 device_printf(sc->super_sc.sc_busdev, 276 "Failed to enumerate AEI resources\n"); 277 free(pins, M_DEVBUF); 278 return; 279 } 280 281 child = BUS_ADD_CHILD(sc->super_sc.sc_busdev, 0, "gpio_aei", 282 DEVICE_UNIT_ANY); 283 if (child == NULL) { 284 device_printf(sc->super_sc.sc_busdev, 285 "Failed to add gpio_aei child\n"); 286 free(pins, M_DEVBUF); 287 return; 288 } 289 290 devi = device_get_ivars(child); 291 devi->gpiobus.npins = pins[0]; 292 devi->handle = aei_handle; 293 294 err = gpiobus_alloc_ivars(&devi->gpiobus); 295 if (err != 0) { 296 device_printf(sc->super_sc.sc_busdev, 297 "Failed to allocate gpio_aei ivars\n"); 298 device_delete_child(sc->super_sc.sc_busdev, child); 299 free(pins, M_DEVBUF); 300 return; 301 } 302 303 for (int i = 0; i < pins[0]; i++) 304 devi->gpiobus.pins[i] = pins[i + 1]; 305 free(pins, M_DEVBUF); 306 307 status = AcpiAttachData(aei_handle, acpi_fake_objhandler, child); 308 if (ACPI_FAILURE(status)) { 309 printf("WARNING: Unable to attach object data to %s - %s\n", 310 acpi_name(aei_handle), AcpiFormatException(status)); 311 } 312 313 bus_attach_children(sc->super_sc.sc_busdev); 314 } 315 316 static int 317 acpi_gpiobus_probe(device_t dev) 318 { 319 device_t controller; 320 321 if (acpi_disabled("gpiobus")) 322 return (ENXIO); 323 324 controller = device_get_parent(dev); 325 if (controller == NULL) 326 return (ENXIO); 327 328 if (acpi_get_handle(controller) == NULL) 329 return (ENXIO); 330 331 device_set_desc(dev, "GPIO bus (ACPI-hinted)"); 332 return (BUS_PROBE_DEFAULT); 333 } 334 335 static int 336 acpi_gpiobus_attach(device_t dev) 337 { 338 struct acpi_gpiobus_softc *sc; 339 struct acpi_gpiobus_ctx ctx; 340 ACPI_HANDLE handle; 341 ACPI_STATUS status; 342 int err; 343 344 if ((err = gpiobus_attach(dev)) != 0) 345 return (err); 346 347 sc = device_get_softc(dev); 348 handle = acpi_get_handle(sc->super_sc.sc_dev); 349 if (handle == NULL) { 350 gpiobus_detach(dev); 351 return (ENXIO); 352 } 353 354 status = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GPIO, 355 acpi_gpiobus_space_handler, NULL, &sc->handler_info); 356 357 if (ACPI_FAILURE(status)) { 358 device_printf(dev, 359 "Failed to install GPIO address space handler\n"); 360 gpiobus_detach(dev); 361 return (ENXIO); 362 } 363 364 ctx.dev_handle = handle; 365 ctx.sc = &sc->super_sc; 366 367 status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 368 ACPI_UINT32_MAX, acpi_gpiobus_enumerate, NULL, &ctx, NULL); 369 370 if (ACPI_FAILURE(status)) 371 device_printf(dev, "Failed to enumerate GPIO resources\n"); 372 373 /* Look for AEI child */ 374 acpi_gpiobus_attach_aei(sc, handle); 375 return (0); 376 } 377 378 static int 379 acpi_gpiobus_detach(device_t dev) 380 { 381 struct gpiobus_softc *super_sc; 382 ACPI_STATUS status; 383 384 super_sc = device_get_softc(dev); 385 status = AcpiRemoveAddressSpaceHandler( 386 acpi_get_handle(super_sc->sc_dev), ACPI_ADR_SPACE_GPIO, 387 acpi_gpiobus_space_handler 388 ); 389 390 if (ACPI_FAILURE(status)) 391 device_printf(dev, 392 "Failed to remove GPIO address space handler\n"); 393 394 return (gpiobus_detach(dev)); 395 } 396 397 static int 398 acpi_gpiobus_read_ivar(device_t dev, device_t child, int which, 399 uintptr_t *result) 400 { 401 struct acpi_gpiobus_ivar *devi = device_get_ivars(child); 402 403 switch (which) { 404 case ACPI_GPIOBUS_IVAR_HANDLE: 405 *result = (uintptr_t)devi->handle; 406 break; 407 default: 408 return (gpiobus_read_ivar(dev, child, which, result)); 409 } 410 411 return (0); 412 } 413 414 static device_t 415 acpi_gpiobus_add_child(device_t dev, u_int order, const char *name, int unit) 416 { 417 return (gpiobus_add_child_common(dev, order, name, unit, 418 sizeof(struct acpi_gpiobus_ivar))); 419 } 420 421 static int 422 acpi_gpiobus_child_location(device_t bus, device_t child, struct sbuf *sb) 423 { 424 struct acpi_gpiobus_ivar *devi; 425 int err; 426 427 err = gpiobus_child_location(bus, child, sb); 428 if (err != 0) 429 return (err); 430 431 devi = device_get_ivars(child); 432 sbuf_printf(sb, " handle=%s", acpi_name(devi->handle)); 433 return (0); 434 } 435 436 static void 437 acpi_gpiobus_child_deleted(device_t bus, device_t child) 438 { 439 struct acpi_gpiobus_ivar *devi = device_get_ivars(child); 440 441 if (acpi_get_device(devi->handle) == child) 442 AcpiDetachData(devi->handle, acpi_fake_objhandler); 443 gpiobus_child_deleted(bus, child); 444 } 445 446 static device_method_t acpi_gpiobus_methods[] = { 447 /* Device interface */ 448 DEVMETHOD(device_probe, acpi_gpiobus_probe), 449 DEVMETHOD(device_attach, acpi_gpiobus_attach), 450 DEVMETHOD(device_detach, acpi_gpiobus_detach), 451 452 /* Bus interface */ 453 DEVMETHOD(bus_read_ivar, acpi_gpiobus_read_ivar), 454 DEVMETHOD(bus_add_child, acpi_gpiobus_add_child), 455 DEVMETHOD(bus_child_location, acpi_gpiobus_child_location), 456 DEVMETHOD(bus_child_deleted, acpi_gpiobus_child_deleted), 457 458 DEVMETHOD_END 459 }; 460 461 DEFINE_CLASS_1(gpiobus, acpi_gpiobus_driver, acpi_gpiobus_methods, 462 sizeof(struct acpi_gpiobus_softc), gpiobus_driver); 463 EARLY_DRIVER_MODULE(acpi_gpiobus, gpio, acpi_gpiobus_driver, NULL, NULL, 464 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 465 MODULE_VERSION(acpi_gpiobus, 1); 466 MODULE_DEPEND(acpi_gpiobus, acpi, 1, 1, 1); 467