]>
git.ipfire.org Git - people/ms/u-boot.git/blob - common/ft_build.c
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(p
, name
) == 0)
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
= (char*)bph
+ bph
->off_dt_struct
;
147 cxt
->p_end
= (char *)bph
+ bph
->totalsize
;
148 cxt
->p
= (char *)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
)) {
222 printf(" = \"%s\"", (char *)data
);
228 printf(" = <%02x>", (*(u8
*) data
) & 0xff);
230 case 2: /* half-word */
231 printf(" = <%04x>", be16_to_cpu(*(u16
*) data
) & 0xffff);
234 printf(" = <%x>", be32_to_cpu(*(u32
*) data
) & 0xffffffffU
);
236 case 8: /* double-word */
237 printf(" = <%qx>", be64_to_cpu(*(uint64_t *) data
));
239 default: /* anything else... hexdump */
241 for (i
= 0, s
= data
; i
< len
; i
++)
242 printf("%02x%s", s
[i
], i
< len
- 1 ? " " : "");
249 void ft_dump_blob(const void *bphp
)
251 const struct boot_param_header
*bph
= bphp
;
252 const uint64_t *p_rsvmap
= (const uint64_t *)
253 ((const char *)bph
+ be32_to_cpu(bph
->off_mem_rsvmap
));
254 const u32
*p_struct
= (const u32
*)
255 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
256 const u32
*p_strings
= (const u32
*)
257 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
261 int depth
, sz
, shift
;
265 if (be32_to_cpu(bph
->magic
) != OF_DT_HEADER
) {
274 addr
= be64_to_cpu(p_rsvmap
[i
* 2]);
275 size
= be64_to_cpu(p_rsvmap
[i
* 2 + 1]);
276 if (addr
== 0 && size
== 0)
279 printf("/memreserve/ %qx %qx;\n", addr
, size
);
283 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
285 /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
287 if (tag
== OF_DT_BEGIN_NODE
) {
289 p
= (u32
*) _ALIGN((unsigned long)p
+ strlen(s
) + 1, 4);
291 printf("%*s%s {\n", depth
* shift
, "", s
);
297 if (tag
== OF_DT_END_NODE
) {
300 printf("%*s};\n", depth
* shift
, "");
304 if (tag
== OF_DT_NOP
) {
305 printf("%*s[NOP]\n", depth
* shift
, "");
309 if (tag
!= OF_DT_PROP
) {
310 fprintf(stderr
, "%*s ** Unknown tag 0x%08x at 0x%x\n",
311 depth
* shift
, "", tag
, --p
);
314 sz
= be32_to_cpu(*p
++);
315 s
= (const char *)p_strings
+ be32_to_cpu(*p
++);
317 p
= (const u32
*)_ALIGN((unsigned long)p
+ sz
, 4);
318 printf("%*s%s", depth
* shift
, "", s
);
324 void ft_backtrack_node(struct ft_cxt
*cxt
)
328 while (be32_to_cpu(*(u32
*) (cxt
->p
- i
)) != OF_DT_END_NODE
)
331 memmove (cxt
->p
- i
, cxt
->p
, cxt
->p_end
- cxt
->p
);
337 void *ft_get_prop(void *bphp
, const char *propname
, int *szp
)
339 struct boot_param_header
*bph
= bphp
;
341 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
342 uint32_t *p_strings
=
343 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
344 uint32_t version
= be32_to_cpu(bph
->version
);
350 static char path
[256], prop
[256];
355 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
357 if (tag
== OF_DT_BEGIN_NODE
) {
359 p
= (uint32_t *) _ALIGN((unsigned long)p
+ strlen(s
) +
366 if (tag
== OF_DT_END_NODE
) {
367 path
[strlen(path
) - 1] = '\0';
368 ss
= strrchr(path
, '/');
374 if (tag
== OF_DT_NOP
)
377 if (tag
!= OF_DT_PROP
)
380 sz
= be32_to_cpu(*p
++);
381 s
= (char *)p_strings
+ be32_to_cpu(*p
++);
382 if (version
< 0x10 && sz
>= 8)
383 p
= (uint32_t *) _ALIGN((unsigned long)p
, 8);
385 p
= (uint32_t *) _ALIGN((unsigned long)p
+ sz
, 4);
390 if (strcmp(prop
, propname
) == 0) {
399 /********************************************************************/
401 /* Function that returns a character from the environment */
402 extern uchar(*env_get_char
) (int);
404 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
406 #ifdef CONFIG_OF_HAS_BD_T
407 static const struct {
418 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
419 || defined(CONFIG_E500)
422 #if defined(CONFIG_MPC5xxx)
425 #if defined(CONFIG_MPC83XX)
428 #if defined(CONFIG_MPC8220)
446 #if defined(CONFIG_MPC5xxx)
454 void ft_setup(void *blob
, bd_t
* bd
, ulong initrd_start
, ulong initrd_end
)
460 #if defined(CONFIG_OF_HAS_UBOOT_ENV)
463 #if defined(CONFIG_OF_HAS_BD_T)
466 #if defined(CONFIG_OF_HAS_UBOOT_ENV) || defined(CONFIG_OF_HAS_BD_T)
468 static char tmpenv
[256];
471 /* disable OF tree; booting old kernel */
472 if (getenv("disable_of") != NULL
) {
473 memcpy(blob
, bd
, sizeof(*bd
));
478 printf ("recieved oftree\n");
482 ft_init_cxt(&cxt
, blob
);
484 if (initrd_start
&& initrd_end
)
485 ft_add_rsvmap(&cxt
, initrd_start
, initrd_end
- initrd_start
+ 1);
488 ft_backtrack_node(&cxt
);
490 #ifdef CONFIG_OF_HAS_UBOOT_ENV
491 ft_begin_node(&cxt
, "u-boot-env");
493 for (i
= 0; env_get_char(i
) != '\0'; i
= nxt
+ 1) {
494 char *s
, *lval
, *rval
;
496 for (nxt
= i
; env_get_char(nxt
) != '\0'; ++nxt
) ;
498 for (k
= i
; k
< nxt
&& s
< &tmpenv
[sizeof(tmpenv
) - 1]; ++k
)
499 *s
++ = env_get_char(k
);
502 s
= strchr(tmpenv
, '=');
508 ft_prop_str(&cxt
, lval
, rval
);
514 ft_begin_node(&cxt
, "chosen");
515 ft_prop_str(&cxt
, "name", "chosen");
517 ft_prop_str(&cxt
, "bootargs", getenv("bootargs"));
518 ft_prop_int(&cxt
, "linux,platform", 0x600); /* what is this? */
519 if (initrd_start
&& initrd_end
) {
520 ft_prop_int(&cxt
, "linux,initrd-start", initrd_start
);
521 ft_prop_int(&cxt
, "linux,initrd-end", initrd_end
);
523 #ifdef OF_STDOUT_PATH
524 ft_prop_str(&cxt
, "linux,stdout-path", OF_STDOUT_PATH
);
529 ft_end_node(&cxt
); /* end root */
532 ft_finalize_tree(&cxt
);
534 #ifdef CONFIG_OF_HAS_BD_T
535 /* paste the bd_t at the end of the flat tree */
537 be32_to_cpu(((struct boot_param_header
*)blob
)->totalsize
);
538 memcpy(end
, bd
, sizeof(*bd
));
543 #ifdef CONFIG_OF_HAS_BD_T
544 for (i
= 0; i
< sizeof(bd_map
)/sizeof(bd_map
[0]); i
++) {
547 sprintf(tmpenv
, "/bd_t/%s", bd_map
[i
].name
);
548 v
= *(uint32_t *)((char *)bd
+ bd_map
[i
].offset
);
550 p
= ft_get_prop(blob
, tmpenv
, &len
);
555 p
= ft_get_prop(blob
, "/bd_t/enetaddr", &len
);
557 memcpy(p
, bd
->bi_enetaddr
, 6);
559 p
= ft_get_prop(blob
, "/bd_t/ethspeed", &len
);
561 *p
= cpu_to_be32((uint32_t) bd
->bi_ethspeed
);
564 clock
= bd
->bi_intfreq
;
565 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/clock-frequency", &len
);
567 *p
= cpu_to_be32(clock
);
571 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/timebase-frequency", &len
);
573 *p
= cpu_to_be32(clock
);
575 #endif /* __powerpc__ */
577 #ifdef CONFIG_OF_BOARD_SETUP
578 ft_board_setup(blob
, bd
);
581 /* in case the size changed in the platform code */
582 ft_finalize_tree(&cxt
);
585 printf("final OF-tree\n");