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