[U-Boot-Users] [PATCH] Add Flat OF tree support.

Hi all.
As you well know, as part of the ongoing cleanup of the linux trees regarding PPC, it has been decreed that the preferred way to pass bootloader information shall be the flat OF tree.
http://ozlabs.org/pipermail/linuxppc-dev/2005-August/019408.html http://ozlabs.org/pipermail/linuxppc-dev/2005-August/019362.html
The following patch (broken in two parts), implements just that.
Please be aware that in order to test it, you'll need a fairly recent dtc tool, which is available by git at
rsync://ozlabs.org/dtc/dtc.git
The xxd binary dumper is needed too which I got from
ftp://ftp.uni-erlangen.de/pub/utilities/etc/xxd-1.10.tar.gz
Linux patches will follow...
Awaiting comments.
Regards
Pantelis
P.S. Sorry for cross-posting, but it seems to be appropriate at this time.
diff --git a/common/Makefile b/common/Makefile --- a/common/Makefile +++ b/common/Makefile @@ -51,7 +51,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug. memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o \ usb.o usb_kbd.o usb_storage.o \ - virtex2.o xilinx.o + virtex2.o xilinx.o ft_build.o
OBJS = $(AOBJS) $(COBJS)
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -34,6 +34,10 @@ #include <environment.h> #include <asm/byteorder.h>
+#ifdef CONFIG_OF_FLAT_TREE +#include <ft_build.h> +#endif + /*cmd_boot.c*/ extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
@@ -487,6 +491,9 @@ fixup_silent_linux () } #endif /* CONFIG_SILENT_CONSOLE */
+extern const unsigned char oftree_dtb[]; +extern const unsigned int oftree_dtb_len; + #ifdef CONFIG_PPC static void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, @@ -509,6 +516,9 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl bd_t *kbd; void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); image_header_t *hdr = &header; +#ifdef CONFIG_OF_FLAT_TREE + char *of_flat_tree; +#endif
if ((s = getenv ("initrd_high")) != NULL) { /* a value of "no" or a similar string will act like 0, @@ -773,16 +783,24 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl initrd_start = 0; initrd_end = 0; } - +#ifdef CONFIG_OF_FLAT_TREE + if (initrd_start == 0) + of_flat_tree = (char *)(((ulong)kbd - OF_FLAT_TREE_MAX_SIZE) & ~0xF); + else + of_flat_tree = (char *)((initrd_start - OF_FLAT_TREE_MAX_SIZE) & ~0xF); +#endif
debug ("## Transferring control to Linux (at address %08lx) ...\n", (ulong)kernel);
SHOW_BOOT_PROGRESS (15);
+#ifndef CONFIG_OF_FLAT_TREE + #if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) unlock_ram_in_cache(); #endif + /* * Linux Kernel Parameters: * r3: ptr to board info data @@ -792,6 +810,25 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl * r7: End of command line string */ (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); +#else + + ft_setup(of_flat_tree, OF_FLAT_TREE_MAX_SIZE, kbd); + /* ft_dump_blob(of_flat_tree); */ + +#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) + unlock_ram_in_cache(); +#endif + /* + * Linux Kernel Parameters: + * r3: ptr to board info data + * r4: initrd_start or 0 if no initrd + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + */ + (*kernel) ((bd_t *)of_flat_tree, initrd_start, initrd_end, cmd_start, cmd_end); + +#endif } #endif /* CONFIG_PPC */
diff --git a/common/ft_build.c b/common/ft_build.c new file mode 100644 --- /dev/null +++ b/common/ft_build.c @@ -0,0 +1,751 @@ +/* + * OF flat tree builder + */ + +#include <common.h> +#include <malloc.h> +#include <environment.h> + +#include <asm/errno.h> + +#include <ft_build.h> + +#ifdef CONFIG_OF_FLAT_TREE + +/* align addr on a size boundary - adjust address up if needed -- Cort */ +#define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1))) + +static void ft_put_word(struct ft_cxt *cxt, u32 v) +{ + if (cxt->overflow) /* do nothing */ + return; + + /* check for overflow */ + if (cxt->p + 4 > cxt->pstr) { + cxt->overflow = 1; + return; + } + + *(u32 *) cxt->p = cpu_to_be32(v); + cxt->p += 4; +} + +static inline void ft_put_bin(struct ft_cxt *cxt, const void *data, int sz) +{ + u8 *p; + + if (cxt->overflow) /* do nothing */ + return; + + /* next pointer pos */ + p = (u8 *) _ALIGN((unsigned long)cxt->p + sz, 4); + + /* check for overflow */ + if (p > cxt->pstr) { + cxt->overflow = 1; + return; + } + + memcpy(cxt->p, data, sz); + if ((sz & 3) != 0) + memset(cxt->p + sz, 0, 4 - (sz & 3)); + cxt->p = p; +} + +void ft_begin_node(struct ft_cxt *cxt, const char *name) +{ + ft_put_word(cxt, OF_DT_BEGIN_NODE); + ft_put_bin(cxt, name, strlen(name) + 1); +} + +void ft_end_node(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_END_NODE); +} + +void ft_nop(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_NOP); +} + +static int lookup_string(struct ft_cxt *cxt, const char *name) +{ + u8 *p; + + p = cxt->pstr; + while (p < cxt->pstr_begin) { + if (strcmp(p, name) == 0) + return p - cxt->p_begin; + p += strlen(p) + 1; + } + + return -1; +} + +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz) +{ + int len, off; + + if (cxt->overflow) + return; + + len = strlen(name) + 1; + + off = lookup_string(cxt, name); + if (off == -1) { + /* check if we have space */ + if (cxt->p + 12 + sz + len > cxt->pstr) { + cxt->overflow = 1; + return; + } + + cxt->pstr -= len; + memcpy(cxt->pstr, name, len); + off = cxt->pstr - cxt->p_begin; + } + + /* now put offset from beginning of *STRUCTURE* */ + /* will be fixed up at the end */ + ft_put_word(cxt, OF_DT_PROP); + ft_put_word(cxt, sz); + ft_put_word(cxt, off); + ft_put_bin(cxt, data, sz); +} + +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str) +{ + ft_prop(cxt, name, str, strlen(str) + 1); +} + +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val) +{ + u32 v = cpu_to_be32((u32) val); + + ft_prop(cxt, name, &v, 4); +} + +/* start construction of the flat OF tree */ +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size) +{ + struct boot_param_header *bph = blob; + u32 off; + + /* clear the cxt */ + memset(cxt, 0, sizeof(*cxt)); + + cxt->bph = bph; + cxt->max_size = max_size; + + /* zero everything in the header area */ + memset(bph, 0, sizeof(*bph)); + + bph->magic = cpu_to_be32(OF_DT_HEADER); + bph->version = cpu_to_be32(0x10); + bph->last_comp_version = cpu_to_be32(0x10); + + /* start pointers */ + cxt->pres_begin = (u8 *) _ALIGN((unsigned long)(bph + 1), 8); + cxt->pres = cxt->pres_begin; + + off = (unsigned long)cxt->pres_begin - (unsigned long)bph; + bph->off_mem_rsvmap = cpu_to_be32(off); + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +/* add a reserver physical area to the rsvmap */ +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size) +{ + ((u64 *) cxt->pres)[0] = cpu_to_be64(physaddr); /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = cpu_to_be64(size); + + cxt->pres += 18; /* advance */ + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + /* keep track of size */ + cxt->res_size = cxt->pres + 16 - cxt->pres_begin; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +void ft_begin_tree(struct ft_cxt *cxt) +{ + cxt->p_begin = cxt->p_anchor; + cxt->pstr_begin = (char *)cxt->bph + cxt->max_size; /* point at the end */ + + cxt->p = cxt->p_begin; + cxt->pstr = cxt->pstr_begin; +} + +int ft_end_tree(struct ft_cxt *cxt) +{ + struct boot_param_header *bph = cxt->bph; + int off, sz, sz1; + u32 tag, v; + u8 *p; + + ft_put_word(cxt, OF_DT_END); + + if (cxt->overflow) + return -ENOMEM; + + /* size of the areas */ + cxt->struct_size = cxt->p - cxt->p_begin; + cxt->strings_size = cxt->pstr_begin - cxt->pstr; + + /* the offset we must move */ + off = (cxt->pstr_begin - cxt->p_begin) - cxt->strings_size; + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + + /* move the whole string area */ + memmove(cxt->pstr_begin, cxt->pstr, cxt->strings_size); + + /* now perform the fixup of the strings */ + p = cxt->p_begin; + while ((tag = be32_to_cpu(*(u32 *) p)) != OF_DT_END) { + p += 4; + + if (tag == OF_DT_BEGIN_NODE) { + p = (u8 *) _ALIGN((unsigned long)p + strlen(p) + 1, 4); + continue; + } + + if (tag == OF_DT_END_NODE || tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + return -EINVAL; + + sz = be32_to_cpu(*(u32 *) p); + p += 4; + + v = be32_to_cpu(*(u32 *) p); + v -= off; + *(u32 *) p = cpu_to_be32(v); /* move down */ + p += 4; + + p = (u8 *) _ALIGN((unsigned long)p + sz, 4); + } + + /* fix sizes */ + p = (char *)cxt->bph; + sz = (cxt->pstr_begin + cxt->strings_size) - p; + sz1 = _ALIGN(sz, 16); /* align at 16 bytes */ + if (sz != sz1) + memset(p + sz, 0, sz1 - sz); + bph->totalsize = cpu_to_be32(sz1); + bph->off_dt_struct = cpu_to_be32(cxt->p_begin - p); + bph->off_dt_strings = cpu_to_be32(cxt->pstr_begin - p); + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + cxt->pstr = cxt->pstr_begin + cxt->strings_size; + + return 0; +} + +/**********************************************************************/ + +static inline int isprint(int c) +{ + return c >= 0x20 && c <= 0x7e; +} + +static int is_printable_string(const void *data, int len) +{ + const char *s = data; + const char *ss; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + ss = s; + while (*s && isprint(*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || (s + 1 - ss) < len) + return 0; + + return 1; +} + +static void print_data(const void *data, int len) +{ + int i; + const u8 *s; + + /* no data, don't print */ + if (len == 0) + return; + + if (is_printable_string(data, len)) { + printf(" = "%s"", (char *)data); + return; + } + + switch (len) { + case 1: /* byte */ + printf(" = <0x%02x>", (*(u8 *) data) & 0xff); + break; + case 2: /* half-word */ + printf(" = <0x%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); + break; + case 4: /* word */ + printf(" = <0x%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); + break; + case 8: /* double-word */ + printf(" = <0x%16llx>", be64_to_cpu(*(uint64_t *) data)); + break; + default: /* anything else... hexdump */ + printf(" = ["); + for (i = 0, s = data; i < len; i++) + printf("%02x%s", s[i], i < len - 1 ? " " : ""); + printf("]"); + + break; + } +} + +void ft_dump_blob(const void *bphp) +{ + const struct boot_param_header *bph = bphp; + const uint64_t *p_rsvmap = (const uint64_t *) + ((const char *)bph + be32_to_cpu(bph->off_mem_rsvmap)); + const u32 *p_struct = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_struct)); + const u32 *p_strings = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag; + const u32 *p; + const char *s, *t; + int depth, sz, shift; + int i; + uint64_t addr, size; + + depth = 0; + shift = 4; + + for (i = 0;; i++) { + addr = be64_to_cpu(p_rsvmap[i * 2]); + size = be64_to_cpu(p_rsvmap[i * 2 + 1]); + if (addr == 0 && size == 0) + break; + + printf("/memreserve/ 0x%llx 0x%llx;\n", addr, size); + } + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (const char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + printf("%*s%s {\n", depth * shift, "", s); + + depth++; + continue; + } + + if (tag == OF_DT_END_NODE) { + depth--; + + printf("%*s};\n", depth * shift, ""); + continue; + } + + if (tag == OF_DT_NOP) { + printf("%*s[NOP]\n", depth * shift, ""); + continue; + } + + if (tag != OF_DT_PROP) { + fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", + depth * shift, "", tag); + break; + } + sz = be32_to_cpu(*p++); + s = (const char *)p_strings + be32_to_cpu(*p++); + t = (const char *)p; + p = (const u32 *)_ALIGN((unsigned long)p + sz, 4); + printf("%*s%s", depth * shift, "", s); + print_data(t, sz); + printf(";\n"); + } +} + +void ft_backtrack_node(struct ft_cxt *cxt) +{ + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; +} + +/* note that the root node of the blob is "peeled" off */ +void ft_merge_blob(struct ft_cxt *cxt, void *blob) +{ + struct boot_param_header *bph = (struct boot_param_header *)blob; + u32 *p_struct = (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + u32 *p_strings = + (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag, *p; + char *s, *t; + int depth, sz; + + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; + + depth = 0; + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d) - %d\n", tag, p - p_struct, depth); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + if (depth++ > 0) + ft_begin_node(cxt, s); + + continue; + } + + if (tag == OF_DT_END_NODE) { + ft_end_node(cxt); + if (--depth == 0) + break; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + t = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + sz, 4); + + ft_prop(cxt, s, t, sz); + } +} + +void *ft_get_prop(void *bphp, const char *propname, int *szp) +{ + struct boot_param_header *bph = bphp; + uint32_t *p_struct = + (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + uint32_t *p_strings = + (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + uint32_t version = be32_to_cpu(bph->version); + uint32_t tag; + uint32_t *p; + char *s, *t; + char *ss; + int sz; + static char path[256], prop[256]; + + path[0] = '\0'; + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (uint32_t *) _ALIGN((unsigned long)p + strlen(s) + + 1, 4); + strcat(path, s); + strcat(path, "/"); + continue; + } + + if (tag == OF_DT_END_NODE) { + path[strlen(path) - 1] = '\0'; + ss = strrchr(path, '/'); + if (ss != NULL) + ss[1] = '\0'; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + if (version < 0x10 && sz >= 8) + p = (uint32_t *) _ALIGN((unsigned long)p, 8); + t = (char *)p; + p = (uint32_t *) _ALIGN((unsigned long)p + sz, 4); + + strcpy(prop, path); + strcat(prop, s); + + if (strcmp(prop, propname) == 0) { + *szp = sz; + return t; + } + } + + return NULL; +} + +/********************************************************************/ + +extern unsigned char oftree_dtb[]; +extern unsigned int oftree_dtb_len; + +/* Function that returns a character from the environment */ +extern uchar(*env_get_char) (int); + +void ft_setup(void *blob, int size, bd_t * bd) +{ + DECLARE_GLOBAL_DATA_PTR; + u8 *end; + u32 *p; + int len; + struct ft_cxt cxt; + int i, k, nxt; + static char tmpenv[256]; + char *s, *lval, *rval; + ulong clock; + + ft_begin(&cxt, blob, size); + + /* fs_add_rsvmap not used */ + + ft_begin_tree(&cxt); + + ft_begin_node(&cxt, ""); + + ft_end_node(&cxt); + + /* copy RO tree */ + ft_merge_blob(&cxt, oftree_dtb); + + /* back into root */ + ft_backtrack_node(&cxt); + + ft_begin_node(&cxt, "u-boot-env"); + + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) ; + s = tmpenv; + for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) + *s++ = env_get_char(k); + *s++ = '\0'; + lval = tmpenv; + s = strchr(tmpenv, '='); + if (s != NULL) { + *s++ = '\0'; + rval = s; + } else + continue; + ft_prop_str(&cxt, lval, rval); + } + + ft_end_node(&cxt); + + ft_begin_node(&cxt, "chosen"); + + ft_prop_str(&cxt, "name", "chosen"); + ft_prop_str(&cxt, "bootargs", getenv("bootargs")); + ft_prop_int(&cxt, "linux,platform", 0x600); /* what is this? */ + + ft_end_node(&cxt); + + ft_end_node(&cxt); /* end root */ + + ft_end_tree(&cxt); + + /* + printf("merged OF-tree\n"); + ft_dump_blob(blob); + */ + + /* paste the bd_t at the end of the flat tree */ + end = (char *)blob + + be32_to_cpu(((struct boot_param_header *)blob)->totalsize); + memcpy(end, bd, sizeof(*bd)); + +#ifdef __powerpc__ + + p = ft_get_prop(blob, "/u-boot-bd_t/memstart", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_memstart); + + p = ft_get_prop(blob, "/u-boot-bd_t/memsize", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_memsize); + + p = ft_get_prop(blob, "/u-boot-bd_t/flashstart", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_flashstart); + + p = ft_get_prop(blob, "/u-boot-bd_t/flashsize", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_flashsize); + + p = ft_get_prop(blob, "/u-boot-bd_t/flashoffset", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_flashoffset); + + p = ft_get_prop(blob, "/u-boot-bd_t/sramstart", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_sramstart); + + p = ft_get_prop(blob, "/u-boot-bd_t/sramsize", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_sramsize); + +#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ + || defined(CONFIG_E500) + p = ft_get_prop(blob, "/u-boot-bd_t/immr_base", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_immr_base); +#endif + +#if defined(CONFIG_MPC5xxx) + p = ft_get_prop(blob, "/u-boot-bd_t/mbar_base", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_mbar_base); +#endif + +#if defined(CONFIG_MPC83XX) + p = ft_get_prop(blob, "/u-boot-bd_t/immrbar", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_immrbar); +#endif + +#if defined(CONFIG_MPC8220) + p = ft_get_prop(blob, "/u-boot-bd_t/mbar_base", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_mbar_base); + + p = ft_get_prop(blob, "/u-boot-bd_t/inpfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_nipfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/pcifreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_pcifreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/pevfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_pevfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/flbfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_flbfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/vcofreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_vcofreq); +#endif + + p = ft_get_prop(blob, "/u-boot-bd_t/bootflags", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_bootflags); + + p = ft_get_prop(blob, "/u-boot-bd_t/ip_addr", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_ip_addr); + + p = ft_get_prop(blob, "/u-boot-bd_t/enetaddr", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); + + p = ft_get_prop(blob, "/u-boot-bd_t/ethspeed", &len); + if (p != NULL) + *p = cpu_to_be32((uint32_t) bd->bi_ethspeed); + + p = ft_get_prop(blob, "/u-boot-bd_t/intfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_intfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/busfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_busfreq); + +#ifdef CONFIG_CPM2 + + p = ft_get_prop(blob, "/u-boot-bd_t/cpmfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_cpmfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/brgfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_brgfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/sccfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_sccfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/vco", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_vco); +#endif + +#if defined(CONFIG_MPC5xxx) + + p = ft_get_prop(blob, "/u-boot-bd_t/ipbfreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_ipbfreq); + + p = ft_get_prop(blob, "/u-boot-bd_t/pcifreq", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_pcifreq); +#endif + + p = ft_get_prop(blob, "/u-boot-bd_t/baudrate", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_baudrate); + +#if defined(CONFIG_8xx) + clock = gd->cpu_clk; +#elif defined(CONFIG_8260) + clock = gd->brg_clk; +#else + clock = 0; +#endif + p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(clock); + + p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(clock / 4); /* XXX I'm just guessing */ + +#endif /* __powerpc__ */ + + /* + printf("final OF-tree\n"); + ft_dump_blob(blob); + */ + +} + +#endif diff --git a/include/ft_build.h b/include/ft_build.h new file mode 100644 --- /dev/null +++ b/include/ft_build.h @@ -0,0 +1,66 @@ +/* + * OF Flat tree builder + * + */ + +#ifndef FT_BUILD_H +#define FT_BUILD_H + +#include <linux/types.h> +#include <asm/u-boot.h> + +/* Definitions used by the flattened device tree */ +#define OF_DT_HEADER 0xd00dfeed /* marker */ +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ +#define OF_DT_END_NODE 0x2 /* End node */ +#define OF_DT_PROP 0x3 /* Property: name off, size, + * content */ +#define OF_DT_NOP 0x4 /* nop */ +#define OF_DT_END 0x9 + +#define OF_DT_VERSION 0x10 + +struct boot_param_header { + u32 magic; /* magic word OF_DT_HEADER */ + u32 totalsize; /* total size of DT block */ + u32 off_dt_struct; /* offset to structure */ + u32 off_dt_strings; /* offset to strings */ + u32 off_mem_rsvmap; /* offset to memory reserve map */ + u32 version; /* format version */ + u32 last_comp_version; /* last compatible version */ + /* version 2 fields below */ + u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + u32 dt_strings_size; /* size of the DT strings block */ +}; + +struct ft_cxt { + struct boot_param_header *bph; + int max_size; /* maximum size of tree */ + int overflow; /* set when this happens */ + u8 *p, *pstr, *pres; /* running pointers */ + u8 *p_begin, *pstr_begin, *pres_begin; /* starting pointers */ + u8 *p_anchor; /* start of constructed area */ + int struct_size, strings_size, res_size; +}; + +void ft_begin_node(struct ft_cxt *cxt, const char *name); +void ft_end_node(struct ft_cxt *cxt); + +void ft_begin_tree(struct ft_cxt *cxt); +int ft_end_tree(struct ft_cxt *cxt); + +void ft_nop(struct ft_cxt *cxt); +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz); +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str); +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val); +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size); +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); + +void ft_setup(void *blob, int size, bd_t * bd); + +void ft_dump_blob(const void *bphp); +void ft_merge_blob(struct ft_cxt *cxt, void *blob); +void *ft_get_prop(void *bphp, const char *propname, int *szp); + +#endif
diff --git a/board/stxxtc/Makefile b/board/stxxtc/Makefile --- a/board/stxxtc/Makefile +++ b/board/stxxtc/Makefile @@ -25,11 +25,19 @@ include $(TOPDIR)/config.mk
LIB = lib$(BOARD).a
-OBJS = $(BOARD).o +OBJS = $(BOARD).o oftree.o
$(LIB): .depend $(OBJS) $(AR) crv $@ $(OBJS)
+%.dtb: %.dts + dtc -f -V 0x10 -I dts -O dtb $< >$@ + +%.c: %.dtb + xxd -i $< \ + | sed -e "s/^unsigned char/const unsigned char/g" \ + | sed -e "s/^unsigned int/const unsigned int/g" > $@ + #########################################################################
.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) @@ -38,3 +46,4 @@ $(LIB): .depend $(OBJS) sinclude .depend
######################################################################### + diff --git a/board/stxxtc/oftree.dts b/board/stxxtc/oftree.dts new file mode 100644 --- /dev/null +++ b/board/stxxtc/oftree.dts @@ -0,0 +1,52 @@ +/ { + model = "STXXTC V1"; + compatible = "STXXTC"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + linux,phandle = <1>; + #address-cells = <1>; + #size-cells = <0>; + PowerPC,MPC870@0 { + linux,phandle = <3>; + name = "PowerPC,MPC870"; + device_type = "cpu"; + reg = <0>; + clock-frequency = <0>; /* place-holder for runtime fillup */ + timebase-frequency = <0>; /* dido */ + linux,boot-cpu; + i-cache-size = <2000>; + d-cache-size = <2000>; + 32-bit; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <00000000 00000000 00000000 20000000>; + }; + + /* copy of the bd_t information (place-holders) */ + u-boot-bd_t { + memstart = <0>; + memsize = <0>; + flashstart = <0>; + flashsize = <0>; + flashoffset = <0>; + sramstart = <0>; + sramsize = <0>; + + immr_base = <0>; + + bootflags = <0>; + ip_addr = <0>; + enetaddr = [ 00 00 00 00 00 00 ]; + ethspeed = <0>; + intfreq = <0>; + busfreq = <0>; + + baudrate = <0>; + }; + +}; diff --git a/board/stxxtc/stxxtc.c b/board/stxxtc/stxxtc.c --- a/board/stxxtc/stxxtc.c +++ b/board/stxxtc/stxxtc.c @@ -38,6 +38,13 @@ #include <watchdog.h> #endif
+#include <ft_build.h> + +/****************************************************************/ + +extern const unsigned char oftree_dtb[]; +extern const unsigned int oftree_dtb_len; + /****************************************************************/
/* some sane bit macros */ diff --git a/include/configs/stxxtc.h b/include/configs/stxxtc.h --- a/include/configs/stxxtc.h +++ b/include/configs/stxxtc.h @@ -574,19 +574,14 @@ typedef unsigned int led_id_t; #define CONFIG_CRC32_VERIFY 1 #define CONFIG_HUSH_OLD_PARSER_COMPATIBLE 1
-/* Note: change below for your network setting!!! - * This was done just to facilitate manufacturing test and configuration. - */ -#define CONFIG_ETHADDR 00:e0:0c:07:9b:8a +/*****************************************************************************/
-#define CONFIG_SERVERIP 192.168.08.1 -#define CONFIG_IPADDR 192.168.08.85 -#define CONFIG_GATEWAYIP 192.168.08.1 -#define CONFIG_NETMASK 255.255.255.0 -#define CONFIG_HOSTNAME stx_xtc -#define CONFIG_ROOTPATH /xtcroot -#define CONFIG_BOOTFILE uImage -#define CONFIG_LOADADDR 0x1000000 +/* pass open firmware flat tree */ +#define CONFIG_OF_FLAT_TREE 1
+/* maximum size of the flat tree (8K) */ +#define OF_FLAT_TREE_MAX_SIZE 8192 + +#define OF_CPU "PowerPC,MPC870@0"
#endif /* __CONFIG_H */

