1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023 Vladimir Kondratyev <wulf@FreeBSD.org> 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 AUTHOR 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 AUTHOR 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/param.h> 29 #include <sys/bus.h> 30 #include <sys/endian.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/rman.h> 35 #include <sys/sbuf.h> 36 #include <sys/systm.h> 37 38 #include <machine/resource.h> 39 40 #include <contrib/dev/acpica/include/acpi.h> 41 #include <contrib/dev/acpica/include/accommon.h> 42 #include <contrib/dev/acpica/include/amlcode.h> 43 #include <dev/acpica/acpivar.h> 44 45 #include <dev/spibus/spibusvar.h> 46 47 /* 48 * Make a copy of ACPI_RESOURCE_SPI_SERIALBUS type and replace "pointer to ACPI 49 * object name string" field with pointer to ACPI object itself. 50 * This saves us extra strdup()/free() pair on acpi_spibus_get_acpi_res call. 51 */ 52 typedef ACPI_RESOURCE_SPI_SERIALBUS ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS; 53 #define ResourceSource_Handle ResourceSource.StringPtr 54 55 /* Hooks for the ACPI CA debugging infrastructure. */ 56 #define _COMPONENT ACPI_BUS 57 ACPI_MODULE_NAME("SPI") 58 59 #if defined (__amd64__) || defined (__i386__) 60 static bool is_apple; 61 #endif 62 63 struct acpi_spibus_ivar { 64 struct spibus_ivar super_ivar; 65 ACPI_HANDLE handle; 66 }; 67 68 static inline bool 69 acpi_resource_is_spi_serialbus(ACPI_RESOURCE *res) 70 { 71 return (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS && 72 res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_SPI); 73 } 74 75 static ACPI_STATUS 76 acpi_spibus_get_acpi_res_cb(ACPI_RESOURCE *res, void *context) 77 { 78 ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS *sb = context; 79 ACPI_STATUS status; 80 ACPI_HANDLE handle; 81 82 if (acpi_resource_is_spi_serialbus(res)) { 83 status = AcpiGetHandle(ACPI_ROOT_OBJECT, 84 res->Data.SpiSerialBus.ResourceSource.StringPtr, &handle); 85 if (ACPI_FAILURE(status)) 86 return (status); 87 memcpy(sb, &res->Data.SpiSerialBus, 88 sizeof(ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS)); 89 /* 90 * replace "pointer to ACPI object name string" field 91 * with pointer to ACPI object itself. 92 */ 93 sb->ResourceSource_Handle = handle; 94 return (AE_CTRL_TERMINATE); 95 } else if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) 96 return (AE_NOT_FOUND); 97 98 return (AE_OK); 99 } 100 101 static void 102 acpi_spibus_dump_res(device_t dev, ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS *sb) 103 { 104 device_printf(dev, "found ACPI child\n"); 105 printf(" DeviceSelection: 0x%04hx\n", sb->DeviceSelection); 106 printf(" ConnectionSpeed: %uHz\n", sb->ConnectionSpeed); 107 printf(" WireMode: %s\n", 108 sb->WireMode == ACPI_SPI_4WIRE_MODE ? 109 "FourWireMode" : "ThreeWireMode"); 110 printf(" DevicePolarity: %s\n", 111 sb->DevicePolarity == ACPI_SPI_ACTIVE_LOW ? 112 "PolarityLow" : "PolarityHigh"); 113 printf(" DataBitLength: %uBit\n", sb->DataBitLength); 114 printf(" ClockPhase: %s\n", 115 sb->ClockPhase == ACPI_SPI_FIRST_PHASE ? 116 "ClockPhaseFirst" : "ClockPhaseSecond"); 117 printf(" ClockPolarity: %s\n", 118 sb->ClockPolarity == ACPI_SPI_START_LOW ? 119 "ClockPolarityLow" : "ClockPolarityHigh"); 120 printf(" SlaveMode: %s\n", 121 sb->SlaveMode == ACPI_CONTROLLER_INITIATED ? 122 "ControllerInitiated" : "DeviceInitiated"); 123 printf(" ConnectionSharing: %s\n", sb->ConnectionSharing == 0 ? 124 "Exclusive" : "Shared"); 125 } 126 127 static int 128 acpi_spibus_get_acpi_res(device_t spibus, ACPI_HANDLE dev, 129 struct spibus_ivar *res) 130 { 131 ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS sb; 132 133 /* 134 * Read "SPI Serial Bus Connection Resource Descriptor" 135 * described in p.19.6.126 of ACPI specification. 136 */ 137 bzero(&sb, sizeof(ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS)); 138 if (ACPI_FAILURE(AcpiWalkResources(dev, "_CRS", 139 acpi_spibus_get_acpi_res_cb, &sb))) 140 return (ENXIO); 141 if (sb.ResourceSource_Handle != 142 acpi_get_handle(device_get_parent(spibus))) 143 return (ENXIO); 144 if (bootverbose) 145 acpi_spibus_dump_res(spibus, &sb); 146 /* 147 * The Windows Baytrail and Braswell SPI host controller 148 * drivers uses 1 as the first (and only) value for ACPI 149 * DeviceSelection. 150 */ 151 if (sb.DeviceSelection != 0 && 152 (acpi_MatchHid(sb.ResourceSource_Handle, "80860F0E") || 153 acpi_MatchHid(sb.ResourceSource_Handle, "8086228E"))) 154 res->cs = sb.DeviceSelection - 1; 155 else 156 res->cs = sb.DeviceSelection; 157 res->mode = 158 (sb.ClockPhase != ACPI_SPI_FIRST_PHASE ? SPIBUS_MODE_CPHA : 0) | 159 (sb.ClockPolarity != ACPI_SPI_START_LOW ? SPIBUS_MODE_CPOL : 0); 160 res->clock = sb.ConnectionSpeed; 161 162 return (0); 163 } 164 165 #if defined (__amd64__) || defined (__i386__) 166 static int 167 acpi_spibus_get_apple_res(device_t spibus, ACPI_HANDLE dev, 168 struct spibus_ivar *ivar) 169 { 170 /* a0b5b7c6-1318-441c-b0c9-fe695eaf949b */ 171 static const uint8_t apple_guid[ACPI_UUID_LENGTH] = { 172 0xC6, 0xB7, 0xB5, 0xA0, 0x18, 0x13, 0x1C, 0x44, 173 0xB0, 0xC9, 0xFE, 0x69, 0x5E, 0xAF, 0x94, 0x9B, 174 }; 175 ACPI_BUFFER buf; 176 ACPI_OBJECT *pkg, *comp; 177 ACPI_HANDLE parent; 178 char *k; 179 uint64_t val; 180 181 /* Apple does not use _CRS but nested devices for SPI slaves */ 182 if (ACPI_FAILURE(AcpiGetParent(dev, &parent))) 183 return (ENXIO); 184 if (parent != acpi_get_handle(device_get_parent(spibus))) 185 return (ENXIO); 186 if (ACPI_FAILURE(acpi_EvaluateDSMTyped(dev, apple_guid, 187 1, 1, NULL, &buf, ACPI_TYPE_PACKAGE))) 188 return (ENXIO); 189 190 pkg = ((ACPI_OBJECT *)buf.Pointer); 191 if (pkg->Package.Count % 2 != 0) { 192 device_printf(spibus, "_DSM length %d not even\n", 193 pkg->Package.Count); 194 AcpiOsFree(pkg); 195 return (ENXIO); 196 } 197 198 if (bootverbose) 199 device_printf(spibus, "found ACPI child\n"); 200 201 for (comp = pkg->Package.Elements; 202 comp < pkg->Package.Elements + pkg->Package.Count; 203 comp += 2) { 204 205 if (comp[0].Type != ACPI_TYPE_STRING || 206 comp[1].Type != ACPI_TYPE_BUFFER) { 207 device_printf(spibus, "expected string+buffer, " 208 "got %d+%d\n", comp[0].Type, comp[1].Type); 209 continue; 210 } 211 k = comp[0].String.Pointer; 212 val = comp[1].Buffer.Length >= 8 ? 213 *(uint64_t *)comp[1].Buffer.Pointer : 0; 214 215 if (bootverbose) 216 printf(" %s: %ju\n", k, (intmax_t)val); 217 218 if (strcmp(k, "spiSclkPeriod") == 0) { 219 if (val != 0) 220 ivar->clock = 1000000000 / val; 221 } else if (strcmp(k, "spiSPO") == 0) { 222 if (val != 0) 223 ivar->mode |= SPIBUS_MODE_CPOL; 224 } else if (strcmp(k, "spiSPH") == 0) { 225 if (val != 0) 226 ivar->mode |= SPIBUS_MODE_CPHA; 227 } else if (strcmp(k, "spiCSDelay") == 0) { 228 ivar->cs_delay = val; 229 } 230 } 231 232 AcpiOsFree(pkg); 233 234 return (0); 235 } 236 #endif 237 238 static int 239 acpi_spibus_delete_acpi_child(ACPI_HANDLE handle) 240 { 241 device_t acpi_child, acpi0; 242 243 /* Delete existing child of acpi bus */ 244 acpi_child = acpi_get_device(handle); 245 if (acpi_child != NULL) { 246 acpi0 = devclass_get_device(devclass_find("acpi"), 0); 247 if (device_get_parent(acpi_child) != acpi0) 248 return (ENXIO); 249 250 if (device_is_attached(acpi_child)) 251 return (ENXIO); 252 253 if (device_delete_child(acpi0, acpi_child) != 0) 254 return (ENXIO); 255 } 256 257 return (0); 258 } 259 260 static device_t 261 acpi_spibus_add_child(device_t dev, u_int order, const char *name, int unit) 262 { 263 return (spibus_add_child_common( 264 dev, order, name, unit, sizeof(struct acpi_spibus_ivar))); 265 } 266 267 static ACPI_STATUS 268 acpi_spibus_enumerate_child(ACPI_HANDLE handle, UINT32 level, 269 void *context, void **result) 270 { 271 device_t spibus, child; 272 struct spibus_ivar res; 273 ACPI_STATUS status; 274 UINT32 sta; 275 bool found = false; 276 277 spibus = context; 278 279 /* 280 * If no _STA method or if it failed, then assume that 281 * the device is present. 282 */ 283 if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) && 284 !ACPI_DEVICE_PRESENT(sta)) 285 return (AE_OK); 286 287 if (!acpi_has_hid(handle)) 288 return (AE_OK); 289 290 bzero(&res, sizeof(res)); 291 if (acpi_spibus_get_acpi_res(spibus, handle, &res) == 0) 292 found = true; 293 #if defined (__amd64__) || defined (__i386__) 294 if (!found && is_apple && 295 acpi_spibus_get_apple_res(spibus, handle, &res) == 0) 296 found = true; 297 #endif 298 if (!found || res.clock == 0) 299 return (AE_OK); 300 301 /* Delete existing child of acpi bus */ 302 if (acpi_spibus_delete_acpi_child(handle) != 0) 303 return (AE_OK); 304 305 child = BUS_ADD_CHILD(spibus, 0, NULL, -1); 306 if (child == NULL) { 307 device_printf(spibus, "add child failed\n"); 308 return (AE_OK); 309 } 310 311 spibus_set_cs(child, res.cs); 312 spibus_set_mode(child, res.mode); 313 spibus_set_clock(child, res.clock); 314 spibus_set_cs_delay(child, res.cs_delay); 315 acpi_set_handle(child, handle); 316 acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL); 317 318 /* 319 * Update ACPI-CA to use the IIC enumerated device_t for this handle. 320 */ 321 status = AcpiAttachData(handle, acpi_fake_objhandler, child); 322 if (ACPI_FAILURE(status)) 323 printf("WARNING: Unable to attach object data to %s - %s\n", 324 acpi_name(handle), AcpiFormatException(status)); 325 326 return (AE_OK); 327 } 328 329 static ACPI_STATUS 330 acpi_spibus_enumerate_children(device_t dev) 331 { 332 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 333 ACPI_UINT32_MAX, acpi_spibus_enumerate_child, NULL, dev, NULL)); 334 } 335 336 static void 337 acpi_spibus_set_power_children(device_t dev, int state, bool all_children) 338 { 339 device_t *devlist; 340 int i, numdevs; 341 342 if (device_get_children(dev, &devlist, &numdevs) != 0) 343 return; 344 345 for (i = 0; i < numdevs; i++) 346 if (all_children || device_is_attached(devlist[i]) != 0) 347 acpi_set_powerstate(devlist[i], state); 348 349 free(devlist, M_TEMP); 350 } 351 352 static int 353 acpi_spibus_probe(device_t dev) 354 { 355 ACPI_HANDLE handle; 356 device_t controller; 357 358 if (acpi_disabled("spibus")) 359 return (ENXIO); 360 361 controller = device_get_parent(dev); 362 if (controller == NULL) 363 return (ENXIO); 364 365 handle = acpi_get_handle(controller); 366 if (handle == NULL) 367 return (ENXIO); 368 369 device_set_desc(dev, "SPI bus (ACPI-hinted)"); 370 return (BUS_PROBE_DEFAULT + 1); 371 } 372 373 static int 374 acpi_spibus_attach(device_t dev) 375 { 376 377 #if defined (__amd64__) || defined (__i386__) 378 char *vendor = kern_getenv("smbios.bios.vendor"); 379 if (vendor != NULL && 380 (strcmp(vendor, "Apple Inc.") == 0 || 381 strcmp(vendor, "Apple Computer, Inc.") == 0)) 382 is_apple = true; 383 #endif 384 385 if (ACPI_FAILURE(acpi_spibus_enumerate_children(dev))) 386 device_printf(dev, "children enumeration failed\n"); 387 388 acpi_spibus_set_power_children(dev, ACPI_STATE_D0, true); 389 return (spibus_attach(dev)); 390 } 391 392 static int 393 acpi_spibus_detach(device_t dev) 394 { 395 acpi_spibus_set_power_children(dev, ACPI_STATE_D3, false); 396 397 return (spibus_detach(dev)); 398 } 399 400 static int 401 acpi_spibus_suspend(device_t dev) 402 { 403 acpi_spibus_set_power_children(dev, ACPI_STATE_D3, false); 404 405 return (bus_generic_suspend(dev)); 406 } 407 408 static int 409 acpi_spibus_resume(device_t dev) 410 { 411 acpi_spibus_set_power_children(dev, ACPI_STATE_D0, false); 412 413 return (bus_generic_resume(dev)); 414 } 415 416 #ifndef INTRNG 417 /* Mostly copy of acpi_alloc_resource() */ 418 static struct resource * 419 acpi_spibus_alloc_resource(device_t dev, device_t child, int type, int *rid, 420 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 421 { 422 ACPI_RESOURCE ares; 423 struct resource_list *rl; 424 struct resource *res; 425 426 if (device_get_parent(child) != dev) 427 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 428 type, rid, start, end, count, flags)); 429 430 rl = BUS_GET_RESOURCE_LIST(dev, child); 431 if (rl == NULL) 432 return (NULL); 433 434 res = resource_list_alloc(rl, dev, child, type, rid, 435 start, end, count, flags); 436 if (res != NULL && type == SYS_RES_IRQ && 437 ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res, &ares))) 438 acpi_config_intr(child, &ares); 439 440 return (res); 441 } 442 #endif 443 444 /* 445 * If this device is an ACPI child but no one claimed it, attempt 446 * to power it off. We'll power it back up when a driver is added. 447 */ 448 static void 449 acpi_spibus_probe_nomatch(device_t bus, device_t child) 450 { 451 spibus_probe_nomatch(bus, child); 452 acpi_set_powerstate(child, ACPI_STATE_D3); 453 } 454 455 /* 456 * If a new driver has a chance to probe a child, first power it up. 457 */ 458 static void 459 acpi_spibus_driver_added(device_t dev, driver_t *driver) 460 { 461 device_t child, *devlist; 462 int i, numdevs; 463 464 DEVICE_IDENTIFY(driver, dev); 465 if (device_get_children(dev, &devlist, &numdevs) != 0) 466 return; 467 468 for (i = 0; i < numdevs; i++) { 469 child = devlist[i]; 470 if (device_get_state(child) == DS_NOTPRESENT) { 471 acpi_set_powerstate(child, ACPI_STATE_D0); 472 if (device_probe_and_attach(child) != 0) 473 acpi_set_powerstate(child, ACPI_STATE_D3); 474 } 475 } 476 free(devlist, M_TEMP); 477 } 478 479 static void 480 acpi_spibus_child_deleted(device_t bus, device_t child) 481 { 482 struct acpi_spibus_ivar *devi = device_get_ivars(child); 483 484 if (acpi_get_device(devi->handle) == child) 485 AcpiDetachData(devi->handle, acpi_fake_objhandler); 486 } 487 488 static int 489 acpi_spibus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res) 490 { 491 struct acpi_spibus_ivar *devi = device_get_ivars(child); 492 493 switch (which) { 494 case ACPI_IVAR_HANDLE: 495 *res = (uintptr_t)devi->handle; 496 break; 497 default: 498 return (spibus_read_ivar(bus, child, which, res)); 499 } 500 501 return (0); 502 } 503 504 static int 505 acpi_spibus_write_ivar(device_t bus, device_t child, int which, uintptr_t val) 506 { 507 struct acpi_spibus_ivar *devi = device_get_ivars(child); 508 509 switch (which) { 510 case ACPI_IVAR_HANDLE: 511 if (devi->handle != NULL) 512 return (EINVAL); 513 devi->handle = (ACPI_HANDLE)val; 514 break; 515 default: 516 return (spibus_write_ivar(bus, child, which, val)); 517 } 518 519 return (0); 520 } 521 522 /* Location hint for devctl(8). Concatenate IIC and ACPI hints. */ 523 static int 524 acpi_spibus_child_location(device_t bus, device_t child, struct sbuf *sb) 525 { 526 struct acpi_spibus_ivar *devi = device_get_ivars(child); 527 int error; 528 529 /* read SPI location hint string into the buffer. */ 530 error = spibus_child_location(bus, child, sb); 531 if (error != 0) 532 return (error); 533 534 /* Place ACPI string right after IIC one's terminating NUL. */ 535 if (devi->handle != NULL) 536 sbuf_printf(sb, " handle=%s", acpi_name(devi->handle)); 537 538 return (0); 539 } 540 541 /* PnP information for devctl(8). */ 542 static int 543 acpi_spibus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb) 544 { 545 struct acpi_spibus_ivar *devi = device_get_ivars(child); 546 547 return ( 548 devi->handle == NULL ? ENOTSUP : acpi_pnpinfo(devi->handle, sb)); 549 } 550 551 static device_method_t acpi_spibus_methods[] = { 552 /* Device interface */ 553 DEVMETHOD(device_probe, acpi_spibus_probe), 554 DEVMETHOD(device_attach, acpi_spibus_attach), 555 DEVMETHOD(device_detach, acpi_spibus_detach), 556 DEVMETHOD(device_suspend, acpi_spibus_suspend), 557 DEVMETHOD(device_resume, acpi_spibus_resume), 558 559 /* Bus interface */ 560 #ifndef INTRNG 561 DEVMETHOD(bus_alloc_resource, acpi_spibus_alloc_resource), 562 #endif 563 DEVMETHOD(bus_add_child, acpi_spibus_add_child), 564 DEVMETHOD(bus_probe_nomatch, acpi_spibus_probe_nomatch), 565 DEVMETHOD(bus_driver_added, acpi_spibus_driver_added), 566 DEVMETHOD(bus_child_deleted, acpi_spibus_child_deleted), 567 DEVMETHOD(bus_read_ivar, acpi_spibus_read_ivar), 568 DEVMETHOD(bus_write_ivar, acpi_spibus_write_ivar), 569 DEVMETHOD(bus_child_location, acpi_spibus_child_location), 570 DEVMETHOD(bus_child_pnpinfo, acpi_spibus_child_pnpinfo), 571 DEVMETHOD(bus_get_device_path, acpi_get_acpi_device_path), 572 573 DEVMETHOD_END, 574 }; 575 576 DEFINE_CLASS_1(spibus, acpi_spibus_driver, acpi_spibus_methods, 577 sizeof(struct spibus_softc), spibus_driver); 578 DRIVER_MODULE(acpi_spibus, spi, acpi_spibus_driver, NULL, NULL); 579 MODULE_VERSION(acpi_spibus, 1); 580 MODULE_DEPEND(acpi_spibus, acpi, 1, 1, 1); 581