3 * Written by: Pantelis Antoniou <pantelis.antoniou@gmail.com>
4 * Updated by: Matthew McClintock <msm@freescale.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 #include <environment.h>
26 #ifdef CONFIG_OF_FLAT_TREE
28 #include <asm/errno.h>
35 /* align addr on a size boundary - adjust address up if needed -- Cort */
36 #define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1)))
37 #ifndef CONFIG_OF_BOOT_CPU
38 #define CONFIG_OF_BOOT_CPU 0
40 #define SIZE_OF_RSVMAP_ENTRY (2*sizeof(u64))
42 static void ft_put_word(struct ft_cxt
*cxt
, u32 v
)
44 memmove(cxt
->p
+ sizeof(u32
), cxt
->p
, cxt
->p_end
- cxt
->p
);
46 *(u32
*) cxt
->p
= cpu_to_be32(v
);
47 cxt
->p
+= sizeof(u32
);
48 cxt
->p_end
+= sizeof(u32
);
51 static inline void ft_put_bin(struct ft_cxt
*cxt
, const void *data
, int sz
)
53 int aligned_size
= ((u8
*)_ALIGN((unsigned long)cxt
->p
+ sz
,
54 sizeof(u32
))) - cxt
->p
;
56 memmove(cxt
->p
+ aligned_size
, cxt
->p
, cxt
->p_end
- cxt
->p
);
58 /* make sure the last bytes are zeroed */
59 memset(cxt
->p
+ aligned_size
- (aligned_size
% sizeof(u32
)), 0,
60 (aligned_size
% sizeof(u32
)));
62 memcpy(cxt
->p
, data
, sz
);
64 cxt
->p
+= aligned_size
;
65 cxt
->p_end
+= aligned_size
;
68 void ft_begin_node(struct ft_cxt
*cxt
, const char *name
)
70 ft_put_word(cxt
, OF_DT_BEGIN_NODE
);
71 ft_put_bin(cxt
, name
, strlen(name
) + 1);
74 void ft_end_node(struct ft_cxt
*cxt
)
76 ft_put_word(cxt
, OF_DT_END_NODE
);
79 void ft_nop(struct ft_cxt
*cxt
)
81 ft_put_word(cxt
, OF_DT_NOP
);
84 static int lookup_string(struct ft_cxt
*cxt
, const char *name
)
89 while (p
< cxt
->p_end
) {
90 if (strcmp((char *)p
, name
) == 0)
92 p
+= strlen((char *)p
) + 1;
98 void ft_prop(struct ft_cxt
*cxt
, const char *name
, const void *data
, int sz
)
102 off
= lookup_string(cxt
, name
);
104 memcpy(cxt
->p_end
, name
, strlen(name
) + 1);
105 off
= cxt
->p_end
- cxt
->p
;
106 cxt
->p_end
+= strlen(name
) + 1;
109 /* now put offset from beginning of *STRUCTURE* */
110 /* will be fixed up at the end */
111 ft_put_word(cxt
, OF_DT_PROP
);
112 ft_put_word(cxt
, sz
);
113 ft_put_word(cxt
, off
);
114 ft_put_bin(cxt
, data
, sz
);
117 void ft_prop_str(struct ft_cxt
*cxt
, const char *name
, const char *str
)
119 ft_prop(cxt
, name
, str
, strlen(str
) + 1);
122 void ft_prop_int(struct ft_cxt
*cxt
, const char *name
, int val
)
124 u32 v
= cpu_to_be32((u32
) val
);
126 ft_prop(cxt
, name
, &v
, sizeof(u32
));
129 /* pick up and start working on a tree in place */
130 void ft_init_cxt(struct ft_cxt
*cxt
, void *blob
)
132 struct boot_param_header
*bph
= blob
;
134 memset(cxt
, 0, sizeof(*cxt
));
137 bph
->boot_cpuid_phys
= CONFIG_OF_BOOT_CPU
;
139 /* find beginning and end of reserve map table (zeros in last entry) */
140 cxt
->p_rsvmap
= (u8
*)bph
+ bph
->off_mem_rsvmap
;
141 while ( ((uint64_t *)cxt
->p_rsvmap
)[0] != 0 &&
142 ((uint64_t *)cxt
->p_rsvmap
)[1] != 0 ) {
143 cxt
->p_rsvmap
+= SIZE_OF_RSVMAP_ENTRY
;
146 cxt
->p_start
= (u8
*)bph
+ bph
->off_dt_struct
;
147 cxt
->p_end
= (u8
*)bph
+ bph
->totalsize
;
148 cxt
->p
= (u8
*)bph
+ bph
->off_dt_strings
;
151 /* add a reserver physical area to the rsvmap */
152 void ft_add_rsvmap(struct ft_cxt
*cxt
, u64 physstart
, u64 physend
)
154 memmove(cxt
->p_rsvmap
+ SIZE_OF_RSVMAP_ENTRY
, cxt
->p_rsvmap
,
155 cxt
->p_end
- cxt
->p_rsvmap
);
157 ((u64
*)cxt
->p_rsvmap
)[0] = cpu_to_be64(physstart
);
158 ((u64
*)cxt
->p_rsvmap
)[1] = cpu_to_be64(physend
);
159 ((u64
*)cxt
->p_rsvmap
)[2] = 0;
160 ((u64
*)cxt
->p_rsvmap
)[3] = 0;
162 cxt
->p_rsvmap
+= SIZE_OF_RSVMAP_ENTRY
;
163 cxt
->p_start
+= SIZE_OF_RSVMAP_ENTRY
;
164 cxt
->p
+= SIZE_OF_RSVMAP_ENTRY
;
165 cxt
->p_end
+= SIZE_OF_RSVMAP_ENTRY
;
168 void ft_end_tree(struct ft_cxt
*cxt
)
170 ft_put_word(cxt
, OF_DT_END
);
173 /* update the boot param header with correct values */
174 void ft_finalize_tree(struct ft_cxt
*cxt
) {
175 struct boot_param_header
*bph
= cxt
->bph
;
177 bph
->totalsize
= cxt
->p_end
- (u8
*)bph
;
178 bph
->off_dt_struct
= cxt
->p_start
- (u8
*)bph
;
179 bph
->off_dt_strings
= cxt
->p
- (u8
*)bph
;
180 bph
->dt_strings_size
= cxt
->p_end
- cxt
->p
;
183 static inline int isprint(int c
)
185 return c
>= 0x20 && c
<= 0x7e;
188 static int is_printable_string(const void *data
, int len
)
190 const char *s
= data
;
193 /* zero length is not */
197 /* must terminate with zero */
198 if (s
[len
- 1] != '\0')
202 while (*s
&& isprint(*s
))
205 /* not zero, or not done yet */
206 if (*s
!= '\0' || (s
+ 1 - ss
) < len
)
212 static void print_data(const void *data
, int len
)
217 /* no data, don't print */
221 if (is_printable_string(data
, len
)) {
230 printf(" = <%02x>", (*(u8
*) data
) & 0xff);
232 case 2: /* half-word */
233 printf(" = <%04x>", be16_to_cpu(*(u16
*) data
) & 0xffff);
236 printf(" = <%x>", be32_to_cpu(*(u32
*) data
) & 0xffffffffU
);
238 case 8: /* double-word */
239 printf(" = <%qx>", be64_to_cpu(*(uint64_t *) data
));
241 default: /* anything else... hexdump */
243 for (i
= 0, s
= data
; i
< len
; i
++)
244 printf("%02x%s", s
[i
], i
< len
- 1 ? " " : "");
251 void ft_dump_blob(const void *bphp
)
253 const struct boot_param_header
*bph
= bphp
;
254 const uint64_t *p_rsvmap
= (const uint64_t *)
255 ((const char *)bph
+ be32_to_cpu(bph
->off_mem_rsvmap
));
256 const u32
*p_struct
= (const u32
*)
257 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
258 const u32
*p_strings
= (const u32
*)
259 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
263 int depth
, sz
, shift
;
267 if (be32_to_cpu(bph
->magic
) != OF_DT_HEADER
) {
276 addr
= be64_to_cpu(p_rsvmap
[i
* 2]);
277 size
= be64_to_cpu(p_rsvmap
[i
* 2 + 1]);
278 if (addr
== 0 && size
== 0)
281 printf("/memreserve/ %qx %qx;\n", addr
, size
);
285 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
287 /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
289 if (tag
== OF_DT_BEGIN_NODE
) {
291 p
= (u32
*) _ALIGN((unsigned long)p
+ strlen(s
) + 1, 4);
293 printf("%*s%s {\n", depth
* shift
, "", s
);
299 if (tag
== OF_DT_END_NODE
) {
302 printf("%*s};\n", depth
* shift
, "");
306 if (tag
== OF_DT_NOP
) {
307 printf("%*s[NOP]\n", depth
* shift
, "");
311 if (tag
!= OF_DT_PROP
) {
312 fprintf(stderr
, "%*s ** Unknown tag 0x%08x at 0x%x\n",
313 depth
* shift
, "", tag
, --p
);
316 sz
= be32_to_cpu(*p
++);
317 s
= (const char *)p_strings
+ be32_to_cpu(*p
++);
319 p
= (const u32
*)_ALIGN((unsigned long)p
+ sz
, 4);
320 printf("%*s%s", depth
* shift
, "", s
);
326 void ft_backtrack_node(struct ft_cxt
*cxt
)
330 while (be32_to_cpu(*(u32
*) (cxt
->p
- i
)) != OF_DT_END_NODE
)
333 memmove (cxt
->p
- i
, cxt
->p
, cxt
->p_end
- cxt
->p
);
339 void *ft_get_prop(void *bphp
, const char *propname
, int *szp
)
341 struct boot_param_header
*bph
= bphp
;
343 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
344 uint32_t *p_strings
=
345 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
346 uint32_t version
= be32_to_cpu(bph
->version
);
352 static char path
[256], prop
[256];
357 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
359 if (tag
== OF_DT_BEGIN_NODE
) {
361 p
= (uint32_t *) _ALIGN((unsigned long)p
+ strlen(s
) +
368 if (tag
== OF_DT_END_NODE
) {
369 path
[strlen(path
) - 1] = '\0';
370 ss
= strrchr(path
, '/');
376 if (tag
== OF_DT_NOP
)
379 if (tag
!= OF_DT_PROP
)
382 sz
= be32_to_cpu(*p
++);
383 s
= (char *)p_strings
+ be32_to_cpu(*p
++);
384 if (version
< 0x10 && sz
>= 8)
385 p
= (uint32_t *) _ALIGN((unsigned long)p
, 8);
387 p
= (uint32_t *) _ALIGN((unsigned long)p
+ sz
, 4);
392 if (strcmp(prop
, propname
) == 0) {
401 /********************************************************************/
403 /* Function that returns a character from the environment */
404 extern uchar(*env_get_char
) (int);
406 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
408 #ifdef CONFIG_OF_HAS_BD_T
409 static const struct {
420 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
421 || defined(CONFIG_E500)
424 #if defined(CONFIG_MPC5xxx)
427 #if defined(CONFIG_MPC83XX)
430 #if defined(CONFIG_MPC8220)
448 #if defined(CONFIG_MPC5xxx)
456 void ft_setup(void *blob
, bd_t
* bd
, ulong initrd_start
, ulong initrd_end
)
462 #if defined(CONFIG_OF_HAS_UBOOT_ENV)
465 #if defined(CONFIG_OF_HAS_BD_T)
468 #if defined(CONFIG_OF_HAS_UBOOT_ENV) || defined(CONFIG_OF_HAS_BD_T)
470 static char tmpenv
[256];
473 /* disable OF tree; booting old kernel */
474 if (getenv("disable_of") != NULL
) {
475 memcpy(blob
, bd
, sizeof(*bd
));
480 printf ("recieved oftree\n");
484 ft_init_cxt(&cxt
, blob
);
486 if (initrd_start
&& initrd_end
)
487 ft_add_rsvmap(&cxt
, initrd_start
, initrd_end
- initrd_start
+ 1);
490 ft_backtrack_node(&cxt
);
492 #ifdef CONFIG_OF_HAS_UBOOT_ENV
493 ft_begin_node(&cxt
, "u-boot-env");
495 for (i
= 0; env_get_char(i
) != '\0'; i
= nxt
+ 1) {
496 char *s
, *lval
, *rval
;
498 for (nxt
= i
; env_get_char(nxt
) != '\0'; ++nxt
) ;
500 for (k
= i
; k
< nxt
&& s
< &tmpenv
[sizeof(tmpenv
) - 1]; ++k
)
501 *s
++ = env_get_char(k
);
504 s
= strchr(tmpenv
, '=');
510 ft_prop_str(&cxt
, lval
, rval
);
516 ft_begin_node(&cxt
, "chosen");
517 ft_prop_str(&cxt
, "name", "chosen");
519 ft_prop_str(&cxt
, "bootargs", getenv("bootargs"));
520 ft_prop_int(&cxt
, "linux,platform", 0x600); /* what is this? */
521 if (initrd_start
&& initrd_end
) {
522 ft_prop_int(&cxt
, "linux,initrd-start", initrd_start
);
523 ft_prop_int(&cxt
, "linux,initrd-end", initrd_end
);
525 #ifdef OF_STDOUT_PATH
526 ft_prop_str(&cxt
, "linux,stdout-path", OF_STDOUT_PATH
);
531 ft_end_node(&cxt
); /* end root */
534 ft_finalize_tree(&cxt
);
536 #ifdef CONFIG_OF_HAS_BD_T
537 /* paste the bd_t at the end of the flat tree */
539 be32_to_cpu(((struct boot_param_header
*)blob
)->totalsize
);
540 memcpy(end
, bd
, sizeof(*bd
));
545 #ifdef CONFIG_OF_HAS_BD_T
546 for (i
= 0; i
< sizeof(bd_map
)/sizeof(bd_map
[0]); i
++) {
549 sprintf(tmpenv
, "/bd_t/%s", bd_map
[i
].name
);
550 v
= *(uint32_t *)((char *)bd
+ bd_map
[i
].offset
);
552 p
= ft_get_prop(blob
, tmpenv
, &len
);
557 p
= ft_get_prop(blob
, "/bd_t/enetaddr", &len
);
559 memcpy(p
, bd
->bi_enetaddr
, 6);
561 p
= ft_get_prop(blob
, "/bd_t/ethspeed", &len
);
563 *p
= cpu_to_be32((uint32_t) bd
->bi_ethspeed
);
566 clock
= bd
->bi_intfreq
;
567 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/clock-frequency", &len
);
569 *p
= cpu_to_be32(clock
);
573 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/timebase-frequency", &len
);
575 *p
= cpu_to_be32(clock
);
577 #endif /* __powerpc__ */
579 #ifdef CONFIG_OF_BOARD_SETUP
580 ft_board_setup(blob
, bd
);
583 /* in case the size changed in the platform code */
584 ft_finalize_tree(&cxt
);
587 printf("final OF-tree\n");