In message 200509021814.08001.pantelis.antoniou@gmail.com you wrote:
As you well know, as part of the ongoing cleanup of the linux trees regarding PPC, it has been decreed that the preferred way to pass bootloader information shall be the flat OF tree.
Hear, hear!
The following patch (broken in two parts), implements just that.
No, it does not. It does more than this on one hand, and less than reqired on the other.
Please clean up and resubmit:
diff --git a/common/Makefile b/common/Makefile --- a/common/Makefile +++ b/common/Makefile @@ -51,7 +51,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug. memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o \ usb.o usb_kbd.o usb_storage.o \
virtex2.o xilinx.o
virtex2.o xilinx.o ft_build.o
Lists shall be kept sorted. Don't be lazy and just append at the end, please.
--- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c
...
- /*
* Linux Kernel Parameters:
* r3: ptr to board info data
* r4: initrd_start or 0 if no initrd
* r5: initrd_end - unused if r4 is 0
* r6: Start of command line string
* r7: End of command line string
*/
- (*kernel) ((bd_t *)of_flat_tree, initrd_start, initrd_end, cmd_start, cmd_end);
Is it board info data or an OF tree? I think the comment needs to be adjusted to match the code.
diff --git a/common/ft_build.c b/common/ft_build.c new file mode 100644 --- /dev/null +++ b/common/ft_build.c
...
- /* paste the bd_t at the end of the flat tree */
- end = (char *)blob +
be32_to_cpu(((struct boot_param_header *)blob)->totalsize);
- memcpy(end, bd, sizeof(*bd));
+#ifdef __powerpc__
I understand that *all* of this is PPC specific, so why do you #ifdef just this part? IMHO all of this should disappear for all non-PPC versions?
- p = ft_get_prop(blob, "/u-boot-bd_t/memstart", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/memsize", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/flashstart", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/flashsize", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/flashoffset", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/sramstart", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/sramsize", &len);
...
That's alot or repeated string constants, which just waste memory in the data segment. Any way for a leaner implementation?
While we are at it: did you check how much this patch adds to the memory footprint?
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/mbar_base", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_mbar_base);
+#endif
...
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/ipbfreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_ipbfreq);
- p = ft_get_prop(blob, "/u-boot-bd_t/pcifreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_pcifreq);
+#endif
Maybe you can sort these things to minimize the groups of #ifdef's needed?
+#if defined(CONFIG_8xx)
- clock = gd->cpu_clk;
+#elif defined(CONFIG_8260)
- clock = gd->brg_clk;
+#else
- clock = 0;
+#endif
- p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len);
- if (p != NULL)
*p = cpu_to_be32(clock);
clock = 0 for anything but 8xx and 8260???
- p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len);
- if (p != NULL)
*p = cpu_to_be32(clock / 4); /* XXX I'm just guessing */
... and probably wrong?
There is no CHANGELOG entry.
Rejected.
Content-Type: text/plain; charset="us-ascii"; name="of-uboot-stxxtc.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="of-uboot-stxxtc.patch"
There is no CHANGELOG entry.
Rejected.
Best regards,
Wolfgang Denk

