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