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>
8 * See file CREDITS for list of people who contributed to this
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.
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.
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,
29 #include <linux/ctype.h>
30 #include <linux/types.h>
32 #ifdef CONFIG_OF_LIBFDT
33 #include <asm/global_data.h>
37 #define MAX_LEVEL 32 /* how deeply nested we will go */
38 #define SCRATCHPAD 1024 /* bytes of scratchpad memory */
41 * Global data (for the gd->bd)
43 DECLARE_GLOBAL_DATA_PTR;
48 static char data[SCRATCHPAD];
52 * Function prototypes/declarations.
54 static int fdt_valid(void);
55 static void print_data(const void *data, int len);
56 static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end);
57 static int fdt_env(void *fdt);
58 static int fdt_bd_t(void *fdt);
62 * Flattened Device Tree command, see the help for parameter definitions.
64 int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
69 printf ("Usage:\n%s\n", cmdtp->usage);
74 * Figure out which subcommand was given
77 /********************************************************************
78 * Set the address of the fdt
79 ********************************************************************/
82 * Set the address [and length] of the fdt.
84 fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
96 len = simple_strtoul(argv[3], NULL, 16);
97 if (len < fdt_totalsize(fdt)) {
98 printf ("New length %d < existing length %d, ignoring.\n",
99 len, fdt_totalsize(fdt));
102 * Open in place with a new length.
104 err = fdt_open_into(fdt, fdt, len);
106 printf ("libfdt: %s\n", fdt_strerror(err));
111 /********************************************************************
113 ********************************************************************/
114 } else if (op == 'm') {
115 struct fdt_header *newaddr;
120 printf ("Usage:\n%s\n", cmdtp->usage);
125 * Set the address and length of the fdt.
127 fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
132 newaddr = (struct fdt_header *)simple_strtoul(argv[3], NULL, 16);
133 len = simple_strtoul(argv[4], NULL, 16);
134 if (len < fdt_totalsize(fdt)) {
135 printf ("New length %d < existing length %d, aborting.\n",
136 len, fdt_totalsize(fdt));
141 * Copy to the new location.
143 err = fdt_open_into(fdt, newaddr, len);
145 printf ("libfdt: %s\n", fdt_strerror(err));
150 /********************************************************************
151 * Set the value of a node in the fdt.
152 ********************************************************************/
153 } else if (op == 's') {
154 char *pathp; /* path */
155 char *prop; /* property */
156 struct fdt_property *nodep; /* node struct pointer */
157 char *newval; /* value from the user (as a string) */
158 char *vp; /* temporary value pointer */
159 char *cp; /* temporary char pointer */
160 int nodeoffset; /* node offset from libfdt */
161 int len; /* new length of the property */
162 int oldlen; /* original length of the property */
163 unsigned long tmp; /* holds converted values */
164 int ret; /* return value */
167 * Parameters: Node path, property, value.
170 printf ("Usage:\n%s\n", cmdtp->usage);
178 if (strcmp(pathp, "/") == 0) {
181 nodeoffset = fdt_path_offset (fdt, pathp);
182 if (nodeoffset < 0) {
184 * Not found or something else bad happened.
186 printf ("libfdt: %s\n", fdt_strerror(nodeoffset));
190 nodep = fdt_getprop (fdt, nodeoffset, prop, &oldlen);
192 printf ("libfdt %s\n", fdt_strerror(oldlen));
194 } else if (oldlen == 0) {
196 * The specified property has no value
198 printf("%s has no value, cannot set one (yet).\n", prop);
202 * Convert the new property
205 if (*newval == '<') {
207 * Bigger values than bytes.
211 while ((*newval != '>') && (*newval != '\0')) {
213 tmp = simple_strtoul(cp, &newval, 16);
214 if ((newval - cp) <= 2) {
218 } else if ((newval - cp) <= 4) {
219 *(uint16_t *)vp = __cpu_to_be16(tmp);
222 } else if ((newval - cp) <= 8) {
223 *(uint32_t *)vp = __cpu_to_be32(tmp);
227 printf("Sorry, I could not convert \"%s\"\n", cp);
230 while (*newval == ' ')
233 if (*newval != '>') {
234 printf("Unexpected character '%c'\n", *newval);
237 } else if (*newval == '[') {
239 * Byte stream. Convert the values.
243 while ((*newval != ']') && (*newval != '\0')) {
244 tmp = simple_strtoul(newval, &newval, 16);
247 while (*newval == ' ')
250 if (*newval != ']') {
251 printf("Unexpected character '%c'\n", *newval);
256 * Assume it is a string. Copy it into our data area for
257 * convenience (including the terminating '\0').
259 len = strlen(newval) + 1;
260 strcpy(data, newval);
263 ret = fdt_setprop(fdt, nodeoffset, prop, data, len);
265 printf ("libfdt %s\n", fdt_strerror(ret));
270 /********************************************************************
271 * Print (recursive) / List (single level)
272 ********************************************************************/
273 } else if ((op == 'p') || (op == 'l')) {
275 * Recursively print (a portion of) the fdt.
277 static int offstack[MAX_LEVEL];
278 static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
279 int depth = MAX_LEVEL; /* how deep to print */
280 char *pathp; /* path */
281 char *prop; /* property */
282 void *nodep; /* property node pointer */
283 int nodeoffset; /* node offset from libfdt */
284 int nextoffset; /* next node offset from libfdt */
285 uint32_t tag; /* tag */
286 int len; /* length of the property */
287 int level = 0; /* keep track of nesting level */
290 * list is an alias for print, but limited to 1 level
297 * Get the starting path. The root node is an oddball,
298 * the offset is zero and has no name.
306 if (strcmp(pathp, "/") == 0) {
310 nodeoffset = fdt_path_offset (fdt, pathp);
311 if (nodeoffset < 0) {
313 * Not found or something else bad happened.
315 printf ("libfdt %s\n", fdt_strerror(nodeoffset));
320 * The user passed in a property as well as node path. Print only
321 * the given property and then return.
324 nodep = fdt_getprop (fdt, nodeoffset, prop, &len);
326 printf("%s %s\n", pathp, prop); /* no property value */
328 } else if (len > 0) {
330 print_data (nodep, len);
334 printf ("libfdt %s\n", fdt_strerror(len));
340 * The user passed in a node path and no property, print the node
343 offstack[0] = nodeoffset;
346 tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, &pathp);
350 printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp);
352 offstack[level] = nodeoffset;
353 if (level >= MAX_LEVEL) {
354 printf("Aaaiii <splat> nested too deep.\n");
361 printf("%s};\n", &tabs[MAX_LEVEL - level]);
363 level = -1; /* exit the loop */
367 nodep = fdt_getprop (fdt, offstack[level], pathp, &len);
369 printf ("libfdt %s\n", fdt_strerror(len));
371 } else if (len == 0) {
372 /* the property has no value */
374 printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp);
377 printf("%s%s=", &tabs[MAX_LEVEL - level], pathp);
378 print_data (nodep, len);
389 printf("Unknown tag 0x%08X\n", tag);
392 nodeoffset = nextoffset;
395 /********************************************************************
396 * Remove a property/node
397 ********************************************************************/
398 } else if (op == 'r') {
399 int nodeoffset; /* node offset from libfdt */
403 * Get the path. The root node is an oddball, the offset
404 * is zero and has no name.
406 if (strcmp(argv[2], "/") == 0) {
409 nodeoffset = fdt_path_offset (fdt, argv[2]);
410 if (nodeoffset < 0) {
412 * Not found or something else bad happened.
414 printf ("libfdt %s\n", fdt_strerror(nodeoffset));
419 * Do the delete. A fourth parameter means delete a property,
420 * otherwise delete the node.
423 err = fdt_delprop(fdt, nodeoffset, argv[3]);
425 printf("fdt_delprop libfdt: %s\n", fdt_strerror(err));
429 err = fdt_del_node(fdt, nodeoffset);
431 printf("fdt_del_node libfdt: %s\n", fdt_strerror(err));
436 /********************************************************************
437 * Create a chosen node
438 ********************************************************************/
439 } else if (op == 'c') {
440 fdt_chosen(fdt, 0, 0);
442 /********************************************************************
443 * Create a u-boot-env node
444 ********************************************************************/
445 } else if (op == 'e') {
448 /********************************************************************
450 ********************************************************************/
451 } else if (op == 'b') {
454 /********************************************************************
455 * Unrecognized command
456 ********************************************************************/
458 printf ("Usage:\n%s\n", cmdtp->usage);
465 /********************************************************************/
467 static int fdt_valid(void)
470 printf ("The address of the fdt is invalid.\n");
473 if (!fdt || (fdt_magic(fdt) != FDT_MAGIC)) {
475 printf ("Unrecognized fdt: bad magic\n");
478 if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) {
479 printf ("Unsupported fdt version: $d < %d\n",
480 FDT_FIRST_SUPPORTED_VERSION, fdt_version(fdt));
484 if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) {
485 printf ("Unsupported fdt version: $d > %d\n",
486 fdt_version(fdt), FDT_LAST_SUPPORTED_VERSION);
493 /********************************************************************/
496 * OF flat tree handling
497 * Written by: Pantelis Antoniou <pantelis.antoniou@gmail.com>
498 * Updated by: Matthew McClintock <msm@freescale.com>
499 * Converted to libfdt by: Gerald Van Baren <vanbaren@cideas.com>
502 static int is_printable_string(const void *data, int len)
504 const char *s = data;
506 /* zero length is not */
510 /* must terminate with zero */
511 if (s[len - 1] != '\0')
514 /* printable or a null byte (concatenated strings) */
515 while (((*s == '\0') || isprint(*s)) && (len > 0)) {
517 * If we see a null, there are three possibilities:
518 * 1) If len == 1, it is the end of the string, printable
519 * 2) Next character also a null, not printable.
520 * 3) Next character not a null, continue to check.
532 /* Not the null termination, or not done yet: not printable */
533 if (*s != '\0' || (len != 0))
539 static void print_data(const void *data, int len)
544 /* no data, don't print */
549 * It is a string, but it may have multiple strings (embedded '\0's).
551 if (is_printable_string(data, len)) {
558 j += strlen(data) + 1;
559 data += strlen(data) + 1;
567 printf("<%02x>", (*(u8 *) data) & 0xff);
569 case 2: /* half-word */
570 printf("<%04x>", be16_to_cpu(*(u16 *) data) & 0xffff);
573 printf("<%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
575 case 8: /* double-word */
577 printf("<%016llx>", be64_to_cpu(*(uint64_t *) data));
579 printf("<%08x ", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
581 printf("%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
584 default: /* anything else... hexdump */
586 for (j = 0, s = data; j < len; j++)
587 printf("%02x%s", s[j], j < len - 1 ? " " : "");
594 /********************************************************************/
596 static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end)
601 u32 tmp; /* used to set 32 bit integer properties */
602 char *str; /* used to set string properties */
605 if (initrd_start && initrd_end) {
606 err = fdt_add_reservemap_entry(fdt,
607 initrd_start, initrd_end - initrd_start + 1);
609 printf("libfdt: %s\n", fdt_strerror(err));
615 * See if we already have a "chosen" node, create it if not.
617 nodeoffset = fdt_path_offset (fdt, "/chosen");
618 if (nodeoffset < 0) {
620 * Create a new node "/chosen" (offset 0 is root level)
622 nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
623 if (nodeoffset < 0) {
624 printf("libfdt: %s\n", fdt_strerror(nodeoffset));
629 str = getenv("bootargs");
631 err = fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1);
633 printf("libfdt: %s\n", fdt_strerror(err));
635 if (initrd_start && initrd_end) {
636 tmp = __cpu_to_be32(initrd_start);
637 err = fdt_setprop(fdt, nodeoffset, "linux,initrd-start", &tmp, sizeof(tmp));
639 printf("libfdt: %s\n", fdt_strerror(err));
640 tmp = __cpu_to_be32(initrd_end);
641 err = fdt_setprop(fdt, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp));
643 printf("libfdt: %s\n", fdt_strerror(err));
645 #ifdef OF_STDOUT_PATH
646 err = fdt_setprop(fdt, nodeoffset, "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
648 printf("libfdt: %s\n", fdt_strerror(err));
651 nodeoffset = fdt_path_offset (fdt, "/cpus");
652 if (nodeoffset >= 0) {
653 clock = cpu_to_be32(bd->bi_intfreq);
654 err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4);
656 printf("libfdt: %s\n", fdt_strerror(err));
659 nodeoffset = fdt_path_offset (fdt, "/cpus/" OF_CPU "/timebase-frequency");
660 if (nodeoffset >= 0) {
661 clock = cpu_to_be32(OF_TBCLK);
662 err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4);
664 printf("libfdt: %s\n", fdt_strerror(err));
669 /********************************************************************/
671 #ifdef CONFIG_OF_HAS_BD_T
673 /* Function that returns a character from the environment */
674 extern uchar(*env_get_char) (int);
676 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
678 static const struct {
689 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
690 || defined(CONFIG_E500)
693 #if defined(CONFIG_MPC5xxx)
696 #if defined(CONFIG_MPC83XX)
699 #if defined(CONFIG_MPC8220)
717 #if defined(CONFIG_MPC5xxx)
724 static int fdt_env(void *fdt)
730 static char tmpenv[256];
733 * See if we already have a "u-boot-env" node, delete it if so.
734 * Then create a new empty node.
736 nodeoffset = fdt_path_offset (fdt, "/u-boot-env");
737 if (nodeoffset >= 0) {
738 err = fdt_del_node(fdt, nodeoffset);
740 printf("libfdt: %s\n", fdt_strerror(err));
745 * Create a new node "/u-boot-env" (offset 0 is root level)
747 nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env");
748 if (nodeoffset < 0) {
749 printf("libfdt: %s\n", fdt_strerror(nodeoffset));
753 for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
754 char *s, *lval, *rval;
757 * Find the end of the name=definition
759 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt)
762 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)
763 *s++ = env_get_char(k);
767 * Find the first '=': it separates the name from the value
769 s = strchr(tmpenv, '=');
775 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1);
777 printf("\"%s\" - libfdt: %s\n", lval, fdt_strerror(err));
783 #endif /* CONFIG_OF_HAS_UBOOT_ENV */
785 /********************************************************************/
787 #ifdef CONFIG_OF_HAS_BD_T
788 static int fdt_bd_t(void *fdt)
793 u32 tmp; /* used to set 32 bit integer properties */
797 * See if we already have a "bd_t" node, delete it if so.
798 * Then create a new empty node.
800 nodeoffset = fdt_path_offset (fdt, "/bd_t");
801 if (nodeoffset >= 0) {
802 err = fdt_del_node(fdt, nodeoffset);
804 printf("libfdt: %s\n", fdt_strerror(err));
809 * Create a new node "/bd_t" (offset 0 is root level)
811 nodeoffset = fdt_add_subnode(fdt, 0, "bd_t");
812 if (nodeoffset < 0) {
813 printf("libfdt: %s\n", fdt_strerror(nodeoffset));
817 * Use the string/pointer structure to create the entries...
819 for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) {
820 tmp = cpu_to_be32(getenv("bootargs"));
821 err = fdt_setprop(fdt, nodeoffset, bd_map[i].name, &tmp, sizeof(tmp));
823 printf("libfdt: %s\n", fdt_strerror(err));
826 * Add a couple of oddball entries...
828 err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
830 printf("libfdt: %s\n", fdt_strerror(err));
831 err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
833 printf("libfdt: %s\n", fdt_strerror(err));
835 #ifdef CONFIG_OF_BOARD_SETUP
836 ft_board_setup(fdt, bd);
841 #endif /* CONFIG_OF_HAS_BD_T */
843 /********************************************************************/
847 "fdt - flattened device tree utility commands\n",
848 "addr <addr> [<length>] - Set the fdt location to <addr>\n"
849 "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr>\n"
850 "fdt print <path> [<prop>] - Recursive print starting at <path>\n"
851 "fdt list <path> [<prop>] - Print one level starting at <path>\n"
852 "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n"
853 "fdt mknode <path> <node> - Create a new node after <path>\n"
854 "fdt rm <path> [<prop>] - Delete the node or <property>\n"
855 "fdt chosen - Add/update the \"/chosen\" branch in the tree\n"
856 #ifdef CONFIG_OF_HAS_UBOOT_ENV
857 "fdt env - Add/replace the \"/u-boot-env\" branch in the tree\n"
859 #ifdef CONFIG_OF_HAS_BD_T
860 "fdt bd_t - Add/replace the \"/bd_t\" branch in the tree\n"
863 " * Set a larger length with the fdt addr command to add to the blob.\n"
864 " * If the property you are setting/printing has a '#' character,\n"
865 " you MUST escape it with a \\ character or quote it with \" or\n"
866 " it will be ignored as a comment.\n"
867 " * If the value has spaces in it, you MUST escape the spaces with\n"
868 " \\ characters or quote it with \"\"\n"
869 "Examples: fdt print / # print the whole tree\n"
870 " fdt print /cpus \"#address-cells\"\n"
871 " fdt set /cpus \"#address-cells\" \"[00 00 00 01]\"\n"
874 #endif /* CONFIG_OF_FLAT_TREE */