1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2017 Google, Inc 4 * Written by Simon Glass <sjg@chromium.org> 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <fdtdec.h> 10 #include <fdt_support.h> 11 #include <linux/libfdt.h> 12 #include <dm/of_access.h> 13 #include <dm/of_addr.h> 14 #include <dm/ofnode.h> 15 #include <linux/err.h> 16 #include <linux/ioport.h> 17 18 int ofnode_read_u32(ofnode node, const char *propname, u32 *outp) 19 { 20 assert(ofnode_valid(node)); 21 debug("%s: %s: ", __func__, propname); 22 23 if (ofnode_is_np(node)) { 24 return of_read_u32(ofnode_to_np(node), propname, outp); 25 } else { 26 const fdt32_t *cell; 27 int len; 28 29 cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), 30 propname, &len); 31 if (!cell || len < sizeof(int)) { 32 debug("(not found)\n"); 33 return -EINVAL; 34 } 35 *outp = fdt32_to_cpu(cell[0]); 36 } 37 debug("%#x (%d)\n", *outp, *outp); 38 39 return 0; 40 } 41 42 int ofnode_read_u32_default(ofnode node, const char *propname, u32 def) 43 { 44 assert(ofnode_valid(node)); 45 ofnode_read_u32(node, propname, &def); 46 47 return def; 48 } 49 50 int ofnode_read_s32_default(ofnode node, const char *propname, s32 def) 51 { 52 assert(ofnode_valid(node)); 53 ofnode_read_u32(node, propname, (u32 *)&def); 54 55 return def; 56 } 57 58 bool ofnode_read_bool(ofnode node, const char *propname) 59 { 60 const void *prop; 61 62 assert(ofnode_valid(node)); 63 debug("%s: %s: ", __func__, propname); 64 65 prop = ofnode_get_property(node, propname, NULL); 66 67 debug("%s\n", prop ? "true" : "false"); 68 69 return prop ? true : false; 70 } 71 72 const char *ofnode_read_string(ofnode node, const char *propname) 73 { 74 const char *str = NULL; 75 int len = -1; 76 77 assert(ofnode_valid(node)); 78 debug("%s: %s: ", __func__, propname); 79 80 if (ofnode_is_np(node)) { 81 struct property *prop = of_find_property( 82 ofnode_to_np(node), propname, NULL); 83 84 if (prop) { 85 str = prop->value; 86 len = prop->length; 87 } 88 } else { 89 str = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), 90 propname, &len); 91 } 92 if (!str) { 93 debug("<not found>\n"); 94 return NULL; 95 } 96 if (strnlen(str, len) >= len) { 97 debug("<invalid>\n"); 98 return NULL; 99 } 100 debug("%s\n", str); 101 102 return str; 103 } 104 105 ofnode ofnode_find_subnode(ofnode node, const char *subnode_name) 106 { 107 ofnode subnode; 108 109 assert(ofnode_valid(node)); 110 debug("%s: %s: ", __func__, subnode_name); 111 112 if (ofnode_is_np(node)) { 113 const struct device_node *np = ofnode_to_np(node); 114 115 for (np = np->child; np; np = np->sibling) { 116 if (!strcmp(subnode_name, np->name)) 117 break; 118 } 119 subnode = np_to_ofnode(np); 120 } else { 121 int ooffset = fdt_subnode_offset(gd->fdt_blob, 122 ofnode_to_offset(node), subnode_name); 123 subnode = offset_to_ofnode(ooffset); 124 } 125 debug("%s\n", ofnode_valid(subnode) ? 126 ofnode_get_name(subnode) : "<none>"); 127 128 return subnode; 129 } 130 131 int ofnode_read_u32_array(ofnode node, const char *propname, 132 u32 *out_values, size_t sz) 133 { 134 assert(ofnode_valid(node)); 135 debug("%s: %s: ", __func__, propname); 136 137 if (ofnode_is_np(node)) { 138 return of_read_u32_array(ofnode_to_np(node), propname, 139 out_values, sz); 140 } else { 141 return fdtdec_get_int_array(gd->fdt_blob, 142 ofnode_to_offset(node), propname, 143 out_values, sz); 144 } 145 } 146 147 ofnode ofnode_first_subnode(ofnode node) 148 { 149 assert(ofnode_valid(node)); 150 if (ofnode_is_np(node)) 151 return np_to_ofnode(node.np->child); 152 153 return offset_to_ofnode( 154 fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node))); 155 } 156 157 ofnode ofnode_next_subnode(ofnode node) 158 { 159 assert(ofnode_valid(node)); 160 if (ofnode_is_np(node)) 161 return np_to_ofnode(node.np->sibling); 162 163 return offset_to_ofnode( 164 fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node))); 165 } 166 167 ofnode ofnode_get_parent(ofnode node) 168 { 169 ofnode parent; 170 171 assert(ofnode_valid(node)); 172 if (ofnode_is_np(node)) 173 parent = np_to_ofnode(of_get_parent(ofnode_to_np(node))); 174 else 175 parent.of_offset = fdt_parent_offset(gd->fdt_blob, 176 ofnode_to_offset(node)); 177 178 return parent; 179 } 180 181 const char *ofnode_get_name(ofnode node) 182 { 183 assert(ofnode_valid(node)); 184 if (ofnode_is_np(node)) 185 return strrchr(node.np->full_name, '/') + 1; 186 187 return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL); 188 } 189 190 ofnode ofnode_get_by_phandle(uint phandle) 191 { 192 ofnode node; 193 194 if (of_live_active()) 195 node = np_to_ofnode(of_find_node_by_phandle(phandle)); 196 else 197 node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob, 198 phandle); 199 200 return node; 201 } 202 203 int ofnode_read_size(ofnode node, const char *propname) 204 { 205 int len; 206 207 if (ofnode_is_np(node)) { 208 struct property *prop = of_find_property( 209 ofnode_to_np(node), propname, NULL); 210 211 if (prop) 212 return prop->length; 213 } else { 214 if (fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname, 215 &len)) 216 return len; 217 } 218 219 return -EINVAL; 220 } 221 222 fdt_addr_t ofnode_get_addr_index(ofnode node, int index) 223 { 224 if (ofnode_is_np(node)) { 225 const __be32 *prop_val; 226 uint flags; 227 u64 size; 228 int na; 229 int ns; 230 231 prop_val = of_get_address(ofnode_to_np(node), index, &size, 232 &flags); 233 if (!prop_val) 234 return FDT_ADDR_T_NONE; 235 236 ns = of_n_size_cells(ofnode_to_np(node)); 237 238 if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) { 239 return of_translate_address(ofnode_to_np(node), prop_val); 240 } else { 241 na = of_n_addr_cells(ofnode_to_np(node)); 242 return of_read_number(prop_val, na); 243 } 244 } else { 245 return fdt_get_base_address(gd->fdt_blob, 246 ofnode_to_offset(node)); 247 } 248 249 return FDT_ADDR_T_NONE; 250 } 251 252 fdt_addr_t ofnode_get_addr(ofnode node) 253 { 254 return ofnode_get_addr_index(node, 0); 255 } 256 257 int ofnode_stringlist_search(ofnode node, const char *property, 258 const char *string) 259 { 260 if (ofnode_is_np(node)) { 261 return of_property_match_string(ofnode_to_np(node), 262 property, string); 263 } else { 264 int ret; 265 266 ret = fdt_stringlist_search(gd->fdt_blob, 267 ofnode_to_offset(node), property, 268 string); 269 if (ret == -FDT_ERR_NOTFOUND) 270 return -ENODATA; 271 else if (ret < 0) 272 return -EINVAL; 273 274 return ret; 275 } 276 } 277 278 int ofnode_read_string_index(ofnode node, const char *property, int index, 279 const char **outp) 280 { 281 if (ofnode_is_np(node)) { 282 return of_property_read_string_index(ofnode_to_np(node), 283 property, index, outp); 284 } else { 285 int len; 286 287 *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node), 288 property, index, &len); 289 if (len < 0) 290 return -EINVAL; 291 return 0; 292 } 293 } 294 295 int ofnode_read_string_count(ofnode node, const char *property) 296 { 297 if (ofnode_is_np(node)) { 298 return of_property_count_strings(ofnode_to_np(node), property); 299 } else { 300 return fdt_stringlist_count(gd->fdt_blob, 301 ofnode_to_offset(node), property); 302 } 303 } 304 305 static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in, 306 struct ofnode_phandle_args *out) 307 { 308 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS); 309 out->node = offset_to_ofnode(in->node); 310 out->args_count = in->args_count; 311 memcpy(out->args, in->args, sizeof(out->args)); 312 } 313 314 static void ofnode_from_of_phandle_args(struct of_phandle_args *in, 315 struct ofnode_phandle_args *out) 316 { 317 assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS); 318 out->node = np_to_ofnode(in->np); 319 out->args_count = in->args_count; 320 memcpy(out->args, in->args, sizeof(out->args)); 321 } 322 323 int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, 324 const char *cells_name, int cell_count, 325 int index, 326 struct ofnode_phandle_args *out_args) 327 { 328 if (ofnode_is_np(node)) { 329 struct of_phandle_args args; 330 int ret; 331 332 ret = of_parse_phandle_with_args(ofnode_to_np(node), 333 list_name, cells_name, index, 334 &args); 335 if (ret) 336 return ret; 337 ofnode_from_of_phandle_args(&args, out_args); 338 } else { 339 struct fdtdec_phandle_args args; 340 int ret; 341 342 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, 343 ofnode_to_offset(node), 344 list_name, cells_name, 345 cell_count, index, &args); 346 if (ret) 347 return ret; 348 ofnode_from_fdtdec_phandle_args(&args, out_args); 349 } 350 351 return 0; 352 } 353 354 int ofnode_count_phandle_with_args(ofnode node, const char *list_name, 355 const char *cells_name) 356 { 357 if (ofnode_is_np(node)) 358 return of_count_phandle_with_args(ofnode_to_np(node), 359 list_name, cells_name); 360 else 361 return fdtdec_parse_phandle_with_args(gd->fdt_blob, 362 ofnode_to_offset(node), list_name, cells_name, 363 0, -1, NULL); 364 } 365 366 ofnode ofnode_path(const char *path) 367 { 368 if (of_live_active()) 369 return np_to_ofnode(of_find_node_by_path(path)); 370 else 371 return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path)); 372 } 373 374 const char *ofnode_get_chosen_prop(const char *name) 375 { 376 ofnode chosen_node; 377 378 chosen_node = ofnode_path("/chosen"); 379 380 return ofnode_read_string(chosen_node, name); 381 } 382 383 ofnode ofnode_get_chosen_node(const char *name) 384 { 385 const char *prop; 386 387 prop = ofnode_get_chosen_prop(name); 388 if (!prop) 389 return ofnode_null(); 390 391 return ofnode_path(prop); 392 } 393 394 static int decode_timing_property(ofnode node, const char *name, 395 struct timing_entry *result) 396 { 397 int length, ret = 0; 398 399 length = ofnode_read_size(node, name); 400 if (length < 0) { 401 debug("%s: could not find property %s\n", 402 ofnode_get_name(node), name); 403 return length; 404 } 405 406 if (length == sizeof(u32)) { 407 result->typ = ofnode_read_u32_default(node, name, 0); 408 result->min = result->typ; 409 result->max = result->typ; 410 } else { 411 ret = ofnode_read_u32_array(node, name, &result->min, 3); 412 } 413 414 return ret; 415 } 416 417 int ofnode_decode_display_timing(ofnode parent, int index, 418 struct display_timing *dt) 419 { 420 int i; 421 ofnode timings, node; 422 u32 val = 0; 423 int ret = 0; 424 425 timings = ofnode_find_subnode(parent, "display-timings"); 426 if (!ofnode_valid(timings)) 427 return -EINVAL; 428 429 i = 0; 430 ofnode_for_each_subnode(node, timings) { 431 if (i++ == index) 432 break; 433 } 434 435 if (!ofnode_valid(node)) 436 return -EINVAL; 437 438 memset(dt, 0, sizeof(*dt)); 439 440 ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch); 441 ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch); 442 ret |= decode_timing_property(node, "hactive", &dt->hactive); 443 ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len); 444 ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch); 445 ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch); 446 ret |= decode_timing_property(node, "vactive", &dt->vactive); 447 ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len); 448 ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock); 449 450 dt->flags = 0; 451 val = ofnode_read_u32_default(node, "vsync-active", -1); 452 if (val != -1) { 453 dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH : 454 DISPLAY_FLAGS_VSYNC_LOW; 455 } 456 val = ofnode_read_u32_default(node, "hsync-active", -1); 457 if (val != -1) { 458 dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH : 459 DISPLAY_FLAGS_HSYNC_LOW; 460 } 461 val = ofnode_read_u32_default(node, "de-active", -1); 462 if (val != -1) { 463 dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH : 464 DISPLAY_FLAGS_DE_LOW; 465 } 466 val = ofnode_read_u32_default(node, "pixelclk-active", -1); 467 if (val != -1) { 468 dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : 469 DISPLAY_FLAGS_PIXDATA_NEGEDGE; 470 } 471 472 if (ofnode_read_bool(node, "interlaced")) 473 dt->flags |= DISPLAY_FLAGS_INTERLACED; 474 if (ofnode_read_bool(node, "doublescan")) 475 dt->flags |= DISPLAY_FLAGS_DOUBLESCAN; 476 if (ofnode_read_bool(node, "doubleclk")) 477 dt->flags |= DISPLAY_FLAGS_DOUBLECLK; 478 479 return ret; 480 } 481 482 const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) 483 { 484 if (ofnode_is_np(node)) 485 return of_get_property(ofnode_to_np(node), propname, lenp); 486 else 487 return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), 488 propname, lenp); 489 } 490 491 bool ofnode_is_available(ofnode node) 492 { 493 if (ofnode_is_np(node)) 494 return of_device_is_available(ofnode_to_np(node)); 495 else 496 return fdtdec_get_is_enabled(gd->fdt_blob, 497 ofnode_to_offset(node)); 498 } 499 500 fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property, 501 fdt_size_t *sizep) 502 { 503 if (ofnode_is_np(node)) { 504 int na, ns; 505 int psize; 506 const struct device_node *np = ofnode_to_np(node); 507 const __be32 *prop = of_get_property(np, property, &psize); 508 509 if (!prop) 510 return FDT_ADDR_T_NONE; 511 na = of_n_addr_cells(np); 512 ns = of_n_addr_cells(np); 513 *sizep = of_read_number(prop + na, ns); 514 return of_read_number(prop, na); 515 } else { 516 return fdtdec_get_addr_size(gd->fdt_blob, 517 ofnode_to_offset(node), property, 518 sizep); 519 } 520 } 521 522 const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, 523 size_t sz) 524 { 525 if (ofnode_is_np(node)) { 526 const struct device_node *np = ofnode_to_np(node); 527 int psize; 528 const __be32 *prop = of_get_property(np, propname, &psize); 529 530 if (!prop || sz != psize) 531 return NULL; 532 return (uint8_t *)prop; 533 534 } else { 535 return fdtdec_locate_byte_array(gd->fdt_blob, 536 ofnode_to_offset(node), propname, sz); 537 } 538 } 539 540 int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, 541 const char *propname, struct fdt_pci_addr *addr) 542 { 543 const fdt32_t *cell; 544 int len; 545 int ret = -ENOENT; 546 547 debug("%s: %s: ", __func__, propname); 548 549 /* 550 * If we follow the pci bus bindings strictly, we should check 551 * the value of the node's parent node's #address-cells and 552 * #size-cells. They need to be 3 and 2 accordingly. However, 553 * for simplicity we skip the check here. 554 */ 555 cell = ofnode_get_property(node, propname, &len); 556 if (!cell) 557 goto fail; 558 559 if ((len % FDT_PCI_REG_SIZE) == 0) { 560 int num = len / FDT_PCI_REG_SIZE; 561 int i; 562 563 for (i = 0; i < num; i++) { 564 debug("pci address #%d: %08lx %08lx %08lx\n", i, 565 (ulong)fdt32_to_cpu(cell[0]), 566 (ulong)fdt32_to_cpu(cell[1]), 567 (ulong)fdt32_to_cpu(cell[2])); 568 if ((fdt32_to_cpu(*cell) & type) == type) { 569 addr->phys_hi = fdt32_to_cpu(cell[0]); 570 addr->phys_mid = fdt32_to_cpu(cell[1]); 571 addr->phys_lo = fdt32_to_cpu(cell[1]); 572 break; 573 } 574 575 cell += (FDT_PCI_ADDR_CELLS + 576 FDT_PCI_SIZE_CELLS); 577 } 578 579 if (i == num) { 580 ret = -ENXIO; 581 goto fail; 582 } 583 584 return 0; 585 } 586 587 ret = -EINVAL; 588 589 fail: 590 debug("(not found)\n"); 591 return ret; 592 } 593 594 int ofnode_read_addr_cells(ofnode node) 595 { 596 if (ofnode_is_np(node)) 597 return of_n_addr_cells(ofnode_to_np(node)); 598 else /* NOTE: this call should walk up the parent stack */ 599 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node)); 600 } 601 602 int ofnode_read_size_cells(ofnode node) 603 { 604 if (ofnode_is_np(node)) 605 return of_n_size_cells(ofnode_to_np(node)); 606 else /* NOTE: this call should walk up the parent stack */ 607 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node)); 608 } 609 610 int ofnode_read_simple_addr_cells(ofnode node) 611 { 612 if (ofnode_is_np(node)) 613 return of_simple_addr_cells(ofnode_to_np(node)); 614 else 615 return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node)); 616 } 617 618 int ofnode_read_simple_size_cells(ofnode node) 619 { 620 if (ofnode_is_np(node)) 621 return of_simple_size_cells(ofnode_to_np(node)); 622 else 623 return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node)); 624 } 625 626 bool ofnode_pre_reloc(ofnode node) 627 { 628 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc")) 629 return true; 630 631 #ifdef CONFIG_TPL_BUILD 632 if (ofnode_read_bool(node, "u-boot,dm-tpl")) 633 return true; 634 #elif defined(CONFIG_SPL_BUILD) 635 if (ofnode_read_bool(node, "u-boot,dm-spl")) 636 return true; 637 #else 638 /* 639 * In regular builds individual spl and tpl handling both 640 * count as handled pre-relocation for later second init. 641 */ 642 if (ofnode_read_bool(node, "u-boot,dm-spl") || 643 ofnode_read_bool(node, "u-boot,dm-tpl")) 644 return true; 645 #endif 646 647 return false; 648 } 649 650 int ofnode_read_resource(ofnode node, uint index, struct resource *res) 651 { 652 if (ofnode_is_np(node)) { 653 return of_address_to_resource(ofnode_to_np(node), index, res); 654 } else { 655 struct fdt_resource fres; 656 int ret; 657 658 ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node), 659 "reg", index, &fres); 660 if (ret < 0) 661 return -EINVAL; 662 memset(res, '\0', sizeof(*res)); 663 res->start = fres.start; 664 res->end = fres.end; 665 666 return 0; 667 } 668 } 669 670 int ofnode_read_resource_byname(ofnode node, const char *name, 671 struct resource *res) 672 { 673 int index; 674 675 index = ofnode_stringlist_search(node, "reg-names", name); 676 if (index < 0) 677 return index; 678 679 return ofnode_read_resource(node, index, res); 680 } 681 682 u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr) 683 { 684 if (ofnode_is_np(node)) 685 return of_translate_address(ofnode_to_np(node), in_addr); 686 else 687 return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr); 688 } 689 690 int ofnode_device_is_compatible(ofnode node, const char *compat) 691 { 692 if (ofnode_is_np(node)) 693 return of_device_is_compatible(ofnode_to_np(node), compat, 694 NULL, NULL); 695 else 696 return !fdt_node_check_compatible(gd->fdt_blob, 697 ofnode_to_offset(node), 698 compat); 699 } 700