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 bool 370 fdt_device_get_interrupt(fdt_device* dev, uint32 ord, 371 device_node** interruptController, uint64* interrupt) 372 { 373 ASSERT(dev != NULL); 374 375 uint32 fdtNode; 376 ASSERT(gDeviceManager->get_attr_uint32( 377 dev->node, "fdt/node", &fdtNode, false) >= B_OK); 378 379 // TODO: handle other interrupt encodings 380 int propLen; 381 const void* prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended", 382 &propLen); 383 if (prop == NULL) { 384 prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts", 385 &propLen); 386 if (prop == NULL) 387 return false; 388 389 if ((ord + 1)*4 > (uint32)propLen) 390 return false; 391 392 if (interrupt != NULL) 393 *interrupt = fdt32_to_cpu(*(((uint32*)prop) + ord)); 394 395 if (interruptController != NULL) { 396 prop = fdt_getprop(gFDT, (int)fdtNode, "interrupt-parent", 397 &propLen); 398 if (prop != NULL && propLen == 4) { 399 uint32 phandle = fdt32_to_cpu(*(uint32*)prop); 400 401 fdt_bus* bus; 402 ASSERT(gDeviceManager->get_driver( 403 dev->bus, NULL, (void**)&bus) >= B_OK); 404 405 *interruptController = fdt_bus_node_by_phandle(bus, phandle); 406 } 407 } 408 return true; 409 } 410 411 // TODO: use '#interrupt-cells' to identify field sizes 412 413 if ((ord + 1)*8 > (uint32)propLen) 414 return false; 415 416 if (interruptController != NULL) { 417 uint32 phandle = fdt32_to_cpu(*(((uint32*)prop) + 2*ord)); 418 419 fdt_bus* bus; 420 ASSERT(gDeviceManager->get_driver( 421 dev->bus, NULL, (void**)&bus) >= B_OK); 422 423 *interruptController = fdt_bus_node_by_phandle(bus, phandle); 424 } 425 426 if (interrupt != NULL) 427 *interrupt = fdt32_to_cpu(*(((uint32*)prop) + 2*ord + 1)); 428 429 return true; 430 } 431 432 433 //#pragma mark - 434 435 fdt_bus_module_info gBusModule = { 436 { 437 { 438 "bus_managers/fdt/root/driver_v1", 439 0, 440 fdt_bus_std_ops 441 }, 442 fdt_bus_supports_device, 443 fdt_bus_register_device, 444 fdt_bus_init, 445 fdt_bus_uninit, 446 fdt_bus_register_child_devices, 447 NULL, // rescan devices 448 NULL, // device removed 449 }, 450 fdt_bus_node_by_phandle, 451 }; 452 453 454 fdt_device_module_info gDeviceModule = { 455 { 456 { 457 "bus_managers/fdt/driver_v1", 458 0, 459 fdt_device_std_ops 460 }, 461 462 NULL, // supports device 463 NULL, // register device (our parent registered us) 464 fdt_device_init_driver, 465 fdt_device_uninit_driver, 466 fdt_device_register_child_devices, 467 NULL, // rescan devices 468 NULL, // device removed 469 }, 470 fdt_device_get_bus, 471 fdt_device_get_name, 472 fdt_device_get_prop, 473 fdt_device_get_reg, 474 fdt_device_get_interrupt, 475 }; 476 477 478 module_info* modules[] = { 479 (module_info*)&gBusModule, 480 (module_info*)&gDeviceModule, 481 NULL 482 }; 483 484 module_dependency module_dependencies[] = { 485 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 486 { NULL } 487 }; 488