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,
26 #include <environment.h>
27 #include <asm/byteorder.h>
37 /* align addr on a size boundary - adjust address up if needed -- Cort */
38 #define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1)))
39 #ifndef CONFIG_OF_BOOT_CPU
40 #define CONFIG_OF_BOOT_CPU 0
42 #define SIZE_OF_RSVMAP_ENTRY (2*sizeof(u64))
44 static void ft_put_word(struct ft_cxt
*cxt
, u32 v
)
46 memmove(cxt
->p
+ sizeof(u32
), cxt
->p
, cxt
->p_end
- cxt
->p
);
48 *(u32
*) cxt
->p
= cpu_to_be32(v
);
49 cxt
->p
+= sizeof(u32
);
50 cxt
->p_end
+= sizeof(u32
);
53 static inline void ft_put_bin(struct ft_cxt
*cxt
, const void *data
, int sz
)
55 int aligned_size
= ((u8
*)_ALIGN((unsigned long)cxt
->p
+ sz
,
56 sizeof(u32
))) - cxt
->p
;
58 memmove(cxt
->p
+ aligned_size
, cxt
->p
, cxt
->p_end
- cxt
->p
);
60 /* make sure the last bytes are zeroed */
61 memset(cxt
->p
+ aligned_size
- (aligned_size
% sizeof(u32
)), 0,
62 (aligned_size
% sizeof(u32
)));
64 memcpy(cxt
->p
, data
, sz
);
66 cxt
->p
+= aligned_size
;
67 cxt
->p_end
+= aligned_size
;
70 void ft_begin_node(struct ft_cxt
*cxt
, const char *name
)
72 ft_put_word(cxt
, OF_DT_BEGIN_NODE
);
73 ft_put_bin(cxt
, name
, strlen(name
) + 1);
76 void ft_end_node(struct ft_cxt
*cxt
)
78 ft_put_word(cxt
, OF_DT_END_NODE
);
81 void ft_nop(struct ft_cxt
*cxt
)
83 ft_put_word(cxt
, OF_DT_NOP
);
86 static int lookup_string(struct ft_cxt
*cxt
, const char *name
)
91 while (p
< cxt
->p_end
) {
92 if (strcmp((char *)p
, name
) == 0)
94 p
+= strlen((char *)p
) + 1;
100 void ft_prop(struct ft_cxt
*cxt
, const char *name
, const void *data
, int sz
)
104 off
= lookup_string(cxt
, name
);
106 memcpy(cxt
->p_end
, name
, strlen(name
) + 1);
107 off
= cxt
->p_end
- cxt
->p
;
108 cxt
->p_end
+= strlen(name
) + 1;
111 /* now put offset from beginning of *STRUCTURE* */
112 /* will be fixed up at the end */
113 ft_put_word(cxt
, OF_DT_PROP
);
114 ft_put_word(cxt
, sz
);
115 ft_put_word(cxt
, off
);
116 ft_put_bin(cxt
, data
, sz
);
119 void ft_prop_str(struct ft_cxt
*cxt
, const char *name
, const char *str
)
121 ft_prop(cxt
, name
, str
, strlen(str
) + 1);
124 void ft_prop_int(struct ft_cxt
*cxt
, const char *name
, int val
)
126 u32 v
= cpu_to_be32((u32
) val
);
128 ft_prop(cxt
, name
, &v
, sizeof(u32
));
131 /* pick up and start working on a tree in place */
132 void ft_init_cxt(struct ft_cxt
*cxt
, void *blob
)
134 struct boot_param_header
*bph
= blob
;
136 memset(cxt
, 0, sizeof(*cxt
));
139 bph
->boot_cpuid_phys
= CONFIG_OF_BOOT_CPU
;
141 /* find beginning and end of reserve map table (zeros in last entry) */
142 cxt
->p_rsvmap
= (u8
*)bph
+ bph
->off_mem_rsvmap
;
143 while ( ((uint64_t *)cxt
->p_rsvmap
)[0] != 0 &&
144 ((uint64_t *)cxt
->p_rsvmap
)[1] != 0 ) {
145 cxt
->p_rsvmap
+= SIZE_OF_RSVMAP_ENTRY
;
148 cxt
->p_start
= (u8
*)bph
+ bph
->off_dt_struct
;
149 cxt
->p_end
= (u8
*)bph
+ bph
->totalsize
;
150 cxt
->p
= (u8
*)bph
+ bph
->off_dt_strings
;
153 /* add a reserver physical area to the rsvmap */
154 void ft_add_rsvmap(struct ft_cxt
*cxt
, u64 physstart
, u64 physend
)
156 memmove(cxt
->p_rsvmap
+ SIZE_OF_RSVMAP_ENTRY
, cxt
->p_rsvmap
,
157 cxt
->p_end
- cxt
->p_rsvmap
);
159 ((u64
*)cxt
->p_rsvmap
)[0] = cpu_to_be64(physstart
);
160 ((u64
*)cxt
->p_rsvmap
)[1] = cpu_to_be64(physend
);
161 ((u64
*)cxt
->p_rsvmap
)[2] = 0;
162 ((u64
*)cxt
->p_rsvmap
)[3] = 0;
164 cxt
->p_rsvmap
+= SIZE_OF_RSVMAP_ENTRY
;
165 cxt
->p_start
+= SIZE_OF_RSVMAP_ENTRY
;
166 cxt
->p
+= SIZE_OF_RSVMAP_ENTRY
;
167 cxt
->p_end
+= SIZE_OF_RSVMAP_ENTRY
;
170 void ft_end_tree(struct ft_cxt
*cxt
)
172 ft_put_word(cxt
, OF_DT_END
);
175 /* update the boot param header with correct values */
176 void ft_finalize_tree(struct ft_cxt
*cxt
) {
177 struct boot_param_header
*bph
= cxt
->bph
;
179 bph
->totalsize
= cxt
->p_end
- (u8
*)bph
;
180 bph
->off_dt_struct
= cxt
->p_start
- (u8
*)bph
;
181 bph
->off_dt_strings
= cxt
->p
- (u8
*)bph
;
182 bph
->dt_strings_size
= cxt
->p_end
- cxt
->p
;
185 static inline int isprint(int c
)
187 return c
>= 0x20 && c
<= 0x7e;
190 static int is_printable_string(const void *data
, int len
)
192 const char *s
= data
;
195 /* zero length is not */
199 /* must terminate with zero */
200 if (s
[len
- 1] != '\0')
204 while (*s
&& isprint(*s
))
207 /* not zero, or not done yet */
208 if (*s
!= '\0' || (s
+ 1 - ss
) < len
)
214 static void print_data(const void *data
, int len
)
219 /* no data, don't print */
223 if (is_printable_string(data
, len
)) {
232 printf(" = <%02x>", (*(u8
*) data
) & 0xff);
234 case 2: /* half-word */
235 printf(" = <%04x>", be16_to_cpu(*(u16
*) data
) & 0xffff);
238 printf(" = <%x>", be32_to_cpu(*(u32
*) data
) & 0xffffffffU
);
240 case 8: /* double-word */
241 printf(" = <%qx>", be64_to_cpu(*(uint64_t *) data
));
243 default: /* anything else... hexdump */
245 for (i
= 0, s
= data
; i
< len
; i
++)
246 printf("%02x%s", s
[i
], i
< len
- 1 ? " " : "");
253 void ft_dump_blob(const void *bphp
)
255 const struct boot_param_header
*bph
= bphp
;
256 const uint64_t *p_rsvmap
= (const uint64_t *)
257 ((const char *)bph
+ be32_to_cpu(bph
->off_mem_rsvmap
));
258 const u32
*p_struct
= (const u32
*)
259 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
260 const u32
*p_strings
= (const u32
*)
261 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
265 int depth
, sz
, shift
;
269 if (be32_to_cpu(bph
->magic
) != OF_DT_HEADER
) {
278 addr
= be64_to_cpu(p_rsvmap
[i
* 2]);
279 size
= be64_to_cpu(p_rsvmap
[i
* 2 + 1]);
280 if (addr
== 0 && size
== 0)
283 printf("/memreserve/ %qx %qx;\n", addr
, size
);
287 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
289 /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
291 if (tag
== OF_DT_BEGIN_NODE
) {
293 p
= (u32
*) _ALIGN((unsigned long)p
+ strlen(s
) + 1, 4);
295 printf("%*s%s {\n", depth
* shift
, "", s
);
301 if (tag
== OF_DT_END_NODE
) {
304 printf("%*s};\n", depth
* shift
, "");
308 if (tag
== OF_DT_NOP
) {
309 printf("%*s[NOP]\n", depth
* shift
, "");
313 if (tag
!= OF_DT_PROP
) {
314 fprintf(stderr
, "%*s ** Unknown tag 0x%08x at 0x%x\n",
315 depth
* shift
, "", tag
, --p
);
318 sz
= be32_to_cpu(*p
++);
319 s
= (const char *)p_strings
+ be32_to_cpu(*p
++);
321 p
= (const u32
*)_ALIGN((unsigned long)p
+ sz
, 4);
322 printf("%*s%s", depth
* shift
, "", s
);
328 void ft_backtrack_node(struct ft_cxt
*cxt
)
332 while (be32_to_cpu(*(u32
*) (cxt
->p
- i
)) != OF_DT_END_NODE
)
335 memmove (cxt
->p
- i
, cxt
->p
, cxt
->p_end
- cxt
->p
);
341 void *ft_get_prop(void *bphp
, const char *propname
, int *szp
)
343 struct boot_param_header
*bph
= bphp
;
345 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
346 uint32_t *p_strings
=
347 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
348 uint32_t version
= be32_to_cpu(bph
->version
);
354 static char path
[256], prop
[256];
359 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
361 if (tag
== OF_DT_BEGIN_NODE
) {
363 p
= (uint32_t *) _ALIGN((unsigned long)p
+ strlen(s
) +
370 if (tag
== OF_DT_END_NODE
) {
371 path
[strlen(path
) - 1] = '\0';
372 ss
= strrchr(path
, '/');
378 if (tag
== OF_DT_NOP
)
381 if (tag
!= OF_DT_PROP
)
384 sz
= be32_to_cpu(*p
++);
385 s
= (char *)p_strings
+ be32_to_cpu(*p
++);
386 if (version
< 0x10 && sz
>= 8)
387 p
= (uint32_t *) _ALIGN((unsigned long)p
, 8);
389 p
= (uint32_t *) _ALIGN((unsigned long)p
+ sz
, 4);
394 if (strcmp(prop
, propname
) == 0) {
403 /********************************************************************/
405 /* Function that returns a character from the environment */
406 extern uchar(*env_get_char
) (int);
408 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
410 #ifdef CONFIG_OF_HAS_BD_T
411 static const struct {
422 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
423 || defined(CONFIG_E500)
426 #if defined(CONFIG_MPC5xxx)
429 #if defined(CONFIG_MPC83XX)
432 #if defined(CONFIG_MPC8220)
450 #if defined(CONFIG_MPC5xxx)
458 void ft_setup(void *blob
, bd_t
* bd
, ulong initrd_start
, ulong initrd_end
)
464 #if defined(CONFIG_OF_HAS_UBOOT_ENV)
467 #if defined(CONFIG_OF_HAS_BD_T)
470 #if defined(CONFIG_OF_HAS_UBOOT_ENV) || defined(CONFIG_OF_HAS_BD_T)
472 static char tmpenv
[256];
475 /* disable OF tree; booting old kernel */
476 if (getenv("disable_of") != NULL
) {
477 memcpy(blob
, bd
, sizeof(*bd
));
482 printf ("recieved oftree\n");
486 ft_init_cxt(&cxt
, blob
);
488 if (initrd_start
&& initrd_end
)
489 ft_add_rsvmap(&cxt
, initrd_start
, initrd_end
- initrd_start
+ 1);
492 ft_backtrack_node(&cxt
);
494 #ifdef CONFIG_OF_HAS_UBOOT_ENV
495 ft_begin_node(&cxt
, "u-boot-env");
497 for (i
= 0; env_get_char(i
) != '\0'; i
= nxt
+ 1) {
498 char *s
, *lval
, *rval
;
500 for (nxt
= i
; env_get_char(nxt
) != '\0'; ++nxt
) ;
502 for (k
= i
; k
< nxt
&& s
< &tmpenv
[sizeof(tmpenv
) - 1]; ++k
)
503 *s
++ = env_get_char(k
);
506 s
= strchr(tmpenv
, '=');
512 ft_prop_str(&cxt
, lval
, rval
);
518 ft_begin_node(&cxt
, "chosen");
519 ft_prop_str(&cxt
, "name", "chosen");
521 ft_prop_str(&cxt
, "bootargs", getenv("bootargs"));
522 ft_prop_int(&cxt
, "linux,platform", 0x600); /* what is this? */
523 if (initrd_start
&& initrd_end
) {
524 ft_prop_int(&cxt
, "linux,initrd-start", initrd_start
);
525 ft_prop_int(&cxt
, "linux,initrd-end", initrd_end
);
527 #ifdef OF_STDOUT_PATH
528 ft_prop_str(&cxt
, "linux,stdout-path", OF_STDOUT_PATH
);
533 ft_end_node(&cxt
); /* end root */
536 ft_finalize_tree(&cxt
);
538 #ifdef CONFIG_OF_HAS_BD_T
539 /* paste the bd_t at the end of the flat tree */
541 be32_to_cpu(((struct boot_param_header
*)blob
)->totalsize
);
542 memcpy(end
, bd
, sizeof(*bd
));
547 #ifdef CONFIG_OF_HAS_BD_T
548 for (i
= 0; i
< sizeof(bd_map
)/sizeof(bd_map
[0]); i
++) {
551 sprintf(tmpenv
, "/bd_t/%s", bd_map
[i
].name
);
552 v
= *(uint32_t *)((char *)bd
+ bd_map
[i
].offset
);
554 p
= ft_get_prop(blob
, tmpenv
, &len
);
559 p
= ft_get_prop(blob
, "/bd_t/enetaddr", &len
);
561 memcpy(p
, bd
->bi_enetaddr
, 6);
563 p
= ft_get_prop(blob
, "/bd_t/ethspeed", &len
);
565 *p
= cpu_to_be32((uint32_t) bd
->bi_ethspeed
);
568 clock
= bd
->bi_intfreq
;
569 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/clock-frequency", &len
);
571 *p
= cpu_to_be32(clock
);
575 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/timebase-frequency", &len
);
577 *p
= cpu_to_be32(clock
);
579 #endif /* __powerpc__ */
581 #ifdef CONFIG_OF_BOARD_SETUP
582 ft_board_setup(blob
, bd
);
585 /* in case the size changed in the platform code */
586 ft_finalize_tree(&cxt
);
589 printf("final OF-tree\n");
594 static int oftree_handler_cmdline_parse(struct image_data
*data
, int opt
,
599 printf("using oftree %s\n", optarg
);
600 data
->oftree
= optarg
;
607 static struct image_handler of_handler
= {
608 .cmdline_options
= "o:",
609 .cmdline_parse
= oftree_handler_cmdline_parse
,
610 .help_string
= " -o <oftree> use oftree",
613 static int oftree_register_image_handler(void)
615 return register_image_handler(&of_handler
);
618 late_initcall(oftree_register_image_handler
);