1 /* 2 * Copyright 2014, Ithamar R. Adema <ithamar@upgrade-android.com> 3 * All rights reserved. Distributed under the terms of the MIT License. 4 * 5 * Copyright 2015-2022, Haiku, Inc. All rights reserved. 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10 #include <drivers/bus/FDT.h> 11 #include <KernelExport.h> 12 #include <util/kernel_cpp.h> 13 #include <util/Vector.h> 14 #include <device_manager.h> 15 16 #include <AutoDeleter.h> 17 #include <AutoDeleterDrivers.h> 18 #include <HashMap.h> 19 #include <debug.h> 20 21 extern "C" { 22 #include <libfdt_env.h> 23 #include <fdt.h> 24 #include <libfdt.h> 25 }; 26 27 28 //#define TRACE_FDT 29 #ifdef TRACE_FDT 30 #define TRACE(x...) dprintf(x) 31 #else 32 #define TRACE(x...) 33 #endif 34 35 36 #define GIC_INTERRUPT_CELL_TYPE 0 37 #define GIC_INTERRUPT_CELL_ID 1 38 #define GIC_INTERRUPT_CELL_FLAGS 2 39 #define GIC_INTERRUPT_TYPE_SPI 0 40 #define GIC_INTERRUPT_TYPE_PPI 1 41 #define GIC_INTERRUPT_BASE_SPI 32 42 #define GIC_INTERRUPT_BASE_PPI 16 43 44 45 extern void* gFDT; 46 47 device_manager_info* gDeviceManager; 48 49 extern fdt_bus_module_info gBusModule; 50 extern fdt_device_module_info gDeviceModule; 51 52 53 //#pragma mark - 54 55 56 struct fdt_bus { 57 device_node* node; 58 HashMap<HashKey32<int32>, device_node*> phandles; 59 }; 60 61 62 struct fdt_device { 63 device_node* node; 64 device_node* bus; 65 }; 66 67 68 struct fdt_interrupt_map_entry { 69 uint32_t childAddr; 70 uint32_t childIrq; 71 uint32_t parentIrqCtrl; 72 uint32_t parentIrq; 73 }; 74 75 76 struct fdt_interrupt_map { 77 uint32_t childAddrMask; 78 uint32_t childIrqMask; 79 80 Vector<fdt_interrupt_map_entry> fInterruptMap; 81 }; 82 83 84 static status_t 85 fdt_register_node(fdt_bus* bus, int node, device_node* parentDev, 86 device_node*& curDev) 87 { 88 TRACE("%s('%s', %p)\n", __func__, fdt_get_name(gFDT, node, NULL), 89 parentDev); 90 91 const void* prop; int propLen; 92 Vector<device_attr> attrs; 93 int nameLen = 0; 94 const char *name = fdt_get_name(gFDT, node, &nameLen); 95 96 if (name == NULL) { 97 dprintf("%s ERROR: fdt_get_name: %s\n", __func__, 98 fdt_strerror(nameLen)); 99 return B_ERROR; 100 } 101 102 attrs.Add({ B_DEVICE_BUS, B_STRING_TYPE, {.string = "fdt"}}); 103 attrs.Add({ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 104 { .string = (strcmp(name, "") != 0) ? name : "Root" }}); 105 attrs.Add({ "fdt/node", B_UINT32_TYPE, {.ui32 = (uint32)node}}); 106 attrs.Add({ "fdt/name", B_STRING_TYPE, {.string = name}}); 107 108 prop = fdt_getprop(gFDT, node, "device_type", &propLen); 109 if (prop != NULL) 110 attrs.Add({ "fdt/device_type", B_STRING_TYPE, { .string = (const char*)prop }}); 111 112 prop = fdt_getprop(gFDT, node, "compatible", &propLen); 113 114 if (prop != NULL) { 115 const char* propStr = (const char*)prop; 116 const char* propEnd = propStr + propLen; 117 while (propEnd - propStr > 0) { 118 int curLen = strlen(propStr); 119 attrs.Add({ "fdt/compatible", B_STRING_TYPE, { .string = propStr }}); 120 propStr += curLen + 1; 121 } 122 } 123 124 attrs.Add({}); 125 126 status_t res = gDeviceManager->register_node(parentDev, 127 "bus_managers/fdt/driver_v1", &attrs[0], NULL, &curDev); 128 129 if (res < B_OK) 130 return res; 131 132 prop = fdt_getprop(gFDT, node, "phandle", &propLen); 133 134 if (prop != NULL) 135 bus->phandles.Put(fdt32_to_cpu(*(uint32_t*)prop), curDev); 136 137 return B_OK; 138 } 139 140 141 static void 142 fdt_traverse(fdt_bus* bus, int &node, int &depth, device_node* parentDev) 143 { 144 int curDepth = depth; 145 #if 0 146 for (int i = 0; i < depth; i++) dprintf(" "); 147 dprintf("node('%s')\n", fdt_get_name(gFDT, node, NULL)); 148 #endif 149 device_node* curDev; 150 fdt_register_node(bus, node, parentDev, curDev); 151 152 node = fdt_next_node(gFDT, node, &depth); 153 while (node >= 0 && depth == curDepth + 1) { 154 fdt_traverse(bus, node, depth, curDev); 155 } 156 } 157 158 159 //#pragma mark bus 160 161 static int32 162 fdt_bus_std_ops(int32 op, ...) 163 { 164 switch (op) { 165 case B_MODULE_INIT: 166 TRACE("fdt root init\n"); 167 return B_OK; 168 169 case B_MODULE_UNINIT: 170 TRACE("fdt root uninit\n"); 171 return B_OK; 172 } 173 174 return B_BAD_VALUE; 175 } 176 177 178 static float 179 fdt_bus_supports_device(device_node* parent) 180 { 181 TRACE("fdt_bus_supports_device\n"); 182 183 // make sure parent is really device root 184 const char* bus; 185 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 186 return B_ERROR; 187 188 if (strcmp(bus, "root")) 189 return 0.0; 190 191 return 1.0; 192 } 193 194 195 static status_t 196 fdt_bus_register_device(device_node* parent) 197 { 198 TRACE("+fdt_bus_register_device\n"); 199 struct ScopeExit { 200 ScopeExit() {TRACE("-fdt_bus_register_device\n");} 201 } scopeExit; 202 203 device_attr attrs[] = { 204 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "FDT"}}, 205 {B_DEVICE_FLAGS, B_UINT32_TYPE, {.ui32 = B_KEEP_DRIVER_LOADED}}, 206 {} 207 }; 208 209 return gDeviceManager->register_node( 210 parent, "bus_managers/fdt/root/driver_v1", attrs, NULL, NULL); 211 } 212 213 214 static status_t 215 fdt_bus_init(device_node* node, void** cookie) 216 { 217 TRACE("fdt_bus_init\n"); 218 219 if (gFDT == NULL) { 220 TRACE("FDT is NULL!\n"); 221 return B_DEVICE_NOT_FOUND; 222 } 223 224 ObjectDeleter<fdt_bus> bus(new(std::nothrow) fdt_bus()); 225 if (!bus.IsSet()) 226 return B_NO_MEMORY; 227 228 bus->node = node; 229 *cookie = bus.Detach(); 230 return B_OK; 231 } 232 233 234 static void 235 fdt_bus_uninit(void* cookie) 236 { 237 TRACE("fdt_bus_uninit\n"); 238 239 ObjectDeleter<fdt_bus> bus((fdt_bus*)cookie); 240 } 241 242 243 static status_t 244 fdt_bus_register_child_devices(void* cookie) 245 { 246 TRACE("fdt_bus_register_child_devices\n"); 247 248 fdt_bus* bus = (fdt_bus*)cookie; 249 250 int node = -1, depth = -1; 251 node = fdt_next_node(gFDT, node, &depth); 252 fdt_traverse(bus, node, depth, bus->node); 253 254 return B_OK; 255 } 256 257 258 device_node* 259 fdt_bus_node_by_phandle(fdt_bus* bus, int phandle) 260 { 261 ASSERT(bus != NULL); 262 263 device_node** devNode; 264 if (!bus->phandles.Get(phandle, devNode)) 265 return NULL; 266 267 return *devNode; 268 } 269 270 271 //#pragma mark device 272 273 274 static status_t 275 fdt_device_std_ops(int32 op, ...) 276 { 277 switch (op) { 278 case B_MODULE_INIT: 279 case B_MODULE_UNINIT: 280 return B_OK; 281 } 282 283 return B_BAD_VALUE; 284 } 285 286 287 static status_t 288 fdt_device_init_driver(device_node* node, void** cookie) 289 { 290 TRACE("fdt_device_init_driver()\n"); 291 292 ObjectDeleter<fdt_device> dev(new(std::nothrow) fdt_device()); 293 if (!dev.IsSet()) 294 return B_NO_MEMORY; 295 296 dev->node = node; 297 298 // get bus from parent node 299 DeviceNodePutter<&gDeviceManager> parent( 300 gDeviceManager->get_parent_node(node)); 301 driver_module_info* parentModule; 302 void* parentDev; 303 ASSERT(gDeviceManager->get_driver( 304 parent.Get(), &parentModule, &parentDev) >= B_OK); 305 if (parentModule == (driver_module_info*)&gDeviceModule) 306 dev->bus = ((fdt_device*)parentDev)->bus; 307 else if (parentModule == (driver_module_info*)&gBusModule) 308 dev->bus = parent.Get(); 309 else 310 panic("bad parent node"); 311 312 *cookie = dev.Detach(); 313 return B_OK; 314 } 315 316 317 static void 318 fdt_device_uninit_driver(void* cookie) 319 { 320 TRACE("fdt_device_uninit_driver()\n"); 321 ObjectDeleter<fdt_device> dev((fdt_device*)cookie); 322 } 323 324 325 static status_t 326 fdt_device_register_child_devices(void* cookie) 327 { 328 TRACE("fdt_device_register_child_devices()\n"); 329 return B_OK; 330 } 331 332 333 static device_node* 334 fdt_device_get_bus(fdt_device* dev) 335 { 336 ASSERT(dev != NULL); 337 return dev->bus; 338 } 339 340 341 static const char* 342 fdt_device_get_name(fdt_device* dev) 343 { 344 ASSERT(dev != NULL); 345 346 uint32 fdtNode; 347 ASSERT(gDeviceManager->get_attr_uint32( 348 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 349 350 return fdt_get_name(gFDT, (int)fdtNode, NULL); 351 } 352 353 354 static const void* 355 fdt_device_get_prop(fdt_device* dev, const char* name, int* len) 356 { 357 ASSERT(dev != NULL); 358 359 uint32 fdtNode; 360 ASSERT(gDeviceManager->get_attr_uint32( 361 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 362 363 return fdt_getprop(gFDT, (int)fdtNode, name, len); 364 } 365 366 367 static bool 368 fdt_device_get_reg(fdt_device* dev, uint32 ord, uint64* regs, uint64* len) 369 { 370 ASSERT(dev != NULL); 371 372 uint32 fdtNode; 373 ASSERT(gDeviceManager->get_attr_uint32( 374 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 375 376 int propLen; 377 const void* prop = fdt_getprop(gFDT, (int)fdtNode, "reg", &propLen); 378 if (prop == NULL) 379 return false; 380 381 // TODO: use '#address-cells', '#size-cells' in parent node to identify 382 // field sizes 383 384 if ((ord + 1)*16 > (uint32)propLen) 385 return false; 386 387 if (regs != NULL) 388 *regs = fdt64_to_cpu(*(((uint64*)prop) + 2*ord)); 389 390 if (len != NULL) 391 *len = fdt64_to_cpu(*(((uint64*)prop) + 2*ord + 1)); 392 393 return true; 394 } 395 396 397 static uint32 398 fdt_get_interrupt_parent(fdt_device* dev, int node) 399 { 400 while (node >= 0) { 401 uint32* prop; 402 int propLen; 403 prop = (uint32*)fdt_getprop(gFDT, node, "interrupt-parent", &propLen); 404 if (prop != NULL && propLen == 4) { 405 return fdt32_to_cpu(*prop); 406 } 407 408 node = fdt_parent_offset(gFDT, node); 409 } 410 411 return 0; 412 } 413 414 415 static uint32 416 fdt_get_interrupt_cells(uint32 interrupt_parent_phandle) 417 { 418 if (interrupt_parent_phandle > 0) { 419 int node = fdt_node_offset_by_phandle(gFDT, interrupt_parent_phandle); 420 if (node >= 0) { 421 uint32* prop; 422 int propLen; 423 prop = (uint32*)fdt_getprop(gFDT, node, "#interrupt-cells", &propLen); 424 if (prop != NULL && propLen == 4) { 425 return fdt32_to_cpu(*prop); 426 } 427 } 428 } 429 return 1; 430 } 431 432 433 static bool 434 fdt_device_get_interrupt(fdt_device* dev, uint32 index, 435 device_node** interruptController, uint64* interrupt) 436 { 437 ASSERT(dev != NULL); 438 439 uint32 fdtNode; 440 ASSERT(gDeviceManager->get_attr_uint32( 441 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 442 443 int propLen; 444 const uint32 *prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended", 445 &propLen); 446 if (prop == NULL) { 447 uint32 interruptParent = fdt_get_interrupt_parent(dev, fdtNode); 448 uint32 interruptCells = fdt_get_interrupt_cells(interruptParent); 449 450 prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts", 451 &propLen); 452 if (prop == NULL) 453 return false; 454 455 if ((index + 1) * interruptCells * sizeof(uint32) > (uint32)propLen) 456 return false; 457 458 uint32 offset = interruptCells * index; 459 uint32 interruptNumber = 0; 460 461 if ((interruptCells == 1) || (interruptCells == 2)) { 462 interruptNumber = fdt32_to_cpu(*(prop + offset)); 463 } else if (interruptCells == 3) { 464 uint32 interruptType = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_TYPE]); 465 interruptNumber = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_ID]); 466 467 if (interruptType == GIC_INTERRUPT_TYPE_SPI) 468 interruptNumber += GIC_INTERRUPT_BASE_SPI; 469 else if (interruptType == GIC_INTERRUPT_TYPE_PPI) 470 interruptNumber += GIC_INTERRUPT_BASE_PPI; 471 } else { 472 panic("unsupported interruptCells"); 473 } 474 475 if (interrupt != NULL) 476 *interrupt = interruptNumber; 477 478 if (interruptController != NULL && interruptParent != 0) { 479 fdt_bus* bus; 480 ASSERT(gDeviceManager->get_driver(dev->bus, NULL, (void**)&bus) >= B_OK); 481 *interruptController = fdt_bus_node_by_phandle(bus, interruptParent); 482 } 483 484 return true; 485 } 486 487 if ((index + 1) * 8 > (uint32)propLen) 488 return false; 489 490 if (interruptController != NULL) { 491 uint32 phandle = fdt32_to_cpu(*(prop + 2 * index)); 492 493 fdt_bus* bus; 494 ASSERT(gDeviceManager->get_driver( 495 dev->bus, NULL, (void**)&bus) >= B_OK); 496 497 *interruptController = fdt_bus_node_by_phandle(bus, phandle); 498 } 499 500 if (interrupt != NULL) 501 *interrupt = fdt32_to_cpu(*(prop + 2 * index + 1)); 502 503 return true; 504 } 505 506 507 static struct fdt_interrupt_map * 508 fdt_device_get_interrupt_map(struct fdt_device* dev) 509 { 510 int fdtNode; 511 ASSERT(gDeviceManager->get_attr_uint32( 512 dev->node, "fdt/node", (uint32*)&fdtNode, false) >= B_OK); 513 514 ObjectDeleter<struct fdt_interrupt_map> interrupt_map(new struct fdt_interrupt_map()); 515 516 int intMapMaskLen; 517 const void* intMapMask = fdt_getprop(gFDT, fdtNode, "interrupt-map-mask", 518 &intMapMaskLen); 519 520 if (intMapMask == NULL || intMapMaskLen != 4 * 4) { 521 dprintf(" interrupt-map-mask property not found or invalid\n"); 522 return NULL; 523 } 524 525 interrupt_map->childAddrMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 0)); 526 interrupt_map->childIrqMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 3)); 527 528 int intMapLen; 529 const void* intMapAddr = fdt_getprop(gFDT, fdtNode, "interrupt-map", &intMapLen); 530 if (intMapAddr == NULL) { 531 dprintf(" interrupt-map property not found\n"); 532 return NULL; 533 } 534 535 int addressCells = 3; 536 int interruptCells = 1; 537 int phandleCells = 1; 538 539 const void *property; 540 541 property = fdt_getprop(gFDT, fdtNode, "#address-cells", NULL); 542 if (property != NULL) 543 addressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property); 544 545 property = fdt_getprop(gFDT, fdtNode, "#interrupt-cells", NULL); 546 if (property != NULL) 547 interruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property); 548 549 uint32_t *it = (uint32_t*)intMapAddr; 550 while ((uint8_t*)it - (uint8_t*)intMapAddr < intMapLen) { 551 struct fdt_interrupt_map_entry irqEntry; 552 553 irqEntry.childAddr = B_BENDIAN_TO_HOST_INT32(*it); 554 it += addressCells; 555 556 irqEntry.childIrq = B_BENDIAN_TO_HOST_INT32(*it); 557 it += interruptCells; 558 559 irqEntry.parentIrqCtrl = B_BENDIAN_TO_HOST_INT32(*it); 560 it += phandleCells; 561 562 int parentAddressCells = 0; 563 int parentInterruptCells = 1; 564 565 int interruptParent = fdt_node_offset_by_phandle(gFDT, irqEntry.parentIrqCtrl); 566 if (interruptParent >= 0) { 567 property = fdt_getprop(gFDT, interruptParent, "#address-cells", NULL); 568 if (property != NULL) 569 parentAddressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property); 570 571 property = fdt_getprop(gFDT, interruptParent, "#interrupt-cells", NULL); 572 if (property != NULL) 573 parentInterruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property); 574 } 575 576 it += parentAddressCells; 577 578 if ((parentInterruptCells == 1) || (parentInterruptCells == 2)) { 579 irqEntry.parentIrq = B_BENDIAN_TO_HOST_INT32(*it); 580 } else if (parentInterruptCells == 3) { 581 uint32 interruptType = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_TYPE]); 582 uint32 interruptNumber = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_ID]); 583 584 if (interruptType == GIC_INTERRUPT_TYPE_SPI) 585 irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_SPI; 586 else if (interruptType == GIC_INTERRUPT_TYPE_PPI) 587 irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_PPI; 588 else 589 irqEntry.parentIrq = interruptNumber; 590 } 591 it += parentInterruptCells; 592 593 interrupt_map->fInterruptMap.PushBack(irqEntry); 594 } 595 596 return interrupt_map.Detach(); 597 } 598 599 600 static void 601 fdt_device_print_interrupt_map(struct fdt_interrupt_map* interruptMap) 602 { 603 if (interruptMap == NULL) 604 return; 605 606 dprintf("interrupt_map_mask: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n", 607 interruptMap->childAddrMask, interruptMap->childIrqMask); 608 dprintf("interrupt_map:\n"); 609 610 for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin(); 611 it != interruptMap->fInterruptMap.End(); 612 it++) { 613 614 dprintf("childAddr=0x%08" PRIx32 ", childIrq=%" PRIu32 ", parentIrqCtrl=%" PRIu32 ", parentIrq=%" PRIu32 "\n", 615 it->childAddr, it->childIrq, it->parentIrqCtrl, it->parentIrq); 616 } 617 } 618 619 620 static uint32 621 fdt_device_lookup_interrupt_map(struct fdt_interrupt_map* interruptMap, uint32 childAddr, uint32 childIrq) 622 { 623 if (interruptMap == NULL) 624 return 0xffffffff; 625 626 childAddr &= interruptMap->childAddrMask; 627 childIrq &= interruptMap->childIrqMask; 628 629 for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin(); 630 it != interruptMap->fInterruptMap.End(); it++) { 631 if ((it->childAddr == childAddr) && (it->childIrq == childIrq)) 632 return it->parentIrq; 633 } 634 635 return 0xffffffff; 636 } 637 638 639 //#pragma mark - 640 641 fdt_bus_module_info gBusModule = { 642 { 643 { 644 "bus_managers/fdt/root/driver_v1", 645 0, 646 fdt_bus_std_ops 647 }, 648 fdt_bus_supports_device, 649 fdt_bus_register_device, 650 fdt_bus_init, 651 fdt_bus_uninit, 652 fdt_bus_register_child_devices, 653 NULL, // rescan devices 654 NULL, // device removed 655 }, 656 fdt_bus_node_by_phandle, 657 }; 658 659 660 fdt_device_module_info gDeviceModule = { 661 { 662 { 663 "bus_managers/fdt/driver_v1", 664 0, 665 fdt_device_std_ops 666 }, 667 668 NULL, // supports device 669 NULL, // register device (our parent registered us) 670 fdt_device_init_driver, 671 fdt_device_uninit_driver, 672 fdt_device_register_child_devices, 673 NULL, // rescan devices 674 NULL, // device removed 675 }, 676 fdt_device_get_bus, 677 fdt_device_get_name, 678 fdt_device_get_prop, 679 fdt_device_get_reg, 680 fdt_device_get_interrupt, 681 fdt_device_get_interrupt_map, 682 fdt_device_print_interrupt_map, 683 fdt_device_lookup_interrupt_map, 684 }; 685 686 687 module_info* modules[] = { 688 (module_info*)&gBusModule, 689 (module_info*)&gDeviceModule, 690 NULL 691 }; 692 693 module_dependency module_dependencies[] = { 694 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 695 { NULL } 696 }; 697