cmd_fdt.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  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. #ifdef CONFIG_OF_LIBFDT
  31. #include <asm/global_data.h>
  32. #include <fdt.h>
  33. #include <libfdt.h>
  34. #include <fdt_support.h>
  35. #define MAX_LEVEL 32 /* how deeply nested we will go */
  36. #define SCRATCHPAD 1024 /* bytes of scratchpad memory */
  37. /*
  38. * Global data (for the gd->bd)
  39. */
  40. DECLARE_GLOBAL_DATA_PTR;
  41. /*
  42. * Function prototypes/declarations.
  43. */
  44. static int fdt_valid(void);
  45. static int fdt_parse_prop(char *pathp, char *prop, char *newval,
  46. char *data, int *len);
  47. static int fdt_print(char *pathp, char *prop, int depth);
  48. /*
  49. * Flattened Device Tree command, see the help for parameter definitions.
  50. */
  51. int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
  52. {
  53. if (argc < 2) {
  54. printf ("Usage:\n%s\n", cmdtp->usage);
  55. return 1;
  56. }
  57. /********************************************************************
  58. * Set the address of the fdt
  59. ********************************************************************/
  60. if (argv[1][0] == 'a') {
  61. /*
  62. * Set the address [and length] of the fdt.
  63. */
  64. fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
  65. if (!fdt_valid()) {
  66. return 1;
  67. }
  68. if (argc >= 4) {
  69. int len;
  70. int err;
  71. /*
  72. * Optional new length
  73. */
  74. len = simple_strtoul(argv[3], NULL, 16);
  75. if (len < fdt_totalsize(fdt)) {
  76. printf ("New length %d < existing length %d, "
  77. "ignoring.\n",
  78. len, fdt_totalsize(fdt));
  79. } else {
  80. /*
  81. * Open in place with a new length.
  82. */
  83. err = fdt_open_into(fdt, fdt, len);
  84. if (err != 0) {
  85. printf ("libfdt fdt_open_into(): %s\n",
  86. fdt_strerror(err));
  87. }
  88. }
  89. }
  90. /********************************************************************
  91. * Move the fdt
  92. ********************************************************************/
  93. } else if ((argv[1][0] == 'm') && (argv[1][1] == 'o')) {
  94. struct fdt_header *newaddr;
  95. int len;
  96. int err;
  97. if (argc < 4) {
  98. printf ("Usage:\n%s\n", cmdtp->usage);
  99. return 1;
  100. }
  101. /*
  102. * Set the address and length of the fdt.
  103. */
  104. fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
  105. if (!fdt_valid()) {
  106. return 1;
  107. }
  108. newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16);
  109. /*
  110. * If the user specifies a length, use that. Otherwise use the
  111. * current length.
  112. */
  113. if (argc <= 4) {
  114. len = fdt_totalsize(fdt);
  115. } else {
  116. len = simple_strtoul(argv[4], NULL, 16);
  117. if (len < fdt_totalsize(fdt)) {
  118. printf ("New length 0x%X < existing length "
  119. "0x%X, aborting.\n",
  120. len, fdt_totalsize(fdt));
  121. return 1;
  122. }
  123. }
  124. /*
  125. * Copy to the new location.
  126. */
  127. err = fdt_open_into(fdt, newaddr, len);
  128. if (err != 0) {
  129. printf ("libfdt fdt_open_into(): %s\n",
  130. fdt_strerror(err));
  131. return 1;
  132. }
  133. fdt = newaddr;
  134. /********************************************************************
  135. * Make a new node
  136. ********************************************************************/
  137. } else if ((argv[1][0] == 'm') && (argv[1][1] == 'k')) {
  138. char *pathp; /* path */
  139. char *nodep; /* new node to add */
  140. int nodeoffset; /* node offset from libfdt */
  141. int err;
  142. /*
  143. * Parameters: Node path, new node to be appended to the path.
  144. */
  145. if (argc < 4) {
  146. printf ("Usage:\n%s\n", cmdtp->usage);
  147. return 1;
  148. }
  149. pathp = argv[2];
  150. nodep = argv[3];
  151. nodeoffset = fdt_find_node_by_path (fdt, pathp);
  152. if (nodeoffset < 0) {
  153. /*
  154. * Not found or something else bad happened.
  155. */
  156. printf ("libfdt fdt_find_node_by_path() returned %s\n",
  157. fdt_strerror(nodeoffset));
  158. return 1;
  159. }
  160. err = fdt_add_subnode(fdt, nodeoffset, nodep);
  161. if (err < 0) {
  162. printf ("libfdt fdt_add_subnode(): %s\n",
  163. fdt_strerror(err));
  164. return 1;
  165. }
  166. /********************************************************************
  167. * Set the value of a property in the fdt.
  168. ********************************************************************/
  169. } else if (argv[1][0] == 's') {
  170. char *pathp; /* path */
  171. char *prop; /* property */
  172. char *newval; /* value from the user (as a string) */
  173. int nodeoffset; /* node offset from libfdt */
  174. static char data[SCRATCHPAD]; /* storage for the property */
  175. int len; /* new length of the property */
  176. int ret; /* return value */
  177. /*
  178. * Parameters: Node path, property, value.
  179. */
  180. if (argc < 5) {
  181. printf ("Usage:\n%s\n", cmdtp->usage);
  182. return 1;
  183. }
  184. pathp = argv[2];
  185. prop = argv[3];
  186. newval = argv[4];
  187. nodeoffset = fdt_find_node_by_path (fdt, pathp);
  188. if (nodeoffset < 0) {
  189. /*
  190. * Not found or something else bad happened.
  191. */
  192. printf ("libfdt fdt_find_node_by_path() returned %s\n",
  193. fdt_strerror(nodeoffset));
  194. return 1;
  195. }
  196. ret = fdt_parse_prop(pathp, prop, newval, data, &len);
  197. if (ret != 0)
  198. return ret;
  199. ret = fdt_setprop(fdt, nodeoffset, prop, data, len);
  200. if (ret < 0) {
  201. printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret));
  202. return 1;
  203. }
  204. /********************************************************************
  205. * Print (recursive) / List (single level)
  206. ********************************************************************/
  207. } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) {
  208. int depth = MAX_LEVEL; /* how deep to print */
  209. char *pathp; /* path */
  210. char *prop; /* property */
  211. int ret; /* return value */
  212. /*
  213. * list is an alias for print, but limited to 1 level
  214. */
  215. if (argv[1][0] == 'l') {
  216. depth = 1;
  217. }
  218. /*
  219. * Get the starting path. The root node is an oddball,
  220. * the offset is zero and has no name.
  221. */
  222. pathp = argv[2];
  223. if (argc > 3)
  224. prop = argv[3];
  225. else
  226. prop = NULL;
  227. ret = fdt_print(pathp, prop, depth);
  228. if (ret != 0)
  229. return ret;
  230. /********************************************************************
  231. * Remove a property/node
  232. ********************************************************************/
  233. } else if (argv[1][0] == 'r') {
  234. int nodeoffset; /* node offset from libfdt */
  235. int err;
  236. /*
  237. * Get the path. The root node is an oddball, the offset
  238. * is zero and has no name.
  239. */
  240. nodeoffset = fdt_find_node_by_path (fdt, argv[2]);
  241. if (nodeoffset < 0) {
  242. /*
  243. * Not found or something else bad happened.
  244. */
  245. printf ("libfdt fdt_find_node_by_path() returned %s\n",
  246. fdt_strerror(nodeoffset));
  247. return 1;
  248. }
  249. /*
  250. * Do the delete. A fourth parameter means delete a property,
  251. * otherwise delete the node.
  252. */
  253. if (argc > 3) {
  254. err = fdt_delprop(fdt, nodeoffset, argv[3]);
  255. if (err < 0) {
  256. printf("libfdt fdt_delprop(): %s\n",
  257. fdt_strerror(err));
  258. return err;
  259. }
  260. } else {
  261. err = fdt_del_node(fdt, nodeoffset);
  262. if (err < 0) {
  263. printf("libfdt fdt_del_node(): %s\n",
  264. fdt_strerror(err));
  265. return err;
  266. }
  267. }
  268. /********************************************************************
  269. * Create a chosen node
  270. ********************************************************************/
  271. } else if (argv[1][0] == 'c') {
  272. fdt_chosen(fdt, 0, 0, 1);
  273. /********************************************************************
  274. * Create a u-boot-env node
  275. ********************************************************************/
  276. } else if (argv[1][0] == 'e') {
  277. fdt_env(fdt);
  278. /********************************************************************
  279. * Create a bd_t node
  280. ********************************************************************/
  281. } else if (argv[1][0] == 'b') {
  282. fdt_bd_t(fdt);
  283. /********************************************************************
  284. * Unrecognized command
  285. ********************************************************************/
  286. } else {
  287. printf ("Usage:\n%s\n", cmdtp->usage);
  288. return 1;
  289. }
  290. return 0;
  291. }
  292. /****************************************************************************/
  293. static int fdt_valid(void)
  294. {
  295. int err;
  296. if (fdt == NULL) {
  297. printf ("The address of the fdt is invalid (NULL).\n");
  298. return 0;
  299. }
  300. err = fdt_check_header(fdt);
  301. if (err == 0)
  302. return 1; /* valid */
  303. if (err < 0) {
  304. printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
  305. /*
  306. * Be more informative on bad version.
  307. */
  308. if (err == -FDT_ERR_BADVERSION) {
  309. if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) {
  310. printf (" - too old, fdt $d < %d",
  311. fdt_version(fdt),
  312. FDT_FIRST_SUPPORTED_VERSION);
  313. fdt = NULL;
  314. }
  315. if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) {
  316. printf (" - too new, fdt $d > %d",
  317. fdt_version(fdt),
  318. FDT_LAST_SUPPORTED_VERSION);
  319. fdt = NULL;
  320. }
  321. return 0;
  322. }
  323. printf("\n");
  324. return 0;
  325. }
  326. return 1;
  327. }
  328. /****************************************************************************/
  329. /*
  330. * Parse the user's input, partially heuristic. Valid formats:
  331. * <00> - hex byte
  332. * <0011> - hex half word (16 bits)
  333. * <00112233> - hex word (32 bits)
  334. * - hex double words (64 bits) are not supported, must use
  335. * a byte stream instead.
  336. * [00 11 22 .. nn] - byte stream
  337. * "string" - If the the value doesn't start with "<" or "[", it is
  338. * treated as a string. Note that the quotes are
  339. * stripped by the parser before we get the string.
  340. */
  341. static int fdt_parse_prop(char *pathp, char *prop, char *newval,
  342. char *data, int *len)
  343. {
  344. char *cp; /* temporary char pointer */
  345. unsigned long tmp; /* holds converted values */
  346. if (*newval == '<') {
  347. /*
  348. * Bigger values than bytes.
  349. */
  350. *len = 0;
  351. newval++;
  352. while ((*newval != '>') && (*newval != '\0')) {
  353. cp = newval;
  354. tmp = simple_strtoul(cp, &newval, 16);
  355. if ((newval - cp) <= 2) {
  356. *data = tmp & 0xFF;
  357. data += 1;
  358. *len += 1;
  359. } else if ((newval - cp) <= 4) {
  360. *(uint16_t *)data = __cpu_to_be16(tmp);
  361. data += 2;
  362. *len += 2;
  363. } else if ((newval - cp) <= 8) {
  364. *(uint32_t *)data = __cpu_to_be32(tmp);
  365. data += 4;
  366. *len += 4;
  367. } else {
  368. printf("Sorry, I could not convert \"%s\"\n",
  369. cp);
  370. return 1;
  371. }
  372. while (*newval == ' ')
  373. newval++;
  374. }
  375. if (*newval != '>') {
  376. printf("Unexpected character '%c'\n", *newval);
  377. return 1;
  378. }
  379. } else if (*newval == '[') {
  380. /*
  381. * Byte stream. Convert the values.
  382. */
  383. *len = 0;
  384. newval++;
  385. while ((*newval != ']') && (*newval != '\0')) {
  386. tmp = simple_strtoul(newval, &newval, 16);
  387. *data++ = tmp & 0xFF;
  388. *len++;
  389. while (*newval == ' ')
  390. newval++;
  391. }
  392. if (*newval != ']') {
  393. printf("Unexpected character '%c'\n", *newval);
  394. return 1;
  395. }
  396. } else {
  397. /*
  398. * Assume it is a string. Copy it into our data area for
  399. * convenience (including the terminating '\0').
  400. */
  401. *len = strlen(newval) + 1;
  402. strcpy(data, newval);
  403. }
  404. return 0;
  405. }
  406. /****************************************************************************/
  407. /*
  408. * Heuristic to guess if this is a string or concatenated strings.
  409. */
  410. static int is_printable_string(const void *data, int len)
  411. {
  412. const char *s = data;
  413. /* zero length is not */
  414. if (len == 0)
  415. return 0;
  416. /* must terminate with zero */
  417. if (s[len - 1] != '\0')
  418. return 0;
  419. /* printable or a null byte (concatenated strings) */
  420. while (((*s == '\0') || isprint(*s)) && (len > 0)) {
  421. /*
  422. * If we see a null, there are three possibilities:
  423. * 1) If len == 1, it is the end of the string, printable
  424. * 2) Next character also a null, not printable.
  425. * 3) Next character not a null, continue to check.
  426. */
  427. if (s[0] == '\0') {
  428. if (len == 1)
  429. return 1;
  430. if (s[1] == '\0')
  431. return 0;
  432. }
  433. s++;
  434. len--;
  435. }
  436. /* Not the null termination, or not done yet: not printable */
  437. if (*s != '\0' || (len != 0))
  438. return 0;
  439. return 1;
  440. }
  441. /*
  442. * Print the property in the best format, a heuristic guess. Print as
  443. * a string, concatenated strings, a byte, word, double word, or (if all
  444. * else fails) it is printed as a stream of bytes.
  445. */
  446. static void print_data(const void *data, int len)
  447. {
  448. int j;
  449. const u8 *s;
  450. /* no data, don't print */
  451. if (len == 0)
  452. return;
  453. /*
  454. * It is a string, but it may have multiple strings (embedded '\0's).
  455. */
  456. if (is_printable_string(data, len)) {
  457. puts("\"");
  458. j = 0;
  459. while (j < len) {
  460. if (j > 0)
  461. puts("\", \"");
  462. puts(data);
  463. j += strlen(data) + 1;
  464. data += strlen(data) + 1;
  465. }
  466. puts("\"");
  467. return;
  468. }
  469. switch (len) {
  470. case 1: /* byte */
  471. printf("<%02x>", (*(u8 *) data) & 0xff);
  472. break;
  473. case 2: /* half-word */
  474. printf("<%04x>", be16_to_cpu(*(u16 *) data) & 0xffff);
  475. break;
  476. case 4: /* word */
  477. printf("<%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
  478. break;
  479. case 8: /* double-word */
  480. #if __WORDSIZE == 64
  481. printf("<%016llx>", be64_to_cpu(*(uint64_t *) data));
  482. #else
  483. printf("<%08x ", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
  484. data += 4;
  485. printf("%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
  486. #endif
  487. break;
  488. default: /* anything else... hexdump */
  489. printf("[");
  490. for (j = 0, s = data; j < len; j++)
  491. printf("%02x%s", s[j], j < len - 1 ? " " : "");
  492. printf("]");
  493. break;
  494. }
  495. }
  496. /****************************************************************************/
  497. /*
  498. * Recursively print (a portion of) the fdt. The depth parameter
  499. * determines how deeply nested the fdt is printed.
  500. */
  501. static int fdt_print(char *pathp, char *prop, int depth)
  502. {
  503. static int offstack[MAX_LEVEL];
  504. static char tabs[MAX_LEVEL+1] =
  505. "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
  506. "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  507. void *nodep; /* property node pointer */
  508. int nodeoffset; /* node offset from libfdt */
  509. int nextoffset; /* next node offset from libfdt */
  510. uint32_t tag; /* tag */
  511. int len; /* length of the property */
  512. int level = 0; /* keep track of nesting level */
  513. nodeoffset = fdt_find_node_by_path (fdt, pathp);
  514. if (nodeoffset < 0) {
  515. /*
  516. * Not found or something else bad happened.
  517. */
  518. printf ("libfdt fdt_find_node_by_path() returned %s\n",
  519. fdt_strerror(nodeoffset));
  520. return 1;
  521. }
  522. /*
  523. * The user passed in a property as well as node path.
  524. * Print only the given property and then return.
  525. */
  526. if (prop) {
  527. nodep = fdt_getprop (fdt, nodeoffset, prop, &len);
  528. if (len == 0) {
  529. /* no property value */
  530. printf("%s %s\n", pathp, prop);
  531. return 0;
  532. } else if (len > 0) {
  533. printf("%s=", prop);
  534. print_data (nodep, len);
  535. printf("\n");
  536. return 0;
  537. } else {
  538. printf ("libfdt fdt_getprop(): %s\n",
  539. fdt_strerror(len));
  540. return 1;
  541. }
  542. }
  543. /*
  544. * The user passed in a node path and no property,
  545. * print the node and all subnodes.
  546. */
  547. offstack[0] = nodeoffset;
  548. while(level >= 0) {
  549. tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, &pathp);
  550. switch(tag) {
  551. case FDT_BEGIN_NODE:
  552. if(level <= depth)
  553. printf("%s%s {\n",
  554. &tabs[MAX_LEVEL - level], pathp);
  555. level++;
  556. offstack[level] = nodeoffset;
  557. if (level >= MAX_LEVEL) {
  558. printf("Aaaiii <splat> nested too deep. "
  559. "Aborting.\n");
  560. return 1;
  561. }
  562. break;
  563. case FDT_END_NODE:
  564. level--;
  565. if(level <= depth)
  566. printf("%s};\n", &tabs[MAX_LEVEL - level]);
  567. if (level == 0) {
  568. level = -1; /* exit the loop */
  569. }
  570. break;
  571. case FDT_PROP:
  572. nodep = fdt_getprop (fdt, offstack[level], pathp, &len);
  573. if (len < 0) {
  574. printf ("libfdt fdt_getprop(): %s\n",
  575. fdt_strerror(len));
  576. return 1;
  577. } else if (len == 0) {
  578. /* the property has no value */
  579. if(level <= depth)
  580. printf("%s%s;\n",
  581. &tabs[MAX_LEVEL - level],
  582. pathp);
  583. } else {
  584. if(level <= depth) {
  585. printf("%s%s=",
  586. &tabs[MAX_LEVEL - level],
  587. pathp);
  588. print_data (nodep, len);
  589. printf(";\n");
  590. }
  591. }
  592. break;
  593. case FDT_NOP:
  594. break;
  595. case FDT_END:
  596. return 1;
  597. default:
  598. if(level <= depth)
  599. printf("Unknown tag 0x%08X\n", tag);
  600. return 1;
  601. }
  602. nodeoffset = nextoffset;
  603. }
  604. return 0;
  605. }
  606. /********************************************************************/
  607. U_BOOT_CMD(
  608. fdt, 5, 0, do_fdt,
  609. "fdt - flattened device tree utility commands\n",
  610. "addr <addr> [<length>] - Set the fdt location to <addr>\n"
  611. "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr>\n"
  612. "fdt print <path> [<prop>] - Recursive print starting at <path>\n"
  613. "fdt list <path> [<prop>] - Print one level starting at <path>\n"
  614. "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n"
  615. "fdt mknode <path> <node> - Create a new node after <path>\n"
  616. "fdt rm <path> [<prop>] - Delete the node or <property>\n"
  617. "fdt chosen - Add/update the \"/chosen\" branch in the tree\n"
  618. #ifdef CONFIG_OF_HAS_UBOOT_ENV
  619. "fdt env - Add/replace the \"/u-boot-env\" branch in the tree\n"
  620. #endif
  621. #ifdef CONFIG_OF_HAS_BD_T
  622. "fdt bd_t - Add/replace the \"/bd_t\" branch in the tree\n"
  623. #endif
  624. "Hints:\n"
  625. " * If the property you are setting/printing has a '#' character,\n"
  626. " you MUST escape it with a \\ character or quote it with \" or\n"
  627. " it will be ignored as a comment.\n"
  628. " * If the value has spaces in it, you MUST escape the spaces with\n"
  629. " \\ characters or quote it with \"\"\n"
  630. "Examples: fdt print / # print the whole tree\n"
  631. " fdt print /cpus \"#address-cells\"\n"
  632. " fdt set /cpus \"#address-cells\" \"[00 00 00 01]\"\n"
  633. );
  634. #endif /* CONFIG_OF_LIBFDT */