diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile | 2 | ||||
-rw-r--r-- | common/cmd_bdinfo.c | 26 | ||||
-rw-r--r-- | common/cmd_bootm.c | 65 | ||||
-rw-r--r-- | common/cmd_fdt.c | 874 |
4 files changed, 956 insertions, 11 deletions
diff --git a/common/Makefile b/common/Makefile index 6f81c4a..74a6af2 100644 --- a/common/Makefile +++ b/common/Makefile @@ -32,7 +32,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug.o circbuf.o cmd_autoscript.o \ cmd_cache.o cmd_console.o \ cmd_date.o cmd_dcr.o cmd_diag.o cmd_display.o cmd_doc.o cmd_dtt.o \ cmd_eeprom.o cmd_elf.o cmd_ext2.o \ - cmd_fat.o cmd_fdc.o cmd_fdos.o cmd_flash.o cmd_fpga.o \ + cmd_fat.o cmd_fdc.o cmd_fdt.o cmd_fdos.o cmd_flash.o cmd_fpga.o \ cmd_i2c.o cmd_ide.o cmd_immap.o cmd_itest.o cmd_jffs2.o \ cmd_load.o cmd_log.o \ cmd_mem.o cmd_mii.o cmd_misc.o cmd_mmc.o \ diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index 70de795..d97c09e 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -180,6 +180,32 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } +#elif defined(CONFIG_MICROBLAZE) /* ! PPC, which leaves Microblaze */ + +int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i; + bd_t *bd = gd->bd; + print_num ("mem start ", (ulong)bd->bi_memstart); + print_num ("mem size ", (ulong)bd->bi_memsize); + print_num ("flash start ", (ulong)bd->bi_flashstart); + print_num ("flash size ", (ulong)bd->bi_flashsize); + print_num ("flash offset ", (ulong)bd->bi_flashoffset); +#if defined(CFG_SRAM_BASE) + print_num ("sram start ", (ulong)bd->bi_sramstart); + print_num ("sram size ", (ulong)bd->bi_sramsize); +#endif +#if defined(CFG_CMD_NET) + puts ("ethaddr ="); + for (i=0; i<6; ++i) { + printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]); + } + puts ("\nip_addr = "); + print_IPaddr (bd->bi_ip_addr); +#endif + printf ("\nbaudrate = %d bps\n", (ulong)bd->bi_baudrate); + return 0; +} #else /* ! PPC, which leaves MIPS */ diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index c0ed076..2721216b 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -34,7 +34,11 @@ #include <environment.h> #include <asm/byteorder.h> -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_LIBFDT) +#include <fdt.h> +#include <libfdt.h> +#endif +#if defined(CONFIG_OF_FLAT_TREE) #include <ft_build.h> #endif @@ -467,7 +471,7 @@ U_BOOT_CMD( "[addr [arg ...]]\n - boot application image stored in memory\n" "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" "\t'arg' can be the address of an initrd image\n" -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) "\tWhen booting a Linux kernel which requires a flat device-tree\n" "\ta third argument is required which is the address of the of the\n" "\tdevice-tree blob. To boot that kernel without an initrd image,\n" @@ -529,7 +533,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, bd_t *kbd; void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); image_header_t *hdr = &header; -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) char *of_flat_tree = NULL; ulong of_data = 0; #endif @@ -622,7 +626,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, * Check if there is an initrd image */ -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) /* Look for a '-' which indicates to ignore the ramdisk argument */ if (argc >= 3 && strcmp(argv[2], "-") == 0) { debug ("Skipping initrd\n"); @@ -739,12 +743,15 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, len = data = 0; } -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) if(argc > 3) { of_flat_tree = (char *) simple_strtoul(argv[3], NULL, 16); hdr = (image_header_t *)of_flat_tree; - - if (*(ulong *)of_flat_tree == OF_DT_HEADER) { +#if defined(CONFIG_OF_LIBFDT) + if (be32_to_cpu(fdt_magic(of_flat_tree)) == FDT_MAGIC) { +#else + if (*(ulong *)of_flat_tree == OF_DT_HEADER) { +#endif #ifndef CFG_NO_FLASH if (addr2info((ulong)of_flat_tree) != NULL) of_data = (ulong)of_flat_tree; @@ -787,7 +794,11 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, printf("ERROR: uImage is not uncompressed\n"); return; } +#if defined(CONFIG_OF_LIBFDT) + if (be32_to_cpu(fdt_magic(of_flat_tree + sizeof(image_header_t))) != FDT_MAGIC) { +#else if (*((ulong *)(of_flat_tree + sizeof(image_header_t))) != OF_DT_HEADER) { +#endif printf ("ERROR: uImage data is not a flat device tree\n"); return; } @@ -824,12 +835,20 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, of_data += 4 - tail; } +#if defined(CONFIG_OF_LIBFDT) + if (be32_to_cpu(fdt_magic(of_data)) != FDT_MAGIC) { +#else if (((struct boot_param_header *)of_data)->magic != OF_DT_HEADER) { +#endif printf ("ERROR: image is not a flat device tree\n"); return; } +#if defined(CONFIG_OF_LIBFDT) + if (be32_to_cpu(fdt_totalsize(of_data)) != ntohl(len_ptr[2])) { +#else if (((struct boot_param_header *)of_data)->totalsize != ntohl(len_ptr[2])) { +#endif printf ("ERROR: flat device tree size does not agree with image\n"); return; } @@ -913,7 +932,31 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, unlock_ram_in_cache(); #endif -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_LIBFDT) + /* move of_flat_tree if needed */ + if (of_data) { + int err; + ulong of_start, of_len; + of_len = be32_to_cpu(fdt_totalsize(of_data)); + /* provide extra 8k pad */ + if (initrd_start) + of_start = initrd_start - of_len - 8192; + else + of_start = (ulong)kbd - of_len - 8192; + of_start &= ~(4096 - 1); /* align on page */ + debug ("## device tree at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n", + of_data, of_data + of_len - 1, of_len, of_len); + + + printf (" Loading Device Tree to %08lx, end %08lx ... ", + of_start, of_start + of_len - 1); + err = fdt_open_into(of_start, of_data, of_len); + if (err != 0) { + printf ("libfdt: %s\n", fdt_strerror(err)); + } + } +#endif +#if defined(CONFIG_OF_FLAT_TREE) /* move of_flat_tree if needed */ if (of_data) { ulong of_start, of_len; @@ -942,13 +985,13 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, * r6: Start of command line string * r7: End of command line string */ -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) if (!of_flat_tree) /* no device tree; boot old style */ #endif (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); /* does not return */ -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) /* * Linux Kernel Parameters (passing device tree): * r3: ptr to OF flat tree, followed by the board info data @@ -957,8 +1000,10 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, * r6: NULL * r7: NULL */ +#if defined(CONFIG_OF_FLAT_TREE) ft_setup(of_flat_tree, kbd, initrd_start, initrd_end); /* ft_dump_blob(of_flat_tree); */ +#endif (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0); #endif diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c new file mode 100644 index 0000000..968bade --- /dev/null +++ b/common/cmd_fdt.c @@ -0,0 +1,874 @@ +/* + * (C) Copyright 2007 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com + * Based on code written by: + * Pantelis Antoniou <pantelis.antoniou@gmail.com> and + * Matthew McClintock <msm@freescale.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <linux/ctype.h> +#include <linux/types.h> + +#ifdef CONFIG_OF_LIBFDT +#include <asm/global_data.h> +#include <fdt.h> +#include <libfdt.h> + +#define MAX_LEVEL 32 /* how deeply nested we will go */ +#define SCRATCHPAD 1024 /* bytes of scratchpad memory */ + +/* + * Global data (for the gd->bd) + */ +DECLARE_GLOBAL_DATA_PTR; + +/* + * Scratchpad memory. + */ +static char data[SCRATCHPAD]; + + +/* + * Function prototypes/declarations. + */ +static int fdt_valid(void); +static void print_data(const void *data, int len); +static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end); +static int fdt_env(void *fdt); +static int fdt_bd_t(void *fdt); + + +/* + * Flattened Device Tree command, see the help for parameter definitions. + */ +int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + char op; + + if (argc < 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* + * Figure out which subcommand was given + */ + op = argv[1][0]; + /******************************************************************** + * Set the address of the fdt + ********************************************************************/ + if (op == 'a') { + /* + * Set the address [and length] of the fdt. + */ + fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); + + if (!fdt_valid()) { + return 1; + } + + if (argc >= 4) { + int len; + int err; + /* + * Optional new length + */ + len = simple_strtoul(argv[3], NULL, 16); + if (len < fdt_totalsize(fdt)) { + printf ("New length %d < existing length %d, ignoring.\n", + len, fdt_totalsize(fdt)); + } else { + /* + * Open in place with a new length. + */ + err = fdt_open_into(fdt, fdt, len); + if (err != 0) { + printf ("libfdt: %s\n", fdt_strerror(err)); + } + } + } + + /******************************************************************** + * Move the fdt + ********************************************************************/ + } else if (op == 'm') { + struct fdt_header *newaddr; + int len; + int err; + + if (argc != 5) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* + * Set the address and length of the fdt. + */ + fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); + if (!fdt_valid()) { + return 1; + } + + newaddr = (struct fdt_header *)simple_strtoul(argv[3], NULL, 16); + len = simple_strtoul(argv[4], NULL, 16); + if (len < fdt_totalsize(fdt)) { + printf ("New length %d < existing length %d, aborting.\n", + len, fdt_totalsize(fdt)); + return 1; + } + + /* + * Copy to the new location. + */ + err = fdt_open_into(fdt, newaddr, len); + if (err != 0) { + printf ("libfdt: %s\n", fdt_strerror(err)); + return 1; + } + fdt = newaddr; + + /******************************************************************** + * Set the value of a node in the fdt. + ********************************************************************/ + } else if (op == 's') { + char *pathp; /* path */ + char *prop; /* property */ + struct fdt_property *nodep; /* node struct pointer */ + char *newval; /* value from the user (as a string) */ + char *vp; /* temporary value pointer */ + char *cp; /* temporary char pointer */ + int nodeoffset; /* node offset from libfdt */ + int len; /* new length of the property */ + int oldlen; /* original length of the property */ + unsigned long tmp; /* holds converted values */ + int ret; /* return value */ + + /* + * Parameters: Node path, property, value. + */ + if (argc < 5) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + pathp = argv[2]; + prop = argv[3]; + newval = argv[4]; + + if (strcmp(pathp, "/") == 0) { + nodeoffset = 0; + } else { + nodeoffset = fdt_path_offset (fdt, pathp); + if (nodeoffset < 0) { + /* + * Not found or something else bad happened. + */ + printf ("libfdt: %s\n", fdt_strerror(nodeoffset)); + return 1; + } + } + nodep = fdt_getprop (fdt, nodeoffset, prop, &oldlen); + if (oldlen < 0) { + printf ("libfdt %s\n", fdt_strerror(oldlen)); + return 1; + } else if (oldlen == 0) { + /* + * The specified property has no value + */ + printf("%s has no value, cannot set one (yet).\n", prop); + return 1; + } else { + /* + * Convert the new property + */ + vp = data; + if (*newval == '<') { + /* + * Bigger values than bytes. + */ + len = 0; + newval++; + while ((*newval != '>') && (*newval != '\0')) { + cp = newval; + tmp = simple_strtoul(cp, &newval, 16); + if ((newval - cp) <= 2) { + *vp = tmp & 0xFF; + vp += 1; + len += 1; + } else if ((newval - cp) <= 4) { + *(uint16_t *)vp = __cpu_to_be16(tmp); + vp += 2; + len += 2; + } else if ((newval - cp) <= 8) { + *(uint32_t *)vp = __cpu_to_be32(tmp); + vp += 4; + len += 4; + } else { + printf("Sorry, I could not convert \"%s\"\n", cp); + return 1; + } + while (*newval == ' ') + newval++; + } + if (*newval != '>') { + printf("Unexpected character '%c'\n", *newval); + return 1; + } + } else if (*newval == '[') { + /* + * Byte stream. Convert the values. + */ + len = 0; + newval++; + while ((*newval != ']') && (*newval != '\0')) { + tmp = simple_strtoul(newval, &newval, 16); + *vp++ = tmp & 0xFF; + len++; + while (*newval == ' ') + newval++; + } + if (*newval != ']') { + printf("Unexpected character '%c'\n", *newval); + return 1; + } + } else { + /* + * Assume it is a string. Copy it into our data area for + * convenience (including the terminating '\0'). + */ + len = strlen(newval) + 1; + strcpy(data, newval); + } + + ret = fdt_setprop(fdt, nodeoffset, prop, data, len); + if (ret < 0) { + printf ("libfdt %s\n", fdt_strerror(ret)); + return 1; + } + } + + /******************************************************************** + * Print (recursive) / List (single level) + ********************************************************************/ + } else if ((op == 'p') || (op == 'l')) { + /* + * Recursively print (a portion of) the fdt. + */ + static int offstack[MAX_LEVEL]; + static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + int depth = MAX_LEVEL; /* how deep to print */ + char *pathp; /* path */ + char *prop; /* property */ + void *nodep; /* property node pointer */ + int nodeoffset; /* node offset from libfdt */ + int nextoffset; /* next node offset from libfdt */ + uint32_t tag; /* tag */ + int len; /* length of the property */ + int level = 0; /* keep track of nesting level */ + + /* + * list is an alias for print, but limited to 1 level + */ + if (op == 'l') { + depth = 1; + } + + /* + * Get the starting path. The root node is an oddball, + * the offset is zero and has no name. + */ + pathp = argv[2]; + if (argc > 3) + prop = argv[3]; + else + prop = NULL; + + if (strcmp(pathp, "/") == 0) { + nodeoffset = 0; + printf("/"); + } else { + nodeoffset = fdt_path_offset (fdt, pathp); + if (nodeoffset < 0) { + /* + * Not found or something else bad happened. + */ + printf ("libfdt %s\n", fdt_strerror(nodeoffset)); + return 1; + } + } + /* + * The user passed in a property as well as node path. Print only + * the given property and then return. + */ + if (prop) { + nodep = fdt_getprop (fdt, nodeoffset, prop, &len); + if (len == 0) { + printf("%s %s\n", pathp, prop); /* no property value */ + return 0; + } else if (len > 0) { + printf("%s=", prop); + print_data (nodep, len); + printf("\n"); + return 0; + } else { + printf ("libfdt %s\n", fdt_strerror(len)); + return 1; + } + } + + /* + * The user passed in a node path and no property, print the node + * and all subnodes. + */ + offstack[0] = nodeoffset; + + while(level >= 0) { + tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, &pathp); + switch(tag) { + case FDT_BEGIN_NODE: + if(level <= depth) + printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp); + level++; + offstack[level] = nodeoffset; + if (level >= MAX_LEVEL) { + printf("Aaaiii <splat> nested too deep.\n"); + return 1; + } + break; + case FDT_END_NODE: + level--; + if(level <= depth) + printf("%s};\n", &tabs[MAX_LEVEL - level]); + if (level == 0) { + level = -1; /* exit the loop */ + } + break; + case FDT_PROP: + nodep = fdt_getprop (fdt, offstack[level], pathp, &len); + if (len < 0) { + printf ("libfdt %s\n", fdt_strerror(len)); + return 1; + } else if (len == 0) { + /* the property has no value */ + if(level <= depth) + printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp); + } else { + if(level <= depth) { + printf("%s%s=", &tabs[MAX_LEVEL - level], pathp); + print_data (nodep, len); + printf(";\n"); + } + } + break; + case FDT_NOP: + break; + case FDT_END: + return 1; + default: + if(level <= depth) + printf("Unknown tag 0x%08X\n", tag); + return 1; + } + nodeoffset = nextoffset; + } + + /******************************************************************** + * Remove a property/node + ********************************************************************/ + } else if (op == 'r') { + int nodeoffset; /* node offset from libfdt */ + int err; + + /* + * Get the path. The root node is an oddball, the offset + * is zero and has no name. + */ + if (strcmp(argv[2], "/") == 0) { + nodeoffset = 0; + } else { + nodeoffset = fdt_path_offset (fdt, argv[2]); + if (nodeoffset < 0) { + /* + * Not found or something else bad happened. + */ + printf ("libfdt %s\n", fdt_strerror(nodeoffset)); + return 1; + } + } + /* + * Do the delete. A fourth parameter means delete a property, + * otherwise delete the node. + */ + if (argc > 3) { + err = fdt_delprop(fdt, nodeoffset, argv[3]); + if (err < 0) { + printf("fdt_delprop libfdt: %s\n", fdt_strerror(err)); + return err; + } + } else { + err = fdt_del_node(fdt, nodeoffset); + if (err < 0) { + printf("fdt_del_node libfdt: %s\n", fdt_strerror(err)); + return err; + } + } + + /******************************************************************** + * Create a chosen node + ********************************************************************/ + } else if (op == 'c') { + fdt_chosen(fdt, 0, 0); + + /******************************************************************** + * Create a u-boot-env node + ********************************************************************/ + } else if (op == 'e') { + fdt_env(fdt); + + /******************************************************************** + * Create a bd_t node + ********************************************************************/ + } else if (op == 'b') { + fdt_bd_t(fdt); + + /******************************************************************** + * Unrecognized command + ********************************************************************/ + } else { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + return 0; +} + +/********************************************************************/ + +static int fdt_valid(void) +{ + if (fdt == NULL) { + printf ("The address of the fdt is invalid.\n"); + return 0; + } + if (!fdt || (fdt_magic(fdt) != FDT_MAGIC)) { + fdt = NULL; + printf ("Unrecognized fdt: bad magic\n"); + return 0; + } + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) { + printf ("Unsupported fdt version: $d < %d\n", + FDT_FIRST_SUPPORTED_VERSION, fdt_version(fdt)); + fdt = NULL; + return 0; + } + if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) { + printf ("Unsupported fdt version: $d > %d\n", + fdt_version(fdt), FDT_LAST_SUPPORTED_VERSION); + fdt = NULL; + return 0; + } + return 1; +} + +/********************************************************************/ + +/* + * OF flat tree handling + * Written by: Pantelis Antoniou <pantelis.antoniou@gmail.com> + * Updated by: Matthew McClintock <msm@freescale.com> + * Converted to libfdt by: Gerald Van Baren <vanbaren@cideas.com> + */ + +static int is_printable_string(const void *data, int len) +{ + const char *s = data; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + /* printable or a null byte (concatenated strings) */ + while (((*s == '\0') || isprint(*s)) && (len > 0)) { + /* + * If we see a null, there are three possibilities: + * 1) If len == 1, it is the end of the string, printable + * 2) Next character also a null, not printable. + * 3) Next character not a null, continue to check. + */ + if (s[0] == '\0') { + if (len == 1) + return 1; + if (s[1] == '\0') + return 0; + } + s++; + len--; + } + + /* Not the null termination, or not done yet: not printable */ + if (*s != '\0' || (len != 0)) + return 0; + + return 1; +} + +static void print_data(const void *data, int len) +{ + int j; + const u8 *s; + + /* no data, don't print */ + if (len == 0) + return; + + /* + * It is a string, but it may have multiple strings (embedded '\0's). + */ + if (is_printable_string(data, len)) { + puts("\""); + j = 0; + while (j < len) { + if (j > 0) + puts("\", \""); + puts(data); + j += strlen(data) + 1; + data += strlen(data) + 1; + } + puts("\""); + return; + } + + switch (len) { + case 1: /* byte */ + printf("<%02x>", (*(u8 *) data) & 0xff); + break; + case 2: /* half-word */ + printf("<%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); + break; + case 4: /* word */ + printf("<%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); + break; + case 8: /* double-word */ +#if __WORDSIZE == 64 + printf("<%016llx>", be64_to_cpu(*(uint64_t *) data)); +#else + printf("<%08x ", be32_to_cpu(*(u32 *) data) & 0xffffffffU); + data += 4; + printf("%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); +#endif + break; + default: /* anything else... hexdump */ + printf("["); + for (j = 0, s = data; j < len; j++) + printf("%02x%s", s[j], j < len - 1 ? " " : ""); + printf("]"); + + break; + } +} + +/********************************************************************/ + +static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end) +{ + bd_t *bd = gd->bd; + int nodeoffset; + int err; + u32 tmp; /* used to set 32 bit integer properties */ + char *str; /* used to set string properties */ + ulong clock; + + if (initrd_start && initrd_end) { + err = fdt_add_reservemap_entry(fdt, + initrd_start, initrd_end - initrd_start + 1); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + } + + /* + * See if we already have a "chosen" node, create it if not. + */ + nodeoffset = fdt_path_offset (fdt, "/chosen"); + if (nodeoffset < 0) { + /* + * Create a new node "/chosen" (offset 0 is root level) + */ + nodeoffset = fdt_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) { + printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + return nodeoffset; + } + } + + str = getenv("bootargs"); + if (str != NULL) { + err = fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } + if (initrd_start && initrd_end) { + tmp = __cpu_to_be32(initrd_start); + err = fdt_setprop(fdt, nodeoffset, "linux,initrd-start", &tmp, sizeof(tmp)); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + tmp = __cpu_to_be32(initrd_end); + err = fdt_setprop(fdt, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp)); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } +#ifdef OF_STDOUT_PATH + err = fdt_setprop(fdt, nodeoffset, "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); +#endif + + nodeoffset = fdt_path_offset (fdt, "/cpus"); + if (nodeoffset >= 0) { + clock = cpu_to_be32(bd->bi_intfreq); + err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } +#ifdef OF_TBCLK + nodeoffset = fdt_path_offset (fdt, "/cpus/" OF_CPU "/timebase-frequency"); + if (nodeoffset >= 0) { + clock = cpu_to_be32(OF_TBCLK); + err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } +#endif +} + +/********************************************************************/ + +#ifdef CONFIG_OF_HAS_BD_T + +/* 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), +}; + +static int fdt_env(void *fdt) +{ + int nodeoffset; + int err; + int k, nxt; + int i; + static char tmpenv[256]; + + /* + * See if we already have a "u-boot-env" node, delete it if so. + * Then create a new empty node. + */ + nodeoffset = fdt_path_offset (fdt, "/u-boot-env"); + if (nodeoffset >= 0) { + err = fdt_del_node(fdt, nodeoffset); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + } + /* + * Create a new node "/u-boot-env" (offset 0 is root level) + */ + nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env"); + if (nodeoffset < 0) { + printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + return nodeoffset; + } + + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + char *s, *lval, *rval; + + /* + * Find the end of the name=definition + */ + 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; + /* + * Find the first '=': it separates the name from the value + */ + s = strchr(tmpenv, '='); + if (s != NULL) { + *s++ = '\0'; + rval = s; + } else + continue; + err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); + if (err < 0) { + printf("\"%s\" - libfdt: %s\n", lval, fdt_strerror(err)); + return err; + } + } + return 0; +} +#endif /* CONFIG_OF_HAS_UBOOT_ENV */ + +/********************************************************************/ + +#ifdef CONFIG_OF_HAS_BD_T +static int fdt_bd_t(void *fdt) +{ + bd_t *bd = gd->bd; + int nodeoffset; + int err; + u32 tmp; /* used to set 32 bit integer properties */ + int i; + + /* + * See if we already have a "bd_t" node, delete it if so. + * Then create a new empty node. + */ + nodeoffset = fdt_path_offset (fdt, "/bd_t"); + if (nodeoffset >= 0) { + err = fdt_del_node(fdt, nodeoffset); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + } + /* + * Create a new node "/bd_t" (offset 0 is root level) + */ + nodeoffset = fdt_add_subnode(fdt, 0, "bd_t"); + if (nodeoffset < 0) { + printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + return nodeoffset; + } + /* + * Use the string/pointer structure to create the entries... + */ + for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { + tmp = cpu_to_be32(getenv("bootargs")); + err = fdt_setprop(fdt, nodeoffset, bd_map[i].name, &tmp, sizeof(tmp)); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } + /* + * Add a couple of oddball entries... + */ + err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + +#ifdef CONFIG_OF_BOARD_SETUP + ft_board_setup(fdt, bd); +#endif + + return 0; +} +#endif /* CONFIG_OF_HAS_BD_T */ + +/********************************************************************/ + +U_BOOT_CMD( + fdt, 5, 0, do_fdt, + "fdt - flattened device tree utility commands\n", + "addr <addr> [<length>] - Set the fdt location to <addr>\n" + "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr>\n" + "fdt print <path> [<prop>] - Recursive print starting at <path>\n" + "fdt list <path> [<prop>] - Print one level starting at <path>\n" + "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n" + "fdt mknode <path> <node> - Create a new node after <path>\n" + "fdt rm <path> [<prop>] - Delete the node or <property>\n" + "fdt chosen - Add/update the \"/chosen\" branch in the tree\n" +#ifdef CONFIG_OF_HAS_UBOOT_ENV + "fdt env - Add/replace the \"/u-boot-env\" branch in the tree\n" +#endif +#ifdef CONFIG_OF_HAS_BD_T + "fdt bd_t - Add/replace the \"/bd_t\" branch in the tree\n" +#endif + "Hints:\n" + " * Set a larger length with the fdt addr command to add to the blob.\n" + " * If the property you are setting/printing has a '#' character,\n" + " you MUST escape it with a \\ character or quote it with \" or\n" + " it will be ignored as a comment.\n" + " * If the value has spaces in it, you MUST escape the spaces with\n" + " \\ characters or quote it with \"\"\n" + "Examples: fdt print / # print the whole tree\n" + " fdt print /cpus \"#address-cells\"\n" + " fdt set /cpus \"#address-cells\" \"[00 00 00 01]\"\n" +); + +#endif /* CONFIG_OF_FLAT_TREE */ |