X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=common%2Fcmd_fdt.c;h=6eec947fcb3ecbf572120b0b9fce7c0de2d94587;hb=a52852c5a65fe6636c7408829eced892deefc1de;hp=d3b19ddc1f4a8d278868af55ddb5b20f6e1d9eb5;hpb=ac5ba41c2234dd513ed2c879914e964cc05a0135;p=oweals%2Fu-boot.git diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index d3b19ddc1f..6eec947fcb 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -29,12 +29,14 @@ #include #include #include -#include #include #include #define MAX_LEVEL 32 /* how deeply nested we will go */ #define SCRATCHPAD 1024 /* bytes of scratchpad memory */ +#ifndef CONFIG_CMD_FDT_MAX_DUMP +#define CONFIG_CMD_FDT_MAX_DUMP 64 +#endif /* * Global data (for the gd->bd) @@ -42,32 +44,79 @@ DECLARE_GLOBAL_DATA_PTR; static int fdt_valid(void); -static int fdt_parse_prop(char **newval, int count, char *data, int *len); +static int fdt_parse_prop(char *const*newval, int count, char *data, int *len); static int fdt_print(const char *pathp, char *prop, int depth); +static int is_printable_string(const void *data, int len); /* * The working_fdt points to our working flattened device tree. */ struct fdt_header *working_fdt; +void set_working_fdt_addr(void *addr) +{ + char buf[17]; + + working_fdt = addr; + + sprintf(buf, "%lx", (unsigned long)addr); + setenv("fdtaddr", buf); +} + /* - * Flattened Device Tree command, see the help for parameter definitions. + * Get a value from the fdt and format it to be set in the environment */ -int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +static int fdt_value_setenv(const void *nodep, int len, const char *var) { - if (argc < 2) { - printf ("Usage:\n%s\n", cmdtp->usage); + if (is_printable_string(nodep, len)) + setenv(var, (void *)nodep); + else if (len == 4) { + char buf[11]; + + sprintf(buf, "0x%08X", *(uint32_t *)nodep); + setenv(var, buf); + } else if (len%4 == 0 && len <= 20) { + /* Needed to print things like sha1 hashes. */ + char buf[41]; + int i; + + for (i = 0; i < len; i += sizeof(unsigned int)) + sprintf(buf + (i * 2), "%08x", + *(unsigned int *)(nodep + i)); + setenv(var, buf); + } else { + printf("error: unprintable value\n"); return 1; } + return 0; +} - /******************************************************************** +/* + * Flattened Device Tree command, see the help for parameter definitions. + */ +static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (argc < 2) + return CMD_RET_USAGE; + + /* * Set the address of the fdt - ********************************************************************/ + */ if (argv[1][0] == 'a') { + unsigned long addr; /* * Set the address [and length] of the fdt. */ - working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); + if (argc == 2) { + if (!fdt_valid()) { + return 1; + } + printf("The address of the fdt is %p\n", working_fdt); + return 0; + } + + addr = simple_strtoul(argv[2], NULL, 16); + set_working_fdt_addr((void *)addr); if (!fdt_valid()) { return 1; @@ -96,18 +145,27 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } } - /******************************************************************** + return CMD_RET_SUCCESS; + } + + if (!working_fdt) { + puts( + "No FDT memory address configured. Please configure\n" + "the FDT address via \"fdt addr
\" command.\n" + "Aborting!\n"); + return CMD_RET_FAILURE; + } + + /* * Move the working_fdt - ********************************************************************/ - } else if (strncmp(argv[1], "mo", 2) == 0) { + */ + if (strncmp(argv[1], "mo", 2) == 0) { struct fdt_header *newaddr; int len; int err; - if (argc < 4) { - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - } + if (argc < 4) + return CMD_RET_USAGE; /* * Set the address and length of the fdt. @@ -146,9 +204,9 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } working_fdt = newaddr; - /******************************************************************** + /* * Make a new node - ********************************************************************/ + */ } else if (strncmp(argv[1], "mk", 2) == 0) { char *pathp; /* path */ char *nodep; /* new node to add */ @@ -158,10 +216,8 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) /* * Parameters: Node path, new node to be appended to the path. */ - if (argc < 4) { - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - } + if (argc < 4) + return CMD_RET_USAGE; pathp = argv[2]; nodep = argv[3]; @@ -182,9 +238,9 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) return 1; } - /******************************************************************** + /* * Set the value of a property in the working_fdt. - ********************************************************************/ + */ } else if (argv[1][0] == 's') { char *pathp; /* path */ char *prop; /* property */ @@ -196,10 +252,8 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) /* * Parameters: Node path, property, optional value. */ - if (argc < 4) { - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - } + if (argc < 4) + return CMD_RET_USAGE; pathp = argv[2]; prop = argv[3]; @@ -228,8 +282,119 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } /******************************************************************** - * Print (recursive) / List (single level) + * Get the value of a property in the working_fdt. ********************************************************************/ + } else if (argv[1][0] == 'g') { + char *subcmd; /* sub-command */ + char *pathp; /* path */ + char *prop; /* property */ + char *var; /* variable to store result */ + int nodeoffset; /* node offset from libfdt */ + const void *nodep; /* property node pointer */ + int len = 0; /* new length of the property */ + + /* + * Parameters: Node path, property, optional value. + */ + if (argc < 5) + return CMD_RET_USAGE; + + subcmd = argv[2]; + + if (argc < 6 && subcmd[0] != 's') + return CMD_RET_USAGE; + + var = argv[3]; + pathp = argv[4]; + prop = argv[5]; + + nodeoffset = fdt_path_offset(working_fdt, pathp); + if (nodeoffset < 0) { + /* + * Not found or something else bad happened. + */ + printf("libfdt fdt_path_offset() returned %s\n", + fdt_strerror(nodeoffset)); + return 1; + } + + if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) { + int reqIndex = -1; + int startDepth = fdt_node_depth( + working_fdt, nodeoffset); + int curDepth = startDepth; + int curIndex = -1; + int nextNodeOffset = fdt_next_node( + working_fdt, nodeoffset, &curDepth); + + if (subcmd[0] == 'n') + reqIndex = simple_strtoul(argv[5], NULL, 16); + + while (curDepth > startDepth) { + if (curDepth == startDepth + 1) + curIndex++; + if (subcmd[0] == 'n' && curIndex == reqIndex) { + const char *nodeName = fdt_get_name( + working_fdt, nextNodeOffset, NULL); + + setenv(var, (char *)nodeName); + return 0; + } + nextNodeOffset = fdt_next_node( + working_fdt, nextNodeOffset, &curDepth); + if (nextNodeOffset < 0) + break; + } + if (subcmd[0] == 's') { + /* get the num nodes at this level */ + char buf[11]; + + sprintf(buf, "%d", curIndex + 1); + setenv(var, buf); + } else { + /* node index not found */ + printf("libfdt node not found\n"); + return 1; + } + } else { + nodep = fdt_getprop( + working_fdt, nodeoffset, prop, &len); + if (len == 0) { + /* no property value */ + setenv(var, ""); + return 0; + } else if (len > 0) { + if (subcmd[0] == 'v') { + int ret; + + ret = fdt_value_setenv(nodep, len, var); + if (ret != 0) + return ret; + } else if (subcmd[0] == 'a') { + /* Get address */ + char buf[11]; + + sprintf(buf, "0x%p", nodep); + setenv(var, buf); + } else if (subcmd[0] == 's') { + /* Get size */ + char buf[11]; + + sprintf(buf, "0x%08X", len); + setenv(var, buf); + } else + return CMD_RET_USAGE; + return 0; + } else { + printf("libfdt fdt_getprop(): %s\n", + fdt_strerror(len)); + return 1; + } + } + + /* + * Print (recursive) / List (single level) + */ } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { int depth = MAX_LEVEL; /* how deep to print */ char *pathp; /* path */ @@ -261,9 +426,9 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) if (ret != 0) return ret; - /******************************************************************** + /* * Remove a property/node - ********************************************************************/ + */ } else if (strncmp(argv[1], "rm", 2) == 0) { int nodeoffset; /* node offset from libfdt */ int err; @@ -301,9 +466,9 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } } - /******************************************************************** + /* * Display header info - ********************************************************************/ + */ } else if (argv[1][0] == 'h') { u32 version = fdt_version(working_fdt); printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt)); @@ -331,33 +496,28 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) fdt_num_mem_rsv(working_fdt)); printf("\n"); - /******************************************************************** + /* * Set boot cpu id - ********************************************************************/ + */ } else if (strncmp(argv[1], "boo", 3) == 0) { unsigned long tmp = simple_strtoul(argv[2], NULL, 16); fdt_set_boot_cpuid_phys(working_fdt, tmp); - /******************************************************************** + /* * memory command - ********************************************************************/ + */ } else if (strncmp(argv[1], "me", 2) == 0) { uint64_t addr, size; int err; -#ifdef CFG_64BIT_STRTOUL - addr = simple_strtoull(argv[2], NULL, 16); - size = simple_strtoull(argv[3], NULL, 16); -#else - addr = simple_strtoul(argv[2], NULL, 16); - size = simple_strtoul(argv[3], NULL, 16); -#endif + addr = simple_strtoull(argv[2], NULL, 16); + size = simple_strtoull(argv[3], NULL, 16); err = fdt_fixup_memory(working_fdt, addr, size); if (err < 0) return err; - /******************************************************************** + /* * mem reserve commands - ********************************************************************/ + */ } else if (strncmp(argv[1], "rs", 2) == 0) { if (argv[2][0] == 'p') { uint64_t addr, size; @@ -382,13 +542,8 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } else if (argv[2][0] == 'a') { uint64_t addr, size; int err; -#ifdef CFG_64BIT_STRTOUL addr = simple_strtoull(argv[3], NULL, 16); size = simple_strtoull(argv[4], NULL, 16); -#else - addr = simple_strtoul(argv[3], NULL, 16); - size = simple_strtoul(argv[4], NULL, 16); -#endif err = fdt_add_mem_rsv(working_fdt, addr, size); if (err < 0) { @@ -407,8 +562,7 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } } else { /* Unrecognized command */ - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; + return CMD_RET_USAGE; } } #ifdef CONFIG_OF_BOARD_SETUP @@ -417,12 +571,27 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) ft_board_setup(working_fdt, gd->bd); #endif /* Create a chosen node */ - else if (argv[1][0] == 'c') - fdt_chosen(working_fdt, 0, 0, 1); + else if (argv[1][0] == 'c') { + unsigned long initrd_start = 0, initrd_end = 0; + + if ((argc != 2) && (argc != 4)) + return CMD_RET_USAGE; + + if (argc == 4) { + initrd_start = simple_strtoul(argv[2], NULL, 16); + initrd_end = simple_strtoul(argv[3], NULL, 16); + } + + fdt_chosen(working_fdt, 1); + fdt_initrd(working_fdt, initrd_start, initrd_end, 1); + } + /* resize the fdt */ + else if (strncmp(argv[1], "re", 2) == 0) { + fdt_resize(working_fdt); + } else { /* Unrecognized command */ - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; + return CMD_RET_USAGE; } return 0; @@ -487,7 +656,7 @@ static int fdt_valid(void) * data: A bytestream to be placed in the property * len: The length of the resulting bytestream */ -static int fdt_parse_prop(char **newval, int count, char *data, int *len) +static int fdt_parse_prop(char * const *newval, int count, char *data, int *len) { char *cp; /* temporary char pointer */ char *newp; /* temporary newval char pointer */ @@ -512,7 +681,7 @@ static int fdt_parse_prop(char **newval, int count, char *data, int *len) cp = newp; tmp = simple_strtoul(cp, &newp, 0); - *(uint32_t *)data = __cpu_to_be32(tmp); + *(__be32 *)data = __cpu_to_be32(tmp); data += 4; *len += 4; @@ -536,14 +705,18 @@ static int fdt_parse_prop(char **newval, int count, char *data, int *len) * Byte stream. Convert the values. */ newp++; - while ((*newp != ']') && (stridx < count)) { - tmp = simple_strtoul(newp, &newp, 16); - *data++ = tmp & 0xFF; - *len = *len + 1; + while ((stridx < count) && (*newp != ']')) { while (*newp == ' ') newp++; - if (*newp != '\0') + if (*newp == '\0') { newp = newval[++stridx]; + continue; + } + if (!isxdigit(*newp)) + break; + tmp = simple_strtoul(newp, &newp, 16); + *data++ = tmp & 0xFF; + *len = *len + 1; } if (*newp != ']') { printf("Unexpected character '%c'\n", *newp); @@ -551,12 +724,15 @@ static int fdt_parse_prop(char **newval, int count, char *data, int *len) } } else { /* - * Assume it is a string. Copy it into our data area for - * convenience (including the terminating '\0'). + * Assume it is one or more strings. Copy it into our + * data area for convenience (including the + * terminating '\0's). */ while (stridx < count) { - *len = strlen(newp) + 1; + size_t length = strlen(newp) + 1; strcpy(data, newp); + data += length; + *len += length; newp = newval[++stridx]; } } @@ -577,12 +753,12 @@ static int is_printable_string(const void *data, int len) if (len == 0) return 0; - /* must terminate with zero */ - if (s[len - 1] != '\0') + /* must terminate with zero or '\n' */ + if (s[len - 1] != '\0' && s[len - 1] != '\n') return 0; /* printable or a null byte (concatenated strings) */ - while (((*s == '\0') || isprint(*s)) && (len > 0)) { + while (((*s == '\0') || isprint(*s) || isspace(*s)) && (len > 0)) { /* * If we see a null, there are three possibilities: * 1) If len == 1, it is the end of the string, printable @@ -638,19 +814,28 @@ static void print_data(const void *data, int len) } if ((len %4) == 0) { - const u32 *p; - - printf("<"); - for (j = 0, p = data; j < len/4; j ++) - printf("0x%x%s", p[j], j < (len/4 - 1) ? " " : ""); - printf(">"); + if (len > CONFIG_CMD_FDT_MAX_DUMP) + printf("* 0x%p [0x%08x]", data, len); + else { + const __be32 *p; + + printf("<"); + for (j = 0, p = data; j < len/4; j++) + printf("0x%08x%s", fdt32_to_cpu(p[j]), + j < (len/4 - 1) ? " " : ""); + printf(">"); + } } else { /* anything else... hexdump */ - const u8 *s; - - printf("["); - for (j = 0, s = data; j < len; j++) - printf("%02x%s", s[j], j < len - 1 ? " " : ""); - printf("]"); + if (len > CONFIG_CMD_FDT_MAX_DUMP) + printf("* 0x%p [0x%08x]", data, len); + else { + const u8 *s; + + printf("["); + for (j = 0, s = data; j < len; j++) + printf("%02x%s", s[j], j < len - 1 ? " " : ""); + printf("]"); + } } } @@ -778,17 +963,20 @@ static int fdt_print(const char *pathp, char *prop, int depth) } /********************************************************************/ - -U_BOOT_CMD( - fdt, 255, 0, do_fdt, - "fdt - flattened device tree utility commands\n", - "addr [] - Set the fdt location to \n" +#ifdef CONFIG_SYS_LONGHELP +static char fdt_help_text[] = + "addr [] - Set the fdt location to \n" #ifdef CONFIG_OF_BOARD_SETUP "fdt boardsetup - Do board-specific set up\n" #endif "fdt move - Copy the fdt to and make it active\n" + "fdt resize - Resize fdt to size + padding to 4k addr\n" "fdt print [] - Recursive print starting at \n" "fdt list [] - Print one level starting at \n" + "fdt get value - Get and store in \n" + "fdt get name - Get name of node and store in \n" + "fdt get addr - Get start address of and store in \n" + "fdt get size [] - Get size of [] or num nodes and store in \n" "fdt set [] - Set [to ]\n" "fdt mknode - Create a new node after \n" "fdt rm [] - Delete the node or \n" @@ -798,7 +986,13 @@ U_BOOT_CMD( "fdt rsvmem print - Show current mem reserves\n" "fdt rsvmem add - Add a mem reserve\n" "fdt rsvmem delete - Delete a mem reserves\n" - "fdt chosen - Add/update the /chosen branch in the tree\n" - "NOTE: If the path or property you are setting/printing has a '#' character\n" - " or spaces, you MUST escape it with a \\ character or quote it with \".\n" + "fdt chosen [ ] - Add/update the /chosen branch in the tree\n" + " / - initrd start/end addr\n" + "NOTE: Dereference aliases by omiting the leading '/', " + "e.g. fdt print ethernet0."; +#endif + +U_BOOT_CMD( + fdt, 255, 0, do_fdt, + "flattened device tree utility commands", fdt_help_text );