cmd_fdt.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. /*
  2. * (C) Copyright 2007
  3. * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
  4. * Based on code written by:
  5. * Pantelis Antoniou <pantelis.antoniou@gmail.com> and
  6. * Matthew McClintock <msm@freescale.com>
  7. *
  8. * See file CREDITS for list of people who contributed to this
  9. * project.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License as
  13. * published by the Free Software Foundation; either version 2 of
  14. * the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24. * MA 02111-1307 USA
  25. */
  26. #include <common.h>
  27. #include <command.h>
  28. #include <linux/ctype.h>
  29. #include <linux/types.h>
  30. #include <asm/global_data.h>
  31. #include <fdt.h>
  32. #include <libfdt.h>
  33. #include <fdt_support.h>
  34. #define MAX_LEVEL 32 /* how deeply nested we will go */
  35. #define SCRATCHPAD 1024 /* bytes of scratchpad memory */
  36. /*
  37. * Global data (for the gd->bd)
  38. */
  39. DECLARE_GLOBAL_DATA_PTR;
  40. static int fdt_valid(void);
  41. static int fdt_parse_prop(char **newval, int count, char *data, int *len);
  42. static int fdt_print(const char *pathp, char *prop, int depth);
  43. /*
  44. * The working_fdt points to our working flattened device tree.
  45. */
  46. struct fdt_header *working_fdt;
  47. /*
  48. * Flattened Device Tree command, see the help for parameter definitions.
  49. */
  50. int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
  51. {
  52. if (argc < 2) {
  53. printf ("Usage:\n%s\n", cmdtp->usage);
  54. return 1;
  55. }
  56. /********************************************************************
  57. * Set the address of the fdt
  58. ********************************************************************/
  59. if (argv[1][0] == 'a') {
  60. /*
  61. * Set the address [and length] of the fdt.
  62. */
  63. if (argc == 2) {
  64. if (!fdt_valid()) {
  65. return 1;
  66. }
  67. printf("The address of the fdt is %p\n", working_fdt);
  68. return 0;
  69. }
  70. working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
  71. if (!fdt_valid()) {
  72. return 1;
  73. }
  74. if (argc >= 4) {
  75. int len;
  76. int err;
  77. /*
  78. * Optional new length
  79. */
  80. len = simple_strtoul(argv[3], NULL, 16);
  81. if (len < fdt_totalsize(working_fdt)) {
  82. printf ("New length %d < existing length %d, "
  83. "ignoring.\n",
  84. len, fdt_totalsize(working_fdt));
  85. } else {
  86. /*
  87. * Open in place with a new length.
  88. */
  89. err = fdt_open_into(working_fdt, working_fdt, len);
  90. if (err != 0) {
  91. printf ("libfdt fdt_open_into(): %s\n",
  92. fdt_strerror(err));
  93. }
  94. }
  95. }
  96. /********************************************************************
  97. * Move the working_fdt
  98. ********************************************************************/
  99. } else if (strncmp(argv[1], "mo", 2) == 0) {
  100. struct fdt_header *newaddr;
  101. int len;
  102. int err;
  103. if (argc < 4) {
  104. printf ("Usage:\n%s\n", cmdtp->usage);
  105. return 1;
  106. }
  107. /*
  108. * Set the address and length of the fdt.
  109. */
  110. working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
  111. if (!fdt_valid()) {
  112. return 1;
  113. }
  114. newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16);
  115. /*
  116. * If the user specifies a length, use that. Otherwise use the
  117. * current length.
  118. */
  119. if (argc <= 4) {
  120. len = fdt_totalsize(working_fdt);
  121. } else {
  122. len = simple_strtoul(argv[4], NULL, 16);
  123. if (len < fdt_totalsize(working_fdt)) {
  124. printf ("New length 0x%X < existing length "
  125. "0x%X, aborting.\n",
  126. len, fdt_totalsize(working_fdt));
  127. return 1;
  128. }
  129. }
  130. /*
  131. * Copy to the new location.
  132. */
  133. err = fdt_open_into(working_fdt, newaddr, len);
  134. if (err != 0) {
  135. printf ("libfdt fdt_open_into(): %s\n",
  136. fdt_strerror(err));
  137. return 1;
  138. }
  139. working_fdt = newaddr;
  140. /********************************************************************
  141. * Make a new node
  142. ********************************************************************/
  143. } else if (strncmp(argv[1], "mk", 2) == 0) {
  144. char *pathp; /* path */
  145. char *nodep; /* new node to add */
  146. int nodeoffset; /* node offset from libfdt */
  147. int err;
  148. /*
  149. * Parameters: Node path, new node to be appended to the path.
  150. */
  151. if (argc < 4) {
  152. printf ("Usage:\n%s\n", cmdtp->usage);
  153. return 1;
  154. }
  155. pathp = argv[2];
  156. nodep = argv[3];
  157. nodeoffset = fdt_path_offset (working_fdt, pathp);
  158. if (nodeoffset < 0) {
  159. /*
  160. * Not found or something else bad happened.
  161. */
  162. printf ("libfdt fdt_path_offset() returned %s\n",
  163. fdt_strerror(nodeoffset));
  164. return 1;
  165. }
  166. err = fdt_add_subnode(working_fdt, nodeoffset, nodep);
  167. if (err < 0) {
  168. printf ("libfdt fdt_add_subnode(): %s\n",
  169. fdt_strerror(err));
  170. return 1;
  171. }
  172. /********************************************************************
  173. * Set the value of a property in the working_fdt.
  174. ********************************************************************/
  175. } else if (argv[1][0] == 's') {
  176. char *pathp; /* path */
  177. char *prop; /* property */
  178. int nodeoffset; /* node offset from libfdt */
  179. static char data[SCRATCHPAD]; /* storage for the property */
  180. int len; /* new length of the property */
  181. int ret; /* return value */
  182. /*
  183. * Parameters: Node path, property, optional value.
  184. */
  185. if (argc < 4) {
  186. printf ("Usage:\n%s\n", cmdtp->usage);
  187. return 1;
  188. }
  189. pathp = argv[2];
  190. prop = argv[3];
  191. if (argc == 4) {
  192. len = 0;
  193. } else {
  194. ret = fdt_parse_prop(&argv[4], argc - 4, data, &len);
  195. if (ret != 0)
  196. return ret;
  197. }
  198. nodeoffset = fdt_path_offset (working_fdt, pathp);
  199. if (nodeoffset < 0) {
  200. /*
  201. * Not found or something else bad happened.
  202. */
  203. printf ("libfdt fdt_path_offset() returned %s\n",
  204. fdt_strerror(nodeoffset));
  205. return 1;
  206. }
  207. ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len);
  208. if (ret < 0) {
  209. printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret));
  210. return 1;
  211. }
  212. /********************************************************************
  213. * Print (recursive) / List (single level)
  214. ********************************************************************/
  215. } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) {
  216. int depth = MAX_LEVEL; /* how deep to print */
  217. char *pathp; /* path */
  218. char *prop; /* property */
  219. int ret; /* return value */
  220. static char root[2] = "/";
  221. /*
  222. * list is an alias for print, but limited to 1 level
  223. */
  224. if (argv[1][0] == 'l') {
  225. depth = 1;
  226. }
  227. /*
  228. * Get the starting path. The root node is an oddball,
  229. * the offset is zero and has no name.
  230. */
  231. if (argc == 2)
  232. pathp = root;
  233. else
  234. pathp = argv[2];
  235. if (argc > 3)
  236. prop = argv[3];
  237. else
  238. prop = NULL;
  239. ret = fdt_print(pathp, prop, depth);
  240. if (ret != 0)
  241. return ret;
  242. /********************************************************************
  243. * Remove a property/node
  244. ********************************************************************/
  245. } else if (strncmp(argv[1], "rm", 2) == 0) {
  246. int nodeoffset; /* node offset from libfdt */
  247. int err;
  248. /*
  249. * Get the path. The root node is an oddball, the offset
  250. * is zero and has no name.
  251. */
  252. nodeoffset = fdt_path_offset (working_fdt, argv[2]);
  253. if (nodeoffset < 0) {
  254. /*
  255. * Not found or something else bad happened.
  256. */
  257. printf ("libfdt fdt_path_offset() returned %s\n",
  258. fdt_strerror(nodeoffset));
  259. return 1;
  260. }
  261. /*
  262. * Do the delete. A fourth parameter means delete a property,
  263. * otherwise delete the node.
  264. */
  265. if (argc > 3) {
  266. err = fdt_delprop(working_fdt, nodeoffset, argv[3]);
  267. if (err < 0) {
  268. printf("libfdt fdt_delprop(): %s\n",
  269. fdt_strerror(err));
  270. return err;
  271. }
  272. } else {
  273. err = fdt_del_node(working_fdt, nodeoffset);
  274. if (err < 0) {
  275. printf("libfdt fdt_del_node(): %s\n",
  276. fdt_strerror(err));
  277. return err;
  278. }
  279. }
  280. /********************************************************************
  281. * Display header info
  282. ********************************************************************/
  283. } else if (argv[1][0] == 'h') {
  284. u32 version = fdt_version(working_fdt);
  285. printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt));
  286. printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt),
  287. fdt_totalsize(working_fdt));
  288. printf("off_dt_struct:\t\t0x%x\n",
  289. fdt_off_dt_struct(working_fdt));
  290. printf("off_dt_strings:\t\t0x%x\n",
  291. fdt_off_dt_strings(working_fdt));
  292. printf("off_mem_rsvmap:\t\t0x%x\n",
  293. fdt_off_mem_rsvmap(working_fdt));
  294. printf("version:\t\t%d\n", version);
  295. printf("last_comp_version:\t%d\n",
  296. fdt_last_comp_version(working_fdt));
  297. if (version >= 2)
  298. printf("boot_cpuid_phys:\t0x%x\n",
  299. fdt_boot_cpuid_phys(working_fdt));
  300. if (version >= 3)
  301. printf("size_dt_strings:\t0x%x\n",
  302. fdt_size_dt_strings(working_fdt));
  303. if (version >= 17)
  304. printf("size_dt_struct:\t\t0x%x\n",
  305. fdt_size_dt_struct(working_fdt));
  306. printf("number mem_rsv:\t\t0x%x\n",
  307. fdt_num_mem_rsv(working_fdt));
  308. printf("\n");
  309. /********************************************************************
  310. * Set boot cpu id
  311. ********************************************************************/
  312. } else if (strncmp(argv[1], "boo", 3) == 0) {
  313. unsigned long tmp = simple_strtoul(argv[2], NULL, 16);
  314. fdt_set_boot_cpuid_phys(working_fdt, tmp);
  315. /********************************************************************
  316. * memory command
  317. ********************************************************************/
  318. } else if (strncmp(argv[1], "me", 2) == 0) {
  319. uint64_t addr, size;
  320. int err;
  321. #ifdef CFG_64BIT_STRTOUL
  322. addr = simple_strtoull(argv[2], NULL, 16);
  323. size = simple_strtoull(argv[3], NULL, 16);
  324. #else
  325. addr = simple_strtoul(argv[2], NULL, 16);
  326. size = simple_strtoul(argv[3], NULL, 16);
  327. #endif
  328. err = fdt_fixup_memory(working_fdt, addr, size);
  329. if (err < 0)
  330. return err;
  331. /********************************************************************
  332. * mem reserve commands
  333. ********************************************************************/
  334. } else if (strncmp(argv[1], "rs", 2) == 0) {
  335. if (argv[2][0] == 'p') {
  336. uint64_t addr, size;
  337. int total = fdt_num_mem_rsv(working_fdt);
  338. int j, err;
  339. printf("index\t\t start\t\t size\n");
  340. printf("-------------------------------"
  341. "-----------------\n");
  342. for (j = 0; j < total; j++) {
  343. err = fdt_get_mem_rsv(working_fdt, j, &addr, &size);
  344. if (err < 0) {
  345. printf("libfdt fdt_get_mem_rsv(): %s\n",
  346. fdt_strerror(err));
  347. return err;
  348. }
  349. printf(" %x\t%08x%08x\t%08x%08x\n", j,
  350. (u32)(addr >> 32),
  351. (u32)(addr & 0xffffffff),
  352. (u32)(size >> 32),
  353. (u32)(size & 0xffffffff));
  354. }
  355. } else if (argv[2][0] == 'a') {
  356. uint64_t addr, size;
  357. int err;
  358. #ifdef CFG_64BIT_STRTOUL
  359. addr = simple_strtoull(argv[3], NULL, 16);
  360. size = simple_strtoull(argv[4], NULL, 16);
  361. #else
  362. addr = simple_strtoul(argv[3], NULL, 16);
  363. size = simple_strtoul(argv[4], NULL, 16);
  364. #endif
  365. err = fdt_add_mem_rsv(working_fdt, addr, size);
  366. if (err < 0) {
  367. printf("libfdt fdt_add_mem_rsv(): %s\n",
  368. fdt_strerror(err));
  369. return err;
  370. }
  371. } else if (argv[2][0] == 'd') {
  372. unsigned long idx = simple_strtoul(argv[3], NULL, 16);
  373. int err = fdt_del_mem_rsv(working_fdt, idx);
  374. if (err < 0) {
  375. printf("libfdt fdt_del_mem_rsv(): %s\n",
  376. fdt_strerror(err));
  377. return err;
  378. }
  379. } else {
  380. /* Unrecognized command */
  381. printf ("Usage:\n%s\n", cmdtp->usage);
  382. return 1;
  383. }
  384. }
  385. #ifdef CONFIG_OF_BOARD_SETUP
  386. /* Call the board-specific fixup routine */
  387. else if (strncmp(argv[1], "boa", 3) == 0)
  388. ft_board_setup(working_fdt, gd->bd);
  389. #endif
  390. /* Create a chosen node */
  391. else if (argv[1][0] == 'c') {
  392. unsigned long initrd_start = 0, initrd_end = 0;
  393. if ((argc != 2) && (argc != 4)) {
  394. printf ("Usage:\n%s\n", cmdtp->usage);
  395. return 1;
  396. }
  397. if (argc == 4) {
  398. initrd_start = simple_strtoul(argv[2], NULL, 16);
  399. initrd_end = simple_strtoul(argv[3], NULL, 16);
  400. }
  401. fdt_chosen(working_fdt, initrd_start, initrd_end, 1);
  402. } else {
  403. /* Unrecognized command */
  404. printf ("Usage:\n%s\n", cmdtp->usage);
  405. return 1;
  406. }
  407. return 0;
  408. }
  409. /****************************************************************************/
  410. static int fdt_valid(void)
  411. {
  412. int err;
  413. if (working_fdt == NULL) {
  414. printf ("The address of the fdt is invalid (NULL).\n");
  415. return 0;
  416. }
  417. err = fdt_check_header(working_fdt);
  418. if (err == 0)
  419. return 1; /* valid */
  420. if (err < 0) {
  421. printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
  422. /*
  423. * Be more informative on bad version.
  424. */
  425. if (err == -FDT_ERR_BADVERSION) {
  426. if (fdt_version(working_fdt) <
  427. FDT_FIRST_SUPPORTED_VERSION) {
  428. printf (" - too old, fdt %d < %d",
  429. fdt_version(working_fdt),
  430. FDT_FIRST_SUPPORTED_VERSION);
  431. working_fdt = NULL;
  432. }
  433. if (fdt_last_comp_version(working_fdt) >
  434. FDT_LAST_SUPPORTED_VERSION) {
  435. printf (" - too new, fdt %d > %d",
  436. fdt_version(working_fdt),
  437. FDT_LAST_SUPPORTED_VERSION);
  438. working_fdt = NULL;
  439. }
  440. return 0;
  441. }
  442. printf("\n");
  443. return 0;
  444. }
  445. return 1;
  446. }
  447. /****************************************************************************/
  448. /*
  449. * Parse the user's input, partially heuristic. Valid formats:
  450. * <0x00112233 4 05> - an array of cells. Numbers follow standard
  451. * C conventions.
  452. * [00 11 22 .. nn] - byte stream
  453. * "string" - If the the value doesn't start with "<" or "[", it is
  454. * treated as a string. Note that the quotes are
  455. * stripped by the parser before we get the string.
  456. * newval: An array of strings containing the new property as specified
  457. * on the command line
  458. * count: The number of strings in the array
  459. * data: A bytestream to be placed in the property
  460. * len: The length of the resulting bytestream
  461. */
  462. static int fdt_parse_prop(char **newval, int count, char *data, int *len)
  463. {
  464. char *cp; /* temporary char pointer */
  465. char *newp; /* temporary newval char pointer */
  466. unsigned long tmp; /* holds converted values */
  467. int stridx = 0;
  468. *len = 0;
  469. newp = newval[0];
  470. /* An array of cells */
  471. if (*newp == '<') {
  472. newp++;
  473. while ((*newp != '>') && (stridx < count)) {
  474. /*
  475. * Keep searching until we find that last ">"
  476. * That way users don't have to escape the spaces
  477. */
  478. if (*newp == '\0') {
  479. newp = newval[++stridx];
  480. continue;
  481. }
  482. cp = newp;
  483. tmp = simple_strtoul(cp, &newp, 0);
  484. *(uint32_t *)data = __cpu_to_be32(tmp);
  485. data += 4;
  486. *len += 4;
  487. /* If the ptr didn't advance, something went wrong */
  488. if ((newp - cp) <= 0) {
  489. printf("Sorry, I could not convert \"%s\"\n",
  490. cp);
  491. return 1;
  492. }
  493. while (*newp == ' ')
  494. newp++;
  495. }
  496. if (*newp != '>') {
  497. printf("Unexpected character '%c'\n", *newp);
  498. return 1;
  499. }
  500. } else if (*newp == '[') {
  501. /*
  502. * Byte stream. Convert the values.
  503. */
  504. newp++;
  505. while ((*newp != ']') && (stridx < count)) {
  506. tmp = simple_strtoul(newp, &newp, 16);
  507. *data++ = tmp & 0xFF;
  508. *len = *len + 1;
  509. while (*newp == ' ')
  510. newp++;
  511. if (*newp != '\0')
  512. newp = newval[++stridx];
  513. }
  514. if (*newp != ']') {
  515. printf("Unexpected character '%c'\n", *newp);
  516. return 1;
  517. }
  518. } else {
  519. /*
  520. * Assume it is a string. Copy it into our data area for
  521. * convenience (including the terminating '\0').
  522. */
  523. while (stridx < count) {
  524. *len = strlen(newp) + 1;
  525. strcpy(data, newp);
  526. newp = newval[++stridx];
  527. }
  528. }
  529. return 0;
  530. }
  531. /****************************************************************************/
  532. /*
  533. * Heuristic to guess if this is a string or concatenated strings.
  534. */
  535. static int is_printable_string(const void *data, int len)
  536. {
  537. const char *s = data;
  538. /* zero length is not */
  539. if (len == 0)
  540. return 0;
  541. /* must terminate with zero */
  542. if (s[len - 1] != '\0')
  543. return 0;
  544. /* printable or a null byte (concatenated strings) */
  545. while (((*s == '\0') || isprint(*s)) && (len > 0)) {
  546. /*
  547. * If we see a null, there are three possibilities:
  548. * 1) If len == 1, it is the end of the string, printable
  549. * 2) Next character also a null, not printable.
  550. * 3) Next character not a null, continue to check.
  551. */
  552. if (s[0] == '\0') {
  553. if (len == 1)
  554. return 1;
  555. if (s[1] == '\0')
  556. return 0;
  557. }
  558. s++;
  559. len--;
  560. }
  561. /* Not the null termination, or not done yet: not printable */
  562. if (*s != '\0' || (len != 0))
  563. return 0;
  564. return 1;
  565. }
  566. /*
  567. * Print the property in the best format, a heuristic guess. Print as
  568. * a string, concatenated strings, a byte, word, double word, or (if all
  569. * else fails) it is printed as a stream of bytes.
  570. */
  571. static void print_data(const void *data, int len)
  572. {
  573. int j;
  574. /* no data, don't print */
  575. if (len == 0)
  576. return;
  577. /*
  578. * It is a string, but it may have multiple strings (embedded '\0's).
  579. */
  580. if (is_printable_string(data, len)) {
  581. puts("\"");
  582. j = 0;
  583. while (j < len) {
  584. if (j > 0)
  585. puts("\", \"");
  586. puts(data);
  587. j += strlen(data) + 1;
  588. data += strlen(data) + 1;
  589. }
  590. puts("\"");
  591. return;
  592. }
  593. if ((len %4) == 0) {
  594. const u32 *p;
  595. printf("<");
  596. for (j = 0, p = data; j < len/4; j ++)
  597. printf("0x%x%s", p[j], j < (len/4 - 1) ? " " : "");
  598. printf(">");
  599. } else { /* anything else... hexdump */
  600. const u8 *s;
  601. printf("[");
  602. for (j = 0, s = data; j < len; j++)
  603. printf("%02x%s", s[j], j < len - 1 ? " " : "");
  604. printf("]");
  605. }
  606. }
  607. /****************************************************************************/
  608. /*
  609. * Recursively print (a portion of) the working_fdt. The depth parameter
  610. * determines how deeply nested the fdt is printed.
  611. */
  612. static int fdt_print(const char *pathp, char *prop, int depth)
  613. {
  614. static char tabs[MAX_LEVEL+1] =
  615. "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
  616. "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  617. const void *nodep; /* property node pointer */
  618. int nodeoffset; /* node offset from libfdt */
  619. int nextoffset; /* next node offset from libfdt */
  620. uint32_t tag; /* tag */
  621. int len; /* length of the property */
  622. int level = 0; /* keep track of nesting level */
  623. const struct fdt_property *fdt_prop;
  624. nodeoffset = fdt_path_offset (working_fdt, pathp);
  625. if (nodeoffset < 0) {
  626. /*
  627. * Not found or something else bad happened.
  628. */
  629. printf ("libfdt fdt_path_offset() returned %s\n",
  630. fdt_strerror(nodeoffset));
  631. return 1;
  632. }
  633. /*
  634. * The user passed in a property as well as node path.
  635. * Print only the given property and then return.
  636. */
  637. if (prop) {
  638. nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len);
  639. if (len == 0) {
  640. /* no property value */
  641. printf("%s %s\n", pathp, prop);
  642. return 0;
  643. } else if (len > 0) {
  644. printf("%s = ", prop);
  645. print_data (nodep, len);
  646. printf("\n");
  647. return 0;
  648. } else {
  649. printf ("libfdt fdt_getprop(): %s\n",
  650. fdt_strerror(len));
  651. return 1;
  652. }
  653. }
  654. /*
  655. * The user passed in a node path and no property,
  656. * print the node and all subnodes.
  657. */
  658. while(level >= 0) {
  659. tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset);
  660. switch(tag) {
  661. case FDT_BEGIN_NODE:
  662. pathp = fdt_get_name(working_fdt, nodeoffset, NULL);
  663. if (level <= depth) {
  664. if (pathp == NULL)
  665. pathp = "/* NULL pointer error */";
  666. if (*pathp == '\0')
  667. pathp = "/"; /* root is nameless */
  668. printf("%s%s {\n",
  669. &tabs[MAX_LEVEL - level], pathp);
  670. }
  671. level++;
  672. if (level >= MAX_LEVEL) {
  673. printf("Nested too deep, aborting.\n");
  674. return 1;
  675. }
  676. break;
  677. case FDT_END_NODE:
  678. level--;
  679. if (level <= depth)
  680. printf("%s};\n", &tabs[MAX_LEVEL - level]);
  681. if (level == 0) {
  682. level = -1; /* exit the loop */
  683. }
  684. break;
  685. case FDT_PROP:
  686. fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset,
  687. sizeof(*fdt_prop));
  688. pathp = fdt_string(working_fdt,
  689. fdt32_to_cpu(fdt_prop->nameoff));
  690. len = fdt32_to_cpu(fdt_prop->len);
  691. nodep = fdt_prop->data;
  692. if (len < 0) {
  693. printf ("libfdt fdt_getprop(): %s\n",
  694. fdt_strerror(len));
  695. return 1;
  696. } else if (len == 0) {
  697. /* the property has no value */
  698. if (level <= depth)
  699. printf("%s%s;\n",
  700. &tabs[MAX_LEVEL - level],
  701. pathp);
  702. } else {
  703. if (level <= depth) {
  704. printf("%s%s = ",
  705. &tabs[MAX_LEVEL - level],
  706. pathp);
  707. print_data (nodep, len);
  708. printf(";\n");
  709. }
  710. }
  711. break;
  712. case FDT_NOP:
  713. printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]);
  714. break;
  715. case FDT_END:
  716. return 1;
  717. default:
  718. if (level <= depth)
  719. printf("Unknown tag 0x%08X\n", tag);
  720. return 1;
  721. }
  722. nodeoffset = nextoffset;
  723. }
  724. return 0;
  725. }
  726. /********************************************************************/
  727. U_BOOT_CMD(
  728. fdt, 255, 0, do_fdt,
  729. "fdt - flattened device tree utility commands\n",
  730. "addr <addr> [<length>] - Set the fdt location to <addr>\n"
  731. #ifdef CONFIG_OF_BOARD_SETUP
  732. "fdt boardsetup - Do board-specific set up\n"
  733. #endif
  734. "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n"
  735. "fdt print <path> [<prop>] - Recursive print starting at <path>\n"
  736. "fdt list <path> [<prop>] - Print one level starting at <path>\n"
  737. "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n"
  738. "fdt mknode <path> <node> - Create a new node after <path>\n"
  739. "fdt rm <path> [<prop>] - Delete the node or <property>\n"
  740. "fdt header - Display header info\n"
  741. "fdt bootcpu <id> - Set boot cpuid\n"
  742. "fdt memory <addr> <size> - Add/Update memory node\n"
  743. "fdt rsvmem print - Show current mem reserves\n"
  744. "fdt rsvmem add <addr> <size> - Add a mem reserve\n"
  745. "fdt rsvmem delete <index> - Delete a mem reserves\n"
  746. "fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n"
  747. " <start>/<end> - initrd start/end addr\n"
  748. "NOTE: Dereference aliases by omiting the leading '/', "
  749. "e.g. fdt print ethernet0.\n"
  750. );