blob: 968bade626d6be43640e84460fe68acdf4f157b5 [file] [log] [blame]
Gerald Van Baren781e09e2007-03-31 12:22:10 -04001/*
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 */
43DECLARE_GLOBAL_DATA_PTR;
44
45/*
46 * Scratchpad memory.
47 */
48static char data[SCRATCHPAD];
49
50
51/*
52 * Function prototypes/declarations.
53 */
54static int fdt_valid(void);
55static void print_data(const void *data, int len);
56static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end);
57static int fdt_env(void *fdt);
58static int fdt_bd_t(void *fdt);
59
60
61/*
62 * Flattened Device Tree command, see the help for parameter definitions.
63 */
64int 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
467static 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
502static 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
539static 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
596static 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 */
674extern uchar(*env_get_char) (int);
675
676#define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
677
678static 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
724static 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
788static 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
845U_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 */