1 /* 2 * Copyright (c) 2011 The Chromium OS Authors. 3 * SPDX-License-Identifier: GPL-2.0+ 4 */ 5 6 #ifndef USE_HOSTCC 7 #include <common.h> 8 #include <errno.h> 9 #include <serial.h> 10 #include <libfdt.h> 11 #include <fdtdec.h> 12 #include <linux/ctype.h> 13 14 #include <asm/gpio.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 /* 19 * Here are the type we know about. One day we might allow drivers to 20 * register. For now we just put them here. The COMPAT macro allows us to 21 * turn this into a sparse list later, and keeps the ID with the name. 22 */ 23 #define COMPAT(id, name) name 24 static const char * const compat_names[COMPAT_COUNT] = { 25 COMPAT(UNKNOWN, "<none>"), 26 COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"), 27 COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"), 28 COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"), 29 COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"), 30 COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"), 31 COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"), 32 COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), 33 COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), 34 COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"), 35 COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), 36 COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), 37 COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), 38 COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"), 39 COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"), 40 COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"), 41 COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"), 42 COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"), 43 COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"), 44 COMPAT(SMSC_LAN9215, "smsc,lan9215"), 45 COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), 46 COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"), 47 COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"), 48 COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"), 49 COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"), 50 COMPAT(GOOGLE_CROS_EC, "google,cros-ec"), 51 COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"), 52 COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), 53 COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"), 54 COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), 55 COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"), 56 COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), 57 COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"), 58 COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"), 59 COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"), 60 COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"), 61 COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"), 62 COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"), 63 COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), 64 COMPAT(GENERIC_SPI_FLASH, "spi-flash"), 65 COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), 66 COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"), 67 COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"), 68 COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), 69 COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), 70 COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"), 71 COMPAT(TI_TPS65090, "ti,tps65090"), 72 COMPAT(COMPAT_NXP_PTN3460, "nxp,ptn3460"), 73 COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"), 74 COMPAT(PARADE_PS8625, "parade,ps8625"), 75 COMPAT(COMPAT_INTEL_LPC, "intel,lpc"), 76 COMPAT(INTEL_MICROCODE, "intel,microcode"), 77 }; 78 79 const char *fdtdec_get_compatible(enum fdt_compat_id id) 80 { 81 /* We allow reading of the 'unknown' ID for testing purposes */ 82 assert(id >= 0 && id < COMPAT_COUNT); 83 return compat_names[id]; 84 } 85 86 fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, 87 const char *prop_name, fdt_size_t *sizep) 88 { 89 const fdt_addr_t *cell; 90 int len; 91 92 debug("%s: %s: ", __func__, prop_name); 93 cell = fdt_getprop(blob, node, prop_name, &len); 94 if (cell && ((!sizep && len == sizeof(fdt_addr_t)) || 95 len == sizeof(fdt_addr_t) * 2)) { 96 fdt_addr_t addr = fdt_addr_to_cpu(*cell); 97 if (sizep) { 98 const fdt_size_t *size; 99 100 size = (fdt_size_t *)((char *)cell + 101 sizeof(fdt_addr_t)); 102 *sizep = fdt_size_to_cpu(*size); 103 debug("addr=%08lx, size=%08x\n", 104 (ulong)addr, *sizep); 105 } else { 106 debug("%08lx\n", (ulong)addr); 107 } 108 return addr; 109 } 110 debug("(not found)\n"); 111 return FDT_ADDR_T_NONE; 112 } 113 114 fdt_addr_t fdtdec_get_addr(const void *blob, int node, 115 const char *prop_name) 116 { 117 return fdtdec_get_addr_size(blob, node, prop_name, NULL); 118 } 119 120 uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, 121 uint64_t default_val) 122 { 123 const uint64_t *cell64; 124 int length; 125 126 cell64 = fdt_getprop(blob, node, prop_name, &length); 127 if (!cell64 || length < sizeof(*cell64)) 128 return default_val; 129 130 return fdt64_to_cpu(*cell64); 131 } 132 133 int fdtdec_get_is_enabled(const void *blob, int node) 134 { 135 const char *cell; 136 137 /* 138 * It should say "okay", so only allow that. Some fdts use "ok" but 139 * this is a bug. Please fix your device tree source file. See here 140 * for discussion: 141 * 142 * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html 143 */ 144 cell = fdt_getprop(blob, node, "status", NULL); 145 if (cell) 146 return 0 == strcmp(cell, "okay"); 147 return 1; 148 } 149 150 enum fdt_compat_id fdtdec_lookup(const void *blob, int node) 151 { 152 enum fdt_compat_id id; 153 154 /* Search our drivers */ 155 for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) 156 if (0 == fdt_node_check_compatible(blob, node, 157 compat_names[id])) 158 return id; 159 return COMPAT_UNKNOWN; 160 } 161 162 int fdtdec_next_compatible(const void *blob, int node, 163 enum fdt_compat_id id) 164 { 165 return fdt_node_offset_by_compatible(blob, node, compat_names[id]); 166 } 167 168 int fdtdec_next_compatible_subnode(const void *blob, int node, 169 enum fdt_compat_id id, int *depthp) 170 { 171 do { 172 node = fdt_next_node(blob, node, depthp); 173 } while (*depthp > 1); 174 175 /* If this is a direct subnode, and compatible, return it */ 176 if (*depthp == 1 && 0 == fdt_node_check_compatible( 177 blob, node, compat_names[id])) 178 return node; 179 180 return -FDT_ERR_NOTFOUND; 181 } 182 183 int fdtdec_next_alias(const void *blob, const char *name, 184 enum fdt_compat_id id, int *upto) 185 { 186 #define MAX_STR_LEN 20 187 char str[MAX_STR_LEN + 20]; 188 int node, err; 189 190 /* snprintf() is not available */ 191 assert(strlen(name) < MAX_STR_LEN); 192 sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); 193 node = fdt_path_offset(blob, str); 194 if (node < 0) 195 return node; 196 err = fdt_node_check_compatible(blob, node, compat_names[id]); 197 if (err < 0) 198 return err; 199 if (err) 200 return -FDT_ERR_NOTFOUND; 201 (*upto)++; 202 return node; 203 } 204 205 int fdtdec_find_aliases_for_id(const void *blob, const char *name, 206 enum fdt_compat_id id, int *node_list, int maxcount) 207 { 208 memset(node_list, '\0', sizeof(*node_list) * maxcount); 209 210 return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount); 211 } 212 213 /* TODO: Can we tighten this code up a little? */ 214 int fdtdec_add_aliases_for_id(const void *blob, const char *name, 215 enum fdt_compat_id id, int *node_list, int maxcount) 216 { 217 int name_len = strlen(name); 218 int nodes[maxcount]; 219 int num_found = 0; 220 int offset, node; 221 int alias_node; 222 int count; 223 int i, j; 224 225 /* find the alias node if present */ 226 alias_node = fdt_path_offset(blob, "/aliases"); 227 228 /* 229 * start with nothing, and we can assume that the root node can't 230 * match 231 */ 232 memset(nodes, '\0', sizeof(nodes)); 233 234 /* First find all the compatible nodes */ 235 for (node = count = 0; node >= 0 && count < maxcount;) { 236 node = fdtdec_next_compatible(blob, node, id); 237 if (node >= 0) 238 nodes[count++] = node; 239 } 240 if (node >= 0) 241 debug("%s: warning: maxcount exceeded with alias '%s'\n", 242 __func__, name); 243 244 /* Now find all the aliases */ 245 for (offset = fdt_first_property_offset(blob, alias_node); 246 offset > 0; 247 offset = fdt_next_property_offset(blob, offset)) { 248 const struct fdt_property *prop; 249 const char *path; 250 int number; 251 int found; 252 253 node = 0; 254 prop = fdt_get_property_by_offset(blob, offset, NULL); 255 path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); 256 if (prop->len && 0 == strncmp(path, name, name_len)) 257 node = fdt_path_offset(blob, prop->data); 258 if (node <= 0) 259 continue; 260 261 /* Get the alias number */ 262 number = simple_strtoul(path + name_len, NULL, 10); 263 if (number < 0 || number >= maxcount) { 264 debug("%s: warning: alias '%s' is out of range\n", 265 __func__, path); 266 continue; 267 } 268 269 /* Make sure the node we found is actually in our list! */ 270 found = -1; 271 for (j = 0; j < count; j++) 272 if (nodes[j] == node) { 273 found = j; 274 break; 275 } 276 277 if (found == -1) { 278 debug("%s: warning: alias '%s' points to a node " 279 "'%s' that is missing or is not compatible " 280 " with '%s'\n", __func__, path, 281 fdt_get_name(blob, node, NULL), 282 compat_names[id]); 283 continue; 284 } 285 286 /* 287 * Add this node to our list in the right place, and mark 288 * it as done. 289 */ 290 if (fdtdec_get_is_enabled(blob, node)) { 291 if (node_list[number]) { 292 debug("%s: warning: alias '%s' requires that " 293 "a node be placed in the list in a " 294 "position which is already filled by " 295 "node '%s'\n", __func__, path, 296 fdt_get_name(blob, node, NULL)); 297 continue; 298 } 299 node_list[number] = node; 300 if (number >= num_found) 301 num_found = number + 1; 302 } 303 nodes[found] = 0; 304 } 305 306 /* Add any nodes not mentioned by an alias */ 307 for (i = j = 0; i < maxcount; i++) { 308 if (!node_list[i]) { 309 for (; j < maxcount; j++) 310 if (nodes[j] && 311 fdtdec_get_is_enabled(blob, nodes[j])) 312 break; 313 314 /* Have we run out of nodes to add? */ 315 if (j == maxcount) 316 break; 317 318 assert(!node_list[i]); 319 node_list[i] = nodes[j++]; 320 if (i >= num_found) 321 num_found = i + 1; 322 } 323 } 324 325 return num_found; 326 } 327 328 int fdtdec_get_alias_seq(const void *blob, const char *base, int offset, 329 int *seqp) 330 { 331 int base_len = strlen(base); 332 const char *find_name; 333 int find_namelen; 334 int prop_offset; 335 int aliases; 336 337 find_name = fdt_get_name(blob, offset, &find_namelen); 338 debug("Looking for '%s' at %d, name %s\n", base, offset, find_name); 339 340 aliases = fdt_path_offset(blob, "/aliases"); 341 for (prop_offset = fdt_first_property_offset(blob, aliases); 342 prop_offset > 0; 343 prop_offset = fdt_next_property_offset(blob, prop_offset)) { 344 const char *prop; 345 const char *name; 346 const char *slash; 347 const char *p; 348 int len; 349 350 prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len); 351 debug(" - %s, %s\n", name, prop); 352 if (len < find_namelen || *prop != '/' || prop[len - 1] || 353 strncmp(name, base, base_len)) 354 continue; 355 356 slash = strrchr(prop, '/'); 357 if (strcmp(slash + 1, find_name)) 358 continue; 359 for (p = name; *p; p++) { 360 if (isdigit(*p)) { 361 *seqp = simple_strtoul(p, NULL, 10); 362 debug("Found seq %d\n", *seqp); 363 return 0; 364 } 365 } 366 } 367 368 debug("Not found\n"); 369 return -ENOENT; 370 } 371 372 int fdtdec_get_alias_node(const void *blob, const char *name) 373 { 374 const char *prop; 375 int alias_node; 376 int len; 377 378 if (!blob) 379 return -FDT_ERR_NOTFOUND; 380 alias_node = fdt_path_offset(blob, "/aliases"); 381 prop = fdt_getprop(blob, alias_node, name, &len); 382 if (!prop) 383 return -FDT_ERR_NOTFOUND; 384 return fdt_path_offset(blob, prop); 385 } 386 387 int fdtdec_get_chosen_node(const void *blob, const char *name) 388 { 389 const char *prop; 390 int chosen_node; 391 int len; 392 393 if (!blob) 394 return -FDT_ERR_NOTFOUND; 395 chosen_node = fdt_path_offset(blob, "/chosen"); 396 prop = fdt_getprop(blob, chosen_node, name, &len); 397 if (!prop) 398 return -FDT_ERR_NOTFOUND; 399 return fdt_path_offset(blob, prop); 400 } 401 402 int fdtdec_check_fdt(void) 403 { 404 /* 405 * We must have an FDT, but we cannot panic() yet since the console 406 * is not ready. So for now, just assert(). Boards which need an early 407 * FDT (prior to console ready) will need to make their own 408 * arrangements and do their own checks. 409 */ 410 assert(!fdtdec_prepare_fdt()); 411 return 0; 412 } 413 414 /* 415 * This function is a little odd in that it accesses global data. At some 416 * point if the architecture board.c files merge this will make more sense. 417 * Even now, it is common code. 418 */ 419 int fdtdec_prepare_fdt(void) 420 { 421 if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || 422 fdt_check_header(gd->fdt_blob)) { 423 printf("No valid FDT found - please append one to U-Boot " 424 "binary, use u-boot-dtb.bin or define " 425 "CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n"); 426 return -1; 427 } 428 return 0; 429 } 430 431 int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) 432 { 433 const u32 *phandle; 434 int lookup; 435 436 debug("%s: %s\n", __func__, prop_name); 437 phandle = fdt_getprop(blob, node, prop_name, NULL); 438 if (!phandle) 439 return -FDT_ERR_NOTFOUND; 440 441 lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle)); 442 return lookup; 443 } 444 445 /** 446 * Look up a property in a node and check that it has a minimum length. 447 * 448 * @param blob FDT blob 449 * @param node node to examine 450 * @param prop_name name of property to find 451 * @param min_len minimum property length in bytes 452 * @param err 0 if ok, or -FDT_ERR_NOTFOUND if the property is not 453 found, or -FDT_ERR_BADLAYOUT if not enough data 454 * @return pointer to cell, which is only valid if err == 0 455 */ 456 static const void *get_prop_check_min_len(const void *blob, int node, 457 const char *prop_name, int min_len, int *err) 458 { 459 const void *cell; 460 int len; 461 462 debug("%s: %s\n", __func__, prop_name); 463 cell = fdt_getprop(blob, node, prop_name, &len); 464 if (!cell) 465 *err = -FDT_ERR_NOTFOUND; 466 else if (len < min_len) 467 *err = -FDT_ERR_BADLAYOUT; 468 else 469 *err = 0; 470 return cell; 471 } 472 473 int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, 474 u32 *array, int count) 475 { 476 const u32 *cell; 477 int i, err = 0; 478 479 debug("%s: %s\n", __func__, prop_name); 480 cell = get_prop_check_min_len(blob, node, prop_name, 481 sizeof(u32) * count, &err); 482 if (!err) { 483 for (i = 0; i < count; i++) 484 array[i] = fdt32_to_cpu(cell[i]); 485 } 486 return err; 487 } 488 489 int fdtdec_get_int_array_count(const void *blob, int node, 490 const char *prop_name, u32 *array, int count) 491 { 492 const u32 *cell; 493 int len, elems; 494 int i; 495 496 debug("%s: %s\n", __func__, prop_name); 497 cell = fdt_getprop(blob, node, prop_name, &len); 498 if (!cell) 499 return -FDT_ERR_NOTFOUND; 500 elems = len / sizeof(u32); 501 if (count > elems) 502 count = elems; 503 for (i = 0; i < count; i++) 504 array[i] = fdt32_to_cpu(cell[i]); 505 506 return count; 507 } 508 509 const u32 *fdtdec_locate_array(const void *blob, int node, 510 const char *prop_name, int count) 511 { 512 const u32 *cell; 513 int err; 514 515 cell = get_prop_check_min_len(blob, node, prop_name, 516 sizeof(u32) * count, &err); 517 return err ? NULL : cell; 518 } 519 520 int fdtdec_get_bool(const void *blob, int node, const char *prop_name) 521 { 522 const s32 *cell; 523 int len; 524 525 debug("%s: %s\n", __func__, prop_name); 526 cell = fdt_getprop(blob, node, prop_name, &len); 527 return cell != NULL; 528 } 529 530 /** 531 * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no 532 * terminating item. 533 * 534 * @param blob FDT blob to use 535 * @param node Node to look at 536 * @param prop_name Node property name 537 * @param gpio Array of gpio elements to fill from FDT. This will be 538 * untouched if either 0 or an error is returned 539 * @param max_count Maximum number of elements allowed 540 * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would 541 * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. 542 */ 543 int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, 544 struct fdt_gpio_state *gpio, int max_count) 545 { 546 const struct fdt_property *prop; 547 const u32 *cell; 548 const char *name; 549 int len, i; 550 551 debug("%s: %s\n", __func__, prop_name); 552 assert(max_count > 0); 553 prop = fdt_get_property(blob, node, prop_name, &len); 554 if (!prop) { 555 debug("%s: property '%s' missing\n", __func__, prop_name); 556 return -FDT_ERR_NOTFOUND; 557 } 558 559 /* We will use the name to tag the GPIO */ 560 name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); 561 cell = (u32 *)prop->data; 562 len /= sizeof(u32) * 3; /* 3 cells per GPIO record */ 563 if (len > max_count) { 564 debug(" %s: too many GPIOs / cells for " 565 "property '%s'\n", __func__, prop_name); 566 return -FDT_ERR_BADLAYOUT; 567 } 568 569 /* Read out the GPIO data from the cells */ 570 for (i = 0; i < len; i++, cell += 3) { 571 gpio[i].gpio = fdt32_to_cpu(cell[1]); 572 gpio[i].flags = fdt32_to_cpu(cell[2]); 573 gpio[i].name = name; 574 } 575 576 return len; 577 } 578 579 int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, 580 struct fdt_gpio_state *gpio) 581 { 582 int err; 583 584 debug("%s: %s\n", __func__, prop_name); 585 gpio->gpio = FDT_GPIO_NONE; 586 gpio->name = NULL; 587 err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1); 588 return err == 1 ? 0 : err; 589 } 590 591 int fdtdec_get_gpio(struct fdt_gpio_state *gpio) 592 { 593 int val; 594 595 if (!fdt_gpio_isvalid(gpio)) 596 return -1; 597 598 val = gpio_get_value(gpio->gpio); 599 return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; 600 } 601 602 int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val) 603 { 604 if (!fdt_gpio_isvalid(gpio)) 605 return -1; 606 607 val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; 608 return gpio_set_value(gpio->gpio, val); 609 } 610 611 int fdtdec_setup_gpio(struct fdt_gpio_state *gpio) 612 { 613 /* 614 * Return success if there is no GPIO defined. This is used for 615 * optional GPIOs) 616 */ 617 if (!fdt_gpio_isvalid(gpio)) 618 return 0; 619 620 if (gpio_request(gpio->gpio, gpio->name)) 621 return -1; 622 return 0; 623 } 624 625 int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, 626 u8 *array, int count) 627 { 628 const u8 *cell; 629 int err; 630 631 cell = get_prop_check_min_len(blob, node, prop_name, count, &err); 632 if (!err) 633 memcpy(array, cell, count); 634 return err; 635 } 636 637 const u8 *fdtdec_locate_byte_array(const void *blob, int node, 638 const char *prop_name, int count) 639 { 640 const u8 *cell; 641 int err; 642 643 cell = get_prop_check_min_len(blob, node, prop_name, count, &err); 644 if (err) 645 return NULL; 646 return cell; 647 } 648 649 int fdtdec_get_config_int(const void *blob, const char *prop_name, 650 int default_val) 651 { 652 int config_node; 653 654 debug("%s: %s\n", __func__, prop_name); 655 config_node = fdt_path_offset(blob, "/config"); 656 if (config_node < 0) 657 return default_val; 658 return fdtdec_get_int(blob, config_node, prop_name, default_val); 659 } 660 661 int fdtdec_get_config_bool(const void *blob, const char *prop_name) 662 { 663 int config_node; 664 const void *prop; 665 666 debug("%s: %s\n", __func__, prop_name); 667 config_node = fdt_path_offset(blob, "/config"); 668 if (config_node < 0) 669 return 0; 670 prop = fdt_get_property(blob, config_node, prop_name, NULL); 671 672 return prop != NULL; 673 } 674 675 char *fdtdec_get_config_string(const void *blob, const char *prop_name) 676 { 677 const char *nodep; 678 int nodeoffset; 679 int len; 680 681 debug("%s: %s\n", __func__, prop_name); 682 nodeoffset = fdt_path_offset(blob, "/config"); 683 if (nodeoffset < 0) 684 return NULL; 685 686 nodep = fdt_getprop(blob, nodeoffset, prop_name, &len); 687 if (!nodep) 688 return NULL; 689 690 return (char *)nodep; 691 } 692 693 int fdtdec_decode_region(const void *blob, int node, 694 const char *prop_name, void **ptrp, size_t *size) 695 { 696 const fdt_addr_t *cell; 697 int len; 698 699 debug("%s: %s\n", __func__, prop_name); 700 cell = fdt_getprop(blob, node, prop_name, &len); 701 if (!cell || (len != sizeof(fdt_addr_t) * 2)) 702 return -1; 703 704 *ptrp = map_sysmem(fdt_addr_to_cpu(*cell), *size); 705 *size = fdt_size_to_cpu(cell[1]); 706 debug("%s: size=%zx\n", __func__, *size); 707 return 0; 708 } 709 710 /** 711 * Read a flash entry from the fdt 712 * 713 * @param blob FDT blob 714 * @param node Offset of node to read 715 * @param name Name of node being read 716 * @param entry Place to put offset and size of this node 717 * @return 0 if ok, -ve on error 718 */ 719 int fdtdec_read_fmap_entry(const void *blob, int node, const char *name, 720 struct fmap_entry *entry) 721 { 722 u32 reg[2]; 723 724 if (fdtdec_get_int_array(blob, node, "reg", reg, 2)) { 725 debug("Node '%s' has bad/missing 'reg' property\n", name); 726 return -FDT_ERR_NOTFOUND; 727 } 728 entry->offset = reg[0]; 729 entry->length = reg[1]; 730 731 return 0; 732 } 733 734 static u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells) 735 { 736 u64 number = 0; 737 738 while (cells--) 739 number = (number << 32) | fdt32_to_cpu(*ptr++); 740 741 return number; 742 } 743 744 int fdt_get_resource(const void *fdt, int node, const char *property, 745 unsigned int index, struct fdt_resource *res) 746 { 747 const fdt32_t *ptr, *end; 748 int na, ns, len, parent; 749 unsigned int i = 0; 750 751 parent = fdt_parent_offset(fdt, node); 752 if (parent < 0) 753 return parent; 754 755 na = fdt_address_cells(fdt, parent); 756 ns = fdt_size_cells(fdt, parent); 757 758 ptr = fdt_getprop(fdt, node, property, &len); 759 if (!ptr) 760 return len; 761 762 end = ptr + len / sizeof(*ptr); 763 764 while (ptr + na + ns <= end) { 765 if (i == index) { 766 res->start = res->end = fdtdec_get_number(ptr, na); 767 res->end += fdtdec_get_number(&ptr[na], ns) - 1; 768 return 0; 769 } 770 771 ptr += na + ns; 772 i++; 773 } 774 775 return -FDT_ERR_NOTFOUND; 776 } 777 778 int fdt_get_named_resource(const void *fdt, int node, const char *property, 779 const char *prop_names, const char *name, 780 struct fdt_resource *res) 781 { 782 int index; 783 784 index = fdt_find_string(fdt, node, prop_names, name); 785 if (index < 0) 786 return index; 787 788 return fdt_get_resource(fdt, node, property, index, res); 789 } 790 791 int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf) 792 { 793 const fdt32_t *prop; 794 int len; 795 796 prop = fdt_getprop(fdt, node, "reg", &len); 797 if (!prop) 798 return len; 799 800 *bdf = fdt32_to_cpu(*prop) & 0xffffff; 801 802 return 0; 803 } 804 #endif 805