fdt.c 27 KB

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