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-2021, 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 <device_manager.h> 14 15 #include <AutoDeleter.h> 16 #include <AutoDeleterDrivers.h> 17 #include <HashMap.h> 18 #include <debug.h> 19 20 extern "C" { 21 #include <libfdt_env.h> 22 #include <fdt.h> 23 #include <libfdt.h> 24 }; 25 26 27 //#define TRACE_FDT 28 #ifdef TRACE_FDT 29 #define TRACE(x...) dprintf(x) 30 #else 31 #define TRACE(x...) 32 #endif 33 34 35 extern void* gFDT; 36 37 device_manager_info* gDeviceManager; 38 39 extern fdt_bus_module_info gBusModule; 40 extern fdt_device_module_info gDeviceModule; 41 42 43 //#pragma mark - 44 45 46 struct fdt_bus { 47 device_node* node; 48 HashMap<HashKey32<int32>, device_node*> phandles; 49 }; 50 51 52 struct fdt_device { 53 device_node* node; 54 device_node* bus; 55 }; 56 57 58 static status_t 59 fdt_register_node(fdt_bus* bus, int node, device_node* parentDev, 60 device_node*& curDev) 61 { 62 TRACE("%s('%s', %p)\n", __func__, fdt_get_name(gFDT, node, NULL), 63 parentDev); 64 65 const void* prop; int propLen; 66 device_attr attrs[8]; 67 device_attr* attr = attrs; 68 int nameLen = 0; 69 const char *name = fdt_get_name(gFDT, node, &nameLen); 70 71 if (name == NULL) { 72 dprintf("%s ERROR: fdt_get_name: %s\n", __func__, 73 fdt_strerror(nameLen)); 74 return B_ERROR; 75 } 76 77 *attr++ = (device_attr) { B_DEVICE_BUS, B_STRING_TYPE, {string: "fdt"}}; 78 *attr++ = (device_attr) { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 79 { string: (strcmp(name, "") != 0) ? name : "Root" } }; 80 *attr++ = (device_attr) { "fdt/node", B_UINT32_TYPE, {ui32: (uint32)node}}; 81 *attr++ = (device_attr) { "fdt/name", B_STRING_TYPE, {string: name}}; 82 83 prop = fdt_getprop(gFDT, node, "device_type", &propLen); 84 if (prop != NULL) { 85 *attr++ = (device_attr) { "fdt/device_type", B_STRING_TYPE, 86 { string: (const char*)prop } }; 87 } 88 89 prop = fdt_getprop(gFDT, node, "compatible", &propLen); 90 91 if (prop != NULL) { 92 *attr++ = (device_attr){ "fdt/compatible", B_STRING_TYPE, 93 { string: (const char*)prop } }; 94 } 95 96 *attr = {0}; 97 98 status_t res = gDeviceManager->register_node(parentDev, 99 "bus_managers/fdt/driver_v1", attrs, NULL, &curDev); 100 101 if (res < B_OK) 102 return res; 103 104 prop = fdt_getprop(gFDT, node, "phandle", &propLen); 105 106 if (prop != NULL) 107 bus->phandles.Put(fdt32_to_cpu(*(uint32_t*)prop), curDev); 108 109 return B_OK; 110 } 111 112 113 static void 114 fdt_traverse(fdt_bus* bus, int &node, int &depth, device_node* parentDev) 115 { 116 int curDepth = depth; 117 #if 0 118 for (int i = 0; i < depth; i++) dprintf(" "); 119 dprintf("node('%s')\n", fdt_get_name(gFDT, node, NULL)); 120 #endif 121 device_node* curDev; 122 fdt_register_node(bus, node, parentDev, curDev); 123 124 node = fdt_next_node(gFDT, node, &depth); 125 while (node >= 0 && depth == curDepth + 1) { 126 fdt_traverse(bus, node, depth, curDev); 127 } 128 } 129 130 131 //#pragma mark bus 132 133 static int32 134 fdt_bus_std_ops(int32 op, ...) 135 { 136 switch (op) { 137 case B_MODULE_INIT: 138 TRACE("fdt root init\n"); 139 return B_OK; 140 141 case B_MODULE_UNINIT: 142 TRACE("fdt root uninit\n"); 143 return B_OK; 144 } 145 146 return B_BAD_VALUE; 147 } 148 149 150 static float 151 fdt_bus_supports_device(device_node* parent) 152 { 153 TRACE("fdt_bus_supports_device\n"); 154 155 // make sure parent is really device root 156 const char* bus; 157 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 158 return B_ERROR; 159 160 if (strcmp(bus, "root")) 161 return 0.0; 162 163 return 1.0; 164 } 165 166 167 static status_t 168 fdt_bus_register_device(device_node* parent) 169 { 170 TRACE("+fdt_bus_register_device\n"); 171 struct ScopeExit { 172 ScopeExit() {TRACE("-fdt_bus_register_device\n");} 173 } scopeExit; 174 175 device_attr attrs[] = { 176 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "FDT"}}, 177 {B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_KEEP_DRIVER_LOADED}}, 178 {} 179 }; 180 181 return gDeviceManager->register_node( 182 parent, "bus_managers/fdt/root/driver_v1", attrs, NULL, NULL); 183 } 184 185 186 static status_t 187 fdt_bus_init(device_node* node, void** cookie) 188 { 189 TRACE("fdt_bus_init\n"); 190 191 if (gFDT == NULL) { 192 TRACE("FDT is NULL!\n"); 193 return B_DEVICE_NOT_FOUND; 194 } 195 196 ObjectDeleter<fdt_bus> bus(new(std::nothrow) fdt_bus()); 197 if (!bus.IsSet()) 198 return B_NO_MEMORY; 199 200 bus->node = node; 201 *cookie = bus.Detach(); 202 return B_OK; 203 } 204 205 206 static void 207 fdt_bus_uninit(void* cookie) 208 { 209 TRACE("fdt_bus_uninit\n"); 210 211 ObjectDeleter<fdt_bus> bus((fdt_bus*)cookie); 212 } 213 214 215 static status_t 216 fdt_bus_register_child_devices(void* cookie) 217 { 218 TRACE("fdt_bus_register_child_devices\n"); 219 220 fdt_bus* bus = (fdt_bus*)cookie; 221 222 int node = -1, depth = -1; 223 node = fdt_next_node(gFDT, node, &depth); 224 fdt_traverse(bus, node, depth, bus->node); 225 226 return B_OK; 227 } 228 229 230 device_node* 231 fdt_bus_node_by_phandle(fdt_bus* bus, int phandle) 232 { 233 ASSERT(bus != NULL); 234 235 device_node** devNode; 236 if (!bus->phandles.Get(phandle, devNode)) 237 return NULL; 238 239 return *devNode; 240 } 241 242 243 //#pragma mark device 244 245 246 static status_t 247 fdt_device_std_ops(int32 op, ...) 248 { 249 switch (op) { 250 case B_MODULE_INIT: 251 case B_MODULE_UNINIT: 252 return B_OK; 253 } 254 255 return B_BAD_VALUE; 256 } 257 258 259 static status_t 260 fdt_device_init_driver(device_node* node, void** cookie) 261 { 262 TRACE("fdt_device_init_driver()\n"); 263 264 ObjectDeleter<fdt_device> dev(new(std::nothrow) fdt_device()); 265 if (!dev.IsSet()) 266 return B_NO_MEMORY; 267 268 dev->node = node; 269 270 // get bus from parent node 271 DeviceNodePutter<&gDeviceManager> parent( 272 gDeviceManager->get_parent_node(node)); 273 driver_module_info* parentModule; 274 void* parentDev; 275 ASSERT(gDeviceManager->get_driver( 276 parent.Get(), &parentModule, &parentDev) >= B_OK); 277 if (parentModule == (driver_module_info*)&gDeviceModule) 278 dev->bus = ((fdt_device*)parentDev)->bus; 279 else if (parentModule == (driver_module_info*)&gBusModule) 280 dev->bus = parent.Get(); 281 else 282 panic("bad parent node"); 283 284 *cookie = dev.Detach(); 285 return B_OK; 286 } 287 288 289 static void 290 fdt_device_uninit_driver(void* cookie) 291 { 292 TRACE("fdt_device_uninit_driver()\n"); 293 ObjectDeleter<fdt_device> dev((fdt_device*)cookie); 294 } 295 296 297 static status_t 298 fdt_device_register_child_devices(void* cookie) 299 { 300 TRACE("fdt_device_register_child_devices()\n"); 301 return B_OK; 302 } 303 304 305 static device_node* 306 fdt_device_get_bus(fdt_device* dev) 307 { 308 ASSERT(dev != NULL); 309 return dev->bus; 310 } 311 312 313 static const char* 314 fdt_device_get_name(fdt_device* dev) 315 { 316 ASSERT(dev != NULL); 317 318 uint32 fdtNode; 319 ASSERT(gDeviceManager->get_attr_uint32( 320 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 321 322 return fdt_get_name(gFDT, (int)fdtNode, NULL); 323 } 324 325 326 static const void* 327 fdt_device_get_prop(fdt_device* dev, const char* name, int* len) 328 { 329 ASSERT(dev != NULL); 330 331 uint32 fdtNode; 332 ASSERT(gDeviceManager->get_attr_uint32( 333 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 334 335 return fdt_getprop(gFDT, (int)fdtNode, name, len); 336 } 337 338 339 static bool 340 fdt_device_get_reg(fdt_device* dev, uint32 ord, uint64* regs, uint64* len) 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 int propLen; 349 const void* prop = fdt_getprop(gFDT, (int)fdtNode, "reg", &propLen); 350 if (prop == NULL) 351 return false; 352 353 // TODO: use '#address-cells', '#size-cells' in parent node to identify 354 // field sizes 355 356 if ((ord + 1)*16 > (uint32)propLen) 357 return false; 358 359 if (regs != NULL) 360 *regs = fdt64_to_cpu(*(((uint64*)prop) + 2*ord)); 361 362 if (len != NULL) 363 *len = fdt64_to_cpu(*(((uint64*)prop) + 2*ord + 1)); 364 365 return true; 366 } 367 368 369 static uint32 370 fdt_get_interrupt_parent(fdt_device* dev, int node) 371 { 372 while (node >= 0) { 373 uint32* prop; 374 int propLen; 375 prop = (uint32*)fdt_getprop(gFDT, node, "interrupt-parent", &propLen); 376 if (prop != NULL && propLen == 4) { 377 return fdt32_to_cpu(*prop); 378 } 379 380 node = fdt_parent_offset(gFDT, node); 381 } 382 383 return 0; 384 } 385 386 387 static uint32 388 fdt_get_interrupt_cells(uint32 interrupt_parent_phandle) 389 { 390 if (interrupt_parent_phandle > 0) { 391 int node = fdt_node_offset_by_phandle(gFDT, interrupt_parent_phandle); 392 if (node >= 0) { 393 uint32* prop; 394 int propLen; 395 prop = (uint32*)fdt_getprop(gFDT, node, "#interrupt-cells", &propLen); 396 if (prop != NULL && propLen == 4) { 397 return fdt32_to_cpu(*prop); 398 } 399 } 400 } 401 return 1; 402 } 403 404 405 static bool 406 fdt_device_get_interrupt(fdt_device* dev, uint32 ord, 407 device_node** interruptController, uint64* interrupt) 408 { 409 ASSERT(dev != NULL); 410 411 uint32 fdtNode; 412 ASSERT(gDeviceManager->get_attr_uint32( 413 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 414 415 int propLen; 416 const void* prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended", 417 &propLen); 418 if (prop == NULL) { 419 uint32 interruptParent = fdt_get_interrupt_parent(dev, fdtNode); 420 uint32 interruptCells = fdt_get_interrupt_cells(interruptParent); 421 422 prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts", 423 &propLen); 424 if (prop == NULL) 425 return false; 426 427 if ((ord + 1) * interruptCells * sizeof(uint32) > (uint32)propLen) 428 return false; 429 430 uint32 offs; 431 if (interruptCells == 3) { 432 offs = 3 * ord + 1; 433 } else { 434 offs = interruptCells * ord; 435 } 436 437 if (interrupt != NULL) 438 *interrupt = fdt32_to_cpu(*(((uint32*)prop) + offs)); 439 440 if (interruptController != NULL && interruptParent != 0) { 441 fdt_bus* bus; 442 ASSERT(gDeviceManager->get_driver(dev->bus, NULL, (void**)&bus) >= B_OK); 443 *interruptController = fdt_bus_node_by_phandle(bus, interruptParent); 444 } 445 446 return true; 447 } 448 449 if ((ord + 1) * 8 > (uint32)propLen) 450 return false; 451 452 if (interruptController != NULL) { 453 uint32 phandle = fdt32_to_cpu(*(((uint32*)prop) + 2 * ord)); 454 455 fdt_bus* bus; 456 ASSERT(gDeviceManager->get_driver( 457 dev->bus, NULL, (void**)&bus) >= B_OK); 458 459 *interruptController = fdt_bus_node_by_phandle(bus, phandle); 460 } 461 462 if (interrupt != NULL) 463 *interrupt = fdt32_to_cpu(*(((uint32*)prop) + 2*ord + 1)); 464 465 return true; 466 } 467 468 469 //#pragma mark - 470 471 fdt_bus_module_info gBusModule = { 472 { 473 { 474 "bus_managers/fdt/root/driver_v1", 475 0, 476 fdt_bus_std_ops 477 }, 478 fdt_bus_supports_device, 479 fdt_bus_register_device, 480 fdt_bus_init, 481 fdt_bus_uninit, 482 fdt_bus_register_child_devices, 483 NULL, // rescan devices 484 NULL, // device removed 485 }, 486 fdt_bus_node_by_phandle, 487 }; 488 489 490 fdt_device_module_info gDeviceModule = { 491 { 492 { 493 "bus_managers/fdt/driver_v1", 494 0, 495 fdt_device_std_ops 496 }, 497 498 NULL, // supports device 499 NULL, // register device (our parent registered us) 500 fdt_device_init_driver, 501 fdt_device_uninit_driver, 502 fdt_device_register_child_devices, 503 NULL, // rescan devices 504 NULL, // device removed 505 }, 506 fdt_device_get_bus, 507 fdt_device_get_name, 508 fdt_device_get_prop, 509 fdt_device_get_reg, 510 fdt_device_get_interrupt, 511 }; 512 513 514 module_info* modules[] = { 515 (module_info*)&gBusModule, 516 (module_info*)&gDeviceModule, 517 NULL 518 }; 519 520 module_dependency module_dependencies[] = { 521 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 522 { NULL } 523 }; 524