1 /* $OpenBSD: fdt.c,v 1.35 2024/03/27 23:05:27 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> 5 * Copyright (c) 2009 Mark Kettenis <kettenis@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/systm.h> 22 #include <sys/malloc.h> 23 24 #include <dev/ofw/fdt.h> 25 #include <dev/ofw/openfirm.h> 26 27 unsigned int fdt_check_head(void *); 28 char *fdt_get_str(u_int32_t); 29 void *skip_property(u_int32_t *); 30 void *skip_props(u_int32_t *); 31 void *skip_node_name(u_int32_t *); 32 void *skip_node(void *); 33 void *skip_nops(u_int32_t *); 34 void *fdt_parent_node_recurse(void *, void *); 35 void *fdt_find_phandle_recurse(void *, uint32_t); 36 int fdt_node_property_int(void *, char *, int *); 37 int fdt_node_property_ints(void *, char *, int *, int); 38 int fdt_translate_reg(void *, struct fdt_reg *); 39 #ifdef DEBUG 40 void fdt_print_node_recurse(void *, int); 41 #endif 42 43 static int tree_inited = 0; 44 static struct fdt tree; 45 46 unsigned int 47 fdt_check_head(void *fdt) 48 { 49 struct fdt_head *fh; 50 u_int32_t *ptr, *tok; 51 52 fh = fdt; 53 ptr = (u_int32_t *)fdt; 54 55 if (betoh32(fh->fh_magic) != FDT_MAGIC) 56 return 0; 57 58 if (betoh32(fh->fh_version) > FDT_CODE_VERSION) 59 return 0; 60 61 tok = skip_nops(ptr + (betoh32(fh->fh_struct_off) / 4)); 62 if (betoh32(*tok) != FDT_NODE_BEGIN) 63 return 0; 64 65 /* check for end signature on version 17 blob */ 66 if ((betoh32(fh->fh_version) >= 17) && 67 (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4) + 68 (betoh32(fh->fh_struct_size) / 4) - 1)) != FDT_END)) 69 return 0; 70 71 return betoh32(fh->fh_version); 72 } 73 74 /* 75 * Initializes internal structures of module. 76 * Has to be called once, preferably in machdep.c. 77 */ 78 int 79 fdt_init(void *fdt) 80 { 81 int version; 82 83 bzero(&tree, sizeof(struct fdt)); 84 tree_inited = 0; 85 86 if (!fdt) 87 return 0; 88 89 if (!(version = fdt_check_head(fdt))) 90 return 0; 91 92 tree.header = (struct fdt_head *)fdt; 93 tree.tree = (char *)fdt + betoh32(tree.header->fh_struct_off); 94 tree.strings = (char *)fdt + betoh32(tree.header->fh_strings_off); 95 tree.memory = (char *)fdt + betoh32(tree.header->fh_reserve_off); 96 tree.end = (char *)fdt + betoh32(tree.header->fh_size); 97 tree.version = version; 98 tree.strings_size = betoh32(tree.header->fh_strings_size); 99 if (tree.version >= 17) 100 tree.struct_size = betoh32(tree.header->fh_struct_size); 101 tree_inited = 1; 102 103 return version; 104 } 105 106 void 107 fdt_finalize(void) 108 { 109 char *start = (char *)tree.header; 110 111 tree.header->fh_size = htobe32(tree.end - start); 112 tree.header->fh_struct_off = htobe32(tree.tree - start); 113 tree.header->fh_strings_off = htobe32(tree.strings - start); 114 tree.header->fh_reserve_off = htobe32(tree.memory - start); 115 tree.header->fh_strings_size = htobe32(tree.strings_size); 116 if (tree.version >= 17) 117 tree.header->fh_struct_size = htobe32(tree.struct_size); 118 } 119 120 /* 121 * Return the size of the FDT. 122 */ 123 size_t 124 fdt_get_size(void *fdt) 125 { 126 if (!fdt) 127 return 0; 128 129 if (!fdt_check_head(fdt)) 130 return 0; 131 132 return betoh32(((struct fdt_head *)fdt)->fh_size); 133 } 134 135 /* 136 * Retrieve string pointer from strings table. 137 */ 138 char * 139 fdt_get_str(u_int32_t num) 140 { 141 if (num > tree.strings_size) 142 return NULL; 143 return (tree.strings) ? (tree.strings + num) : NULL; 144 } 145 146 int 147 fdt_add_str(char *name) 148 { 149 size_t len = roundup(strlen(name) + 1, sizeof(uint32_t)); 150 char *end = tree.strings + tree.strings_size; 151 152 memmove(end + len, end, tree.end - end); 153 tree.strings_size += len; 154 if (tree.tree > tree.strings) 155 tree.tree += len; 156 if (tree.memory > tree.strings) 157 tree.memory += len; 158 tree.end += len; 159 memset(end, 0, len); 160 memcpy(end, name, strlen(name)); 161 162 return (end - tree.strings); 163 } 164 165 /* 166 * Utility functions for skipping parts of tree. 167 */ 168 169 void * 170 skip_nops(u_int32_t *ptr) 171 { 172 while (betoh32(*ptr) == FDT_NOP) 173 ptr++; 174 175 return ptr; 176 } 177 178 void * 179 skip_property(u_int32_t *ptr) 180 { 181 u_int32_t size; 182 183 size = betoh32(*(ptr + 1)); 184 /* move forward by magic + size + nameid + rounded up property size */ 185 ptr += 3 + roundup(size, sizeof(u_int32_t)) / sizeof(u_int32_t); 186 187 return skip_nops(ptr); 188 } 189 190 void * 191 skip_props(u_int32_t *ptr) 192 { 193 while (betoh32(*ptr) == FDT_PROPERTY) { 194 ptr = skip_property(ptr); 195 } 196 return ptr; 197 } 198 199 void * 200 skip_node_name(u_int32_t *ptr) 201 { 202 /* skip name, aligned to 4 bytes, this is NULL term., so must add 1 */ 203 ptr += roundup(strlen((char *)ptr) + 1, 204 sizeof(u_int32_t)) / sizeof(u_int32_t); 205 206 return skip_nops(ptr); 207 } 208 209 /* 210 * Retrieves node property, the returned pointer is inside the fdt tree, 211 * so we should not modify content pointed by it directly. 212 */ 213 int 214 fdt_node_property(void *node, char *name, char **out) 215 { 216 u_int32_t *ptr; 217 u_int32_t nameid; 218 char *tmp; 219 220 if (!tree_inited) 221 return -1; 222 223 ptr = (u_int32_t *)node; 224 225 if (betoh32(*ptr) != FDT_NODE_BEGIN) 226 return -1; 227 228 ptr = skip_node_name(ptr + 1); 229 230 while (betoh32(*ptr) == FDT_PROPERTY) { 231 nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ 232 tmp = fdt_get_str(nameid); 233 if (!strcmp(name, tmp)) { 234 *out = (char *)(ptr + 3); /* beginning of the value */ 235 return betoh32(*(ptr + 1)); /* size of value */ 236 } 237 ptr = skip_property(ptr); 238 } 239 return -1; 240 } 241 242 int 243 fdt_node_set_property(void *node, char *name, void *data, int len) 244 { 245 uint32_t *ptr, *next; 246 uint32_t nameid; 247 uint32_t curlen; 248 size_t delta; 249 char *tmp; 250 251 if (!tree_inited) 252 return 0; 253 254 ptr = (uint32_t *)node; 255 256 if (betoh32(*ptr) != FDT_NODE_BEGIN) 257 return 0; 258 259 ptr = skip_node_name(ptr + 1); 260 261 while (betoh32(*ptr) == FDT_PROPERTY) { 262 nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ 263 tmp = fdt_get_str(nameid); 264 next = skip_property(ptr); 265 if (!strcmp(name, tmp)) { 266 curlen = betoh32(*(ptr + 1)); 267 delta = roundup(len, sizeof(uint32_t)) - 268 roundup(curlen, sizeof(uint32_t)); 269 memmove((char *)next + delta, next, 270 tree.end - (char *)next); 271 tree.struct_size += delta; 272 if (tree.strings > tree.tree) 273 tree.strings += delta; 274 if (tree.memory > tree.tree) 275 tree.memory += delta; 276 tree.end += delta; 277 *(ptr + 1) = htobe32(len); 278 memcpy(ptr + 3, data, len); 279 return 1; 280 } 281 ptr = next; 282 } 283 return 0; 284 } 285 286 int 287 fdt_node_add_property(void *node, char *name, void *data, int len) 288 { 289 char *dummy; 290 291 if (!tree_inited) 292 return 0; 293 294 if (fdt_node_property(node, name, &dummy) == -1) { 295 uint32_t *ptr = (uint32_t *)node; 296 297 if (betoh32(*ptr) != FDT_NODE_BEGIN) 298 return 0; 299 300 ptr = skip_node_name(ptr + 1); 301 302 memmove(ptr + 3, ptr, tree.end - (char *)ptr); 303 tree.struct_size += 3 * sizeof(uint32_t); 304 if (tree.strings > tree.tree) 305 tree.strings += 3 * sizeof(uint32_t); 306 if (tree.memory > tree.tree) 307 tree.memory += 3 * sizeof(uint32_t); 308 tree.end += 3 * sizeof(uint32_t); 309 *ptr++ = htobe32(FDT_PROPERTY); 310 *ptr++ = htobe32(0); 311 *ptr++ = htobe32(fdt_add_str(name)); 312 } 313 314 return fdt_node_set_property(node, name, data, len); 315 } 316 317 /* 318 * Retrieves next node, skipping all the children nodes of the pointed node, 319 * returns pointer to next node, no matter if it exists or not. 320 */ 321 void * 322 skip_node(void *node) 323 { 324 u_int32_t *ptr = node; 325 326 ptr++; 327 328 ptr = skip_node_name(ptr); 329 ptr = skip_props(ptr); 330 331 /* skip children */ 332 while (betoh32(*ptr) == FDT_NODE_BEGIN) 333 ptr = skip_node(ptr); 334 335 return skip_nops(ptr + 1); 336 } 337 338 /* 339 * Retrieves next node, skipping all the children nodes of the pointed node, 340 * returns pointer to next node if exists, otherwise returns NULL. 341 * If passed 0 will return first node of the tree (root). 342 */ 343 void * 344 fdt_next_node(void *node) 345 { 346 u_int32_t *ptr; 347 348 if (!tree_inited) 349 return NULL; 350 351 ptr = node; 352 353 if (node == NULL) { 354 ptr = skip_nops((uint32_t *)tree.tree); 355 return (betoh32(*ptr) == FDT_NODE_BEGIN) ? ptr : NULL; 356 } 357 358 if (betoh32(*ptr) != FDT_NODE_BEGIN) 359 return NULL; 360 361 ptr++; 362 363 ptr = skip_node_name(ptr); 364 ptr = skip_props(ptr); 365 366 /* skip children */ 367 while (betoh32(*ptr) == FDT_NODE_BEGIN) 368 ptr = skip_node(ptr); 369 370 if (betoh32(*ptr) != FDT_NODE_END) 371 return NULL; 372 373 ptr = skip_nops(ptr + 1); 374 375 if (betoh32(*ptr) != FDT_NODE_BEGIN) 376 return NULL; 377 378 return ptr; 379 } 380 381 int 382 fdt_next_property(void *node, char *name, char **nextname) 383 { 384 u_int32_t *ptr; 385 u_int32_t nameid; 386 387 if (!tree_inited) 388 return 0; 389 390 ptr = (u_int32_t *)node; 391 392 if (betoh32(*ptr) != FDT_NODE_BEGIN) 393 return 0; 394 395 ptr = skip_node_name(ptr + 1); 396 397 while (betoh32(*ptr) == FDT_PROPERTY) { 398 nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ 399 if (strcmp(name, "") == 0) { 400 *nextname = fdt_get_str(nameid); 401 return 1; 402 } 403 if (strcmp(name, fdt_get_str(nameid)) == 0) { 404 ptr = skip_property(ptr); 405 if (betoh32(*ptr) != FDT_PROPERTY) 406 break; 407 nameid = betoh32(*(ptr + 2)); 408 *nextname = fdt_get_str(nameid); 409 return 1; 410 } 411 ptr = skip_property(ptr); 412 } 413 *nextname = ""; 414 return 1; 415 } 416 417 /* 418 * Retrieves node property as integers and puts them in the given 419 * integer array. 420 */ 421 int 422 fdt_node_property_ints(void *node, char *name, int *out, int outlen) 423 { 424 int *data; 425 int i, inlen; 426 427 inlen = fdt_node_property(node, name, (char **)&data) / sizeof(int); 428 if (inlen <= 0) 429 return -1; 430 431 for (i = 0; i < inlen && i < outlen; i++) 432 out[i] = betoh32(data[i]); 433 434 return i; 435 } 436 437 /* 438 * Retrieves node property as an integer. 439 */ 440 int 441 fdt_node_property_int(void *node, char *name, int *out) 442 { 443 return fdt_node_property_ints(node, name, out, 1); 444 } 445 446 /* 447 * Retrieves next node, skipping all the children nodes of the pointed node 448 */ 449 void * 450 fdt_child_node(void *node) 451 { 452 u_int32_t *ptr; 453 454 if (!tree_inited) 455 return NULL; 456 457 ptr = node; 458 459 if (betoh32(*ptr) != FDT_NODE_BEGIN) 460 return NULL; 461 462 ptr++; 463 464 ptr = skip_node_name(ptr); 465 ptr = skip_props(ptr); 466 /* check if there is a child node */ 467 return (betoh32(*ptr) == FDT_NODE_BEGIN) ? (ptr) : NULL; 468 } 469 470 /* 471 * Retrieves node name. 472 */ 473 char * 474 fdt_node_name(void *node) 475 { 476 u_int32_t *ptr; 477 478 if (!tree_inited) 479 return NULL; 480 481 ptr = node; 482 483 if (betoh32(*ptr) != FDT_NODE_BEGIN) 484 return NULL; 485 486 return (char *)(ptr + 1); 487 } 488 489 void * 490 fdt_find_node(char *name) 491 { 492 void *node = fdt_next_node(0); 493 const char *p = name; 494 495 if (!tree_inited) 496 return NULL; 497 498 if (*p != '/') 499 return NULL; 500 501 while (*p) { 502 void *child; 503 const char *q; 504 const char *s; 505 506 while (*p == '/') 507 p++; 508 if (*p == 0) 509 return node; 510 q = strchr(p, '/'); 511 if (q == NULL) 512 q = p + strlen(p); 513 514 /* Check for a complete match. */ 515 for (child = fdt_child_node(node); child; 516 child = fdt_next_node(child)) { 517 s = fdt_node_name(child); 518 if (strncmp(p, s, q - p) == 0 && s[q - p] == '\0') 519 break; 520 } 521 if (child) { 522 node = child; 523 p = q; 524 continue; 525 } 526 527 /* Check for a match without the unit name. */ 528 for (child = fdt_child_node(node); child; 529 child = fdt_next_node(child)) { 530 s = fdt_node_name(child); 531 if (strncmp(p, s, q - p) == 0 && s[q - p] == '@') 532 break; 533 } 534 if (child) { 535 node = child; 536 p = q; 537 continue; 538 } 539 540 return NULL; /* No match found. */ 541 } 542 543 return node; 544 } 545 546 void * 547 fdt_parent_node_recurse(void *pnode, void *child) 548 { 549 void *node = fdt_child_node(pnode); 550 void *tmp; 551 552 while (node && (node != child)) { 553 if ((tmp = fdt_parent_node_recurse(node, child))) 554 return tmp; 555 node = fdt_next_node(node); 556 } 557 return (node) ? pnode : NULL; 558 } 559 560 void * 561 fdt_parent_node(void *node) 562 { 563 void *pnode = fdt_next_node(0); 564 565 if (!tree_inited) 566 return NULL; 567 568 if (node == pnode) 569 return NULL; 570 571 return fdt_parent_node_recurse(pnode, node); 572 } 573 574 void * 575 fdt_find_phandle_recurse(void *node, uint32_t phandle) 576 { 577 void *child; 578 char *data; 579 void *tmp; 580 int len; 581 582 len = fdt_node_property(node, "phandle", &data); 583 if (len < 0) 584 len = fdt_node_property(node, "linux,phandle", &data); 585 586 if (len == sizeof(uint32_t) && bemtoh32(data) == phandle) 587 return node; 588 589 for (child = fdt_child_node(node); child; child = fdt_next_node(child)) 590 if ((tmp = fdt_find_phandle_recurse(child, phandle))) 591 return tmp; 592 593 return NULL; 594 } 595 596 void * 597 fdt_find_phandle(uint32_t phandle) 598 { 599 return fdt_find_phandle_recurse(fdt_next_node(0), phandle); 600 } 601 602 void 603 fdt_get_cells(void *node, int *ac, int *sc) 604 { 605 void *parent; 606 607 parent = fdt_parent_node(node); 608 if (parent == NULL) 609 *ac = *sc = 1; 610 else 611 fdt_get_cells(parent, ac, sc); 612 613 fdt_node_property_int(node, "#address-cells", ac); 614 fdt_node_property_int(node, "#size-cells", sc); 615 } 616 617 /* 618 * Translate memory address depending on parent's range. 619 * 620 * Ranges are a way of mapping one address to another. This ranges attribute 621 * is set on a node's parent. This means if a node does not have a parent, 622 * there's nothing to translate. If it does have a parent and the parent does 623 * not have a ranges attribute, there's nothing to translate either. 624 * 625 * If the parent has a ranges attribute and the attribute is not empty, the 626 * node's memory address has to be in one of the given ranges. This range is 627 * then used to translate the memory address. 628 * 629 * If the parent has a ranges attribute, but the attribute is empty, there's 630 * nothing to translate. But it's not a translation barrier. It can be treated 631 * as a simple 1:1 mapping. 632 * 633 * Translation does not end here. We need to check if the parent's parent also 634 * has a ranges attribute and ask the same questions again. 635 */ 636 int 637 fdt_translate_reg(void *node, struct fdt_reg *reg) 638 { 639 void *parent; 640 int pac, psc, ac, sc, rlen, rone, *range; 641 uint64_t from, to, size; 642 643 /* No parent, no translation. */ 644 parent = fdt_parent_node(node); 645 if (parent == NULL) 646 return 0; 647 648 /* Extract ranges property from node. */ 649 rlen = fdt_node_property(node, "ranges", (char **)&range) / sizeof(int); 650 651 /* No ranges means translation barrier. Translation stops here. */ 652 if (range == NULL) 653 return 0; 654 655 /* Empty ranges means 1:1 mapping. Continue translation on parent. */ 656 if (rlen <= 0) 657 return fdt_translate_reg(parent, reg); 658 659 /* 660 * Get parent address/size width. We only support 32-bit (1) 661 * and 64-bit (2) wide addresses and sizes here. 662 */ 663 fdt_get_cells(parent, &pac, &psc); 664 if (pac <= 0 || pac > 2 || psc <= 0 || psc > 2) 665 return EINVAL; 666 667 /* 668 * Get our own address/size width. Again, we only support 669 * 32-bit (1) and 64-bit (2) wide addresses and sizes here. 670 */ 671 fdt_get_cells(node, &ac, &sc); 672 if (ac <= 0 || ac > 2 || sc <= 0 || sc > 2) 673 return EINVAL; 674 675 /* Must have at least one range. */ 676 rone = pac + ac + sc; 677 if (rlen < rone) 678 return ESRCH; 679 680 /* For each range. */ 681 for (; rlen >= rone; rlen -= rone, range += rone) { 682 /* Extract from and size, so we can see if we fit. */ 683 from = betoh32(range[0]); 684 if (ac == 2) 685 from = (from << 32) + betoh32(range[1]); 686 size = betoh32(range[ac + pac]); 687 if (sc == 2) 688 size = (size << 32) + betoh32(range[ac + pac + 1]); 689 690 /* Try next, if we're not in the range. */ 691 if (reg->addr < from || (reg->addr + reg->size) > (from + size)) 692 continue; 693 694 /* All good, extract to address and translate. */ 695 to = betoh32(range[ac]); 696 if (pac == 2) 697 to = (to << 32) + betoh32(range[ac + 1]); 698 699 reg->addr -= from; 700 reg->addr += to; 701 return fdt_translate_reg(parent, reg); 702 } 703 704 /* To be successful, we must have returned in the for-loop. */ 705 return ESRCH; 706 } 707 708 /* 709 * Parse the memory address and size of a node. 710 */ 711 int 712 fdt_get_reg(void *node, int idx, struct fdt_reg *reg) 713 { 714 void *parent; 715 int ac, sc, off, *in, inlen; 716 717 if (node == NULL || reg == NULL) 718 return EINVAL; 719 720 parent = fdt_parent_node(node); 721 if (parent == NULL) 722 return EINVAL; 723 724 /* 725 * Get parent address/size width. We only support 32-bit (1) 726 * and 64-bit (2) wide addresses and sizes here. 727 */ 728 fdt_get_cells(parent, &ac, &sc); 729 if (ac <= 0 || ac > 2 || sc <= 0 || sc > 2) 730 return EINVAL; 731 732 inlen = fdt_node_property(node, "reg", (char **)&in) / sizeof(int); 733 if (inlen < ((idx + 1) * (ac + sc))) 734 return EINVAL; 735 736 off = idx * (ac + sc); 737 738 reg->addr = betoh32(in[off]); 739 if (ac == 2) 740 reg->addr = (reg->addr << 32) + betoh32(in[off + 1]); 741 742 reg->size = betoh32(in[off + ac]); 743 if (sc == 2) 744 reg->size = (reg->size << 32) + betoh32(in[off + ac + 1]); 745 746 return fdt_translate_reg(parent, reg); 747 } 748 749 int 750 fdt_is_compatible(void *node, const char *name) 751 { 752 char *data; 753 int len; 754 755 len = fdt_node_property(node, "compatible", &data); 756 while (len > 0) { 757 if (strcmp(data, name) == 0) 758 return 1; 759 len -= strlen(data) + 1; 760 data += strlen(data) + 1; 761 } 762 763 return 0; 764 } 765 766 #ifdef DEBUG 767 /* 768 * Debug methods for printing whole tree, particular nodes and properties 769 */ 770 void * 771 fdt_print_property(void *node, int level) 772 { 773 u_int32_t *ptr; 774 char *tmp, *value; 775 int cnt; 776 u_int32_t nameid, size; 777 778 ptr = (u_int32_t *)node; 779 780 if (!tree_inited) 781 return NULL; 782 783 if (betoh32(*ptr) != FDT_PROPERTY) 784 return ptr; /* should never happen */ 785 786 /* extract property name_id and size */ 787 size = betoh32(*++ptr); 788 nameid = betoh32(*++ptr); 789 790 for (cnt = 0; cnt < level; cnt++) 791 printf("\t"); 792 793 tmp = fdt_get_str(nameid); 794 printf("\t%s : ", tmp ? tmp : "NO_NAME"); 795 796 ptr++; 797 value = (char *)ptr; 798 799 if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") || 800 !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") || 801 !strcmp(tmp, "linux,stdout-path")) { 802 printf("%s", value); 803 } else if (!strcmp(tmp, "clock-frequency") || 804 !strcmp(tmp, "timebase-frequency")) { 805 printf("%d", betoh32(*((unsigned int *)value))); 806 } else { 807 for (cnt = 0; cnt < size; cnt++) { 808 if ((cnt % sizeof(u_int32_t)) == 0) 809 printf(" "); 810 printf("%02x", value[cnt]); 811 } 812 } 813 ptr += roundup(size, sizeof(u_int32_t)) / sizeof(u_int32_t); 814 printf("\n"); 815 816 return ptr; 817 } 818 819 void 820 fdt_print_node(void *node, int level) 821 { 822 u_int32_t *ptr; 823 int cnt; 824 825 ptr = (u_int32_t *)node; 826 827 if (betoh32(*ptr) != FDT_NODE_BEGIN) 828 return; 829 830 ptr++; 831 832 for (cnt = 0; cnt < level; cnt++) 833 printf("\t"); 834 printf("%s :\n", fdt_node_name(node)); 835 ptr = skip_node_name(ptr); 836 837 while (betoh32(*ptr) == FDT_PROPERTY) 838 ptr = fdt_print_property(ptr, level); 839 } 840 841 void 842 fdt_print_node_recurse(void *node, int level) 843 { 844 void *child; 845 846 fdt_print_node(node, level); 847 for (child = fdt_child_node(node); child; child = fdt_next_node(child)) 848 fdt_print_node_recurse(child, level + 1); 849 } 850 851 void 852 fdt_print_tree(void) 853 { 854 fdt_print_node_recurse(fdt_next_node(0), 0); 855 } 856 #endif 857 858 int 859 OF_peer(int handle) 860 { 861 void *node = (char *)tree.header + handle; 862 863 if (handle == 0) 864 node = fdt_find_node("/"); 865 else 866 node = fdt_next_node(node); 867 return node ? ((char *)node - (char *)tree.header) : 0; 868 } 869 870 int 871 OF_child(int handle) 872 { 873 void *node = (char *)tree.header + handle; 874 875 node = fdt_child_node(node); 876 return node ? ((char *)node - (char *)tree.header) : 0; 877 } 878 879 int 880 OF_parent(int handle) 881 { 882 void *node = (char *)tree.header + handle; 883 884 node = fdt_parent_node(node); 885 return node ? ((char *)node - (char *)tree.header) : 0; 886 } 887 888 int 889 OF_finddevice(char *name) 890 { 891 void *node; 892 893 node = fdt_find_node(name); 894 return node ? ((char *)node - (char *)tree.header) : -1; 895 } 896 897 int 898 OF_getnodebyname(int handle, const char *name) 899 { 900 void *node = (char *)tree.header + handle; 901 void *child; 902 char *data; 903 int len; 904 905 if (handle == 0) 906 node = fdt_find_node("/"); 907 908 for (child = fdt_child_node(node); child; 909 child = fdt_next_node(child)) { 910 if (strcmp(name, fdt_node_name(child)) == 0) 911 break; 912 } 913 if (child) 914 return (char *)child - (char *)tree.header; 915 916 len = strlen(name); 917 for (child = fdt_child_node(node); child; 918 child = fdt_next_node(child)) { 919 data = fdt_node_name(child); 920 if (strncmp(name, data, len) == 0 && 921 strlen(data) > len && data[len] == '@') 922 break; 923 } 924 if (child) 925 return (char *)child - (char *)tree.header; 926 927 return 0; 928 } 929 930 int 931 OF_getnodebyphandle(uint32_t phandle) 932 { 933 void *node; 934 935 node = fdt_find_phandle(phandle); 936 return node ? ((char *)node - (char *)tree.header) : 0; 937 } 938 939 int 940 OF_getproplen(int handle, char *prop) 941 { 942 void *node = (char *)tree.header + handle; 943 char *data, *name; 944 int len; 945 946 len = fdt_node_property(node, prop, &data); 947 948 /* 949 * The "name" property is optional since version 16 of the 950 * flattened device tree specification, so we synthesize one 951 * from the unit name of the node if it is missing. 952 */ 953 if (len < 0 && strcmp(prop, "name") == 0) { 954 name = fdt_node_name(node); 955 data = strchr(name, '@'); 956 if (data) 957 len = data - name; 958 else 959 len = strlen(name); 960 return len + 1; 961 } 962 963 return len; 964 } 965 966 int 967 OF_getprop(int handle, char *prop, void *buf, int buflen) 968 { 969 void *node = (char *)tree.header + handle; 970 char *data; 971 int len; 972 973 len = fdt_node_property(node, prop, &data); 974 975 /* 976 * The "name" property is optional since version 16 of the 977 * flattened device tree specification, so we synthesize one 978 * from the unit name of the node if it is missing. 979 */ 980 if (len < 0 && strcmp(prop, "name") == 0) { 981 data = fdt_node_name(node); 982 if (data) { 983 len = strlcpy(buf, data, buflen); 984 data = strchr(buf, '@'); 985 if (data) { 986 *data = 0; 987 len = data - (char *)buf; 988 } 989 return len + 1; 990 } 991 } 992 993 if (len > 0) 994 memcpy(buf, data, min(len, buflen)); 995 return len; 996 } 997 998 int 999 OF_getpropbool(int handle, char *prop) 1000 { 1001 void *node = (char *)tree.header + handle; 1002 char *data; 1003 1004 return (fdt_node_property(node, prop, &data) >= 0); 1005 } 1006 1007 uint32_t 1008 OF_getpropint(int handle, char *prop, uint32_t defval) 1009 { 1010 uint32_t val; 1011 int len; 1012 1013 len = OF_getprop(handle, prop, &val, sizeof(val)); 1014 if (len != sizeof(val)) 1015 return defval; 1016 1017 return betoh32(val); 1018 } 1019 1020 int 1021 OF_getpropintarray(int handle, char *prop, uint32_t *buf, int buflen) 1022 { 1023 int len; 1024 int i; 1025 1026 len = OF_getprop(handle, prop, buf, buflen); 1027 if (len < 0 || (len % sizeof(uint32_t))) 1028 return -1; 1029 1030 for (i = 0; i < min(len, buflen) / sizeof(uint32_t); i++) 1031 buf[i] = betoh32(buf[i]); 1032 1033 return len; 1034 } 1035 1036 uint64_t 1037 OF_getpropint64(int handle, char *prop, uint64_t defval) 1038 { 1039 uint64_t val; 1040 int len; 1041 1042 len = OF_getprop(handle, prop, &val, sizeof(val)); 1043 if (len != sizeof(val)) 1044 return defval; 1045 1046 return betoh64(val); 1047 } 1048 1049 int 1050 OF_getpropint64array(int handle, char *prop, uint64_t *buf, int buflen) 1051 { 1052 int len; 1053 int i; 1054 1055 len = OF_getprop(handle, prop, buf, buflen); 1056 if (len < 0 || (len % sizeof(uint64_t))) 1057 return -1; 1058 1059 for (i = 0; i < min(len, buflen) / sizeof(uint64_t); i++) 1060 buf[i] = betoh64(buf[i]); 1061 1062 return len; 1063 } 1064 1065 int 1066 OF_nextprop(int handle, char *prop, void *nextprop) 1067 { 1068 void *node = (char *)tree.header + handle; 1069 char *data; 1070 1071 if (fdt_node_property(node, "name", &data) == -1) { 1072 if (strcmp(prop, "") == 0) 1073 return strlcpy(nextprop, "name", OFMAXPARAM); 1074 if (strcmp(prop, "name") == 0) 1075 prop = ""; 1076 } 1077 1078 if (fdt_next_property(node, prop, &data)) 1079 return strlcpy(nextprop, data, OFMAXPARAM); 1080 return -1; 1081 } 1082 1083 int 1084 OF_is_compatible(int handle, const char *name) 1085 { 1086 void *node = (char *)tree.header + handle; 1087 return (fdt_is_compatible(node, name)); 1088 } 1089 1090 int 1091 OF_getindex(int handle, const char *entry, const char *prop) 1092 { 1093 char *names; 1094 char *name; 1095 char *end; 1096 int idx = 0; 1097 int len; 1098 1099 if (entry == NULL) 1100 return 0; 1101 1102 len = OF_getproplen(handle, (char *)prop); 1103 if (len <= 0) 1104 return -1; 1105 1106 names = malloc(len, M_TEMP, M_WAITOK); 1107 OF_getprop(handle, (char *)prop, names, len); 1108 end = names + len; 1109 name = names; 1110 while (name < end) { 1111 if (strcmp(name, entry) == 0) { 1112 free(names, M_TEMP, len); 1113 return idx; 1114 } 1115 name += strlen(name) + 1; 1116 idx++; 1117 } 1118 free(names, M_TEMP, len); 1119 return -1; 1120 } 1121