fdt_support.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * (C) Copyright 2007
  3. * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <linux/ctype.h>
  25. #include <linux/types.h>
  26. #include <asm/global_data.h>
  27. #include <fdt.h>
  28. #include <libfdt.h>
  29. #include <fdt_support.h>
  30. #include <exports.h>
  31. /*
  32. * Global data (for the gd->bd)
  33. */
  34. DECLARE_GLOBAL_DATA_PTR;
  35. /*
  36. * fdt points to our working device tree.
  37. */
  38. struct fdt_header *fdt;
  39. /**
  40. * fdt_find_and_setprop: Find a node and set it's property
  41. *
  42. * @fdt: ptr to device tree
  43. * @node: path of node
  44. * @prop: property name
  45. * @val: ptr to new value
  46. * @len: length of new property value
  47. * @create: flag to create the property if it doesn't exist
  48. *
  49. * Convenience function to directly set a property given the path to the node.
  50. */
  51. int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
  52. const void *val, int len, int create)
  53. {
  54. int nodeoff = fdt_path_offset(fdt, node);
  55. if (nodeoff < 0)
  56. return nodeoff;
  57. if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL))
  58. return 0; /* create flag not set; so exit quietly */
  59. return fdt_setprop(fdt, nodeoff, prop, val, len);
  60. }
  61. #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
  62. static int fdt_fixup_stdout(void *fdt, int choosenoff)
  63. {
  64. int err = 0;
  65. #ifdef CONFIG_CONS_INDEX
  66. int node;
  67. char sername[9] = { 0 };
  68. const char *path;
  69. sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
  70. err = node = fdt_path_offset(fdt, "/aliases");
  71. if (node >= 0) {
  72. int len;
  73. path = fdt_getprop(fdt, node, sername, &len);
  74. if (path) {
  75. char *p = malloc(len);
  76. err = -FDT_ERR_NOSPACE;
  77. if (p) {
  78. memcpy(p, path, len);
  79. err = fdt_setprop(fdt, choosenoff,
  80. "linux,stdout-path", p, len);
  81. free(p);
  82. }
  83. } else {
  84. err = len;
  85. }
  86. }
  87. #endif
  88. if (err < 0)
  89. printf("WARNING: could not set linux,stdout-path %s.\n",
  90. fdt_strerror(err));
  91. return err;
  92. }
  93. #endif
  94. int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
  95. {
  96. int nodeoffset;
  97. int err;
  98. u32 tmp; /* used to set 32 bit integer properties */
  99. char *str; /* used to set string properties */
  100. const char *path;
  101. err = fdt_check_header(fdt);
  102. if (err < 0) {
  103. printf("fdt_chosen: %s\n", fdt_strerror(err));
  104. return err;
  105. }
  106. if (initrd_start && initrd_end) {
  107. uint64_t addr, size;
  108. int total = fdt_num_mem_rsv(fdt);
  109. int j;
  110. /*
  111. * Look for an existing entry and update it. If we don't find
  112. * the entry, we will j be the next available slot.
  113. */
  114. for (j = 0; j < total; j++) {
  115. err = fdt_get_mem_rsv(fdt, j, &addr, &size);
  116. if (addr == initrd_start) {
  117. fdt_del_mem_rsv(fdt, j);
  118. break;
  119. }
  120. }
  121. err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
  122. if (err < 0) {
  123. printf("fdt_chosen: %s\n", fdt_strerror(err));
  124. return err;
  125. }
  126. }
  127. /*
  128. * Find the "chosen" node.
  129. */
  130. nodeoffset = fdt_path_offset (fdt, "/chosen");
  131. /*
  132. * If there is no "chosen" node in the blob, create it.
  133. */
  134. if (nodeoffset < 0) {
  135. /*
  136. * Create a new node "/chosen" (offset 0 is root level)
  137. */
  138. nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
  139. if (nodeoffset < 0) {
  140. printf("WARNING: could not create /chosen %s.\n",
  141. fdt_strerror(nodeoffset));
  142. return nodeoffset;
  143. }
  144. }
  145. /*
  146. * Create /chosen properites that don't exist in the fdt.
  147. * If the property exists, update it only if the "force" parameter
  148. * is true.
  149. */
  150. str = getenv("bootargs");
  151. if (str != NULL) {
  152. path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
  153. if ((path == NULL) || force) {
  154. err = fdt_setprop(fdt, nodeoffset,
  155. "bootargs", str, strlen(str)+1);
  156. if (err < 0)
  157. printf("WARNING: could not set bootargs %s.\n",
  158. fdt_strerror(err));
  159. }
  160. }
  161. if (initrd_start && initrd_end) {
  162. path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
  163. if ((path == NULL) || force) {
  164. tmp = __cpu_to_be32(initrd_start);
  165. err = fdt_setprop(fdt, nodeoffset,
  166. "linux,initrd-start", &tmp, sizeof(tmp));
  167. if (err < 0)
  168. printf("WARNING: "
  169. "could not set linux,initrd-start %s.\n",
  170. fdt_strerror(err));
  171. tmp = __cpu_to_be32(initrd_end);
  172. err = fdt_setprop(fdt, nodeoffset,
  173. "linux,initrd-end", &tmp, sizeof(tmp));
  174. if (err < 0)
  175. printf("WARNING: could not set linux,initrd-end %s.\n",
  176. fdt_strerror(err));
  177. }
  178. }
  179. #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
  180. path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
  181. if ((path == NULL) || force)
  182. err = fdt_fixup_stdout(fdt, nodeoffset);
  183. #endif
  184. #ifdef OF_STDOUT_PATH
  185. path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
  186. if ((path == NULL) || force) {
  187. err = fdt_setprop(fdt, nodeoffset,
  188. "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
  189. if (err < 0)
  190. printf("WARNING: could not set linux,stdout-path %s.\n",
  191. fdt_strerror(err));
  192. }
  193. #endif
  194. return err;
  195. }
  196. void do_fixup_by_path(void *fdt, const char *path, const char *prop,
  197. const void *val, int len, int create)
  198. {
  199. #if defined(DEBUG)
  200. int i;
  201. debug("Updating property '%s/%s' = ", path, prop);
  202. for (i = 0; i < len; i++)
  203. debug(" %.2x", *(u8*)(val+i));
  204. debug("\n");
  205. #endif
  206. int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
  207. if (rc)
  208. printf("Unable to update property %s:%s, err=%s\n",
  209. path, prop, fdt_strerror(rc));
  210. }
  211. void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
  212. u32 val, int create)
  213. {
  214. val = cpu_to_fdt32(val);
  215. do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create);
  216. }
  217. void do_fixup_by_prop(void *fdt,
  218. const char *pname, const void *pval, int plen,
  219. const char *prop, const void *val, int len,
  220. int create)
  221. {
  222. int off;
  223. #if defined(DEBUG)
  224. int i;
  225. debug("Updating property '%s' = ", prop);
  226. for (i = 0; i < len; i++)
  227. debug(" %.2x", *(u8*)(val+i));
  228. debug("\n");
  229. #endif
  230. off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
  231. while (off != -FDT_ERR_NOTFOUND) {
  232. if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
  233. fdt_setprop(fdt, off, prop, val, len);
  234. off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
  235. }
  236. }
  237. void do_fixup_by_prop_u32(void *fdt,
  238. const char *pname, const void *pval, int plen,
  239. const char *prop, u32 val, int create)
  240. {
  241. val = cpu_to_fdt32(val);
  242. do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create);
  243. }
  244. void do_fixup_by_compat(void *fdt, const char *compat,
  245. const char *prop, const void *val, int len, int create)
  246. {
  247. int off = -1;
  248. #if defined(DEBUG)
  249. int i;
  250. debug("Updating property '%s' = ", prop);
  251. for (i = 0; i < len; i++)
  252. debug(" %.2x", *(u8*)(val+i));
  253. debug("\n");
  254. #endif
  255. off = fdt_node_offset_by_compatible(fdt, -1, compat);
  256. while (off != -FDT_ERR_NOTFOUND) {
  257. if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
  258. fdt_setprop(fdt, off, prop, val, len);
  259. off = fdt_node_offset_by_compatible(fdt, off, compat);
  260. }
  261. }
  262. void do_fixup_by_compat_u32(void *fdt, const char *compat,
  263. const char *prop, u32 val, int create)
  264. {
  265. val = cpu_to_fdt32(val);
  266. do_fixup_by_compat(fdt, compat, prop, &val, 4, create);
  267. }
  268. int fdt_fixup_memory(void *blob, u64 start, u64 size)
  269. {
  270. int err, nodeoffset, len = 0;
  271. u8 tmp[16];
  272. const u32 *addrcell, *sizecell;
  273. err = fdt_check_header(blob);
  274. if (err < 0) {
  275. printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
  276. return err;
  277. }
  278. /* update, or add and update /memory node */
  279. nodeoffset = fdt_path_offset(blob, "/memory");
  280. if (nodeoffset < 0) {
  281. nodeoffset = fdt_add_subnode(blob, 0, "memory");
  282. if (nodeoffset < 0)
  283. printf("WARNING: could not create /memory: %s.\n",
  284. fdt_strerror(nodeoffset));
  285. return nodeoffset;
  286. }
  287. err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
  288. sizeof("memory"));
  289. if (err < 0) {
  290. printf("WARNING: could not set %s %s.\n", "device_type",
  291. fdt_strerror(err));
  292. return err;
  293. }
  294. addrcell = fdt_getprop(blob, 0, "#address-cells", NULL);
  295. /* use shifts and mask to ensure endianness */
  296. if ((addrcell) && (*addrcell == 2)) {
  297. tmp[0] = (start >> 56) & 0xff;
  298. tmp[1] = (start >> 48) & 0xff;
  299. tmp[2] = (start >> 40) & 0xff;
  300. tmp[3] = (start >> 32) & 0xff;
  301. tmp[4] = (start >> 24) & 0xff;
  302. tmp[5] = (start >> 16) & 0xff;
  303. tmp[6] = (start >> 8) & 0xff;
  304. tmp[7] = (start ) & 0xff;
  305. len = 8;
  306. } else {
  307. tmp[0] = (start >> 24) & 0xff;
  308. tmp[1] = (start >> 16) & 0xff;
  309. tmp[2] = (start >> 8) & 0xff;
  310. tmp[3] = (start ) & 0xff;
  311. len = 4;
  312. }
  313. sizecell = fdt_getprop(blob, 0, "#size-cells", NULL);
  314. /* use shifts and mask to ensure endianness */
  315. if ((sizecell) && (*sizecell == 2)) {
  316. tmp[0+len] = (size >> 56) & 0xff;
  317. tmp[1+len] = (size >> 48) & 0xff;
  318. tmp[2+len] = (size >> 40) & 0xff;
  319. tmp[3+len] = (size >> 32) & 0xff;
  320. tmp[4+len] = (size >> 24) & 0xff;
  321. tmp[5+len] = (size >> 16) & 0xff;
  322. tmp[6+len] = (size >> 8) & 0xff;
  323. tmp[7+len] = (size ) & 0xff;
  324. len += 8;
  325. } else {
  326. tmp[0+len] = (size >> 24) & 0xff;
  327. tmp[1+len] = (size >> 16) & 0xff;
  328. tmp[2+len] = (size >> 8) & 0xff;
  329. tmp[3+len] = (size ) & 0xff;
  330. len += 4;
  331. }
  332. err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
  333. if (err < 0) {
  334. printf("WARNING: could not set %s %s.\n",
  335. "reg", fdt_strerror(err));
  336. return err;
  337. }
  338. return 0;
  339. }
  340. #if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
  341. defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
  342. void fdt_fixup_ethernet(void *fdt, bd_t *bd)
  343. {
  344. int node;
  345. const char *path;
  346. node = fdt_path_offset(fdt, "/aliases");
  347. if (node >= 0) {
  348. #if defined(CONFIG_HAS_ETH0)
  349. path = fdt_getprop(fdt, node, "ethernet0", NULL);
  350. if (path) {
  351. do_fixup_by_path(fdt, path, "mac-address",
  352. bd->bi_enetaddr, 6, 0);
  353. do_fixup_by_path(fdt, path, "local-mac-address",
  354. bd->bi_enetaddr, 6, 1);
  355. }
  356. #endif
  357. #if defined(CONFIG_HAS_ETH1)
  358. path = fdt_getprop(fdt, node, "ethernet1", NULL);
  359. if (path) {
  360. do_fixup_by_path(fdt, path, "mac-address",
  361. bd->bi_enet1addr, 6, 0);
  362. do_fixup_by_path(fdt, path, "local-mac-address",
  363. bd->bi_enet1addr, 6, 1);
  364. }
  365. #endif
  366. #if defined(CONFIG_HAS_ETH2)
  367. path = fdt_getprop(fdt, node, "ethernet2", NULL);
  368. if (path) {
  369. do_fixup_by_path(fdt, path, "mac-address",
  370. bd->bi_enet2addr, 6, 0);
  371. do_fixup_by_path(fdt, path, "local-mac-address",
  372. bd->bi_enet2addr, 6, 1);
  373. }
  374. #endif
  375. #if defined(CONFIG_HAS_ETH3)
  376. path = fdt_getprop(fdt, node, "ethernet3", NULL);
  377. if (path) {
  378. do_fixup_by_path(fdt, path, "mac-address",
  379. bd->bi_enet3addr, 6, 0);
  380. do_fixup_by_path(fdt, path, "local-mac-address",
  381. bd->bi_enet3addr, 6, 1);
  382. }
  383. #endif
  384. }
  385. }
  386. #endif
  387. #ifdef CONFIG_HAS_FSL_DR_USB
  388. void fdt_fixup_dr_usb(void *blob, bd_t *bd)
  389. {
  390. char *mode;
  391. const char *compat = "fsl-usb2-dr";
  392. const char *prop = "dr_mode";
  393. int node_offset;
  394. int err;
  395. mode = getenv("usb_dr_mode");
  396. if (!mode)
  397. return;
  398. node_offset = fdt_node_offset_by_compatible(blob, 0, compat);
  399. if (node_offset < 0)
  400. printf("WARNING: could not find compatible node %s: %s.\n",
  401. compat, fdt_strerror(node_offset));
  402. err = fdt_setprop(blob, node_offset, prop, mode, strlen(mode) + 1);
  403. if (err < 0)
  404. printf("WARNING: could not set %s for %s: %s.\n",
  405. prop, compat, fdt_strerror(err));
  406. }
  407. #endif /* CONFIG_HAS_FSL_DR_USB */