]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_fdt.c
Add a flattened device tree (fdt) command (1 of 2)
[karo-tx-uboot.git] / common / cmd_fdt.c
1 /*
2  * (C) Copyright 2007
3  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
4  * Based on code written by:
5  *   Pantelis Antoniou <pantelis.antoniou@gmail.com> and
6  *   Matthew McClintock <msm@freescale.com>
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 #include <common.h>
28 #include <command.h>
29 #include <linux/ctype.h>
30 #include <linux/types.h>
31
32 #ifdef CONFIG_OF_LIBFDT
33 #include <asm/global_data.h>
34 #include <fdt.h>
35 #include <libfdt.h>
36
37 #define MAX_LEVEL       32              /* how deeply nested we will go */
38 #define SCRATCHPAD      1024    /* bytes of scratchpad memory */
39
40 /*
41  * Global data (for the gd->bd)
42  */
43 DECLARE_GLOBAL_DATA_PTR;
44
45 /*
46  * Scratchpad memory.
47  */
48 static char data[SCRATCHPAD];
49
50
51 /*
52  * Function prototypes/declarations.
53  */
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);
59
60
61 /*
62  * Flattened Device Tree command, see the help for parameter definitions.
63  */
64 int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
65 {
66         char            op;
67
68         if (argc < 2) {
69                 printf ("Usage:\n%s\n", cmdtp->usage);
70                 return 1;
71         }
72
73         /*
74          * Figure out which subcommand was given
75          */
76         op = argv[1][0];
77         /********************************************************************
78          * Set the address of the fdt
79          ********************************************************************/
80         if (op == 'a') {
81                 /*
82                  * Set the address [and length] of the fdt.
83                  */
84                 fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
85
86                 if (!fdt_valid()) {
87                         return 1;
88                 }
89
90                 if (argc >= 4) {
91                         int  len;
92                         int  err;
93                         /*
94                          * Optional new length
95                          */
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));
100                         } else {
101                                 /*
102                                  * Open in place with a new length.
103                                  */
104                                 err = fdt_open_into(fdt, fdt, len);
105                                 if (err != 0) {
106                                         printf ("libfdt: %s\n", fdt_strerror(err));
107                                 }
108                         }
109                 }
110
111         /********************************************************************
112          * Move the fdt
113          ********************************************************************/
114         } else if (op == 'm') {
115                 struct fdt_header *newaddr;
116                 int  len;
117                 int  err;
118
119                 if (argc != 5) {
120                         printf ("Usage:\n%s\n", cmdtp->usage);
121                         return 1;
122                 }
123
124                 /*
125                  * Set the address and length of the fdt.
126                  */
127                 fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
128                 if (!fdt_valid()) {
129                         return 1;
130                 }
131
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));
137                         return 1;
138                 }
139
140                 /*
141                  * Copy to the new location.
142                  */
143                 err = fdt_open_into(fdt, newaddr, len);
144                 if (err != 0) {
145                         printf ("libfdt: %s\n", fdt_strerror(err));
146                         return 1;
147                 }
148                 fdt = newaddr;
149
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 */
165
166                 /*
167                  * Parameters: Node path, property, value.
168                  */
169                 if (argc < 5) {
170                         printf ("Usage:\n%s\n", cmdtp->usage);
171                         return 1;
172                 }
173
174                 pathp  = argv[2];
175                 prop   = argv[3];
176                 newval = argv[4];
177
178                 if (strcmp(pathp, "/") == 0) {
179                         nodeoffset = 0;
180                 } else {
181                         nodeoffset = fdt_path_offset (fdt, pathp);
182                         if (nodeoffset < 0) {
183                                 /*
184                                  * Not found or something else bad happened.
185                                  */
186                                 printf ("libfdt: %s\n", fdt_strerror(nodeoffset));
187                                 return 1;
188                         }
189                 }
190                 nodep = fdt_getprop (fdt, nodeoffset, prop, &oldlen);
191                 if (oldlen < 0) {
192                         printf ("libfdt %s\n", fdt_strerror(oldlen));
193                         return 1;
194                 } else if (oldlen == 0) {
195                         /*
196                          * The specified property has no value
197                          */
198                         printf("%s has no value, cannot set one (yet).\n", prop);
199                         return 1;
200                 } else {
201                         /*
202                          * Convert the new property
203                          */
204                         vp = data;
205                         if (*newval == '<') {
206                                 /*
207                                  * Bigger values than bytes.
208                                  */
209                                 len = 0;
210                                 newval++;
211                                 while ((*newval != '>') && (*newval != '\0')) {
212                                         cp = newval;
213                                         tmp = simple_strtoul(cp, &newval, 16);
214                                         if ((newval - cp) <= 2) {
215                                                 *vp = tmp & 0xFF;
216                                                 vp  += 1;
217                                                 len += 1;
218                                         } else if ((newval - cp) <= 4) {
219                                                 *(uint16_t *)vp = __cpu_to_be16(tmp);
220                                                 vp  += 2;
221                                                 len += 2;
222                                         } else if ((newval - cp) <= 8) {
223                                                 *(uint32_t *)vp = __cpu_to_be32(tmp);
224                                                 vp  += 4;
225                                                 len += 4;
226                                         } else {
227                                                 printf("Sorry, I could not convert \"%s\"\n", cp);
228                                                 return 1;
229                                         }
230                                         while (*newval == ' ')
231                                                 newval++;
232                                 }
233                                 if (*newval != '>') {
234                                         printf("Unexpected character '%c'\n", *newval);
235                                         return 1;
236                                 }
237                         } else if (*newval == '[') {
238                                 /*
239                                  * Byte stream.  Convert the values.
240                                  */
241                                 len = 0;
242                                 newval++;
243                                 while ((*newval != ']') && (*newval != '\0')) {
244                                         tmp = simple_strtoul(newval, &newval, 16);
245                                         *vp++ = tmp & 0xFF;
246                                         len++;
247                                         while (*newval == ' ')
248                                                 newval++;
249                                 }
250                                 if (*newval != ']') {
251                                         printf("Unexpected character '%c'\n", *newval);
252                                         return 1;
253                                 }
254                         } else {
255                                 /*
256                                  * Assume it is a string.  Copy it into our data area for
257                                  * convenience (including the terminating '\0').
258                                  */
259                                 len = strlen(newval) + 1;
260                                 strcpy(data, newval);
261                         }
262
263                         ret = fdt_setprop(fdt, nodeoffset, prop, data, len);
264                         if (ret < 0) {
265                                 printf ("libfdt %s\n", fdt_strerror(ret));
266                                 return 1;
267                         }
268                 }
269
270         /********************************************************************
271          * Print (recursive) / List (single level)
272          ********************************************************************/
273         } else if ((op == 'p') || (op == 'l')) {
274                 /*
275                  * Recursively print (a portion of) the fdt.
276                  */
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 */
288
289                 /*
290                  * list is an alias for print, but limited to 1 level
291                  */
292                 if (op == 'l') {
293                         depth = 1;
294                 }
295
296                 /*
297                  * Get the starting path.  The root node is an oddball,
298                  * the offset is zero and has no name.
299                  */
300                 pathp = argv[2];
301                 if (argc > 3)
302                         prop = argv[3];
303                 else
304                         prop = NULL;
305
306                 if (strcmp(pathp, "/") == 0) {
307                         nodeoffset = 0;
308                         printf("/");
309                 } else {
310                         nodeoffset = fdt_path_offset (fdt, pathp);
311                         if (nodeoffset < 0) {
312                                 /*
313                                  * Not found or something else bad happened.
314                                  */
315                                 printf ("libfdt %s\n", fdt_strerror(nodeoffset));
316                                 return 1;
317                         }
318                 }
319                 /*
320                  * The user passed in a property as well as node path.  Print only
321                  * the given property and then return.
322                  */
323                 if (prop) {
324                         nodep = fdt_getprop (fdt, nodeoffset, prop, &len);
325                         if (len == 0) {
326                                 printf("%s %s\n", pathp, prop); /* no property value */
327                                 return 0;
328                         } else if (len > 0) {
329                                 printf("%s=", prop);
330                                 print_data (nodep, len);
331                                 printf("\n");
332                                 return 0;
333                         } else {
334                                 printf ("libfdt %s\n", fdt_strerror(len));
335                                 return 1;
336                         }
337                 }
338
339                 /*
340                  * The user passed in a node path and no property, print the node
341                  * and all subnodes.
342                  */
343                 offstack[0] = nodeoffset;
344
345                 while(level >= 0) {
346                         tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, &pathp);
347                         switch(tag) {
348                         case FDT_BEGIN_NODE:
349                                 if(level <= depth)
350                                         printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp);
351                                 level++;
352                                 offstack[level] = nodeoffset;
353                                 if (level >= MAX_LEVEL) {
354                                         printf("Aaaiii <splat> nested too deep.\n");
355                                         return 1;
356                                 }
357                                 break;
358                         case FDT_END_NODE:
359                                 level--;
360                                 if(level <= depth)
361                                         printf("%s};\n", &tabs[MAX_LEVEL - level]);
362                                 if (level == 0) {
363                                         level = -1;             /* exit the loop */
364                                 }
365                                 break;
366                         case FDT_PROP:
367                                 nodep = fdt_getprop (fdt, offstack[level], pathp, &len);
368                                 if (len < 0) {
369                                         printf ("libfdt %s\n", fdt_strerror(len));
370                                         return 1;
371                                 } else if (len == 0) {
372                                         /* the property has no value */
373                                         if(level <= depth)
374                                                 printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp);
375                                 } else {
376                                         if(level <= depth) {
377                                                 printf("%s%s=", &tabs[MAX_LEVEL - level], pathp);
378                                                 print_data (nodep, len);
379                                                 printf(";\n");
380                                         }
381                                 }
382                                 break;
383                         case FDT_NOP:
384                                 break;
385                         case FDT_END:
386                                 return 1;
387                         default:
388                                 if(level <= depth)
389                                         printf("Unknown tag 0x%08X\n", tag);
390                                 return 1;
391                         }
392                         nodeoffset = nextoffset;
393                 }
394
395         /********************************************************************
396          * Remove a property/node
397          ********************************************************************/
398         } else if (op == 'r') {
399                 int  nodeoffset;        /* node offset from libfdt */
400                 int  err;
401
402                 /*
403                  * Get the path.  The root node is an oddball, the offset
404                  * is zero and has no name.
405                  */
406                 if (strcmp(argv[2], "/") == 0) {
407                         nodeoffset = 0;
408                 } else {
409                         nodeoffset = fdt_path_offset (fdt, argv[2]);
410                         if (nodeoffset < 0) {
411                                 /*
412                                  * Not found or something else bad happened.
413                                  */
414                                 printf ("libfdt %s\n", fdt_strerror(nodeoffset));
415                                 return 1;
416                         }
417                 }
418                 /*
419                  * Do the delete.  A fourth parameter means delete a property,
420                  * otherwise delete the node.
421                  */
422                 if (argc > 3) {
423                         err = fdt_delprop(fdt, nodeoffset, argv[3]);
424                         if (err < 0) {
425                                 printf("fdt_delprop libfdt: %s\n", fdt_strerror(err));
426                                 return err;
427                         }
428                 } else {
429                         err = fdt_del_node(fdt, nodeoffset);
430                         if (err < 0) {
431                                 printf("fdt_del_node libfdt: %s\n", fdt_strerror(err));
432                                 return err;
433                         }
434                 }
435
436         /********************************************************************
437          * Create a chosen node
438          ********************************************************************/
439         } else if (op == 'c') {
440                 fdt_chosen(fdt, 0, 0);
441
442         /********************************************************************
443          * Create a u-boot-env node
444          ********************************************************************/
445         } else if (op == 'e') {
446                 fdt_env(fdt);
447
448         /********************************************************************
449          * Create a bd_t node
450          ********************************************************************/
451         } else if (op == 'b') {
452                 fdt_bd_t(fdt);
453
454         /********************************************************************
455          * Unrecognized command
456          ********************************************************************/
457         } else {
458                 printf ("Usage:\n%s\n", cmdtp->usage);
459                 return 1;
460         }
461
462         return 0;
463 }
464
465 /********************************************************************/
466
467 static int fdt_valid(void)
468 {
469         if (fdt == NULL) {
470                 printf ("The address of the fdt is invalid.\n");
471                 return 0;
472         }
473         if (!fdt || (fdt_magic(fdt) != FDT_MAGIC)) {
474                 fdt = NULL;
475                 printf ("Unrecognized fdt: bad magic\n");
476                 return 0;
477         }
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));
481                 fdt = NULL;
482                 return 0;
483         }
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);
487                 fdt = NULL;
488                 return 0;
489         }
490         return 1;
491 }
492
493 /********************************************************************/
494
495 /*
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>
500  */
501
502 static int is_printable_string(const void *data, int len)
503 {
504         const char *s = data;
505
506         /* zero length is not */
507         if (len == 0)
508                 return 0;
509
510         /* must terminate with zero */
511         if (s[len - 1] != '\0')
512                 return 0;
513
514         /* printable or a null byte (concatenated strings) */
515         while (((*s == '\0') || isprint(*s)) && (len > 0)) {
516                 /*
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.
521                  */
522                 if (s[0] == '\0') {
523                         if (len == 1)
524                                 return 1;
525                         if (s[1] == '\0')
526                                 return 0;
527                 }
528                 s++;
529                 len--;
530         }
531
532         /* Not the null termination, or not done yet: not printable */
533         if (*s != '\0' || (len != 0))
534                 return 0;
535
536         return 1;
537 }
538
539 static void print_data(const void *data, int len)
540 {
541         int j;
542         const u8 *s;
543
544         /* no data, don't print */
545         if (len == 0)
546                 return;
547
548         /*
549          * It is a string, but it may have multiple strings (embedded '\0's).
550          */
551         if (is_printable_string(data, len)) {
552                 puts("\"");
553                 j = 0;
554                 while (j < len) {
555                         if (j > 0)
556                                 puts("\", \"");
557                         puts(data);
558                         j    += strlen(data) + 1;
559                         data += strlen(data) + 1;
560                 }
561                 puts("\"");
562                 return;
563         }
564
565         switch (len) {
566         case 1:  /* byte */
567                 printf("<%02x>", (*(u8 *) data) & 0xff);
568                 break;
569         case 2:  /* half-word */
570                 printf("<%04x>", be16_to_cpu(*(u16 *) data) & 0xffff);
571                 break;
572         case 4:  /* word */
573                 printf("<%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
574                 break;
575         case 8:  /* double-word */
576 #if __WORDSIZE == 64
577                 printf("<%016llx>", be64_to_cpu(*(uint64_t *) data));
578 #else
579                 printf("<%08x ", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
580                 data += 4;
581                 printf("%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);
582 #endif
583                 break;
584         default:                /* anything else... hexdump */
585                 printf("[");
586                 for (j = 0, s = data; j < len; j++)
587                         printf("%02x%s", s[j], j < len - 1 ? " " : "");
588                 printf("]");
589
590                 break;
591         }
592 }
593
594 /********************************************************************/
595
596 static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end)
597 {
598         bd_t *bd = gd->bd;
599         int   nodeoffset;
600         int   err;
601         u32   tmp;                      /* used to set 32 bit integer properties */
602         char  *str;                     /* used to set string properties */
603         ulong clock;
604
605         if (initrd_start && initrd_end) {
606                 err = fdt_add_reservemap_entry(fdt,
607                         initrd_start, initrd_end - initrd_start + 1);
608                 if (err < 0) {
609                         printf("libfdt: %s\n", fdt_strerror(err));
610                         return err;
611                 }
612         }
613
614         /*
615          * See if we already have a "chosen" node, create it if not.
616          */
617         nodeoffset = fdt_path_offset (fdt, "/chosen");
618         if (nodeoffset < 0) {
619                 /*
620                  * Create a new node "/chosen" (offset 0 is root level)
621                  */
622                 nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
623                 if (nodeoffset < 0) {
624                         printf("libfdt: %s\n", fdt_strerror(nodeoffset));
625                         return nodeoffset;
626                 }
627         }
628
629         str = getenv("bootargs");
630         if (str != NULL) {
631                 err = fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1);
632                 if (err < 0)
633                         printf("libfdt: %s\n", fdt_strerror(err));
634         }
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));
638                 if (err < 0)
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));
642                 if (err < 0)
643                         printf("libfdt: %s\n", fdt_strerror(err));
644         }
645 #ifdef OF_STDOUT_PATH
646         err = fdt_setprop(fdt, nodeoffset, "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
647         if (err < 0)
648                 printf("libfdt: %s\n", fdt_strerror(err));
649 #endif
650
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);
655                 if (err < 0)
656                         printf("libfdt: %s\n", fdt_strerror(err));
657         }
658 #ifdef OF_TBCLK
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);
663                 if (err < 0)
664                         printf("libfdt: %s\n", fdt_strerror(err));
665         }
666 #endif
667 }
668
669 /********************************************************************/
670
671 #ifdef CONFIG_OF_HAS_BD_T
672
673 /* Function that returns a character from the environment */
674 extern uchar(*env_get_char) (int);
675
676 #define BDM(x)  {       .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
677
678 static const struct {
679         const char *name;
680         int offset;
681 } bd_map[] = {
682         BDM(memstart),
683         BDM(memsize),
684         BDM(flashstart),
685         BDM(flashsize),
686         BDM(flashoffset),
687         BDM(sramstart),
688         BDM(sramsize),
689 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
690         || defined(CONFIG_E500)
691         BDM(immr_base),
692 #endif
693 #if defined(CONFIG_MPC5xxx)
694         BDM(mbar_base),
695 #endif
696 #if defined(CONFIG_MPC83XX)
697         BDM(immrbar),
698 #endif
699 #if defined(CONFIG_MPC8220)
700         BDM(mbar_base),
701         BDM(inpfreq),
702         BDM(pcifreq),
703         BDM(pevfreq),
704         BDM(flbfreq),
705         BDM(vcofreq),
706 #endif
707         BDM(bootflags),
708         BDM(ip_addr),
709         BDM(intfreq),
710         BDM(busfreq),
711 #ifdef CONFIG_CPM2
712         BDM(cpmfreq),
713         BDM(brgfreq),
714         BDM(sccfreq),
715         BDM(vco),
716 #endif
717 #if defined(CONFIG_MPC5xxx)
718         BDM(ipbfreq),
719         BDM(pcifreq),
720 #endif
721         BDM(baudrate),
722 };
723
724 static int fdt_env(void *fdt)
725 {
726         int   nodeoffset;
727         int   err;
728         int   k, nxt;
729         int i;
730         static char tmpenv[256];
731
732         /*
733          * See if we already have a "u-boot-env" node, delete it if so.
734          * Then create a new empty node.
735          */
736         nodeoffset = fdt_path_offset (fdt, "/u-boot-env");
737         if (nodeoffset >= 0) {
738                 err = fdt_del_node(fdt, nodeoffset);
739                 if (err < 0) {
740                         printf("libfdt: %s\n", fdt_strerror(err));
741                         return err;
742                 }
743         }
744         /*
745          * Create a new node "/u-boot-env" (offset 0 is root level)
746          */
747         nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env");
748         if (nodeoffset < 0) {
749                 printf("libfdt: %s\n", fdt_strerror(nodeoffset));
750                 return nodeoffset;
751         }
752
753         for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
754                 char *s, *lval, *rval;
755
756                 /*
757                  * Find the end of the name=definition
758                  */
759                 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt)
760                         ;
761                 s = tmpenv;
762                 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)
763                         *s++ = env_get_char(k);
764                 *s++ = '\0';
765                 lval = tmpenv;
766                 /*
767                  * Find the first '=': it separates the name from the value
768                  */
769                 s = strchr(tmpenv, '=');
770                 if (s != NULL) {
771                         *s++ = '\0';
772                         rval = s;
773                 } else
774                         continue;
775                 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1);
776                 if (err < 0) {
777                         printf("\"%s\" - libfdt: %s\n", lval, fdt_strerror(err));
778                         return err;
779                 }
780         }
781         return 0;
782 }
783 #endif /* CONFIG_OF_HAS_UBOOT_ENV */
784
785 /********************************************************************/
786
787 #ifdef CONFIG_OF_HAS_BD_T
788 static int fdt_bd_t(void *fdt)
789 {
790         bd_t *bd = gd->bd;
791         int   nodeoffset;
792         int   err;
793         u32   tmp;                      /* used to set 32 bit integer properties */
794         int i;
795
796         /*
797          * See if we already have a "bd_t" node, delete it if so.
798          * Then create a new empty node.
799          */
800         nodeoffset = fdt_path_offset (fdt, "/bd_t");
801         if (nodeoffset >= 0) {
802                 err = fdt_del_node(fdt, nodeoffset);
803                 if (err < 0) {
804                         printf("libfdt: %s\n", fdt_strerror(err));
805                         return err;
806                 }
807         }
808         /*
809          * Create a new node "/bd_t" (offset 0 is root level)
810          */
811         nodeoffset = fdt_add_subnode(fdt, 0, "bd_t");
812         if (nodeoffset < 0) {
813                 printf("libfdt: %s\n", fdt_strerror(nodeoffset));
814                 return nodeoffset;
815         }
816         /*
817          * Use the string/pointer structure to create the entries...
818          */
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));
822                 if (err < 0)
823                         printf("libfdt: %s\n", fdt_strerror(err));
824         }
825         /*
826          * Add a couple of oddball entries...
827          */
828         err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
829         if (err < 0)
830                 printf("libfdt: %s\n", fdt_strerror(err));
831         err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
832         if (err < 0)
833                 printf("libfdt: %s\n", fdt_strerror(err));
834
835 #ifdef CONFIG_OF_BOARD_SETUP
836         ft_board_setup(fdt, bd);
837 #endif
838
839         return 0;
840 }
841 #endif /* CONFIG_OF_HAS_BD_T */
842
843 /********************************************************************/
844
845 U_BOOT_CMD(
846         fdt,    5,      0,      do_fdt,
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"
858 #endif
859 #ifdef CONFIG_OF_HAS_BD_T
860         "fdt bd_t   - Add/replace the \"/bd_t\" branch in the tree\n"
861 #endif
862         "Hints:\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"
872 );
873
874 #endif /* CONFIG_OF_FLAT_TREE */