fdt.c 28 KB

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