fdt.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Functions for working with the Flattened Device Tree data format
  3. *
  4. * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
  5. * benh@kernel.crashing.org
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2 as published by the Free Software Foundation.
  10. */
  11. #include <linux/of.h>
  12. #include <linux/of_fdt.h>
  13. struct boot_param_header *initial_boot_params;
  14. char *find_flat_dt_string(u32 offset)
  15. {
  16. return ((char *)initial_boot_params) +
  17. initial_boot_params->off_dt_strings + offset;
  18. }
  19. /**
  20. * of_scan_flat_dt - scan flattened tree blob and call callback on each.
  21. * @it: callback function
  22. * @data: context data pointer
  23. *
  24. * This function is used to scan the flattened device-tree, it is
  25. * used to extract the memory information at boot before we can
  26. * unflatten the tree
  27. */
  28. int __init of_scan_flat_dt(int (*it)(unsigned long node,
  29. const char *uname, int depth,
  30. void *data),
  31. void *data)
  32. {
  33. unsigned long p = ((unsigned long)initial_boot_params) +
  34. initial_boot_params->off_dt_struct;
  35. int rc = 0;
  36. int depth = -1;
  37. do {
  38. u32 tag = *((u32 *)p);
  39. char *pathp;
  40. p += 4;
  41. if (tag == OF_DT_END_NODE) {
  42. depth--;
  43. continue;
  44. }
  45. if (tag == OF_DT_NOP)
  46. continue;
  47. if (tag == OF_DT_END)
  48. break;
  49. if (tag == OF_DT_PROP) {
  50. u32 sz = *((u32 *)p);
  51. p += 8;
  52. if (initial_boot_params->version < 0x10)
  53. p = _ALIGN(p, sz >= 8 ? 8 : 4);
  54. p += sz;
  55. p = _ALIGN(p, 4);
  56. continue;
  57. }
  58. if (tag != OF_DT_BEGIN_NODE) {
  59. pr_err("Invalid tag %x in flat device tree!\n", tag);
  60. return -EINVAL;
  61. }
  62. depth++;
  63. pathp = (char *)p;
  64. p = _ALIGN(p + strlen(pathp) + 1, 4);
  65. if ((*pathp) == '/') {
  66. char *lp, *np;
  67. for (lp = NULL, np = pathp; *np; np++)
  68. if ((*np) == '/')
  69. lp = np+1;
  70. if (lp != NULL)
  71. pathp = lp;
  72. }
  73. rc = it(p, pathp, depth, data);
  74. if (rc != 0)
  75. break;
  76. } while (1);
  77. return rc;
  78. }
  79. /**
  80. * of_get_flat_dt_root - find the root node in the flat blob
  81. */
  82. unsigned long __init of_get_flat_dt_root(void)
  83. {
  84. unsigned long p = ((unsigned long)initial_boot_params) +
  85. initial_boot_params->off_dt_struct;
  86. while (*((u32 *)p) == OF_DT_NOP)
  87. p += 4;
  88. BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE);
  89. p += 4;
  90. return _ALIGN(p + strlen((char *)p) + 1, 4);
  91. }
  92. /**
  93. * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
  94. *
  95. * This function can be used within scan_flattened_dt callback to get
  96. * access to properties
  97. */
  98. void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
  99. unsigned long *size)
  100. {
  101. unsigned long p = node;
  102. do {
  103. u32 tag = *((u32 *)p);
  104. u32 sz, noff;
  105. const char *nstr;
  106. p += 4;
  107. if (tag == OF_DT_NOP)
  108. continue;
  109. if (tag != OF_DT_PROP)
  110. return NULL;
  111. sz = *((u32 *)p);
  112. noff = *((u32 *)(p + 4));
  113. p += 8;
  114. if (initial_boot_params->version < 0x10)
  115. p = _ALIGN(p, sz >= 8 ? 8 : 4);
  116. nstr = find_flat_dt_string(noff);
  117. if (nstr == NULL) {
  118. pr_warning("Can't find property index name !\n");
  119. return NULL;
  120. }
  121. if (strcmp(name, nstr) == 0) {
  122. if (size)
  123. *size = sz;
  124. return (void *)p;
  125. }
  126. p += sz;
  127. p = _ALIGN(p, 4);
  128. } while (1);
  129. }
  130. /**
  131. * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
  132. * @node: node to test
  133. * @compat: compatible string to compare with compatible list.
  134. */
  135. int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
  136. {
  137. const char *cp;
  138. unsigned long cplen, l;
  139. cp = of_get_flat_dt_prop(node, "compatible", &cplen);
  140. if (cp == NULL)
  141. return 0;
  142. while (cplen > 0) {
  143. if (strncasecmp(cp, compat, strlen(compat)) == 0)
  144. return 1;
  145. l = strlen(cp) + 1;
  146. cp += l;
  147. cplen -= l;
  148. }
  149. return 0;
  150. }