cmd_fdt.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  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 <libfdt.h>
  32. #include <fdt_support.h>
  33. #define MAX_LEVEL 32 /* how deeply nested we will go */
  34. #define SCRATCHPAD 1024 /* bytes of scratchpad memory */
  35. #ifndef CONFIG_CMD_FDT_MAX_DUMP
  36. #define CONFIG_CMD_FDT_MAX_DUMP 64
  37. #endif
  38. /*
  39. * Global data (for the gd->bd)
  40. */
  41. DECLARE_GLOBAL_DATA_PTR;
  42. static int fdt_valid(void);
  43. static int fdt_parse_prop(char *const*newval, int count, char *data, int *len);
  44. static int fdt_print(const char *pathp, char *prop, int depth);
  45. static int is_printable_string(const void *data, int len);
  46. /*
  47. * The working_fdt points to our working flattened device tree.
  48. */
  49. struct fdt_header *working_fdt;
  50. void set_working_fdt_addr(void *addr)
  51. {
  52. working_fdt = addr;
  53. setenv_addr("fdtaddr", addr);
  54. }
  55. /*
  56. * Get a value from the fdt and format it to be set in the environment
  57. */
  58. static int fdt_value_setenv(const void *nodep, int len, const char *var)
  59. {
  60. if (is_printable_string(nodep, len))
  61. setenv(var, (void *)nodep);
  62. else if (len == 4) {
  63. char buf[11];
  64. sprintf(buf, "0x%08X", *(uint32_t *)nodep);
  65. setenv(var, buf);
  66. } else if (len%4 == 0 && len <= 20) {
  67. /* Needed to print things like sha1 hashes. */
  68. char buf[41];
  69. int i;
  70. for (i = 0; i < len; i += sizeof(unsigned int))
  71. sprintf(buf + (i * 2), "%08x",
  72. *(unsigned int *)(nodep + i));
  73. setenv(var, buf);
  74. } else {
  75. printf("error: unprintable value\n");
  76. return 1;
  77. }
  78. return 0;
  79. }
  80. /*
  81. * Flattened Device Tree command, see the help for parameter definitions.
  82. */
  83. static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  84. {
  85. if (argc < 2)
  86. return CMD_RET_USAGE;
  87. /*
  88. * Set the address of the fdt
  89. */
  90. if (argv[1][0] == 'a') {
  91. unsigned long addr;
  92. /*
  93. * Set the address [and length] of the fdt.
  94. */
  95. if (argc == 2) {
  96. if (!fdt_valid()) {
  97. return 1;
  98. }
  99. printf("The address of the fdt is %p\n", working_fdt);
  100. return 0;
  101. }
  102. addr = simple_strtoul(argv[2], NULL, 16);
  103. set_working_fdt_addr((void *)addr);
  104. if (!fdt_valid()) {
  105. return 1;
  106. }
  107. if (argc >= 4) {
  108. int len;
  109. int err;
  110. /*
  111. * Optional new length
  112. */
  113. len = simple_strtoul(argv[3], NULL, 16);
  114. if (len < fdt_totalsize(working_fdt)) {
  115. printf ("New length %d < existing length %d, "
  116. "ignoring.\n",
  117. len, fdt_totalsize(working_fdt));
  118. } else {
  119. /*
  120. * Open in place with a new length.
  121. */
  122. err = fdt_open_into(working_fdt, working_fdt, len);
  123. if (err != 0) {
  124. printf ("libfdt fdt_open_into(): %s\n",
  125. fdt_strerror(err));
  126. }
  127. }
  128. }
  129. return CMD_RET_SUCCESS;
  130. }
  131. if (!working_fdt) {
  132. puts(
  133. "No FDT memory address configured. Please configure\n"
  134. "the FDT address via \"fdt addr <address>\" command.\n"
  135. "Aborting!\n");
  136. return CMD_RET_FAILURE;
  137. }
  138. /*
  139. * Move the working_fdt
  140. */
  141. if (strncmp(argv[1], "mo", 2) == 0) {
  142. struct fdt_header *newaddr;
  143. int len;
  144. int err;
  145. if (argc < 4)
  146. return CMD_RET_USAGE;
  147. /*
  148. * Set the address and length of the fdt.
  149. */
  150. working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
  151. if (!fdt_valid()) {
  152. return 1;
  153. }
  154. newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16);
  155. /*
  156. * If the user specifies a length, use that. Otherwise use the
  157. * current length.
  158. */
  159. if (argc <= 4) {
  160. len = fdt_totalsize(working_fdt);
  161. } else {
  162. len = simple_strtoul(argv[4], NULL, 16);
  163. if (len < fdt_totalsize(working_fdt)) {
  164. printf ("New length 0x%X < existing length "
  165. "0x%X, aborting.\n",
  166. len, fdt_totalsize(working_fdt));
  167. return 1;
  168. }
  169. }
  170. /*
  171. * Copy to the new location.
  172. */
  173. err = fdt_open_into(working_fdt, newaddr, len);
  174. if (err != 0) {
  175. printf ("libfdt fdt_open_into(): %s\n",
  176. fdt_strerror(err));
  177. return 1;
  178. }
  179. working_fdt = newaddr;
  180. /*
  181. * Make a new node
  182. */
  183. } else if (strncmp(argv[1], "mk", 2) == 0) {
  184. char *pathp; /* path */
  185. char *nodep; /* new node to add */
  186. int nodeoffset; /* node offset from libfdt */
  187. int err;
  188. /*
  189. * Parameters: Node path, new node to be appended to the path.
  190. */
  191. if (argc < 4)
  192. return CMD_RET_USAGE;
  193. pathp = argv[2];
  194. nodep = argv[3];
  195. nodeoffset = fdt_path_offset (working_fdt, pathp);
  196. if (nodeoffset < 0) {
  197. /*
  198. * Not found or something else bad happened.
  199. */
  200. printf ("libfdt fdt_path_offset() returned %s\n",
  201. fdt_strerror(nodeoffset));
  202. return 1;
  203. }
  204. err = fdt_add_subnode(working_fdt, nodeoffset, nodep);
  205. if (err < 0) {
  206. printf ("libfdt fdt_add_subnode(): %s\n",
  207. fdt_strerror(err));
  208. return 1;
  209. }
  210. /*
  211. * Set the value of a property in the working_fdt.
  212. */
  213. } else if (argv[1][0] == 's') {
  214. char *pathp; /* path */
  215. char *prop; /* property */
  216. int nodeoffset; /* node offset from libfdt */
  217. static char data[SCRATCHPAD]; /* storage for the property */
  218. int len; /* new length of the property */
  219. int ret; /* return value */
  220. /*
  221. * Parameters: Node path, property, optional value.
  222. */
  223. if (argc < 4)
  224. return CMD_RET_USAGE;
  225. pathp = argv[2];
  226. prop = argv[3];
  227. if (argc == 4) {
  228. len = 0;
  229. } else {
  230. ret = fdt_parse_prop(&argv[4], argc - 4, data, &len);
  231. if (ret != 0)
  232. return ret;
  233. }
  234. nodeoffset = fdt_path_offset (working_fdt, pathp);
  235. if (nodeoffset < 0) {
  236. /*
  237. * Not found or something else bad happened.
  238. */
  239. printf ("libfdt fdt_path_offset() returned %s\n",
  240. fdt_strerror(nodeoffset));
  241. return 1;
  242. }
  243. ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len);
  244. if (ret < 0) {
  245. printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret));
  246. return 1;
  247. }
  248. /********************************************************************
  249. * Get the value of a property in the working_fdt.
  250. ********************************************************************/
  251. } else if (argv[1][0] == 'g') {
  252. char *subcmd; /* sub-command */
  253. char *pathp; /* path */
  254. char *prop; /* property */
  255. char *var; /* variable to store result */
  256. int nodeoffset; /* node offset from libfdt */
  257. const void *nodep; /* property node pointer */
  258. int len = 0; /* new length of the property */
  259. /*
  260. * Parameters: Node path, property, optional value.
  261. */
  262. if (argc < 5)
  263. return CMD_RET_USAGE;
  264. subcmd = argv[2];
  265. if (argc < 6 && subcmd[0] != 's')
  266. return CMD_RET_USAGE;
  267. var = argv[3];
  268. pathp = argv[4];
  269. prop = argv[5];
  270. nodeoffset = fdt_path_offset(working_fdt, pathp);
  271. if (nodeoffset < 0) {
  272. /*
  273. * Not found or something else bad happened.
  274. */
  275. printf("libfdt fdt_path_offset() returned %s\n",
  276. fdt_strerror(nodeoffset));
  277. return 1;
  278. }
  279. if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) {
  280. int reqIndex = -1;
  281. int startDepth = fdt_node_depth(
  282. working_fdt, nodeoffset);
  283. int curDepth = startDepth;
  284. int curIndex = -1;
  285. int nextNodeOffset = fdt_next_node(
  286. working_fdt, nodeoffset, &curDepth);
  287. if (subcmd[0] == 'n')
  288. reqIndex = simple_strtoul(argv[5], NULL, 16);
  289. while (curDepth > startDepth) {
  290. if (curDepth == startDepth + 1)
  291. curIndex++;
  292. if (subcmd[0] == 'n' && curIndex == reqIndex) {
  293. const char *nodeName = fdt_get_name(
  294. working_fdt, nextNodeOffset, NULL);
  295. setenv(var, (char *)nodeName);
  296. return 0;
  297. }
  298. nextNodeOffset = fdt_next_node(
  299. working_fdt, nextNodeOffset, &curDepth);
  300. if (nextNodeOffset < 0)
  301. break;
  302. }
  303. if (subcmd[0] == 's') {
  304. /* get the num nodes at this level */
  305. setenv_ulong(var, curIndex + 1);
  306. } else {
  307. /* node index not found */
  308. printf("libfdt node not found\n");
  309. return 1;
  310. }
  311. } else {
  312. nodep = fdt_getprop(
  313. working_fdt, nodeoffset, prop, &len);
  314. if (len == 0) {
  315. /* no property value */
  316. setenv(var, "");
  317. return 0;
  318. } else if (len > 0) {
  319. if (subcmd[0] == 'v') {
  320. int ret;
  321. ret = fdt_value_setenv(nodep, len, var);
  322. if (ret != 0)
  323. return ret;
  324. } else if (subcmd[0] == 'a') {
  325. /* Get address */
  326. char buf[11];
  327. sprintf(buf, "0x%p", nodep);
  328. setenv(var, buf);
  329. } else if (subcmd[0] == 's') {
  330. /* Get size */
  331. char buf[11];
  332. sprintf(buf, "0x%08X", len);
  333. setenv(var, buf);
  334. } else
  335. return CMD_RET_USAGE;
  336. return 0;
  337. } else {
  338. printf("libfdt fdt_getprop(): %s\n",
  339. fdt_strerror(len));
  340. return 1;
  341. }
  342. }
  343. /*
  344. * Print (recursive) / List (single level)
  345. */
  346. } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) {
  347. int depth = MAX_LEVEL; /* how deep to print */
  348. char *pathp; /* path */
  349. char *prop; /* property */
  350. int ret; /* return value */
  351. static char root[2] = "/";
  352. /*
  353. * list is an alias for print, but limited to 1 level
  354. */
  355. if (argv[1][0] == 'l') {
  356. depth = 1;
  357. }
  358. /*
  359. * Get the starting path. The root node is an oddball,
  360. * the offset is zero and has no name.
  361. */
  362. if (argc == 2)
  363. pathp = root;
  364. else
  365. pathp = argv[2];
  366. if (argc > 3)
  367. prop = argv[3];
  368. else
  369. prop = NULL;
  370. ret = fdt_print(pathp, prop, depth);
  371. if (ret != 0)
  372. return ret;
  373. /*
  374. * Remove a property/node
  375. */
  376. } else if (strncmp(argv[1], "rm", 2) == 0) {
  377. int nodeoffset; /* node offset from libfdt */
  378. int err;
  379. /*
  380. * Get the path. The root node is an oddball, the offset
  381. * is zero and has no name.
  382. */
  383. nodeoffset = fdt_path_offset (working_fdt, argv[2]);
  384. if (nodeoffset < 0) {
  385. /*
  386. * Not found or something else bad happened.
  387. */
  388. printf ("libfdt fdt_path_offset() returned %s\n",
  389. fdt_strerror(nodeoffset));
  390. return 1;
  391. }
  392. /*
  393. * Do the delete. A fourth parameter means delete a property,
  394. * otherwise delete the node.
  395. */
  396. if (argc > 3) {
  397. err = fdt_delprop(working_fdt, nodeoffset, argv[3]);
  398. if (err < 0) {
  399. printf("libfdt fdt_delprop(): %s\n",
  400. fdt_strerror(err));
  401. return err;
  402. }
  403. } else {
  404. err = fdt_del_node(working_fdt, nodeoffset);
  405. if (err < 0) {
  406. printf("libfdt fdt_del_node(): %s\n",
  407. fdt_strerror(err));
  408. return err;
  409. }
  410. }
  411. /*
  412. * Display header info
  413. */
  414. } else if (argv[1][0] == 'h') {
  415. u32 version = fdt_version(working_fdt);
  416. printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt));
  417. printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt),
  418. fdt_totalsize(working_fdt));
  419. printf("off_dt_struct:\t\t0x%x\n",
  420. fdt_off_dt_struct(working_fdt));
  421. printf("off_dt_strings:\t\t0x%x\n",
  422. fdt_off_dt_strings(working_fdt));
  423. printf("off_mem_rsvmap:\t\t0x%x\n",
  424. fdt_off_mem_rsvmap(working_fdt));
  425. printf("version:\t\t%d\n", version);
  426. printf("last_comp_version:\t%d\n",
  427. fdt_last_comp_version(working_fdt));
  428. if (version >= 2)
  429. printf("boot_cpuid_phys:\t0x%x\n",
  430. fdt_boot_cpuid_phys(working_fdt));
  431. if (version >= 3)
  432. printf("size_dt_strings:\t0x%x\n",
  433. fdt_size_dt_strings(working_fdt));
  434. if (version >= 17)
  435. printf("size_dt_struct:\t\t0x%x\n",
  436. fdt_size_dt_struct(working_fdt));
  437. printf("number mem_rsv:\t\t0x%x\n",
  438. fdt_num_mem_rsv(working_fdt));
  439. printf("\n");
  440. /*
  441. * Set boot cpu id
  442. */
  443. } else if (strncmp(argv[1], "boo", 3) == 0) {
  444. unsigned long tmp = simple_strtoul(argv[2], NULL, 16);
  445. fdt_set_boot_cpuid_phys(working_fdt, tmp);
  446. /*
  447. * memory command
  448. */
  449. } else if (strncmp(argv[1], "me", 2) == 0) {
  450. uint64_t addr, size;
  451. int err;
  452. addr = simple_strtoull(argv[2], NULL, 16);
  453. size = simple_strtoull(argv[3], NULL, 16);
  454. err = fdt_fixup_memory(working_fdt, addr, size);
  455. if (err < 0)
  456. return err;
  457. /*
  458. * mem reserve commands
  459. */
  460. } else if (strncmp(argv[1], "rs", 2) == 0) {
  461. if (argv[2][0] == 'p') {
  462. uint64_t addr, size;
  463. int total = fdt_num_mem_rsv(working_fdt);
  464. int j, err;
  465. printf("index\t\t start\t\t size\n");
  466. printf("-------------------------------"
  467. "-----------------\n");
  468. for (j = 0; j < total; j++) {
  469. err = fdt_get_mem_rsv(working_fdt, j, &addr, &size);
  470. if (err < 0) {
  471. printf("libfdt fdt_get_mem_rsv(): %s\n",
  472. fdt_strerror(err));
  473. return err;
  474. }
  475. printf(" %x\t%08x%08x\t%08x%08x\n", j,
  476. (u32)(addr >> 32),
  477. (u32)(addr & 0xffffffff),
  478. (u32)(size >> 32),
  479. (u32)(size & 0xffffffff));
  480. }
  481. } else if (argv[2][0] == 'a') {
  482. uint64_t addr, size;
  483. int err;
  484. addr = simple_strtoull(argv[3], NULL, 16);
  485. size = simple_strtoull(argv[4], NULL, 16);
  486. err = fdt_add_mem_rsv(working_fdt, addr, size);
  487. if (err < 0) {
  488. printf("libfdt fdt_add_mem_rsv(): %s\n",
  489. fdt_strerror(err));
  490. return err;
  491. }
  492. } else if (argv[2][0] == 'd') {
  493. unsigned long idx = simple_strtoul(argv[3], NULL, 16);
  494. int err = fdt_del_mem_rsv(working_fdt, idx);
  495. if (err < 0) {
  496. printf("libfdt fdt_del_mem_rsv(): %s\n",
  497. fdt_strerror(err));
  498. return err;
  499. }
  500. } else {
  501. /* Unrecognized command */
  502. return CMD_RET_USAGE;
  503. }
  504. }
  505. #ifdef CONFIG_OF_BOARD_SETUP
  506. /* Call the board-specific fixup routine */
  507. else if (strncmp(argv[1], "boa", 3) == 0)
  508. ft_board_setup(working_fdt, gd->bd);
  509. #endif
  510. /* Create a chosen node */
  511. else if (argv[1][0] == 'c') {
  512. unsigned long initrd_start = 0, initrd_end = 0;
  513. if ((argc != 2) && (argc != 4))
  514. return CMD_RET_USAGE;
  515. if (argc == 4) {
  516. initrd_start = simple_strtoul(argv[2], NULL, 16);
  517. initrd_end = simple_strtoul(argv[3], NULL, 16);
  518. }
  519. fdt_chosen(working_fdt, 1);
  520. fdt_initrd(working_fdt, initrd_start, initrd_end, 1);
  521. }
  522. /* resize the fdt */
  523. else if (strncmp(argv[1], "re", 2) == 0) {
  524. fdt_resize(working_fdt);
  525. }
  526. else {
  527. /* Unrecognized command */
  528. return CMD_RET_USAGE;
  529. }
  530. return 0;
  531. }
  532. /****************************************************************************/
  533. static int fdt_valid(void)
  534. {
  535. int err;
  536. if (working_fdt == NULL) {
  537. printf ("The address of the fdt is invalid (NULL).\n");
  538. return 0;
  539. }
  540. err = fdt_check_header(working_fdt);
  541. if (err == 0)
  542. return 1; /* valid */
  543. if (err < 0) {
  544. printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
  545. /*
  546. * Be more informative on bad version.
  547. */
  548. if (err == -FDT_ERR_BADVERSION) {
  549. if (fdt_version(working_fdt) <
  550. FDT_FIRST_SUPPORTED_VERSION) {
  551. printf (" - too old, fdt %d < %d",
  552. fdt_version(working_fdt),
  553. FDT_FIRST_SUPPORTED_VERSION);
  554. working_fdt = NULL;
  555. }
  556. if (fdt_last_comp_version(working_fdt) >
  557. FDT_LAST_SUPPORTED_VERSION) {
  558. printf (" - too new, fdt %d > %d",
  559. fdt_version(working_fdt),
  560. FDT_LAST_SUPPORTED_VERSION);
  561. working_fdt = NULL;
  562. }
  563. return 0;
  564. }
  565. printf("\n");
  566. return 0;
  567. }
  568. return 1;
  569. }
  570. /****************************************************************************/
  571. /*
  572. * Parse the user's input, partially heuristic. Valid formats:
  573. * <0x00112233 4 05> - an array of cells. Numbers follow standard
  574. * C conventions.
  575. * [00 11 22 .. nn] - byte stream
  576. * "string" - If the the value doesn't start with "<" or "[", it is
  577. * treated as a string. Note that the quotes are
  578. * stripped by the parser before we get the string.
  579. * newval: An array of strings containing the new property as specified
  580. * on the command line
  581. * count: The number of strings in the array
  582. * data: A bytestream to be placed in the property
  583. * len: The length of the resulting bytestream
  584. */
  585. static int fdt_parse_prop(char * const *newval, int count, char *data, int *len)
  586. {
  587. char *cp; /* temporary char pointer */
  588. char *newp; /* temporary newval char pointer */
  589. unsigned long tmp; /* holds converted values */
  590. int stridx = 0;
  591. *len = 0;
  592. newp = newval[0];
  593. /* An array of cells */
  594. if (*newp == '<') {
  595. newp++;
  596. while ((*newp != '>') && (stridx < count)) {
  597. /*
  598. * Keep searching until we find that last ">"
  599. * That way users don't have to escape the spaces
  600. */
  601. if (*newp == '\0') {
  602. newp = newval[++stridx];
  603. continue;
  604. }
  605. cp = newp;
  606. tmp = simple_strtoul(cp, &newp, 0);
  607. *(__be32 *)data = __cpu_to_be32(tmp);
  608. data += 4;
  609. *len += 4;
  610. /* If the ptr didn't advance, something went wrong */
  611. if ((newp - cp) <= 0) {
  612. printf("Sorry, I could not convert \"%s\"\n",
  613. cp);
  614. return 1;
  615. }
  616. while (*newp == ' ')
  617. newp++;
  618. }
  619. if (*newp != '>') {
  620. printf("Unexpected character '%c'\n", *newp);
  621. return 1;
  622. }
  623. } else if (*newp == '[') {
  624. /*
  625. * Byte stream. Convert the values.
  626. */
  627. newp++;
  628. while ((stridx < count) && (*newp != ']')) {
  629. while (*newp == ' ')
  630. newp++;
  631. if (*newp == '\0') {
  632. newp = newval[++stridx];
  633. continue;
  634. }
  635. if (!isxdigit(*newp))
  636. break;
  637. tmp = simple_strtoul(newp, &newp, 16);
  638. *data++ = tmp & 0xFF;
  639. *len = *len + 1;
  640. }
  641. if (*newp != ']') {
  642. printf("Unexpected character '%c'\n", *newp);
  643. return 1;
  644. }
  645. } else {
  646. /*
  647. * Assume it is one or more strings. Copy it into our
  648. * data area for convenience (including the
  649. * terminating '\0's).
  650. */
  651. while (stridx < count) {
  652. size_t length = strlen(newp) + 1;
  653. strcpy(data, newp);
  654. data += length;
  655. *len += length;
  656. newp = newval[++stridx];
  657. }
  658. }
  659. return 0;
  660. }
  661. /****************************************************************************/
  662. /*
  663. * Heuristic to guess if this is a string or concatenated strings.
  664. */
  665. static int is_printable_string(const void *data, int len)
  666. {
  667. const char *s = data;
  668. /* zero length is not */
  669. if (len == 0)
  670. return 0;
  671. /* must terminate with zero or '\n' */
  672. if (s[len - 1] != '\0' && s[len - 1] != '\n')
  673. return 0;
  674. /* printable or a null byte (concatenated strings) */
  675. while (((*s == '\0') || isprint(*s) || isspace(*s)) && (len > 0)) {
  676. /*
  677. * If we see a null, there are three possibilities:
  678. * 1) If len == 1, it is the end of the string, printable
  679. * 2) Next character also a null, not printable.
  680. * 3) Next character not a null, continue to check.
  681. */
  682. if (s[0] == '\0') {
  683. if (len == 1)
  684. return 1;
  685. if (s[1] == '\0')
  686. return 0;
  687. }
  688. s++;
  689. len--;
  690. }
  691. /* Not the null termination, or not done yet: not printable */
  692. if (*s != '\0' || (len != 0))
  693. return 0;
  694. return 1;
  695. }
  696. /*
  697. * Print the property in the best format, a heuristic guess. Print as
  698. * a string, concatenated strings, a byte, word, double word, or (if all
  699. * else fails) it is printed as a stream of bytes.
  700. */
  701. static void print_data(const void *data, int len)
  702. {
  703. int j;
  704. /* no data, don't print */
  705. if (len == 0)
  706. return;
  707. /*
  708. * It is a string, but it may have multiple strings (embedded '\0's).
  709. */
  710. if (is_printable_string(data, len)) {
  711. puts("\"");
  712. j = 0;
  713. while (j < len) {
  714. if (j > 0)
  715. puts("\", \"");
  716. puts(data);
  717. j += strlen(data) + 1;
  718. data += strlen(data) + 1;
  719. }
  720. puts("\"");
  721. return;
  722. }
  723. if ((len %4) == 0) {
  724. if (len > CONFIG_CMD_FDT_MAX_DUMP)
  725. printf("* 0x%p [0x%08x]", data, len);
  726. else {
  727. const __be32 *p;
  728. printf("<");
  729. for (j = 0, p = data; j < len/4; j++)
  730. printf("0x%08x%s", fdt32_to_cpu(p[j]),
  731. j < (len/4 - 1) ? " " : "");
  732. printf(">");
  733. }
  734. } else { /* anything else... hexdump */
  735. if (len > CONFIG_CMD_FDT_MAX_DUMP)
  736. printf("* 0x%p [0x%08x]", data, len);
  737. else {
  738. const u8 *s;
  739. printf("[");
  740. for (j = 0, s = data; j < len; j++)
  741. printf("%02x%s", s[j], j < len - 1 ? " " : "");
  742. printf("]");
  743. }
  744. }
  745. }
  746. /****************************************************************************/
  747. /*
  748. * Recursively print (a portion of) the working_fdt. The depth parameter
  749. * determines how deeply nested the fdt is printed.
  750. */
  751. static int fdt_print(const char *pathp, char *prop, int depth)
  752. {
  753. static char tabs[MAX_LEVEL+1] =
  754. "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
  755. "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  756. const void *nodep; /* property node pointer */
  757. int nodeoffset; /* node offset from libfdt */
  758. int nextoffset; /* next node offset from libfdt */
  759. uint32_t tag; /* tag */
  760. int len; /* length of the property */
  761. int level = 0; /* keep track of nesting level */
  762. const struct fdt_property *fdt_prop;
  763. nodeoffset = fdt_path_offset (working_fdt, pathp);
  764. if (nodeoffset < 0) {
  765. /*
  766. * Not found or something else bad happened.
  767. */
  768. printf ("libfdt fdt_path_offset() returned %s\n",
  769. fdt_strerror(nodeoffset));
  770. return 1;
  771. }
  772. /*
  773. * The user passed in a property as well as node path.
  774. * Print only the given property and then return.
  775. */
  776. if (prop) {
  777. nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len);
  778. if (len == 0) {
  779. /* no property value */
  780. printf("%s %s\n", pathp, prop);
  781. return 0;
  782. } else if (len > 0) {
  783. printf("%s = ", prop);
  784. print_data (nodep, len);
  785. printf("\n");
  786. return 0;
  787. } else {
  788. printf ("libfdt fdt_getprop(): %s\n",
  789. fdt_strerror(len));
  790. return 1;
  791. }
  792. }
  793. /*
  794. * The user passed in a node path and no property,
  795. * print the node and all subnodes.
  796. */
  797. while(level >= 0) {
  798. tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset);
  799. switch(tag) {
  800. case FDT_BEGIN_NODE:
  801. pathp = fdt_get_name(working_fdt, nodeoffset, NULL);
  802. if (level <= depth) {
  803. if (pathp == NULL)
  804. pathp = "/* NULL pointer error */";
  805. if (*pathp == '\0')
  806. pathp = "/"; /* root is nameless */
  807. printf("%s%s {\n",
  808. &tabs[MAX_LEVEL - level], pathp);
  809. }
  810. level++;
  811. if (level >= MAX_LEVEL) {
  812. printf("Nested too deep, aborting.\n");
  813. return 1;
  814. }
  815. break;
  816. case FDT_END_NODE:
  817. level--;
  818. if (level <= depth)
  819. printf("%s};\n", &tabs[MAX_LEVEL - level]);
  820. if (level == 0) {
  821. level = -1; /* exit the loop */
  822. }
  823. break;
  824. case FDT_PROP:
  825. fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset,
  826. sizeof(*fdt_prop));
  827. pathp = fdt_string(working_fdt,
  828. fdt32_to_cpu(fdt_prop->nameoff));
  829. len = fdt32_to_cpu(fdt_prop->len);
  830. nodep = fdt_prop->data;
  831. if (len < 0) {
  832. printf ("libfdt fdt_getprop(): %s\n",
  833. fdt_strerror(len));
  834. return 1;
  835. } else if (len == 0) {
  836. /* the property has no value */
  837. if (level <= depth)
  838. printf("%s%s;\n",
  839. &tabs[MAX_LEVEL - level],
  840. pathp);
  841. } else {
  842. if (level <= depth) {
  843. printf("%s%s = ",
  844. &tabs[MAX_LEVEL - level],
  845. pathp);
  846. print_data (nodep, len);
  847. printf(";\n");
  848. }
  849. }
  850. break;
  851. case FDT_NOP:
  852. printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]);
  853. break;
  854. case FDT_END:
  855. return 1;
  856. default:
  857. if (level <= depth)
  858. printf("Unknown tag 0x%08X\n", tag);
  859. return 1;
  860. }
  861. nodeoffset = nextoffset;
  862. }
  863. return 0;
  864. }
  865. /********************************************************************/
  866. #ifdef CONFIG_SYS_LONGHELP
  867. static char fdt_help_text[] =
  868. "addr <addr> [<length>] - Set the fdt location to <addr>\n"
  869. #ifdef CONFIG_OF_BOARD_SETUP
  870. "fdt boardsetup - Do board-specific set up\n"
  871. #endif
  872. "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n"
  873. "fdt resize - Resize fdt to size + padding to 4k addr\n"
  874. "fdt print <path> [<prop>] - Recursive print starting at <path>\n"
  875. "fdt list <path> [<prop>] - Print one level starting at <path>\n"
  876. "fdt get value <var> <path> <prop> - Get <property> and store in <var>\n"
  877. "fdt get name <var> <path> <index> - Get name of node <index> and store in <var>\n"
  878. "fdt get addr <var> <path> <prop> - Get start address of <property> and store in <var>\n"
  879. "fdt get size <var> <path> [<prop>] - Get size of [<property>] or num nodes and store in <var>\n"
  880. "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n"
  881. "fdt mknode <path> <node> - Create a new node after <path>\n"
  882. "fdt rm <path> [<prop>] - Delete the node or <property>\n"
  883. "fdt header - Display header info\n"
  884. "fdt bootcpu <id> - Set boot cpuid\n"
  885. "fdt memory <addr> <size> - Add/Update memory node\n"
  886. "fdt rsvmem print - Show current mem reserves\n"
  887. "fdt rsvmem add <addr> <size> - Add a mem reserve\n"
  888. "fdt rsvmem delete <index> - Delete a mem reserves\n"
  889. "fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n"
  890. " <start>/<end> - initrd start/end addr\n"
  891. "NOTE: Dereference aliases by omiting the leading '/', "
  892. "e.g. fdt print ethernet0.";
  893. #endif
  894. U_BOOT_CMD(
  895. fdt, 255, 0, do_fdt,
  896. "flattened device tree utility commands", fdt_help_text
  897. );