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