On Sunday 04 September 2005 02:08, Wolfgang Denk wrote:
In message 200509021814.08001.pantelis.antoniou@gmail.com you wrote:
As you well know, as part of the ongoing cleanup of the linux trees regarding PPC, it has been decreed that the preferred way to pass bootloader information shall be the flat OF tree.
Hear, hear!
The following patch (broken in two parts), implements just that.
No, it does not. It does more than this on one hand, and less than reqired on the other.
That's vague, to put it mildly.
Please clean up and resubmit:
diff --git a/common/Makefile b/common/Makefile --- a/common/Makefile +++ b/common/Makefile @@ -51,7 +51,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug. memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o \ usb.o usb_kbd.o usb_storage.o \
virtex2.o xilinx.o
virtex2.o xilinx.o ft_build.o
Lists shall be kept sorted. Don't be lazy and just append at the end, please.
OK
--- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c
...
- /*
* Linux Kernel Parameters:
* r3: ptr to board info data
* r4: initrd_start or 0 if no initrd
* r5: initrd_end - unused if r4 is 0
* r6: Start of command line string
* r7: End of command line string
*/
- (*kernel) ((bd_t *)of_flat_tree, initrd_start, initrd_end, cmd_start,
cmd_end);
Is it board info data or an OF tree? I think the comment needs to be adjusted to match the code.
It's both, after the OF tree the bd_t is pasted. We'll have a nice transition period when both are present. The target is for bd_t to be gone completely.
diff --git a/common/ft_build.c b/common/ft_build.c new file mode 100644 --- /dev/null +++ b/common/ft_build.c
...
- /* paste the bd_t at the end of the flat tree */
- end = (char *)blob +
be32_to_cpu(((struct boot_param_header *)blob)->totalsize);
- memcpy(end, bd, sizeof(*bd));
+#ifdef __powerpc__
I understand that *all* of this is PPC specific, so why do you #ifdef just this part? IMHO all of this should disappear for all non-PPC versions?
There's nothing PPC specific about the patch. Endianess issues are handled. OF trees are a superset of all the current ways that firmware passes settings to the kernel. In theory other architectures can use it for the same reason.
- p = ft_get_prop(blob, "/u-boot-bd_t/memstart", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/memsize", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/flashstart", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/flashsize", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/flashoffset", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/sramstart", &len);
...
- p = ft_get_prop(blob, "/u-boot-bd_t/sramsize", &len);
...
That's alot or repeated string constants, which just waste memory in the data segment. Any way for a leaner implementation?
Fixed.
While we are at it: did you check how much this patch adds to the memory footprint?
It is controlled by a define, CONFIG_OF_FLAT_TREE, so if you don't use it there's no overhead.
The difference between a build with and without was about 5.5K. About 1K was the OF tree proper, which will grow when we start populating it with the device tree.
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/mbar_base", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_mbar_base);
+#endif
...
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/ipbfreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_ipbfreq);
- p = ft_get_prop(blob, "/u-boot-bd_t/pcifreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_pcifreq);
+#endif
Maybe you can sort these things to minimize the groups of #ifdef's needed?
???
The define mess on the bd_t is one of the reasons we're moving to this format.
bd_t is not long for this world anyway.
+#if defined(CONFIG_8xx)
- clock = gd->cpu_clk;
+#elif defined(CONFIG_8260)
- clock = gd->brg_clk;
+#else
- clock = 0;
+#endif
- p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len);
- if (p != NULL)
*p = cpu_to_be32(clock);
clock = 0 for anything but 8xx and 8260???
Used intfreq instead.
- p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len);
- if (p != NULL)
*p = cpu_to_be32(clock / 4); /* XXX I'm just guessing */
... and probably wrong?
Yeah, put a OF_TBCLK define instead, since it's board specific.
There is no CHANGELOG entry.
Rejected.
Content-Type: text/plain; charset="us-ascii"; name="of-uboot-stxxtc.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="of-uboot-stxxtc.patch"
There is no CHANGELOG entry.
Rejected.
Changelog entry added.
Best regards,
Wolfgang Denk
Regards
Pantelis
diff --git a/common/Makefile b/common/Makefile --- a/common/Makefile +++ b/common/Makefile @@ -46,7 +46,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug. env_nand.o env_dataflash.o env_flash.o env_eeprom.o \ env_nvram.o env_nowhere.o \ exports.o \ - flash.o fpga.o \ + flash.o fpga.o ft_build.o \ hush.o kgdb.o lcd.o lists.o lynxkdi.o \ memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o \ diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -34,6 +34,10 @@ #include <environment.h> #include <asm/byteorder.h>
+#ifdef CONFIG_OF_FLAT_TREE +#include <ft_build.h> +#endif + /*cmd_boot.c*/ extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
@@ -487,6 +491,9 @@ fixup_silent_linux () } #endif /* CONFIG_SILENT_CONSOLE */
+extern const unsigned char oftree_dtb[]; +extern const unsigned int oftree_dtb_len; + #ifdef CONFIG_PPC static void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, @@ -509,6 +516,9 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl bd_t *kbd; void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); image_header_t *hdr = &header; +#ifdef CONFIG_OF_FLAT_TREE + char *of_flat_tree; +#endif
if ((s = getenv ("initrd_high")) != NULL) { /* a value of "no" or a similar string will act like 0, @@ -773,16 +783,26 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl initrd_start = 0; initrd_end = 0; } - +#ifdef CONFIG_OF_FLAT_TREE + if (initrd_start == 0) + of_flat_tree = (char *)(((ulong)kbd - OF_FLAT_TREE_MAX_SIZE - + sizeof(bd_t)) & ~0xF); + else + of_flat_tree = (char *)((initrd_start - OF_FLAT_TREE_MAX_SIZE - + sizeof(bd_t)) & ~0xF); +#endif
debug ("## Transferring control to Linux (at address %08lx) ...\n", (ulong)kernel);
SHOW_BOOT_PROGRESS (15);
+#ifndef CONFIG_OF_FLAT_TREE + #if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) unlock_ram_in_cache(); #endif + /* * Linux Kernel Parameters: * r3: ptr to board info data @@ -792,6 +812,25 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl * r7: End of command line string */ (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); +#else + + ft_setup(of_flat_tree, OF_FLAT_TREE_MAX_SIZE, kbd); + /* ft_dump_blob(of_flat_tree); */ + +#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) + unlock_ram_in_cache(); +#endif + /* + * Linux Kernel Parameters: + * r3: ptr to OF flat tree, followed by the board info data + * r4: initrd_start or 0 if no initrd + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + */ + (*kernel) ((bd_t *)of_flat_tree, initrd_start, initrd_end, cmd_start, cmd_end); + +#endif } #endif /* CONFIG_PPC */
diff --git a/common/ft_build.c b/common/ft_build.c new file mode 100644 --- /dev/null +++ b/common/ft_build.c @@ -0,0 +1,684 @@ +/* + * OF flat tree builder + */ + +#include <common.h> +#include <malloc.h> +#include <environment.h> + +#include <asm/errno.h> +#include <stddef.h> + +#include <ft_build.h> + +#ifdef CONFIG_OF_FLAT_TREE + +/* align addr on a size boundary - adjust address up if needed -- Cort */ +#define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1))) + +static void ft_put_word(struct ft_cxt *cxt, u32 v) +{ + if (cxt->overflow) /* do nothing */ + return; + + /* check for overflow */ + if (cxt->p + 4 > cxt->pstr) { + cxt->overflow = 1; + return; + } + + *(u32 *) cxt->p = cpu_to_be32(v); + cxt->p += 4; +} + +static inline void ft_put_bin(struct ft_cxt *cxt, const void *data, int sz) +{ + u8 *p; + + if (cxt->overflow) /* do nothing */ + return; + + /* next pointer pos */ + p = (u8 *) _ALIGN((unsigned long)cxt->p + sz, 4); + + /* check for overflow */ + if (p > cxt->pstr) { + cxt->overflow = 1; + return; + } + + memcpy(cxt->p, data, sz); + if ((sz & 3) != 0) + memset(cxt->p + sz, 0, 4 - (sz & 3)); + cxt->p = p; +} + +void ft_begin_node(struct ft_cxt *cxt, const char *name) +{ + ft_put_word(cxt, OF_DT_BEGIN_NODE); + ft_put_bin(cxt, name, strlen(name) + 1); +} + +void ft_end_node(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_END_NODE); +} + +void ft_nop(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_NOP); +} + +static int lookup_string(struct ft_cxt *cxt, const char *name) +{ + u8 *p; + + p = cxt->pstr; + while (p < cxt->pstr_begin) { + if (strcmp(p, name) == 0) + return p - cxt->p_begin; + p += strlen(p) + 1; + } + + return -1; +} + +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz) +{ + int len, off; + + if (cxt->overflow) + return; + + len = strlen(name) + 1; + + off = lookup_string(cxt, name); + if (off == -1) { + /* check if we have space */ + if (cxt->p + 12 + sz + len > cxt->pstr) { + cxt->overflow = 1; + return; + } + + cxt->pstr -= len; + memcpy(cxt->pstr, name, len); + off = cxt->pstr - cxt->p_begin; + } + + /* now put offset from beginning of *STRUCTURE* */ + /* will be fixed up at the end */ + ft_put_word(cxt, OF_DT_PROP); + ft_put_word(cxt, sz); + ft_put_word(cxt, off); + ft_put_bin(cxt, data, sz); +} + +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str) +{ + ft_prop(cxt, name, str, strlen(str) + 1); +} + +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val) +{ + u32 v = cpu_to_be32((u32) val); + + ft_prop(cxt, name, &v, 4); +} + +/* start construction of the flat OF tree */ +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size) +{ + struct boot_param_header *bph = blob; + u32 off; + + /* clear the cxt */ + memset(cxt, 0, sizeof(*cxt)); + + cxt->bph = bph; + cxt->max_size = max_size; + + /* zero everything in the header area */ + memset(bph, 0, sizeof(*bph)); + + bph->magic = cpu_to_be32(OF_DT_HEADER); + bph->version = cpu_to_be32(0x10); + bph->last_comp_version = cpu_to_be32(0x10); + + /* start pointers */ + cxt->pres_begin = (u8 *) _ALIGN((unsigned long)(bph + 1), 8); + cxt->pres = cxt->pres_begin; + + off = (unsigned long)cxt->pres_begin - (unsigned long)bph; + bph->off_mem_rsvmap = cpu_to_be32(off); + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +/* add a reserver physical area to the rsvmap */ +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size) +{ + ((u64 *) cxt->pres)[0] = cpu_to_be64(physaddr); /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = cpu_to_be64(size); + + cxt->pres += 18; /* advance */ + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + /* keep track of size */ + cxt->res_size = cxt->pres + 16 - cxt->pres_begin; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +void ft_begin_tree(struct ft_cxt *cxt) +{ + cxt->p_begin = cxt->p_anchor; + cxt->pstr_begin = (char *)cxt->bph + cxt->max_size; /* point at the end */ + + cxt->p = cxt->p_begin; + cxt->pstr = cxt->pstr_begin; +} + +int ft_end_tree(struct ft_cxt *cxt) +{ + struct boot_param_header *bph = cxt->bph; + int off, sz, sz1; + u32 tag, v; + u8 *p; + + ft_put_word(cxt, OF_DT_END); + + if (cxt->overflow) + return -ENOMEM; + + /* size of the areas */ + cxt->struct_size = cxt->p - cxt->p_begin; + cxt->strings_size = cxt->pstr_begin - cxt->pstr; + + /* the offset we must move */ + off = (cxt->pstr_begin - cxt->p_begin) - cxt->strings_size; + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + + /* move the whole string area */ + memmove(cxt->pstr_begin, cxt->pstr, cxt->strings_size); + + /* now perform the fixup of the strings */ + p = cxt->p_begin; + while ((tag = be32_to_cpu(*(u32 *) p)) != OF_DT_END) { + p += 4; + + if (tag == OF_DT_BEGIN_NODE) { + p = (u8 *) _ALIGN((unsigned long)p + strlen(p) + 1, 4); + continue; + } + + if (tag == OF_DT_END_NODE || tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + return -EINVAL; + + sz = be32_to_cpu(*(u32 *) p); + p += 4; + + v = be32_to_cpu(*(u32 *) p); + v -= off; + *(u32 *) p = cpu_to_be32(v); /* move down */ + p += 4; + + p = (u8 *) _ALIGN((unsigned long)p + sz, 4); + } + + /* fix sizes */ + p = (char *)cxt->bph; + sz = (cxt->pstr_begin + cxt->strings_size) - p; + sz1 = _ALIGN(sz, 16); /* align at 16 bytes */ + if (sz != sz1) + memset(p + sz, 0, sz1 - sz); + bph->totalsize = cpu_to_be32(sz1); + bph->off_dt_struct = cpu_to_be32(cxt->p_begin - p); + bph->off_dt_strings = cpu_to_be32(cxt->pstr_begin - p); + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + cxt->pstr = cxt->pstr_begin + cxt->strings_size; + + return 0; +} + +/**********************************************************************/ + +static inline int isprint(int c) +{ + return c >= 0x20 && c <= 0x7e; +} + +static int is_printable_string(const void *data, int len) +{ + const char *s = data; + const char *ss; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + ss = s; + while (*s && isprint(*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || (s + 1 - ss) < len) + return 0; + + return 1; +} + +static void print_data(const void *data, int len) +{ + int i; + const u8 *s; + + /* no data, don't print */ + if (len == 0) + return; + + if (is_printable_string(data, len)) { + printf(" = "%s"", (char *)data); + return; + } + + switch (len) { + case 1: /* byte */ + printf(" = <0x%02x>", (*(u8 *) data) & 0xff); + break; + case 2: /* half-word */ + printf(" = <0x%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); + break; + case 4: /* word */ + printf(" = <0x%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); + break; + case 8: /* double-word */ + printf(" = <0x%16llx>", be64_to_cpu(*(uint64_t *) data)); + break; + default: /* anything else... hexdump */ + printf(" = ["); + for (i = 0, s = data; i < len; i++) + printf("%02x%s", s[i], i < len - 1 ? " " : ""); + printf("]"); + + break; + } +} + +void ft_dump_blob(const void *bphp) +{ + const struct boot_param_header *bph = bphp; + const uint64_t *p_rsvmap = (const uint64_t *) + ((const char *)bph + be32_to_cpu(bph->off_mem_rsvmap)); + const u32 *p_struct = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_struct)); + const u32 *p_strings = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag; + const u32 *p; + const char *s, *t; + int depth, sz, shift; + int i; + uint64_t addr, size; + + depth = 0; + shift = 4; + + for (i = 0;; i++) { + addr = be64_to_cpu(p_rsvmap[i * 2]); + size = be64_to_cpu(p_rsvmap[i * 2 + 1]); + if (addr == 0 && size == 0) + break; + + printf("/memreserve/ 0x%llx 0x%llx;\n", addr, size); + } + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (const char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + printf("%*s%s {\n", depth * shift, "", s); + + depth++; + continue; + } + + if (tag == OF_DT_END_NODE) { + depth--; + + printf("%*s};\n", depth * shift, ""); + continue; + } + + if (tag == OF_DT_NOP) { + printf("%*s[NOP]\n", depth * shift, ""); + continue; + } + + if (tag != OF_DT_PROP) { + fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", + depth * shift, "", tag); + break; + } + sz = be32_to_cpu(*p++); + s = (const char *)p_strings + be32_to_cpu(*p++); + t = (const char *)p; + p = (const u32 *)_ALIGN((unsigned long)p + sz, 4); + printf("%*s%s", depth * shift, "", s); + print_data(t, sz); + printf(";\n"); + } +} + +void ft_backtrack_node(struct ft_cxt *cxt) +{ + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; +} + +/* note that the root node of the blob is "peeled" off */ +void ft_merge_blob(struct ft_cxt *cxt, void *blob) +{ + struct boot_param_header *bph = (struct boot_param_header *)blob; + u32 *p_struct = (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + u32 *p_strings = + (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag, *p; + char *s, *t; + int depth, sz; + + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; + + depth = 0; + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d) - %d\n", tag, p - p_struct, depth); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + if (depth++ > 0) + ft_begin_node(cxt, s); + + continue; + } + + if (tag == OF_DT_END_NODE) { + ft_end_node(cxt); + if (--depth == 0) + break; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + t = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + sz, 4); + + ft_prop(cxt, s, t, sz); + } +} + +void *ft_get_prop(void *bphp, const char *propname, int *szp) +{ + struct boot_param_header *bph = bphp; + uint32_t *p_struct = + (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + uint32_t *p_strings = + (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + uint32_t version = be32_to_cpu(bph->version); + uint32_t tag; + uint32_t *p; + char *s, *t; + char *ss; + int sz; + static char path[256], prop[256]; + + path[0] = '\0'; + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (uint32_t *) _ALIGN((unsigned long)p + strlen(s) + + 1, 4); + strcat(path, s); + strcat(path, "/"); + continue; + } + + if (tag == OF_DT_END_NODE) { + path[strlen(path) - 1] = '\0'; + ss = strrchr(path, '/'); + if (ss != NULL) + ss[1] = '\0'; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + if (version < 0x10 && sz >= 8) + p = (uint32_t *) _ALIGN((unsigned long)p, 8); + t = (char *)p; + p = (uint32_t *) _ALIGN((unsigned long)p + sz, 4); + + strcpy(prop, path); + strcat(prop, s); + + if (strcmp(prop, propname) == 0) { + *szp = sz; + return t; + } + } + + return NULL; +} + +/********************************************************************/ + +extern unsigned char oftree_dtb[]; +extern unsigned int oftree_dtb_len; + +/* Function that returns a character from the environment */ +extern uchar(*env_get_char) (int); + +#define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } + +static const struct { + const char *name; + int offset; +} bd_map[] = { + BDM(memstart), + BDM(memsize), + BDM(flashstart), + BDM(flashsize), + BDM(flashoffset), + BDM(sramstart), + BDM(sramsize), +#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ + || defined(CONFIG_E500) + BDM(immr_base), +#endif +#if defined(CONFIG_MPC5xxx) + BDM(mbar_base), +#endif +#if defined(CONFIG_MPC83XX) + BDM(immrbar), +#endif +#if defined(CONFIG_MPC8220) + BDM(mbar_base), + BDM(inpfreq), + BDM(pcifreq), + BDM(pevfreq), + BDM(flbfreq), + BDM(vcofreq), +#endif + BDM(bootflags), + BDM(ip_addr), + BDM(intfreq), + BDM(busfreq), +#ifdef CONFIG_CPM2 + BDM(cpmfreq), + BDM(brgfreq), + BDM(sccfreq), + BDM(vco), +#endif +#if defined(CONFIG_MPC5xxx) + BDM(ipbfreq), + BDM(pcifreq), +#endif + BDM(baudrate), +}; + +void ft_setup(void *blob, int size, bd_t * bd) +{ + DECLARE_GLOBAL_DATA_PTR; + u8 *end; + u32 *p; + int len; + struct ft_cxt cxt; + int i, k, nxt; + static char tmpenv[256]; + char *s, *lval, *rval; + ulong clock; + uint32_t v; + + ft_begin(&cxt, blob, size); + + /* fs_add_rsvmap not used */ + + ft_begin_tree(&cxt); + + ft_begin_node(&cxt, ""); + + ft_end_node(&cxt); + + /* copy RO tree */ + ft_merge_blob(&cxt, oftree_dtb); + + /* back into root */ + ft_backtrack_node(&cxt); + + ft_begin_node(&cxt, "u-boot-env"); + + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) ; + s = tmpenv; + for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) + *s++ = env_get_char(k); + *s++ = '\0'; + lval = tmpenv; + s = strchr(tmpenv, '='); + if (s != NULL) { + *s++ = '\0'; + rval = s; + } else + continue; + ft_prop_str(&cxt, lval, rval); + } + + ft_end_node(&cxt); + + ft_begin_node(&cxt, "chosen"); + + ft_prop_str(&cxt, "name", "chosen"); + ft_prop_str(&cxt, "bootargs", getenv("bootargs")); + ft_prop_int(&cxt, "linux,platform", 0x600); /* what is this? */ + + ft_end_node(&cxt); + + ft_end_node(&cxt); /* end root */ + + ft_end_tree(&cxt); + + /* + printf("merged OF-tree\n"); + ft_dump_blob(blob); + */ + + /* paste the bd_t at the end of the flat tree */ + end = (char *)blob + + be32_to_cpu(((struct boot_param_header *)blob)->totalsize); + memcpy(end, bd, sizeof(*bd)); + +#ifdef __powerpc__ + + for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { + sprintf(tmpenv, "/u-boot-bd_t/%s", bd_map[i].name); + v = *(uint32_t *)((char *)bd + bd_map[i].offset); + + p = ft_get_prop(blob, tmpenv, &len); + if (p != NULL) + *p = cpu_to_be32(v); + } + + p = ft_get_prop(blob, "/u-boot-bd_t/enetaddr", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); + + p = ft_get_prop(blob, "/u-boot-bd_t/ethspeed", &len); + if (p != NULL) + *p = cpu_to_be32((uint32_t) bd->bi_ethspeed); + + clock = bd->bi_intfreq; + p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(clock); + +#ifdef OF_TBCLK + clock = OF_TBCLK; + p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(OF_TBCLK); +#endif + +#endif /* __powerpc__ */ + + /* + printf("final OF-tree\n"); + ft_dump_blob(blob); + */ + +} + +#endif diff --git a/include/ft_build.h b/include/ft_build.h new file mode 100644 --- /dev/null +++ b/include/ft_build.h @@ -0,0 +1,66 @@ +/* + * OF Flat tree builder + * + */ + +#ifndef FT_BUILD_H +#define FT_BUILD_H + +#include <linux/types.h> +#include <asm/u-boot.h> + +/* Definitions used by the flattened device tree */ +#define OF_DT_HEADER 0xd00dfeed /* marker */ +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ +#define OF_DT_END_NODE 0x2 /* End node */ +#define OF_DT_PROP 0x3 /* Property: name off, size, + * content */ +#define OF_DT_NOP 0x4 /* nop */ +#define OF_DT_END 0x9 + +#define OF_DT_VERSION 0x10 + +struct boot_param_header { + u32 magic; /* magic word OF_DT_HEADER */ + u32 totalsize; /* total size of DT block */ + u32 off_dt_struct; /* offset to structure */ + u32 off_dt_strings; /* offset to strings */ + u32 off_mem_rsvmap; /* offset to memory reserve map */ + u32 version; /* format version */ + u32 last_comp_version; /* last compatible version */ + /* version 2 fields below */ + u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + u32 dt_strings_size; /* size of the DT strings block */ +}; + +struct ft_cxt { + struct boot_param_header *bph; + int max_size; /* maximum size of tree */ + int overflow; /* set when this happens */ + u8 *p, *pstr, *pres; /* running pointers */ + u8 *p_begin, *pstr_begin, *pres_begin; /* starting pointers */ + u8 *p_anchor; /* start of constructed area */ + int struct_size, strings_size, res_size; +}; + +void ft_begin_node(struct ft_cxt *cxt, const char *name); +void ft_end_node(struct ft_cxt *cxt); + +void ft_begin_tree(struct ft_cxt *cxt); +int ft_end_tree(struct ft_cxt *cxt); + +void ft_nop(struct ft_cxt *cxt); +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz); +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str); +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val); +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size); +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); + +void ft_setup(void *blob, int size, bd_t * bd); + +void ft_dump_blob(const void *bphp); +void ft_merge_blob(struct ft_cxt *cxt, void *blob); +void *ft_get_prop(void *bphp, const char *propname, int *szp); + +#endif
diff --git a/board/stxxtc/Makefile b/board/stxxtc/Makefile --- a/board/stxxtc/Makefile +++ b/board/stxxtc/Makefile @@ -25,11 +25,19 @@ include $(TOPDIR)/config.mk
LIB = lib$(BOARD).a
-OBJS = $(BOARD).o +OBJS = $(BOARD).o oftree.o
$(LIB): .depend $(OBJS) $(AR) crv $@ $(OBJS)
+%.dtb: %.dts + dtc -f -V 0x10 -I dts -O dtb $< >$@ + +%.c: %.dtb + xxd -i $< \ + | sed -e "s/^unsigned char/const unsigned char/g" \ + | sed -e "s/^unsigned int/const unsigned int/g" > $@ + #########################################################################
.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) @@ -38,3 +46,4 @@ $(LIB): .depend $(OBJS) sinclude .depend
######################################################################### + diff --git a/board/stxxtc/oftree.dts b/board/stxxtc/oftree.dts new file mode 100644 --- /dev/null +++ b/board/stxxtc/oftree.dts @@ -0,0 +1,52 @@ +/ { + model = "STXXTC V1"; + compatible = "STXXTC"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + linux,phandle = <1>; + #address-cells = <1>; + #size-cells = <0>; + PowerPC,MPC870@0 { + linux,phandle = <3>; + name = "PowerPC,MPC870"; + device_type = "cpu"; + reg = <0>; + clock-frequency = <0>; /* place-holder for runtime fillup */ + timebase-frequency = <0>; /* dido */ + linux,boot-cpu; + i-cache-size = <2000>; + d-cache-size = <2000>; + 32-bit; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <00000000 00000000 00000000 20000000>; + }; + + /* copy of the bd_t information (place-holders) */ + u-boot-bd_t { + memstart = <0>; + memsize = <0>; + flashstart = <0>; + flashsize = <0>; + flashoffset = <0>; + sramstart = <0>; + sramsize = <0>; + + immr_base = <0>; + + bootflags = <0>; + ip_addr = <0>; + enetaddr = [ 00 00 00 00 00 00 ]; + ethspeed = <0>; + intfreq = <0>; + busfreq = <0>; + + baudrate = <0>; + }; + +}; diff --git a/include/configs/stxxtc.h b/include/configs/stxxtc.h --- a/include/configs/stxxtc.h +++ b/include/configs/stxxtc.h @@ -574,19 +574,15 @@ typedef unsigned int led_id_t; #define CONFIG_CRC32_VERIFY 1 #define CONFIG_HUSH_OLD_PARSER_COMPATIBLE 1
-/* Note: change below for your network setting!!! - * This was done just to facilitate manufacturing test and configuration. - */ -#define CONFIG_ETHADDR 00:e0:0c:07:9b:8a +/*****************************************************************************/
-#define CONFIG_SERVERIP 192.168.08.1 -#define CONFIG_IPADDR 192.168.08.85 -#define CONFIG_GATEWAYIP 192.168.08.1 -#define CONFIG_NETMASK 255.255.255.0 -#define CONFIG_HOSTNAME stx_xtc -#define CONFIG_ROOTPATH /xtcroot -#define CONFIG_BOOTFILE uImage -#define CONFIG_LOADADDR 0x1000000 +/* pass open firmware flat tree */ +#define CONFIG_OF_FLAT_TREE 1
+/* maximum size of the flat tree (8K) */ +#define OF_FLAT_TREE_MAX_SIZE 8192 + +#define OF_CPU "PowerPC,MPC870@0" +#define OF_TBCLK (MPC8XX_HZ / 16)
#endif /* __CONFIG_H */
diff --git a/CHANGELOG b/CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ Changes for U-Boot 1.1.4: ======================================================================
+* Support passing of OF flat trees to the kernel. + Patch by Pantelis Antoniou, 04 Sep 2005 + * Fix default command set (don't include CFG_CMD_DISPLAY command) Patch by Pantelis Antoniou, 02 Sep 2005

In message 200509041132.18328.pantelis.antoniou@gmail.com you wrote:
- /*
* Linux Kernel Parameters:
* r3: ptr to board info data
* r4: initrd_start or 0 if no initrd
* r5: initrd_end - unused if r4 is 0
* r6: Start of command line string
* r7: End of command line string
*/
- (*kernel) ((bd_t *)of_flat_tree, initrd_start, initrd_end, cmd_start,
cmd_end);
Is it board info data or an OF tree? I think the comment needs to be adjusted to match the code.
It's both, after the OF tree the bd_t is pasted.
Where is this done? I don't see it. And "after" does not help - an old kernel is still expecting it right at the address pointed to by r3.
We'll have a nice transition period when both are present.
Please explain how this is supposed to work. You code does not contain much comments or explanations for the implementation (which is IMHO bad), but at first glance I had the impression that with your patch there are two situations:
1) CONFIG_OF_FLAT_TREE is not defined; we pass a bd_t to the kernel, and everything is as before. Only kernels expecting an bd_t can be booted.
2) CONFIG_OF_FLAT_TREE is defined; we pass an OF tree to the kernel. No backward compatibility is provided: kernels expecting an bd_t will crash miserably. Only kernels expecting an OF tree can be booted.
The target is for bd_t to be gone completely.
Yes, but I don't see where the "transition period" is implemented.
I would expect that (when CONFIG_OF_FLAT_TREE is enabled) there is an environment variable that allows to switch between boot interfaces (similar to the clock_in_mhz variable), so that one and the same U-Boot image can boot both older and newer kernels?
Am I missing something?
I understand that *all* of this is PPC specific, so why do you #ifdef just this part? IMHO all of this should disappear for all non-PPC versions?
There's nothing PPC specific about the patch. Endianess issues are handled.
Come on, be realistic. There is not the slightest hint that ARM or MIPS considered using this.
All this *is* PPC specific code only.
And by the way: the whole function do_bootm_linux() you're patching is already enclosed in "#ifdef CONFIG_PPC" - ARM and MIPS etc. use different implementations of this function which you did not modify.
Also, in the rest of the code we use "#ifdef CONFIG_PPC", so please use this consistently (instead of "#ifdef __powerpc__".
OF trees are a superset of all the current ways that firmware passes settings to the kernel. In theory other architectures can use it for the same reason.
The key words here are "in theory". Do you have any information that there might be a realistic chance they would?
While we are at it: did you check how much this patch adds to the memory footprint?
It is controlled by a define, CONFIG_OF_FLAT_TREE, so if you don't use it there's no overhead.
That was not the question.
The difference between a build with and without was about 5.5K. About 1K was the OF tree proper, which will grow when we start populating it with the device tree.
6.5k or typically 5 % of the total size of U-Boot, tendency growing?
Outch...
There was discussion that we could leave out the OFT builder and just "load" a pre-built blob.Do you intend to implement this, too?
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/mbar_base", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_mbar_base);
+#endif
...
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/ipbfreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_ipbfreq);
- p = ft_get_prop(blob, "/u-boot-bd_t/pcifreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_pcifreq);
+#endif
Maybe you can sort these things to minimize the groups of #ifdef's needed?
???
Why must you have several blocks "#if defined(CONFIG_MPC5xxx)" ? Put all this code in a single block.
BTW: where is the name "u-boot-bd_t" coming from? I think it's ugly. Can we shorten this to either "u-boot" or "bd_t", please?
Now you submit two patches: "of-uboot-base.patch" and "of-uboot-stxxtc.patch" and a separate "of-uboot-changelog.patch" which does not mention a bit about what the second patch does.
Each patch needs it's own description and it's own CHANGELOG entry (commit message). Also, as documented by the RAEDME, CHANGELOG entries are required as plain text.
Best regards,
Wolfgang Denk

On Sunday 04 September 2005 12:36, Wolfgang Denk wrote:
In message 200509041132.18328.pantelis.antoniou@gmail.com you wrote:
- /*
* Linux Kernel Parameters:
* r3: ptr to board info data
* r4: initrd_start or 0 if no initrd
* r5: initrd_end - unused if r4 is 0
* r6: Start of command line string
* r7: End of command line string
*/
- (*kernel) ((bd_t *)of_flat_tree, initrd_start, initrd_end,
cmd_start, cmd_end);
Is it board info data or an OF tree? I think the comment needs to be adjusted to match the code.
It's both, after the OF tree the bd_t is pasted.
Where is this done? I don't see it. And "after" does not help - an old kernel is still expecting it right at the address pointed to by r3.
A new kernel detects a OF flat tree by the magic signature, and fallbacks to bd_t in that case.
Check ft_build and see what it does.
We'll have a nice transition period when both are present.
Please explain how this is supposed to work. You code does not contain much comments or explanations for the implementation (which is IMHO bad), but at first glance I had the impression that with your patch there are two situations:
- CONFIG_OF_FLAT_TREE is not defined; we pass a bd_t to the kernel, and everything is as before. Only kernels expecting an bd_t can be booted.
No, newer kernels detect that the OF tree is missing and use the bd_t as before.
- CONFIG_OF_FLAT_TREE is defined; we pass an OF tree to the kernel. No backward compatibility is provided: kernels expecting an bd_t will crash miserably. Only kernels expecting an OF tree can be booted.
There is a reason for that. As you well know as per the ppc64 docs r3 points to the OF tree, so taking into account the ongoing merge that's where the OF tree is expected to be.
The fact that now r3 points to bd_t is unfortunate.
The target is for bd_t to be gone completely.
Yes, but I don't see where the "transition period" is implemented.
I would expect that (when CONFIG_OF_FLAT_TREE is enabled) there is an environment variable that allows to switch between boot interfaces (similar to the clock_in_mhz variable), so that one and the same U-Boot image can boot both older and newer kernels?
Am I missing something?
OK, that's reasonable.
I understand that *all* of this is PPC specific, so why do you #ifdef just this part? IMHO all of this should disappear for all non-PPC versions?
There's nothing PPC specific about the patch. Endianess issues are handled.
Come on, be realistic. There is not the slightest hint that ARM or MIPS considered using this.
All this *is* PPC specific code only.
We shall see.
And by the way: the whole function do_bootm_linux() you're patching is already enclosed in "#ifdef CONFIG_PPC" - ARM and MIPS etc. use different implementations of this function which you did not modify.
Also, in the rest of the code we use "#ifdef CONFIG_PPC", so please use this consistently (instead of "#ifdef __powerpc__".
OF trees are a superset of all the current ways that firmware passes settings to the kernel. In theory other architectures can use it for the same reason.
The key words here are "in theory". Do you have any information that there might be a realistic chance they would?
I know that MIPS is contemplating porting over the ppc platform devices. And at least MIPS does not have a defined firmware interface. ARM I guess not.
While we are at it: did you check how much this patch adds to the memory footprint?
It is controlled by a define, CONFIG_OF_FLAT_TREE, so if you don't use it there's no overhead.
That was not the question.
The difference between a build with and without was about 5.5K. About 1K was the OF tree proper, which will grow when we start populating it with the device tree.
6.5k or typically 5 % of the total size of U-Boot, tendency growing?
Outch...
That's the price of progress. No-one is forcing to use this on old-designs. Just take this into account on newer designs.
There was discussion that we could leave out the OFT builder and just "load" a pre-built blob.Do you intend to implement this, too?
No. A pre-build blob does not contain the full environment. The specs are clear; at least the chosen node must reflect current settings.
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/mbar_base", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_mbar_base);
+#endif
...
+#if defined(CONFIG_MPC5xxx)
- p = ft_get_prop(blob, "/u-boot-bd_t/ipbfreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_ipbfreq);
- p = ft_get_prop(blob, "/u-boot-bd_t/pcifreq", &len);
- if (p != NULL)
*p = cpu_to_be32(bd->bi_pcifreq);
+#endif
Maybe you can sort these things to minimize the groups of #ifdef's needed?
???
Why must you have several blocks "#if defined(CONFIG_MPC5xxx)" ? Put all this code in a single block.
BTW: where is the name "u-boot-bd_t" coming from? I think it's ugly. Can we shorten this to either "u-boot" or "bd_t", please?
bd_t then.
Now you submit two patches: "of-uboot-base.patch" and "of-uboot-stxxtc.patch" and a separate "of-uboot-changelog.patch" which does not mention a bit about what the second patch does.
Each patch needs it's own description and it's own CHANGELOG entry (commit message). Also, as documented by the RAEDME, CHANGELOG entries are required as plain text.
----------------------- snip ------------------------------ * Support passing of OF flat trees to the kernel. Specific support for the STXtc. Patch by Pantelis Antoniou, 04 Sep 2005
----------------------- snip ------------------------------
Best regards,
Wolfgang Denk
Combined patch follows.
Regards
Pantelis
diff --git a/CHANGELOG b/CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ Changes for U-Boot 1.1.4: ======================================================================
+* Support passing of OF flat trees to the kernel. + Patch by Pantelis Antoniou, 04 Sep 2005 + * Fix default command set (don't include CFG_CMD_DISPLAY command) Patch by Pantelis Antoniou, 02 Sep 2005
diff --git a/README b/README --- a/README +++ b/README @@ -397,6 +397,20 @@ The following options need to be configu expect it to be in bytes, others in MB. Define CONFIG_MEMSIZE_IN_BYTES to make it in bytes.
+ CONFIG_OF_FLAT_TREE + + New kernel versions are expecting firmware settings to be + passed using the flat open firmware trees. + The environment variable "disable_of" when set, disables this + functionality. + + CONFIG_OF_FLAT_TREE_MAX_SIZE + + The maximum size of the constructed OF tree. + + OF_CPU - The proper name of the cpus node. + OF_TBCLK - The timebase frequency. + - Serial Ports: CFG_PL010_SERIAL
diff --git a/board/stxxtc/Makefile b/board/stxxtc/Makefile --- a/board/stxxtc/Makefile +++ b/board/stxxtc/Makefile @@ -25,11 +25,19 @@ include $(TOPDIR)/config.mk
LIB = lib$(BOARD).a
-OBJS = $(BOARD).o +OBJS = $(BOARD).o oftree.o
$(LIB): .depend $(OBJS) $(AR) crv $@ $(OBJS)
+%.dtb: %.dts + dtc -f -V 0x10 -I dts -O dtb $< >$@ + +%.c: %.dtb + xxd -i $< \ + | sed -e "s/^unsigned char/const unsigned char/g" \ + | sed -e "s/^unsigned int/const unsigned int/g" > $@ + #########################################################################
.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) @@ -38,3 +46,4 @@ $(LIB): .depend $(OBJS) sinclude .depend
######################################################################### + diff --git a/board/stxxtc/oftree.dts b/board/stxxtc/oftree.dts new file mode 100644 --- /dev/null +++ b/board/stxxtc/oftree.dts @@ -0,0 +1,52 @@ +/ { + model = "STXXTC V1"; + compatible = "STXXTC"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + linux,phandle = <1>; + #address-cells = <1>; + #size-cells = <0>; + PowerPC,MPC870@0 { + linux,phandle = <3>; + name = "PowerPC,MPC870"; + device_type = "cpu"; + reg = <0>; + clock-frequency = <0>; /* place-holder for runtime fillup */ + timebase-frequency = <0>; /* dido */ + linux,boot-cpu; + i-cache-size = <2000>; + d-cache-size = <2000>; + 32-bit; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <00000000 00000000 00000000 20000000>; + }; + + /* copy of the bd_t information (place-holders) */ + bd_t { + memstart = <0>; + memsize = <0>; + flashstart = <0>; + flashsize = <0>; + flashoffset = <0>; + sramstart = <0>; + sramsize = <0>; + + immr_base = <0>; + + bootflags = <0>; + ip_addr = <0>; + enetaddr = [ 00 00 00 00 00 00 ]; + ethspeed = <0>; + intfreq = <0>; + busfreq = <0>; + + baudrate = <0>; + }; + +}; diff --git a/common/Makefile b/common/Makefile --- a/common/Makefile +++ b/common/Makefile @@ -46,7 +46,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug. env_nand.o env_dataflash.o env_flash.o env_eeprom.o \ env_nvram.o env_nowhere.o \ exports.o \ - flash.o fpga.o \ + flash.o fpga.o ft_build.o \ hush.o kgdb.o lcd.o lists.o lynxkdi.o \ memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o \ diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -34,6 +34,10 @@ #include <environment.h> #include <asm/byteorder.h>
+#ifdef CONFIG_OF_FLAT_TREE +#include <ft_build.h> +#endif + /*cmd_boot.c*/ extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
@@ -487,6 +491,9 @@ fixup_silent_linux () } #endif /* CONFIG_SILENT_CONSOLE */
+extern const unsigned char oftree_dtb[]; +extern const unsigned int oftree_dtb_len; + #ifdef CONFIG_PPC static void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, @@ -509,6 +516,9 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl bd_t *kbd; void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); image_header_t *hdr = &header; +#ifdef CONFIG_OF_FLAT_TREE + char *of_flat_tree; +#endif
if ((s = getenv ("initrd_high")) != NULL) { /* a value of "no" or a similar string will act like 0, @@ -773,16 +783,26 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl initrd_start = 0; initrd_end = 0; } - +#ifdef CONFIG_OF_FLAT_TREE + if (initrd_start == 0) + of_flat_tree = (char *)(((ulong)kbd - OF_FLAT_TREE_MAX_SIZE - + sizeof(bd_t)) & ~0xF); + else + of_flat_tree = (char *)((initrd_start - OF_FLAT_TREE_MAX_SIZE - + sizeof(bd_t)) & ~0xF); +#endif
debug ("## Transferring control to Linux (at address %08lx) ...\n", (ulong)kernel);
SHOW_BOOT_PROGRESS (15);
+#ifndef CONFIG_OF_FLAT_TREE + #if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) unlock_ram_in_cache(); #endif + /* * Linux Kernel Parameters: * r3: ptr to board info data @@ -792,6 +812,25 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int fl * r7: End of command line string */ (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); +#else + + ft_setup(of_flat_tree, OF_FLAT_TREE_MAX_SIZE, kbd); + /* ft_dump_blob(of_flat_tree); */ + +#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) + unlock_ram_in_cache(); +#endif + /* + * Linux Kernel Parameters: + * r3: ptr to OF flat tree, followed by the board info data + * r4: initrd_start or 0 if no initrd + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + */ + (*kernel) ((bd_t *)of_flat_tree, initrd_start, initrd_end, cmd_start, cmd_end); + +#endif } #endif /* CONFIG_PPC */
diff --git a/common/ft_build.c b/common/ft_build.c new file mode 100644 --- /dev/null +++ b/common/ft_build.c @@ -0,0 +1,695 @@ +/* + * OF flat tree builder + */ + +#include <common.h> +#include <malloc.h> +#include <environment.h> + +#include <asm/errno.h> +#include <stddef.h> + +#include <ft_build.h> + +#ifdef CONFIG_OF_FLAT_TREE + +/* align addr on a size boundary - adjust address up if needed -- Cort */ +#define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1))) + +static void ft_put_word(struct ft_cxt *cxt, u32 v) +{ + if (cxt->overflow) /* do nothing */ + return; + + /* check for overflow */ + if (cxt->p + 4 > cxt->pstr) { + cxt->overflow = 1; + return; + } + + *(u32 *) cxt->p = cpu_to_be32(v); + cxt->p += 4; +} + +static inline void ft_put_bin(struct ft_cxt *cxt, const void *data, int sz) +{ + u8 *p; + + if (cxt->overflow) /* do nothing */ + return; + + /* next pointer pos */ + p = (u8 *) _ALIGN((unsigned long)cxt->p + sz, 4); + + /* check for overflow */ + if (p > cxt->pstr) { + cxt->overflow = 1; + return; + } + + memcpy(cxt->p, data, sz); + if ((sz & 3) != 0) + memset(cxt->p + sz, 0, 4 - (sz & 3)); + cxt->p = p; +} + +void ft_begin_node(struct ft_cxt *cxt, const char *name) +{ + ft_put_word(cxt, OF_DT_BEGIN_NODE); + ft_put_bin(cxt, name, strlen(name) + 1); +} + +void ft_end_node(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_END_NODE); +} + +void ft_nop(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_NOP); +} + +static int lookup_string(struct ft_cxt *cxt, const char *name) +{ + u8 *p; + + p = cxt->pstr; + while (p < cxt->pstr_begin) { + if (strcmp(p, name) == 0) + return p - cxt->p_begin; + p += strlen(p) + 1; + } + + return -1; +} + +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz) +{ + int len, off; + + if (cxt->overflow) + return; + + len = strlen(name) + 1; + + off = lookup_string(cxt, name); + if (off == -1) { + /* check if we have space */ + if (cxt->p + 12 + sz + len > cxt->pstr) { + cxt->overflow = 1; + return; + } + + cxt->pstr -= len; + memcpy(cxt->pstr, name, len); + off = cxt->pstr - cxt->p_begin; + } + + /* now put offset from beginning of *STRUCTURE* */ + /* will be fixed up at the end */ + ft_put_word(cxt, OF_DT_PROP); + ft_put_word(cxt, sz); + ft_put_word(cxt, off); + ft_put_bin(cxt, data, sz); +} + +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str) +{ + ft_prop(cxt, name, str, strlen(str) + 1); +} + +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val) +{ + u32 v = cpu_to_be32((u32) val); + + ft_prop(cxt, name, &v, 4); +} + +/* start construction of the flat OF tree */ +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size) +{ + struct boot_param_header *bph = blob; + u32 off; + + /* clear the cxt */ + memset(cxt, 0, sizeof(*cxt)); + + cxt->bph = bph; + cxt->max_size = max_size; + + /* zero everything in the header area */ + memset(bph, 0, sizeof(*bph)); + + bph->magic = cpu_to_be32(OF_DT_HEADER); + bph->version = cpu_to_be32(0x10); + bph->last_comp_version = cpu_to_be32(0x10); + + /* start pointers */ + cxt->pres_begin = (u8 *) _ALIGN((unsigned long)(bph + 1), 8); + cxt->pres = cxt->pres_begin; + + off = (unsigned long)cxt->pres_begin - (unsigned long)bph; + bph->off_mem_rsvmap = cpu_to_be32(off); + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +/* add a reserver physical area to the rsvmap */ +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size) +{ + ((u64 *) cxt->pres)[0] = cpu_to_be64(physaddr); /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = cpu_to_be64(size); + + cxt->pres += 18; /* advance */ + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + /* keep track of size */ + cxt->res_size = cxt->pres + 16 - cxt->pres_begin; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +void ft_begin_tree(struct ft_cxt *cxt) +{ + cxt->p_begin = cxt->p_anchor; + cxt->pstr_begin = (char *)cxt->bph + cxt->max_size; /* point at the end */ + + cxt->p = cxt->p_begin; + cxt->pstr = cxt->pstr_begin; +} + +int ft_end_tree(struct ft_cxt *cxt) +{ + struct boot_param_header *bph = cxt->bph; + int off, sz, sz1; + u32 tag, v; + u8 *p; + + ft_put_word(cxt, OF_DT_END); + + if (cxt->overflow) + return -ENOMEM; + + /* size of the areas */ + cxt->struct_size = cxt->p - cxt->p_begin; + cxt->strings_size = cxt->pstr_begin - cxt->pstr; + + /* the offset we must move */ + off = (cxt->pstr_begin - cxt->p_begin) - cxt->strings_size; + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + + /* move the whole string area */ + memmove(cxt->pstr_begin, cxt->pstr, cxt->strings_size); + + /* now perform the fixup of the strings */ + p = cxt->p_begin; + while ((tag = be32_to_cpu(*(u32 *) p)) != OF_DT_END) { + p += 4; + + if (tag == OF_DT_BEGIN_NODE) { + p = (u8 *) _ALIGN((unsigned long)p + strlen(p) + 1, 4); + continue; + } + + if (tag == OF_DT_END_NODE || tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + return -EINVAL; + + sz = be32_to_cpu(*(u32 *) p); + p += 4; + + v = be32_to_cpu(*(u32 *) p); + v -= off; + *(u32 *) p = cpu_to_be32(v); /* move down */ + p += 4; + + p = (u8 *) _ALIGN((unsigned long)p + sz, 4); + } + + /* fix sizes */ + p = (char *)cxt->bph; + sz = (cxt->pstr_begin + cxt->strings_size) - p; + sz1 = _ALIGN(sz, 16); /* align at 16 bytes */ + if (sz != sz1) + memset(p + sz, 0, sz1 - sz); + bph->totalsize = cpu_to_be32(sz1); + bph->off_dt_struct = cpu_to_be32(cxt->p_begin - p); + bph->off_dt_strings = cpu_to_be32(cxt->pstr_begin - p); + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + cxt->pstr = cxt->pstr_begin + cxt->strings_size; + + return 0; +} + +/**********************************************************************/ + +static inline int isprint(int c) +{ + return c >= 0x20 && c <= 0x7e; +} + +static int is_printable_string(const void *data, int len) +{ + const char *s = data; + const char *ss; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + ss = s; + while (*s && isprint(*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || (s + 1 - ss) < len) + return 0; + + return 1; +} + +static void print_data(const void *data, int len) +{ + int i; + const u8 *s; + + /* no data, don't print */ + if (len == 0) + return; + + if (is_printable_string(data, len)) { + printf(" = "%s"", (char *)data); + return; + } + + switch (len) { + case 1: /* byte */ + printf(" = <0x%02x>", (*(u8 *) data) & 0xff); + break; + case 2: /* half-word */ + printf(" = <0x%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); + break; + case 4: /* word */ + printf(" = <0x%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); + break; + case 8: /* double-word */ + printf(" = <0x%16llx>", be64_to_cpu(*(uint64_t *) data)); + break; + default: /* anything else... hexdump */ + printf(" = ["); + for (i = 0, s = data; i < len; i++) + printf("%02x%s", s[i], i < len - 1 ? " " : ""); + printf("]"); + + break; + } +} + +void ft_dump_blob(const void *bphp) +{ + const struct boot_param_header *bph = bphp; + const uint64_t *p_rsvmap = (const uint64_t *) + ((const char *)bph + be32_to_cpu(bph->off_mem_rsvmap)); + const u32 *p_struct = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_struct)); + const u32 *p_strings = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag; + const u32 *p; + const char *s, *t; + int depth, sz, shift; + int i; + uint64_t addr, size; + + if (be32_to_cpu(bph->magic) != OF_DT_HEADER) { + /* not valid tree */ + return; + } + + depth = 0; + shift = 4; + + for (i = 0;; i++) { + addr = be64_to_cpu(p_rsvmap[i * 2]); + size = be64_to_cpu(p_rsvmap[i * 2 + 1]); + if (addr == 0 && size == 0) + break; + + printf("/memreserve/ 0x%llx 0x%llx;\n", addr, size); + } + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (const char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + printf("%*s%s {\n", depth * shift, "", s); + + depth++; + continue; + } + + if (tag == OF_DT_END_NODE) { + depth--; + + printf("%*s};\n", depth * shift, ""); + continue; + } + + if (tag == OF_DT_NOP) { + printf("%*s[NOP]\n", depth * shift, ""); + continue; + } + + if (tag != OF_DT_PROP) { + fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", + depth * shift, "", tag); + break; + } + sz = be32_to_cpu(*p++); + s = (const char *)p_strings + be32_to_cpu(*p++); + t = (const char *)p; + p = (const u32 *)_ALIGN((unsigned long)p + sz, 4); + printf("%*s%s", depth * shift, "", s); + print_data(t, sz); + printf(";\n"); + } +} + +void ft_backtrack_node(struct ft_cxt *cxt) +{ + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; +} + +/* note that the root node of the blob is "peeled" off */ +void ft_merge_blob(struct ft_cxt *cxt, void *blob) +{ + struct boot_param_header *bph = (struct boot_param_header *)blob; + u32 *p_struct = (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + u32 *p_strings = + (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag, *p; + char *s, *t; + int depth, sz; + + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; + + depth = 0; + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d) - %d\n", tag, p - p_struct, depth); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + if (depth++ > 0) + ft_begin_node(cxt, s); + + continue; + } + + if (tag == OF_DT_END_NODE) { + ft_end_node(cxt); + if (--depth == 0) + break; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + t = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + sz, 4); + + ft_prop(cxt, s, t, sz); + } +} + +void *ft_get_prop(void *bphp, const char *propname, int *szp) +{ + struct boot_param_header *bph = bphp; + uint32_t *p_struct = + (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + uint32_t *p_strings = + (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + uint32_t version = be32_to_cpu(bph->version); + uint32_t tag; + uint32_t *p; + char *s, *t; + char *ss; + int sz; + static char path[256], prop[256]; + + path[0] = '\0'; + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (uint32_t *) _ALIGN((unsigned long)p + strlen(s) + + 1, 4); + strcat(path, s); + strcat(path, "/"); + continue; + } + + if (tag == OF_DT_END_NODE) { + path[strlen(path) - 1] = '\0'; + ss = strrchr(path, '/'); + if (ss != NULL) + ss[1] = '\0'; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + if (version < 0x10 && sz >= 8) + p = (uint32_t *) _ALIGN((unsigned long)p, 8); + t = (char *)p; + p = (uint32_t *) _ALIGN((unsigned long)p + sz, 4); + + strcpy(prop, path); + strcat(prop, s); + + if (strcmp(prop, propname) == 0) { + *szp = sz; + return t; + } + } + + return NULL; +} + +/********************************************************************/ + +extern unsigned char oftree_dtb[]; +extern unsigned int oftree_dtb_len; + +/* Function that returns a character from the environment */ +extern uchar(*env_get_char) (int); + +#define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } + +static const struct { + const char *name; + int offset; +} bd_map[] = { + BDM(memstart), + BDM(memsize), + BDM(flashstart), + BDM(flashsize), + BDM(flashoffset), + BDM(sramstart), + BDM(sramsize), +#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ + || defined(CONFIG_E500) + BDM(immr_base), +#endif +#if defined(CONFIG_MPC5xxx) + BDM(mbar_base), +#endif +#if defined(CONFIG_MPC83XX) + BDM(immrbar), +#endif +#if defined(CONFIG_MPC8220) + BDM(mbar_base), + BDM(inpfreq), + BDM(pcifreq), + BDM(pevfreq), + BDM(flbfreq), + BDM(vcofreq), +#endif + BDM(bootflags), + BDM(ip_addr), + BDM(intfreq), + BDM(busfreq), +#ifdef CONFIG_CPM2 + BDM(cpmfreq), + BDM(brgfreq), + BDM(sccfreq), + BDM(vco), +#endif +#if defined(CONFIG_MPC5xxx) + BDM(ipbfreq), + BDM(pcifreq), +#endif + BDM(baudrate), +}; + +void ft_setup(void *blob, int size, bd_t * bd) +{ + DECLARE_GLOBAL_DATA_PTR; + u8 *end; + u32 *p; + int len; + struct ft_cxt cxt; + int i, k, nxt; + static char tmpenv[256]; + char *s, *lval, *rval; + ulong clock; + uint32_t v; + + /* disable OF tree; booting old kernel */ + if (getenv("disable_of") != NULL) { + memcpy(blob, bd, sizeof(*bd)); + return; + } + + ft_begin(&cxt, blob, size); + + /* fs_add_rsvmap not used */ + + ft_begin_tree(&cxt); + + ft_begin_node(&cxt, ""); + + ft_end_node(&cxt); + + /* copy RO tree */ + ft_merge_blob(&cxt, oftree_dtb); + + /* back into root */ + ft_backtrack_node(&cxt); + + ft_begin_node(&cxt, "u-boot-env"); + + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) ; + s = tmpenv; + for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) + *s++ = env_get_char(k); + *s++ = '\0'; + lval = tmpenv; + s = strchr(tmpenv, '='); + if (s != NULL) { + *s++ = '\0'; + rval = s; + } else + continue; + ft_prop_str(&cxt, lval, rval); + } + + ft_end_node(&cxt); + + ft_begin_node(&cxt, "chosen"); + + ft_prop_str(&cxt, "name", "chosen"); + ft_prop_str(&cxt, "bootargs", getenv("bootargs")); + ft_prop_int(&cxt, "linux,platform", 0x600); /* what is this? */ + + ft_end_node(&cxt); + + ft_end_node(&cxt); /* end root */ + + ft_end_tree(&cxt); + + /* + printf("merged OF-tree\n"); + ft_dump_blob(blob); + */ + + /* paste the bd_t at the end of the flat tree */ + end = (char *)blob + + be32_to_cpu(((struct boot_param_header *)blob)->totalsize); + memcpy(end, bd, sizeof(*bd)); + +#ifdef CONFIG_PPC + + for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { + sprintf(tmpenv, "/bd_t/%s", bd_map[i].name); + v = *(uint32_t *)((char *)bd + bd_map[i].offset); + + p = ft_get_prop(blob, tmpenv, &len); + if (p != NULL) + *p = cpu_to_be32(v); + } + + p = ft_get_prop(blob, "/bd_t/enetaddr", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); + + p = ft_get_prop(blob, "/bd_t/ethspeed", &len); + if (p != NULL) + *p = cpu_to_be32((uint32_t) bd->bi_ethspeed); + + clock = bd->bi_intfreq; + p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(clock); + +#ifdef OF_TBCLK + clock = OF_TBCLK; + p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(OF_TBCLK); +#endif + +#endif /* __powerpc__ */ + + /* + printf("final OF-tree\n"); + ft_dump_blob(blob); + */ + +} + +#endif diff --git a/include/configs/stxxtc.h b/include/configs/stxxtc.h --- a/include/configs/stxxtc.h +++ b/include/configs/stxxtc.h @@ -574,19 +574,15 @@ typedef unsigned int led_id_t; #define CONFIG_CRC32_VERIFY 1 #define CONFIG_HUSH_OLD_PARSER_COMPATIBLE 1
-/* Note: change below for your network setting!!! - * This was done just to facilitate manufacturing test and configuration. - */ -#define CONFIG_ETHADDR 00:e0:0c:07:9b:8a +/*****************************************************************************/
-#define CONFIG_SERVERIP 192.168.08.1 -#define CONFIG_IPADDR 192.168.08.85 -#define CONFIG_GATEWAYIP 192.168.08.1 -#define CONFIG_NETMASK 255.255.255.0 -#define CONFIG_HOSTNAME stx_xtc -#define CONFIG_ROOTPATH /xtcroot -#define CONFIG_BOOTFILE uImage -#define CONFIG_LOADADDR 0x1000000 +/* pass open firmware flat tree */ +#define CONFIG_OF_FLAT_TREE 1
+/* maximum size of the flat tree (8K) */ +#define OF_FLAT_TREE_MAX_SIZE 8192 + +#define OF_CPU "PowerPC,MPC870@0" +#define OF_TBCLK (MPC8XX_HZ / 16)
#endif /* __CONFIG_H */ diff --git a/include/ft_build.h b/include/ft_build.h new file mode 100644 --- /dev/null +++ b/include/ft_build.h @@ -0,0 +1,66 @@ +/* + * OF Flat tree builder + * + */ + +#ifndef FT_BUILD_H +#define FT_BUILD_H + +#include <linux/types.h> +#include <asm/u-boot.h> + +/* Definitions used by the flattened device tree */ +#define OF_DT_HEADER 0xd00dfeed /* marker */ +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ +#define OF_DT_END_NODE 0x2 /* End node */ +#define OF_DT_PROP 0x3 /* Property: name off, size, + * content */ +#define OF_DT_NOP 0x4 /* nop */ +#define OF_DT_END 0x9 + +#define OF_DT_VERSION 0x10 + +struct boot_param_header { + u32 magic; /* magic word OF_DT_HEADER */ + u32 totalsize; /* total size of DT block */ + u32 off_dt_struct; /* offset to structure */ + u32 off_dt_strings; /* offset to strings */ + u32 off_mem_rsvmap; /* offset to memory reserve map */ + u32 version; /* format version */ + u32 last_comp_version; /* last compatible version */ + /* version 2 fields below */ + u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + u32 dt_strings_size; /* size of the DT strings block */ +}; + +struct ft_cxt { + struct boot_param_header *bph; + int max_size; /* maximum size of tree */ + int overflow; /* set when this happens */ + u8 *p, *pstr, *pres; /* running pointers */ + u8 *p_begin, *pstr_begin, *pres_begin; /* starting pointers */ + u8 *p_anchor; /* start of constructed area */ + int struct_size, strings_size, res_size; +}; + +void ft_begin_node(struct ft_cxt *cxt, const char *name); +void ft_end_node(struct ft_cxt *cxt); + +void ft_begin_tree(struct ft_cxt *cxt); +int ft_end_tree(struct ft_cxt *cxt); + +void ft_nop(struct ft_cxt *cxt); +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz); +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str); +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val); +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size); +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); + +void ft_setup(void *blob, int size, bd_t * bd); + +void ft_dump_blob(const void *bphp); +void ft_merge_blob(struct ft_cxt *cxt, void *blob); +void *ft_get_prop(void *bphp, const char *propname, int *szp); + +#endif

In message 200509041336.52311.pantelis.antoniou@gmail.com you wrote:
Where is this done? I don't see it. And "after" does not help - an old kernel is still expecting it right at the address pointed to by r3.
A new kernel detects a OF flat tree by the magic signature, and fallbacks to bd_t in that case.
Yes - but what about old kernels?
- CONFIG_OF_FLAT_TREE is not defined; we pass a bd_t to the kernel, and everything is as before. Only kernels expecting an bd_t can be booted.
No, newer kernels detect that the OF tree is missing and use the bd_t as before.
OK. So an old version of U-Boot is compatible with old and new kernels. At least for some transition period. Good.
- CONFIG_OF_FLAT_TREE is defined; we pass an OF tree to the kernel. No backward compatibility is provided: kernels expecting an bd_t will crash miserably. Only kernels expecting an OF tree can be booted.
There is a reason for that. As you well know as per the ppc64 docs
No matter what the reason is... It is an indispensable practical requirement that we will have to be able to install a version of U-Boot on a certain hardware which can boot both old and new kernels.
Yes, but I don't see where the "transition period" is implemented.
I would expect that (when CONFIG_OF_FLAT_TREE is enabled) there is an environment variable that allows to switch between boot interfaces (similar to the clock_in_mhz variable), so that one and the same U-Boot image can boot both older and newer kernels?
Am I missing something?
OK, that's reasonable.
Can you please implement that?
No. A pre-build blob does not contain the full environment. The specs are clear; at least the chosen node must reflect current settings.
It was one of Ben's major arguments in this debate that we might leave out of this OFT building code and just load a small binary blob; IIRC he was talking about less than 0.5 kB ...
Combined patch follows.
Thanks.
...
+#if defined(CONFIG_MPC5xxx)
- BDM(mbar_base),
+#endif
...
+#if defined(CONFIG_MPC5xxx)
- BDM(ipbfreq),
- BDM(pcifreq),
+#endif
Did you just miss this (in which case I will clean it up), or is there any technical reason for not combining these two groups into one?
Best regards,
Wolfgang Denk

In message 200509041336.52311.pantelis.antoniou@gmail.com you wrote:
Where is this done? I don't see it. And "after" does not help - an old kernel is still expecting it right at the address pointed to by r3.
A new kernel detects a OF flat tree by the magic signature, and fallbacks to bd_t in that case.
Yes - but what about old kernels?
- CONFIG_OF_FLAT_TREE is not defined; we pass a bd_t to the kernel, and everything is as before. Only kernels expecting an bd_t can be booted.
No, newer kernels detect that the OF tree is missing and use the bd_t as before.
OK. So an old version of U-Boot is compatible with old and new kernels. At least for some transition period. Good.
- CONFIG_OF_FLAT_TREE is defined; we pass an OF tree to the kernel. No backward compatibility is provided: kernels expecting an bd_t will crash miserably. Only kernels expecting an OF tree can be booted.
There is a reason for that. As you well know as per the ppc64 docs
No matter what the reason is... It is an indispensable practical requirement that we will have to be able to install a version of U-Boot on a certain hardware which can boot both old and new kernels.
Yes, but I don't see where the "transition period" is implemented.
I would expect that (when CONFIG_OF_FLAT_TREE is enabled) there is an environment variable that allows to switch between boot interfaces (similar to the clock_in_mhz variable), so that one and the same U-Boot image can boot both older and newer kernels?
Am I missing something?
OK, that's reasonable.
Can you please implement that?
No. A pre-build blob does not contain the full environment. The specs are clear; at least the chosen node must reflect current settings.
It was one of Ben's major arguments in this debate that we might leave out of this OFT building code and just load a small binary blob; IIRC he was talking about less than 0.5 kB ...
Combined patch follows.
Thanks.
...
+#if defined(CONFIG_MPC5xxx)
- BDM(mbar_base),
+#endif
...
+#if defined(CONFIG_MPC5xxx)
- BDM(ipbfreq),
- BDM(pcifreq),
+#endif
Did you just miss this (in which case I will clean it up), or is there any technical reason for not combining these two groups into one?
Best regards,
Wolfgang Denk

In message 200509041336.52311.pantelis.antoniou@gmail.com you wrote: ...
- Support passing of OF flat trees to the kernel. Specific support for the STXtc. Patch by Pantelis Antoniou, 04 Sep 2005
Added, thanks.
Note 1: can you please submit a new patch to add a show doc/README.OFT or so which explains where the required dtc tool can be found?
Note 2: you owe Stefan Roese a beer or two.
Best regards,
Wolfgang Denk

On Thursday 13 October 2005 02:52, Wolfgang Denk wrote:
In message 200509041336.52311.pantelis.antoniou@gmail.com you wrote: ...
- Support passing of OF flat trees to the kernel. Specific support for the STXtc. Patch by Pantelis Antoniou, 04 Sep 2005
Added, thanks.
Note 1: can you please submit a new patch to add a show doc/README.OFT or so which explains where the required dtc tool can be found?
Here you go.
Note 2: you owe Stefan Roese a beer or two.
Only one? I was thinking of a case :).
Best regards,
Wolfgang Denk
Regards
Pantelis
Added a small doc file for pointing out where the tools for OF tree support are located.
--- commit a014911ad67dfcdd40b5258be8fe666bc13930c0 tree 10cddfbab8571a2a459a54441b4fdf29e5464cf6 parent 0cdd3d61b6489a8a25cd07e256072b6581200871 author Pantelis Antoniou pantelis.antoniou@gmail.com Thu, 13 Oct 2005 08:30:11 +0300 committer Pantelis Antoniou pantelins.antoniou@gmail.com Thu, 13 Oct 2005 08:30:11 +0300
doc/README.OFT | 26 ++++++++++++++++++++++++++ 1 files changed, 26 insertions(+), 0 deletions(-)
diff --git a/doc/README.OFT b/doc/README.OFT new file mode 100644 --- /dev/null +++ b/doc/README.OFT @@ -0,0 +1,26 @@ +Open Firmware Flat Tree and usage. +---------------------------------- + +As part of the ongoing cleanup of the linux PPC trees, the preferred +way to pass bootloader and board setup information is the open +firmware flat tree. + +Please take a look at the following email discussion for some +background. + + http://ozlabs.org/pipermail/linuxppc-dev/2005-August/019408.html + http://ozlabs.org/pipermail/linuxppc-dev/2005-August/019362.html + +The generated tree is part static and part dynamic. + +There is a static part which is compiled in with DTC and a dynamic +part which is programmatically appended. + +You'll need a fairly recent DTC tool, which is available by git at. + + rsync://ozlabs.org/dtc/dtc.git + +The xxd binary dumper is needed too which I got from + + ftp://ftp.uni-erlangen.de/pub/utilities/etc/xxd-1.10.tar.gz +

In message 200510130832.21894.pantelis.antoniou@gmail.com you wrote:
Note 1: can you please submit a new patch to add a show doc/README.OFT or so which explains where the required dtc tool can be found?
Here you go.
Checked in, thanks.
Note 2: you owe Stefan Roese a beer or two.
Only one? I was thinking of a case :).
Please don't. He needs to get some work done :-)
Best regards,
Wolfgang Denk
participants (2)
-
Pantelis Antoniou
-
Wolfgang Denk