diff options
-rw-r--r-- | common/cmd_bootm.c | 208 | ||||
-rw-r--r-- | common/cmd_fdt.c | 619 | ||||
-rw-r--r-- | common/fdt_support.c | 101 | ||||
-rw-r--r-- | include/fdt_support.h | 6 | ||||
-rw-r--r-- | include/libfdt.h | 8 | ||||
-rw-r--r-- | include/libfdt_env.h | 2 | ||||
-rw-r--r-- | libfdt/fdt.c | 5 | ||||
-rw-r--r-- | libfdt/fdt_ro.c | 173 | ||||
-rw-r--r-- | libfdt/fdt_rw.c | 5 | ||||
-rw-r--r-- | libfdt/fdt_strerror.c | 5 | ||||
-rw-r--r-- | libfdt/fdt_sw.c | 5 | ||||
-rw-r--r-- | libfdt/fdt_wip.c | 5 |
12 files changed, 689 insertions, 453 deletions
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 2436581..e19f83e 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -45,8 +45,8 @@ DECLARE_GLOBAL_DATA_PTR; - /*cmd_boot.c*/ - extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +/*cmd_boot.c*/ +extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) #include <rtc.h> @@ -362,7 +362,6 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) if (i != BZ_OK) { printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i); show_boot_progress (-6); - udelay(100000); do_reset (cmdtp, flag, argc, argv); } break; @@ -741,59 +740,65 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, if(argc > 3) { of_flat_tree = (char *) simple_strtoul(argv[3], NULL, 16); hdr = (image_header_t *)of_flat_tree; -#if defined(CONFIG_OF_LIBFDT) - if (fdt_check_header(of_flat_tree) == 0) { +#if defined(CONFIG_OF_FLAT_TREE) + if (*((ulong *)(of_flat_tree + sizeof(image_header_t))) != OF_DT_HEADER) { #else - if (*(ulong *)of_flat_tree == OF_DT_HEADER) { + if (fdt_check_header(of_flat_tree + sizeof(image_header_t)) != 0) { #endif #ifndef CFG_NO_FLASH if (addr2info((ulong)of_flat_tree) != NULL) of_data = (ulong)of_flat_tree; #endif } else if (ntohl(hdr->ih_magic) == IH_MAGIC) { - printf("## Flat Device Tree Image at %08lX\n", hdr); + printf("## Flat Device Tree at %08lX\n", hdr); print_image_hdr(hdr); if ((ntohl(hdr->ih_load) < ((unsigned long)hdr + ntohl(hdr->ih_size) + sizeof(hdr))) && ((ntohl(hdr->ih_load) + ntohl(hdr->ih_size)) > (unsigned long)hdr)) { - printf ("ERROR: Load address overwrites Flat Device Tree uImage\n"); - return; + puts ("ERROR: fdt overwritten - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } - printf(" Verifying Checksum ... "); + puts (" Verifying Checksum ... "); memmove (&header, (char *)hdr, sizeof(image_header_t)); checksum = ntohl(header.ih_hcrc); header.ih_hcrc = 0; if(checksum != crc32(0, (uchar *)&header, sizeof(image_header_t))) { - printf("ERROR: Flat Device Tree header checksum is invalid\n"); - return; + puts ("ERROR: fdt header checksum invalid - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } checksum = ntohl(hdr->ih_dcrc); addr = (ulong)((uchar *)(hdr) + sizeof(image_header_t)); if(checksum != crc32(0, (uchar *)addr, ntohl(hdr->ih_size))) { - printf("ERROR: Flat Device Tree checksum is invalid\n"); - return; + puts ("ERROR: fdt checksum invalid - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } - printf("OK\n"); + puts ("OK\n"); if (ntohl(hdr->ih_type) != IH_TYPE_FLATDT) { - printf ("ERROR: uImage not Flat Device Tree type\n"); - return; + puts ("ERROR: uImage is not a fdt - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } if (ntohl(hdr->ih_comp) != IH_COMP_NONE) { - printf("ERROR: uImage is not uncompressed\n"); - return; + puts ("ERROR: uImage is compressed - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } -#if defined(CONFIG_OF_LIBFDT) - if (fdt_check_header(of_flat_tree + sizeof(image_header_t)) == 0) { -#else +#if defined(CONFIG_OF_FLAT_TREE) if (*((ulong *)(of_flat_tree + sizeof(image_header_t))) != OF_DT_HEADER) { +#else + if (fdt_check_header(of_flat_tree + sizeof(image_header_t)) != 0) { #endif - printf ("ERROR: uImage data is not a flat device tree\n"); - return; + puts ("ERROR: uImage data is not a fdt - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } memmove((void *)ntohl(hdr->ih_load), @@ -801,10 +806,11 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, ntohl(hdr->ih_size)); of_flat_tree = (char *)ntohl(hdr->ih_load); } else { - printf ("Did not find a flat flat device tree at address %08lX\n", of_flat_tree); - return; + puts ("Did not find a flat Flat Device Tree.\n" + "Must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } - printf (" Booting using flat device tree at 0x%x\n", + printf (" Booting using the fdt at 0x%x\n", of_flat_tree); } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1]) && (len_ptr[2])) { u_long tail = ntohl(len_ptr[0]) % 4; @@ -828,22 +834,24 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, of_data += 4 - tail; } -#if defined(CONFIG_OF_LIBFDT) - if (fdt_check_header((void *)of_data) != 0) { +#if defined(CONFIG_OF_FLAT_TREE) + if (*((ulong *)(of_flat_tree + sizeof(image_header_t))) != OF_DT_HEADER) { #else - if (((struct boot_param_header *)of_data)->magic != OF_DT_HEADER) { + if (fdt_check_header(of_flat_tree + sizeof(image_header_t)) != 0) { #endif - printf ("ERROR: image is not a flat device tree\n"); - return; + puts ("ERROR: image is not a fdt - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } -#if defined(CONFIG_OF_LIBFDT) - if (be32_to_cpu(fdt_totalsize(of_data)) != ntohl(len_ptr[2])) { -#else +#if defined(CONFIG_OF_FLAT_TREE) if (((struct boot_param_header *)of_data)->totalsize != ntohl(len_ptr[2])) { +#else + if (be32_to_cpu(fdt_totalsize(of_data)) != ntohl(len_ptr[2])) { #endif - printf ("ERROR: flat device tree size does not agree with image\n"); - return; + puts ("ERROR: fdt size != image size - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } } #endif @@ -916,15 +924,6 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, initrd_end = 0; } - debug ("## Transferring control to Linux (at address %08lx) ...\n", - (ulong)kernel); - - show_boot_progress (15); - -#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) - unlock_ram_in_cache(); -#endif - #if defined(CONFIG_OF_LIBFDT) /* move of_flat_tree if needed */ if (of_data) { @@ -944,32 +943,41 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, of_flat_tree = (char *)of_start; printf (" Loading Device Tree to %08lx, end %08lx ... ", of_start, of_start + of_len - 1); - err = fdt_open_into((void *)of_start, (void *)of_data, of_len); + err = fdt_open_into((void *)of_data, (void *)of_start, of_len); if (err != 0) { - printf ("libfdt: %s " __FILE__ " %d\n", fdt_strerror(err), __LINE__); - } - /* - * Add the chosen node if it doesn't exist, add the env and bd_t - * if the user wants it (the logic is in the subroutines). - */ - if (fdt_chosen(of_flat_tree, initrd_start, initrd_end, 0) < 0) { - printf("Failed creating the /chosen node (0x%08X), aborting.\n", of_flat_tree); - return; + puts ("ERROR: fdt move failed - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } + } + /* + * Add the chosen node if it doesn't exist, add the env and bd_t + * if the user wants it (the logic is in the subroutines). + */ + if (fdt_chosen(of_flat_tree, initrd_start, initrd_end, 0) < 0) { + puts ("ERROR: /chosen node create failed - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); + } #ifdef CONFIG_OF_HAS_UBOOT_ENV - if (fdt_env(of_flat_tree) < 0) { - printf("Failed creating the /u-boot-env node, aborting.\n"); - return; - } + if (fdt_env(of_flat_tree) < 0) { + puts ("ERROR: /u-boot-env node create failed - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); + } #endif #ifdef CONFIG_OF_HAS_BD_T - if (fdt_bd_t(of_flat_tree) < 0) { - printf("Failed creating the /bd_t node, aborting.\n"); - return; - } -#endif + if (fdt_bd_t(of_flat_tree) < 0) { + puts ("ERROR: /bd_t node create failed - " + "must RESET the board to recover.\n"); + do_reset (cmdtp, flag, argc, argv); } #endif +#ifdef CONFIG_OF_BOARD_SETUP + /* Call the board-specific fixup routine */ + ft_board_setup(of_flat_tree, gd->bd); +#endif +#endif /* CONFIG_OF_LIBFDT */ #if defined(CONFIG_OF_FLAT_TREE) /* move of_flat_tree if needed */ if (of_data) { @@ -989,8 +997,36 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, of_start, of_start + of_len - 1); memmove ((void *)of_start, (void *)of_data, of_len); } + /* + * Create the /chosen node and modify the blob with board specific + * values as needed. + */ + ft_setup(of_flat_tree, kbd, initrd_start, initrd_end); + /* ft_dump_blob(of_flat_tree); */ +#endif + debug ("## Transferring control to Linux (at address %08lx) ...\n", + (ulong)kernel); + + show_boot_progress (15); + +#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) + unlock_ram_in_cache(); #endif +#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) + if (of_flat_tree) { /* device tree; boot new style */ + /* + * Linux Kernel Parameters (passing device tree): + * r3: pointer to the fdt, followed by the board info data + * r4: physical pointer to the kernel itself + * r5: NULL + * r6: NULL + * r7: NULL + */ + (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0); + /* does not return */ + } +#endif /* * Linux Kernel Parameters (passing board info data): * r3: ptr to board info data @@ -999,46 +1035,8 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, * r6: Start of command line string * r7: End of command line string */ -#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 */ - -#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 - * r4: physical pointer to the kernel itself - * r5: NULL - * 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 -#if defined(CONFIG_OF_LIBFDT) - if (fdt_chosen(of_flat_tree, initrd_start, initrd_end, 0) < 0) { - printf("Failed creating the /chosen node (0x%08X), aborting.\n", of_flat_tree); - return; - } -#ifdef CONFIG_OF_HAS_UBOOT_ENV - if (fdt_env(of_flat_tree) < 0) { - printf("Failed creating the /u-boot-env node, aborting.\n"); - return; - } -#endif -#ifdef CONFIG_OF_HAS_BD_T - if (fdt_bd_t(of_flat_tree) < 0) { - printf("Failed creating the /bd_t node, aborting.\n"); - return; - } -#endif -#endif /* if defined(CONFIG_OF_LIBFDT) */ - - (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0); -#endif + (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); + /* does not return */ } #endif /* CONFIG_PPC */ diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 08fe351..571b8f1 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -37,46 +37,32 @@ #include <fdt_support.h> #define MAX_LEVEL 32 /* how deeply nested we will go */ -#define SCRATCHPAD 1024 /* bytes of scratchpad memory */ +#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_parse_prop(char *pathp, char *prop, char *newval, + char *data, int *len); +static int fdt_print(char *pathp, char *prop, int depth); /* * 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') { + if (argv[1][0] == 'a') { /* * Set the address [and length] of the fdt. */ @@ -94,7 +80,8 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) */ len = simple_strtoul(argv[3], NULL, 16); if (len < fdt_totalsize(fdt)) { - printf ("New length %d < existing length %d, ignoring.\n", + printf ("New length %d < existing length %d, " + "ignoring.\n", len, fdt_totalsize(fdt)); } else { /* @@ -102,7 +89,8 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) */ err = fdt_open_into(fdt, fdt, len); if (err != 0) { - printf ("libfdt: %s\n", fdt_strerror(err)); + printf ("libfdt fdt_open_into(): %s\n", + fdt_strerror(err)); } } } @@ -110,12 +98,12 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) /******************************************************************** * Move the fdt ********************************************************************/ - } else if (op == 'm') { + } else if ((argv[1][0] == 'm') && (argv[1][1] == 'o')) { struct fdt_header *newaddr; int len; int err; - if (argc != 5) { + if (argc < 4) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } @@ -128,12 +116,22 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 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; + newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16); + + /* + * If the user specifies a length, use that. Otherwise use the + * current length. + */ + if (argc <= 4) { + len = fdt_totalsize(fdt); + } else { + len = simple_strtoul(argv[4], NULL, 16); + if (len < fdt_totalsize(fdt)) { + printf ("New length 0x%X < existing length " + "0x%X, aborting.\n", + len, fdt_totalsize(fdt)); + return 1; + } } /* @@ -141,26 +139,59 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) */ err = fdt_open_into(fdt, newaddr, len); if (err != 0) { - printf ("libfdt: %s\n", fdt_strerror(err)); + printf ("libfdt fdt_open_into(): %s\n", + fdt_strerror(err)); return 1; } fdt = newaddr; /******************************************************************** - * Set the value of a node in the fdt. + * Make a new node + ********************************************************************/ + } else if ((argv[1][0] == 'm') && (argv[1][1] == 'k')) { + char *pathp; /* path */ + char *nodep; /* new node to add */ + int nodeoffset; /* node offset from libfdt */ + int err; + + /* + * Parameters: Node path, new node to be appended to the path. + */ + if (argc < 4) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + pathp = argv[2]; + nodep = argv[3]; + + nodeoffset = fdt_find_node_by_path (fdt, pathp); + if (nodeoffset < 0) { + /* + * Not found or something else bad happened. + */ + printf ("libfdt fdt_find_node_by_path() returned %s\n", + fdt_strerror(nodeoffset)); + return 1; + } + err = fdt_add_subnode(fdt, nodeoffset, nodep); + if (err < 0) { + printf ("libfdt fdt_add_subnode(): %s\n", + fdt_strerror(err)); + return 1; + } + + /******************************************************************** + * Set the value of a property in the fdt. ********************************************************************/ - } else if (op == 's') { + } else if (argv[1][0] == 's') { char *pathp; /* path */ - char *prop; /* property */ - struct fdt_property *nodep; /* node struct pointer */ + char *prop; /* property */ 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 */ + static char data[SCRATCHPAD]; /* storage for the property */ + int len; /* new length of the property */ + int ret; /* return value */ /* * Parameters: Node path, property, value. @@ -174,121 +205,38 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 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) { + nodeoffset = fdt_find_node_by_path (fdt, pathp); + if (nodeoffset < 0) { /* - * The specified property has no value + * Not found or something else bad happened. */ - printf("%s has no value, cannot set one (yet).\n", prop); + printf ("libfdt fdt_find_node_by_path() returned %s\n", + fdt_strerror(nodeoffset)); 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_parse_prop(pathp, prop, newval, data, &len); + if (ret != 0) + return ret; - ret = fdt_setprop(fdt, nodeoffset, prop, data, len); - if (ret < 0) { - printf ("libfdt %s\n", fdt_strerror(ret)); - return 1; - } + ret = fdt_setprop(fdt, nodeoffset, prop, data, len); + if (ret < 0) { + printf ("libfdt fdt_setprop(): %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"; + } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { 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 */ + char *prop; /* property */ + int ret; /* return value */ /* * list is an alias for print, but limited to 1 level */ - if (op == 'l') { + if (argv[1][0] == 'l') { depth = 1; } @@ -302,99 +250,14 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 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; - } + ret = fdt_print(pathp, prop, depth); + if (ret != 0) + return ret; /******************************************************************** * Remove a property/node ********************************************************************/ - } else if (op == 'r') { + } else if (argv[1][0] == 'r') { int nodeoffset; /* node offset from libfdt */ int err; @@ -402,17 +265,14 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) * 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; - } + nodeoffset = fdt_find_node_by_path (fdt, argv[2]); + if (nodeoffset < 0) { + /* + * Not found or something else bad happened. + */ + printf ("libfdt fdt_find_node_by_path() returned %s\n", + fdt_strerror(nodeoffset)); + return 1; } /* * Do the delete. A fourth parameter means delete a property, @@ -421,39 +281,40 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) if (argc > 3) { err = fdt_delprop(fdt, nodeoffset, argv[3]); if (err < 0) { - printf("fdt_delprop libfdt: %s\n", fdt_strerror(err)); + printf("libfdt fdt_delprop(): %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)); + printf("libfdt fdt_del_node(): %s\n", + fdt_strerror(err)); return err; } } - - /******************************************************************** - * Create a chosen node - ********************************************************************/ - } else if (op == 'c') { + } +#ifdef CONFIG_OF_BOARD_SETUP + /* Call the board-specific fixup routine */ + else if (argv[1][0] == 'b') + ft_board_setup(fdt, gd->bd); +#endif + /* Create a chosen node */ + else if (argv[1][0] == 'c') fdt_chosen(fdt, 0, 0, 1); - /******************************************************************** - * Create a u-boot-env node - ********************************************************************/ - } else if (op == 'e') { +#ifdef CONFIG_OF_HAS_UBOOT_ENV + /* Create a u-boot-env node */ + else if (argv[1][0] == 'e') fdt_env(fdt); - - /******************************************************************** - * Create a bd_t node - ********************************************************************/ - } else if (op == 'b') { +#endif +#ifdef CONFIG_OF_HAS_BD_T + /* Create a bd_t node */ + else if (argv[1][0] == 'b') fdt_bd_t(fdt); - - /******************************************************************** - * Unrecognized command - ********************************************************************/ - } else { +#endif + else { + /* Unrecognized command */ printf ("Usage:\n%s\n", cmdtp->usage); return 1; } @@ -461,7 +322,7 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) return 0; } -/********************************************************************/ +/****************************************************************************/ static int fdt_valid(void) { @@ -477,19 +338,21 @@ static int fdt_valid(void) return 1; /* valid */ if (err < 0) { - printf("libfdt: %s", fdt_strerror(err)); + printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); /* * Be more informative on bad version. */ if (err == -FDT_ERR_BADVERSION) { if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) { printf (" - too old, fdt $d < %d", - fdt_version(fdt), FDT_FIRST_SUPPORTED_VERSION); + fdt_version(fdt), + FDT_FIRST_SUPPORTED_VERSION); fdt = NULL; } if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) { printf (" - too new, fdt $d > %d", - fdt_version(fdt), FDT_LAST_SUPPORTED_VERSION); + fdt_version(fdt), + FDT_LAST_SUPPORTED_VERSION); fdt = NULL; } return 0; @@ -500,13 +363,91 @@ static int fdt_valid(void) 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> + * Parse the user's input, partially heuristic. Valid formats: + * <00> - hex byte + * <0011> - hex half word (16 bits) + * <00112233> - hex word (32 bits) + * - hex double words (64 bits) are not supported, must use + * a byte stream instead. + * [00 11 22 .. nn] - byte stream + * "string" - If the the value doesn't start with "<" or "[", it is + * treated as a string. Note that the quotes are + * stripped by the parser before we get the string. + */ +static int fdt_parse_prop(char *pathp, char *prop, char *newval, + char *data, int *len) +{ + char *cp; /* temporary char pointer */ + unsigned long tmp; /* holds converted values */ + + 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) { + *data = tmp & 0xFF; + data += 1; + *len += 1; + } else if ((newval - cp) <= 4) { + *(uint16_t *)data = __cpu_to_be16(tmp); + data += 2; + *len += 2; + } else if ((newval - cp) <= 8) { + *(uint32_t *)data = __cpu_to_be32(tmp); + data += 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); + *data++ = tmp & 0xFF; + *len = *len + 1; + 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); + } + return 0; +} + +/****************************************************************************/ + +/* + * Heuristic to guess if this is a string or concatenated strings. */ static int is_printable_string(const void *data, int len) @@ -546,6 +487,12 @@ static int is_printable_string(const void *data, int len) return 1; } + +/* + * Print the property in the best format, a heuristic guess. Print as + * a string, concatenated strings, a byte, word, double word, or (if all + * else fails) it is printed as a stream of bytes. + */ static void print_data(const void *data, int len) { int j; @@ -601,32 +548,146 @@ static void print_data(const void *data, int len) } } +/****************************************************************************/ + +/* + * Recursively print (a portion of) the fdt. The depth parameter + * determines how deeply nested the fdt is printed. + */ +static int fdt_print(char *pathp, char *prop, int depth) +{ + 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"; + 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 */ + + nodeoffset = fdt_find_node_by_path (fdt, pathp); + if (nodeoffset < 0) { + /* + * Not found or something else bad happened. + */ + printf ("libfdt fdt_find_node_by_path() returned %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) { + /* no property value */ + printf("%s %s\n", pathp, prop); + return 0; + } else if (len > 0) { + printf("%s=", prop); + print_data (nodep, len); + printf("\n"); + return 0; + } else { + printf ("libfdt fdt_getprop(): %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. " + "Aborting.\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 fdt_getprop(): %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; + } + return 0; +} + /********************************************************************/ 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" +#ifdef CONFIG_OF_BOARD_SETUP + "fdt boardsetup - Do board-specific set up\n" +#endif "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" + "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" + "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" + "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" + " If the property you are setting/printing has a '#' character or spaces,\n" + " you MUST escape it with a \\ character 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" diff --git a/common/fdt_support.c b/common/fdt_support.c index 69099c4..caaa682 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -37,6 +37,10 @@ */ DECLARE_GLOBAL_DATA_PTR; +/* + * fdt points to our working device tree. + */ +struct fdt_header *fdt; /********************************************************************/ @@ -45,13 +49,12 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) 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; + u32 tmp; /* used to set 32 bit integer properties */ + char *str; /* used to set string properties */ err = fdt_check_header(fdt); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("fdt_chosen: %s\n", fdt_strerror(err)); return err; } @@ -63,11 +66,12 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) err = fdt_num_reservemap(fdt, &used, &total); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("fdt_chosen: %s\n", fdt_strerror(err)); return err; } if (used >= total) { - printf("fdt_chosen: no room in the reserved map (%d of %d)\n", + printf("WARNING: " + "no room in the reserved map (%d of %d)\n", used, total); return -1; } @@ -84,7 +88,7 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) err = fdt_replace_reservemap_entry(fdt, j, initrd_start, initrd_end - initrd_start + 1); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("fdt_chosen: %s\n", fdt_strerror(err)); return err; } } @@ -92,7 +96,7 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) /* * Find the "chosen" node. */ - nodeoffset = fdt_path_offset (fdt, "/chosen"); + nodeoffset = fdt_find_node_by_path (fdt, "/chosen"); /* * If we have a "chosen" node already the "force the writing" @@ -110,7 +114,8 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) */ nodeoffset = fdt_add_subnode(fdt, 0, "chosen"); if (nodeoffset < 0) { - printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + printf("WARNING: could not create /chosen %s.\n", + fdt_strerror(nodeoffset)); return nodeoffset; } } @@ -120,42 +125,35 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) */ str = getenv("bootargs"); if (str != NULL) { - err = fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1); + err = fdt_setprop(fdt, nodeoffset, + "bootargs", str, strlen(str)+1); if (err < 0) - printf("libfdt: %s\n", fdt_strerror(err)); + printf("WARNING: could not set bootargs %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)); + err = fdt_setprop(fdt, nodeoffset, + "linux,initrd-start", &tmp, sizeof(tmp)); if (err < 0) - printf("libfdt: %s\n", fdt_strerror(err)); + printf("WARNING: " + "could not set linux,initrd-start %s.\n", + fdt_strerror(err)); tmp = __cpu_to_be32(initrd_end); - err = fdt_setprop(fdt, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp)); + err = fdt_setprop(fdt, nodeoffset, + "linux,initrd-end", &tmp, sizeof(tmp)); if (err < 0) - printf("libfdt: %s\n", fdt_strerror(err)); + printf("WARNING: could not set linux,initrd-end %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); + 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)); + printf("WARNING: could not set linux,stdout-path %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 return err; } @@ -177,7 +175,7 @@ int fdt_env(void *fdt) err = fdt_check_header(fdt); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("fdt_env: %s\n", fdt_strerror(err)); return err; } @@ -185,11 +183,11 @@ int fdt_env(void *fdt) * 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"); + nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env"); if (nodeoffset >= 0) { err = fdt_del_node(fdt, nodeoffset); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("fdt_env: %s\n", fdt_strerror(err)); return err; } } @@ -198,7 +196,8 @@ int fdt_env(void *fdt) */ nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env"); if (nodeoffset < 0) { - printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + printf("WARNING: could not create /u-boot-env %s.\n", + fdt_strerror(nodeoffset)); return nodeoffset; } @@ -226,7 +225,8 @@ int fdt_env(void *fdt) continue; err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("WARNING: could not set %s %s.\n", + lval, fdt_strerror(err)); return err; } } @@ -292,12 +292,12 @@ int fdt_bd_t(void *fdt) bd_t *bd = gd->bd; int nodeoffset; int err; - u32 tmp; /* used to set 32 bit integer properties */ + u32 tmp; /* used to set 32 bit integer properties */ int i; err = fdt_check_header(fdt); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("fdt_bd_t: %s\n", fdt_strerror(err)); return err; } @@ -305,11 +305,11 @@ int fdt_bd_t(void *fdt) * 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"); + nodeoffset = fdt_find_node_by_path (fdt, "/bd_t"); if (nodeoffset >= 0) { err = fdt_del_node(fdt, nodeoffset); if (err < 0) { - printf("libfdt: %s\n", fdt_strerror(err)); + printf("fdt_bd_t: %s\n", fdt_strerror(err)); return err; } } @@ -318,7 +318,9 @@ int fdt_bd_t(void *fdt) */ nodeoffset = fdt_add_subnode(fdt, 0, "bd_t"); if (nodeoffset < 0) { - printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + printf("WARNING: could not create /bd_t %s.\n", + fdt_strerror(nodeoffset)); + printf("fdt_bd_t: %s\n", fdt_strerror(nodeoffset)); return nodeoffset; } /* @@ -326,20 +328,23 @@ int fdt_bd_t(void *fdt) */ 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)); + err = fdt_setprop(fdt, nodeoffset, + bd_map[i].name, &tmp, sizeof(tmp)); if (err < 0) - printf("libfdt: %s\n", fdt_strerror(err)); + printf("WARNING: could not set %s %s.\n", + bd_map[i].name, 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)); + printf("WARNING: could not set enetaddr %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)); - + printf("WARNING: could not set ethspeed %s.\n", + fdt_strerror(err)); return 0; } #endif /* ifdef CONFIG_OF_HAS_BD_T */ diff --git a/include/fdt_support.h b/include/fdt_support.h index a276834..60fa423 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -38,5 +38,11 @@ int fdt_env(void *fdt); int fdt_bd_t(void *fdt); #endif +#ifdef CONFIG_OF_BOARD_SETUP +void ft_board_setup(void *blob, bd_t *bd); +void ft_cpu_setup(void *blob, bd_t *bd); +void ft_pci_setup(void *blob, bd_t *bd); +#endif + #endif /* ifdef CONFIG_OF_LIBFDT */ #endif /* ifndef __FDT_SUPPORT_H */ diff --git a/include/libfdt.h b/include/libfdt.h index f8bac73..340e89d 100644 --- a/include/libfdt.h +++ b/include/libfdt.h @@ -77,7 +77,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, const char *name, int namelen); int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); -int fdt_path_offset(const void *fdt, const char *path); +int fdt_find_node_by_path(const void *fdt, const char *path); +int fdt_find_node_by_type(const void *fdt, int nodeoffset, const char *type); + +int fdt_node_is_compatible(const void *fdt, int nodeoffset, + const char *compat); +int fdt_find_compatible_node(const void *fdt, int nodeoffset, + const char *type, const char *compat); struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp); diff --git a/include/libfdt_env.h b/include/libfdt_env.h index e746314..78f7258 100644 --- a/include/libfdt_env.h +++ b/include/libfdt_env.h @@ -26,7 +26,7 @@ #include <asm/byteorder.h> #include <linux/string.h> -struct fdt_header *fdt; /* Pointer to the working fdt */ +extern struct fdt_header *fdt; /* Pointer to the working fdt */ #define fdt32_to_cpu(x) __be32_to_cpu(x) #define cpu_to_fdt32(x) __cpu_to_be32(x) diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 212b838..1ee67ad 100644 --- a/libfdt/fdt.c +++ b/libfdt/fdt.c @@ -16,6 +16,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if CONFIG_OF_LIBFDT + #include "libfdt_env.h" #include <fdt.h> @@ -83,3 +86,5 @@ int fdt_move(const void *fdt, void *buf, int bufsize) memmove(buf, fdt, fdt_totalsize(fdt)); return 0; } + +#endif /* CONFIG_OF_LIBFDT */ diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 4e2c325..ffd9209 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -16,6 +16,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if CONFIG_OF_LIBFDT + #include "libfdt_env.h" #include <fdt.h> @@ -48,6 +51,33 @@ static int offset_streq(const void *fdt, int offset, } /* + * Checks if the property name matches. + */ +static int prop_name_eq(const void *fdt, int offset, const char *name, + struct fdt_property **prop, int *lenp) +{ + int namestroff, len; + + *prop = fdt_offset_ptr_typed(fdt, offset, *prop); + if (! *prop) + return -FDT_ERR_BADSTRUCTURE; + + namestroff = fdt32_to_cpu((*prop)->nameoff); + if (streq(fdt_string(fdt, namestroff), name)) { + len = fdt32_to_cpu((*prop)->len); + *prop = fdt_offset_ptr(fdt, offset, + sizeof(**prop) + len); + if (*prop) { + if (lenp) + *lenp = len; + return 1; + } else + return -FDT_ERR_BADSTRUCTURE; + } + return 0; +} + +/* * Return a pointer to the string at the given string offset. */ char *fdt_string(const void *fdt, int stroffset) @@ -56,6 +86,118 @@ char *fdt_string(const void *fdt, int stroffset) } /* + * Check if the specified node is compatible by comparing the tokens + * in its "compatible" property with the specified string: + * + * nodeoffset - starting place of the node + * compat - the string to match to one of the tokens in the + * "compatible" list. + */ +int fdt_node_is_compatible(const void *fdt, int nodeoffset, + const char *compat) +{ + const char* cp; + int cplen, len; + + cp = fdt_getprop(fdt, nodeoffset, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strncmp(cp, compat, strlen(compat)) == 0) + return 1; + len = strlen(cp) + 1; + cp += len; + cplen -= len; + } + + return 0; +} + +/* + * Find a node by its device type property. On success, the offset of that + * node is returned or an error code otherwise: + * + * nodeoffset - the node to start searching from or 0, the node you pass + * will not be searched, only the next one will; typically, + * you pass 0 to start the search and then what the previous + * call returned. + * type - the device type string to match against. + */ +int fdt_find_node_by_type(const void *fdt, int nodeoffset, const char *type) +{ + int offset, nextoffset; + struct fdt_property *prop; + uint32_t tag; + int len, ret; + + CHECK_HEADER(fdt); + + tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL); + if (tag != FDT_BEGIN_NODE) + return -FDT_ERR_BADOFFSET; + if (nodeoffset) + nodeoffset = 0; /* start searching with next node */ + + while (1) { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset, NULL); + + switch (tag) { + case FDT_BEGIN_NODE: + nodeoffset = offset; + break; + + case FDT_PROP: + if (nodeoffset == 0) + break; + ret = prop_name_eq(fdt, offset, "device_type", + &prop, &len); + if (ret < 0) + return ret; + else if (ret > 0 && + strncmp(prop->data, type, len - 1) == 0) + return nodeoffset; + break; + + case FDT_END_NODE: + case FDT_NOP: + break; + + case FDT_END: + return -FDT_ERR_NOTFOUND; + + default: + return -FDT_ERR_BADSTRUCTURE; + } + } +} + +/* + * Find a node based on its device type and one of the tokens in its its + * "compatible" property. On success, the offset of that node is returned + * or an error code otherwise: + * + * nodeoffset - the node to start searching from or 0, the node you pass + * will not be searched, only the next one will; typically, + * you pass 0 to start the search and then what the previous + * call returned. + * type - the device type string to match against. + * compat - the string to match to one of the tokens in the + * "compatible" list. + */ +int fdt_find_compatible_node(const void *fdt, int nodeoffset, + const char *type, const char *compat) +{ + int offset; + + offset = fdt_find_node_by_type(fdt, nodeoffset, type); + if (offset < 0 || fdt_node_is_compatible(fdt, offset, compat)) + return offset; + + return -FDT_ERR_NOTFOUND; +} + +/* * Return the node offset of the node specified by: * parentoffset - starting place (0 to start at the root) * name - name being searched for @@ -129,7 +271,7 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, * Searches for the node corresponding to the given path and returns the * offset of that node. */ -int fdt_path_offset(const void *fdt, const char *path) +int fdt_find_node_by_path(const void *fdt, const char *path) { const char *end = path + strlen(path); const char *p = path; @@ -141,6 +283,10 @@ int fdt_path_offset(const void *fdt, const char *path) if (*path != '/') return -FDT_ERR_BADPATH; + /* Handle the root path: root offset is 0 */ + if (strcmp(path, "/") == 0) + return 0; + while (*p) { const char *q; @@ -184,7 +330,6 @@ struct fdt_property *fdt_get_property(const void *fdt, int level = 0; uint32_t tag; struct fdt_property *prop; - int namestroff; int offset, nextoffset; int err; @@ -224,24 +369,11 @@ struct fdt_property *fdt_get_property(const void *fdt, if (level != 0) continue; - err = -FDT_ERR_BADSTRUCTURE; - prop = fdt_offset_ptr_typed(fdt, offset, prop); - if (! prop) - goto fail; - namestroff = fdt32_to_cpu(prop->nameoff); - if (streq(fdt_string(fdt, namestroff), name)) { - /* Found it! */ - int len = fdt32_to_cpu(prop->len); - prop = fdt_offset_ptr(fdt, offset, - sizeof(*prop)+len); - if (! prop) - goto fail; - - if (lenp) - *lenp = len; - + err = prop_name_eq(fdt, offset, name, &prop, lenp); + if (err > 0) return prop; - } + else if (err < 0) + goto fail; break; case FDT_NOP: @@ -400,3 +532,6 @@ int fdt_get_reservemap(void *fdt, int n, struct fdt_reserve_entry *re) } return 0; } + +#endif /* CONFIG_OF_LIBFDT */ + diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index aaafc53..693bfe4 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -16,6 +16,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if CONFIG_OF_LIBFDT + #include "libfdt_env.h" #include <fdt.h> @@ -291,3 +294,5 @@ int fdt_pack(void *fdt) fdt_set_header(fdt, totalsize, _blob_data_size(fdt)); return 0; } + +#endif /* CONFIG_OF_LIBFDT */ diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c index 7f231ce..b49c952 100644 --- a/libfdt/fdt_strerror.c +++ b/libfdt/fdt_strerror.c @@ -16,6 +16,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if CONFIG_OF_LIBFDT + #include "libfdt_env.h" #include <fdt.h> @@ -62,3 +65,5 @@ const char *fdt_strerror(int errval) return "<unknown error>"; } + +#endif /* CONFIG_OF_LIBFDT */ diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c index 672f4dd..c7eea8f 100644 --- a/libfdt/fdt_sw.c +++ b/libfdt/fdt_sw.c @@ -16,6 +16,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if CONFIG_OF_LIBFDT + #include "libfdt_env.h" #include <fdt.h> @@ -224,3 +227,5 @@ int fdt_finish(void *fdt) fdt_set_header(fdt, magic, FDT_MAGIC); return 0; } + +#endif /* CONFIG_OF_LIBFDT */ diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index 2d2ed37..2d39aab 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -16,6 +16,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if CONFIG_OF_LIBFDT + #include "libfdt_env.h" #include <fdt.h> @@ -135,3 +138,5 @@ int fdt_replace_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size) return 0; } + +#endif /* CONFIG_OF_LIBFDT */ |