diff options
| -rw-r--r-- | board/cm5200/cm5200.c | 2 | ||||
| -rw-r--r-- | board/freescale/mpc832xemds/pci.c | 2 | ||||
| -rw-r--r-- | board/freescale/mpc8349emds/pci.c | 4 | ||||
| -rw-r--r-- | board/freescale/mpc8349itx/pci.c | 4 | ||||
| -rw-r--r-- | board/freescale/mpc8360emds/pci.c | 2 | ||||
| -rw-r--r-- | common/cmd_fdt.c | 76 | ||||
| -rw-r--r-- | common/fdt_support.c | 183 | ||||
| -rw-r--r-- | cpu/mpc5xxx/cpu.c | 40 | ||||
| -rw-r--r-- | cpu/mpc8260/cpu.c | 30 | ||||
| -rw-r--r-- | cpu/mpc83xx/cpu.c | 4 | ||||
| -rw-r--r-- | cpu/mpc83xx/pci.c | 4 | ||||
| -rw-r--r-- | include/fdt.h | 49 | ||||
| -rw-r--r-- | include/fdt_support.h | 16 | ||||
| -rw-r--r-- | include/libfdt.h | 715 | ||||
| -rw-r--r-- | libfdt/Makefile | 2 | ||||
| -rw-r--r-- | libfdt/fdt.c | 102 | ||||
| -rw-r--r-- | libfdt/fdt_ro.c | 713 | ||||
| -rw-r--r-- | libfdt/fdt_rw.c | 271 | ||||
| -rw-r--r-- | libfdt/fdt_strerror.c | 59 | ||||
| -rw-r--r-- | libfdt/fdt_sw.c | 97 | ||||
| -rw-r--r-- | libfdt/fdt_wip.c | 94 | ||||
| -rw-r--r-- | libfdt/libfdt_internal.h | 77 | 
22 files changed, 1779 insertions, 767 deletions
| diff --git a/board/cm5200/cm5200.c b/board/cm5200/cm5200.c index e2ab5b8e2..4a86d3c55 100644 --- a/board/cm5200/cm5200.c +++ b/board/cm5200/cm5200.c @@ -276,7 +276,7 @@ static void ft_blob_update(void *blob, bd_t *bd)  	memory_data[0] = cpu_to_be32(bd->bi_memstart);  	memory_data[1] = cpu_to_be32(bd->bi_memsize); -	nodeoffset = fdt_find_node_by_path (blob, "/memory"); +	nodeoffset = fdt_path_offset (blob, "/memory");  	if (nodeoffset >= 0) {  		ret = fdt_setprop(blob, nodeoffset, "reg", memory_data,  					sizeof(memory_data)); diff --git a/board/freescale/mpc832xemds/pci.c b/board/freescale/mpc832xemds/pci.c index 6bc35c70f..7818a2e1e 100644 --- a/board/freescale/mpc832xemds/pci.c +++ b/board/freescale/mpc832xemds/pci.c @@ -269,7 +269,7 @@ ft_pci_setup(void *blob, bd_t *bd)  	int err;  	int tmp[2]; -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8500");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(hose[0].first_busno);  		tmp[1] = cpu_to_be32(hose[0].last_busno); diff --git a/board/freescale/mpc8349emds/pci.c b/board/freescale/mpc8349emds/pci.c index ae94a2f38..7bcdccbcc 100644 --- a/board/freescale/mpc8349emds/pci.c +++ b/board/freescale/mpc8349emds/pci.c @@ -396,7 +396,7 @@ ft_pci_setup(void *blob, bd_t *bd)  	int err;  	int tmp[2]; -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8500");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(pci_hose[0].first_busno);  		tmp[1] = cpu_to_be32(pci_hose[0].last_busno); @@ -408,7 +408,7 @@ ft_pci_setup(void *blob, bd_t *bd)  				  tmp, sizeof(tmp[0]));  	}  #ifdef CONFIG_MPC83XX_PCI2 -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8600"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8600");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(pci_hose[1].first_busno);  		tmp[1] = cpu_to_be32(pci_hose[1].last_busno); diff --git a/board/freescale/mpc8349itx/pci.c b/board/freescale/mpc8349itx/pci.c index 5ca094d4c..a764a6186 100644 --- a/board/freescale/mpc8349itx/pci.c +++ b/board/freescale/mpc8349itx/pci.c @@ -342,7 +342,7 @@ ft_pci_setup(void *blob, bd_t *bd)  	int err;  	int tmp[2]; -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8500");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(pci_hose[0].first_busno);  		tmp[1] = cpu_to_be32(pci_hose[0].last_busno); @@ -354,7 +354,7 @@ ft_pci_setup(void *blob, bd_t *bd)  				  tmp, sizeof(tmp[0]));  	}  #ifdef CONFIG_MPC83XX_PCI2 -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8500");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(pci_hose[1].first_busno);  		tmp[1] = cpu_to_be32(pci_hose[1].last_busno); diff --git a/board/freescale/mpc8360emds/pci.c b/board/freescale/mpc8360emds/pci.c index cf7ef9044..f18e532ef 100644 --- a/board/freescale/mpc8360emds/pci.c +++ b/board/freescale/mpc8360emds/pci.c @@ -269,7 +269,7 @@ ft_pci_setup(void *blob, bd_t *bd)  	int err;  	int tmp[2]; -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8500");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(hose[0].first_busno);  		tmp[1] = cpu_to_be32(hose[0].last_busno); diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index f18c58385..629c9b413 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -44,7 +44,7 @@ DECLARE_GLOBAL_DATA_PTR;  static int fdt_valid(void);  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); +static int fdt_print(const char *pathp, char *prop, int depth);  /*   * Flattened Device Tree command, see the help for parameter definitions. @@ -75,7 +75,7 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			/*  			 * Optional new length  			 */ -			len =  simple_strtoul(argv[3], NULL, 16); +			len = simple_strtoul(argv[3], NULL, 16);  			if (len < fdt_totalsize(fdt)) {  				printf ("New length %d < existing length %d, "  					"ignoring.\n", @@ -162,12 +162,12 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		pathp = argv[2];  		nodep = argv[3]; -		nodeoffset = fdt_find_node_by_path (fdt, pathp); +		nodeoffset = fdt_path_offset (fdt, pathp);  		if (nodeoffset < 0) {  			/*  			 * Not found or something else bad happened.  			 */ -			printf ("libfdt fdt_find_node_by_path() returned %s\n", +			printf ("libfdt fdt_path_offset() returned %s\n",  				fdt_strerror(nodeoffset));  			return 1;  		} @@ -202,12 +202,12 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		prop   = argv[3];  		newval = argv[4]; -		nodeoffset = fdt_find_node_by_path (fdt, pathp); +		nodeoffset = fdt_path_offset (fdt, pathp);  		if (nodeoffset < 0) {  			/*  			 * Not found or something else bad happened.  			 */ -			printf ("libfdt fdt_find_node_by_path() returned %s\n", +			printf ("libfdt fdt_path_offset() returned %s\n",  				fdt_strerror(nodeoffset));  			return 1;  		} @@ -229,6 +229,7 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		char *pathp;		/* path */  		char *prop;		/* property */  		int  ret;		/* return value */ +		static char root[2] = "/";  		/*  		 * list is an alias for print, but limited to 1 level @@ -241,7 +242,10 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		 * Get the starting path.  The root node is an oddball,  		 * the offset is zero and has no name.  		 */ -		pathp = argv[2]; +		if (argc == 2) +			pathp = root; +		else +			pathp = argv[2];  		if (argc > 3)  			prop = argv[3];  		else @@ -262,12 +266,12 @@ 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.  		 */ -		nodeoffset = fdt_find_node_by_path (fdt, argv[2]); +		nodeoffset = fdt_path_offset (fdt, argv[2]);  		if (nodeoffset < 0) {  			/*  			 * Not found or something else bad happened.  			 */ -			printf ("libfdt fdt_find_node_by_path() returned %s\n", +			printf ("libfdt fdt_path_offset() returned %s\n",  				fdt_strerror(nodeoffset));  			return 1;  		} @@ -518,21 +522,21 @@ static void print_data(const void *data, int len)  	switch (len) {  	case 1:	 /* byte */ -		printf("<%02x>", (*(u8 *) data) & 0xff); +		printf("<0x%02x>", (*(u8 *) data) & 0xff);  		break;  	case 2:	 /* half-word */ -		printf("<%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); +		printf("<0x%04x>", be16_to_cpu(*(u16 *) data) & 0xffff);  		break;  	case 4:	 /* word */ -		printf("<%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); +		printf("<0x%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);  		break;  	case 8:	 /* double-word */  #if __WORDSIZE == 64 -		printf("<%016llx>", be64_to_cpu(*(uint64_t *) data)); +		printf("<0x%016llx>", be64_to_cpu(*(uint64_t *) data));  #else -		printf("<%08x ", be32_to_cpu(*(u32 *) data) & 0xffffffffU); +		printf("<0x%08x ", be32_to_cpu(*(u32 *) data) & 0xffffffffU);  		data += 4; -		printf("%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); +		printf("0x%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);  #endif  		break;  	default:		/* anything else... hexdump */ @@ -551,25 +555,25 @@ 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 fdt_print(const 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 */ +	const 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 */ +	const struct fdt_property *fdt_prop; -	nodeoffset = fdt_find_node_by_path (fdt, pathp); +	nodeoffset = fdt_path_offset (fdt, pathp);  	if (nodeoffset < 0) {  		/*  		 * Not found or something else bad happened.  		 */ -		printf ("libfdt fdt_find_node_by_path() returned %s\n", +		printf ("libfdt fdt_path_offset() returned %s\n",  			fdt_strerror(nodeoffset));  		return 1;  	} @@ -599,45 +603,52 @@ static int fdt_print(char *pathp, char *prop, int depth)  	 * 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); +		tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);  		switch(tag) {  		case FDT_BEGIN_NODE: -			if(level <= depth) +			pathp = fdt_get_name(fdt, nodeoffset, NULL); +			if (level <= depth) { +				if (pathp == NULL) +					pathp = "/* NULL pointer error */"; +				if (*pathp == '\0') +					pathp = "/";	/* root is nameless */  				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"); +				printf("Nested too deep, aborting.\n");  				return 1;  			}  			break;  		case FDT_END_NODE:  			level--; -			if(level <= depth) +			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); +			fdt_prop = fdt_offset_ptr(fdt, nodeoffset, +					sizeof(*fdt_prop)); +			pathp    = fdt_string(fdt, +					fdt32_to_cpu(fdt_prop->nameoff)); +			len      = fdt32_to_cpu(fdt_prop->len); +			nodep    = fdt_prop->data;  			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) +				if (level <= depth)  					printf("%s%s;\n",  						&tabs[MAX_LEVEL - level],  						pathp);  			} else { -				if(level <= depth) { +				if (level <= depth) {  					printf("%s%s=",  						&tabs[MAX_LEVEL - level],  						pathp); @@ -647,11 +658,12 @@ static int fdt_print(char *pathp, char *prop, int depth)  			}  			break;  		case FDT_NOP: +			printf("/* NOP */\n", &tabs[MAX_LEVEL - level]);  			break;  		case FDT_END:  			return 1;  		default: -			if(level <= depth) +			if (level <= depth)  				printf("Unknown tag 0x%08X\n", tag);  			return 1;  		} diff --git a/common/fdt_support.c b/common/fdt_support.c index 175d59eb9..c67bb3d39 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -44,6 +44,32 @@ struct fdt_header *fdt;  /********************************************************************/ +/** + * fdt_find_and_setprop: Find a node and set it's property + * + * @fdt: ptr to device tree + * @node: path of node + * @prop: property name + * @val: ptr to new value + * @len: length of new property value + * @create: flag to create the property if it doesn't exist + * + * Convenience function to directly set a property given the path to the node. + */ +int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, +			 const void *val, int len, int create) +{ +	int nodeoff = fdt_path_offset(fdt, node); + +	if (nodeoff < 0) +		return nodeoff; + +	if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL)) +		return 0; /* create flag not set; so exit quietly */ + +	return fdt_setprop(fdt, nodeoff, prop, val, len); +} +  int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)  {  	int   nodeoffset; @@ -58,34 +84,23 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)  	}  	if (initrd_start && initrd_end) { -		struct fdt_reserve_entry re; -		int  used; -		int  total; +		uint64_t addr, size; +		int  total = fdt_num_mem_rsv(fdt);  		int  j; -		err = fdt_num_reservemap(fdt, &used, &total); -		if (err < 0) { -			printf("fdt_chosen: %s\n", fdt_strerror(err)); -			return err; -		} -		if (used >= total) { -			printf("WARNING: " -				"no room in the reserved map (%d of %d)\n", -				used, total); -			return -1; -		}  		/*  		 * Look for an existing entry and update it.  If we don't find  		 * the entry, we will j be the next available slot.  		 */ -		for (j = 0; j < used; j++) { -			err = fdt_get_reservemap(fdt, j, &re); -			if (re.address == initrd_start) { +		for (j = 0; j < total; j++) { +			err = fdt_get_mem_rsv(fdt, j, &addr, &size); +			if (addr == initrd_start) { +				fdt_del_mem_rsv(fdt, j);  				break;  			}  		} -		err = fdt_replace_reservemap_entry(fdt, j, -			initrd_start, initrd_end - initrd_start + 1); + +		err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);  		if (err < 0) {  			printf("fdt_chosen: %s\n", fdt_strerror(err));  			return err; @@ -95,7 +110,7 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)  	/*  	 * Find the "chosen" node.  	 */ -	nodeoffset = fdt_find_node_by_path (fdt, "/chosen"); +	nodeoffset = fdt_path_offset (fdt, "/chosen");  	/*  	 * If we have a "chosen" node already the "force the writing" @@ -182,7 +197,7 @@ 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_find_node_by_path (fdt, "/u-boot-env"); +	nodeoffset = fdt_path_offset (fdt, "/u-boot-env");  	if (nodeoffset >= 0) {  		err = fdt_del_node(fdt, nodeoffset);  		if (err < 0) { @@ -304,7 +319,7 @@ 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_find_node_by_path (fdt, "/bd_t"); +	nodeoffset = fdt_path_offset (fdt, "/bd_t");  	if (nodeoffset >= 0) {  		err = fdt_del_node(fdt, nodeoffset);  		if (err < 0) { @@ -348,4 +363,128 @@ int fdt_bd_t(void *fdt)  }  #endif /* ifdef CONFIG_OF_HAS_BD_T */ +void do_fixup_by_path(void *fdt, const char *path, const char *prop, +		      const void *val, int len, int create) +{ +#if defined(DEBUG) +	int i; +	debug("Updating property '%s/%s' = ", node, prop); +	for (i = 0; i < len; i++) +		debug(" %.2x", *(u8*)(val+i)); +	debug("\n"); +#endif +	int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create); +	if (rc) +		printf("Unable to update property %s:%s, err=%s\n", +			path, prop, fdt_strerror(rc)); +} + +void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, +			  u32 val, int create) +{ +	val = cpu_to_fdt32(val); +	do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create); +} + +void do_fixup_by_prop(void *fdt, +		      const char *pname, const void *pval, int plen, +		      const char *prop, const void *val, int len, +		      int create) +{ +	int off; +#if defined(DEBUG) +	int i; +	debug("Updating property '%s/%s' = ", node, prop); +	for (i = 0; i < len; i++) +		debug(" %.2x", *(u8*)(val+i)); +	debug("\n"); +#endif +	off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); +	while (off != -FDT_ERR_NOTFOUND) { +		if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) +			fdt_setprop(fdt, off, prop, val, len); +		off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); +	} +} + +void do_fixup_by_prop_u32(void *fdt, +			  const char *pname, const void *pval, int plen, +			  const char *prop, u32 val, int create) +{ +	val = cpu_to_fdt32(val); +	do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create); +} + +void do_fixup_by_compat(void *fdt, const char *compat, +			const char *prop, const void *val, int len, int create) +{ +	int off = -1; +#if defined(DEBUG) +	int i; +	debug("Updating property '%s/%s' = ", node, prop); +	for (i = 0; i < len; i++) +		debug(" %.2x", *(u8*)(val+i)); +	debug("\n"); +#endif +	off = fdt_node_offset_by_compatible(fdt, -1, compat); +	while (off != -FDT_ERR_NOTFOUND) { +		if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) +			fdt_setprop(fdt, off, prop, val, len); +		off = fdt_node_offset_by_compatible(fdt, off, compat); +	} +} + +void do_fixup_by_compat_u32(void *fdt, const char *compat, +			    const char *prop, u32 val, int create) +{ +	val = cpu_to_fdt32(val); +	do_fixup_by_compat(fdt, compat, prop, &val, 4, create); +} + +void fdt_fixup_ethernet(void *fdt, bd_t *bd) +{ +	int node; +	const char *path; + +	node = fdt_path_offset(fdt, "/aliases"); +	if (node >= 0) { +#if defined(CONFIG_HAS_ETH0) +		path = fdt_getprop(fdt, node, "ethernet0", NULL); +		if (path) { +			do_fixup_by_path(fdt, path, "mac-address", +				bd->bi_enetaddr, 6, 0); +			do_fixup_by_path(fdt, path, "local-mac-address", +				bd->bi_enetaddr, 6, 1); +		} +#endif +#if defined(CONFIG_HAS_ETH1) +		path = fdt_getprop(fdt, node, "ethernet1", NULL); +		if (path) { +			do_fixup_by_path(fdt, path, "mac-address", +				bd->bi_enet1addr, 6, 0); +			do_fixup_by_path(fdt, path, "local-mac-address", +				bd->bi_enet1addr, 6, 1); +		} +#endif +#if defined(CONFIG_HAS_ETH2) +		path = fdt_getprop(fdt, node, "ethernet2", NULL); +		if (path) { +			do_fixup_by_path(fdt, path, "mac-address", +				bd->bi_enet2addr, 6, 0); +			do_fixup_by_path(fdt, path, "local-mac-address", +				bd->bi_enet2addr, 6, 1); +		} +#endif +#if defined(CONFIG_HAS_ETH3) +		path = fdt_getprop(fdt, node, "ethernet3", NULL); +		if (path) { +			do_fixup_by_path(fdt, path, "mac-address", +				bd->bi_enet3addr, 6, 0); +			do_fixup_by_path(fdt, path, "local-mac-address", +				bd->bi_enet3addr, 6, 1); +		} +#endif +	} +} +  #endif /* CONFIG_OF_LIBFDT */ diff --git a/cpu/mpc5xxx/cpu.c b/cpu/mpc5xxx/cpu.c index 7f16b92a6..e4d616822 100644 --- a/cpu/mpc5xxx/cpu.c +++ b/cpu/mpc5xxx/cpu.c @@ -35,6 +35,7 @@  #if defined(CONFIG_OF_LIBFDT)  #include <libfdt.h>  #include <libfdt_env.h> +#include <fdt_support.h>  #endif  DECLARE_GLOBAL_DATA_PTR; @@ -114,42 +115,19 @@ unsigned long get_tbclk (void)  /* ------------------------------------------------------------------------- */  #ifdef CONFIG_OF_LIBFDT -static void do_fixup(void *fdt, const char *node, const char *prop, -		     const void *val, int len, int create) -{ -#if defined(DEBUG) -	int i; -	debug("Updating property '%s/%s' = ", node, prop); -	for (i = 0; i < len; i++) -		debug(" %.2x", *(u8*)(val+i)); -	debug("\n"); -#endif -	int rc = fdt_find_and_setprop(fdt, node, prop, val, len, create); -	if (rc) -		printf("Unable to update property %s:%s, err=%s\n", -		       node, prop, fdt_strerror(rc)); -} - -static void do_fixup_u32(void *fdt, const char *node, const char *prop, -			 u32 val, int create) -{ -	val = cpu_to_fdt32(val); -	do_fixup(fdt, node, prop, &val, sizeof(val), create); -} -  void ft_cpu_setup(void *blob, bd_t *bd)  {  	int div = in_8((void*)CFG_MBAR + 0x204) & 0x0020 ? 8 : 4;  	char * cpu_path = "/cpus/" OF_CPU;  	char * eth_path = "/" OF_SOC "/ethernet@3000"; -	do_fixup_u32(blob, cpu_path, "timebase-frequency", OF_TBCLK, 1); -	do_fixup_u32(blob, cpu_path, "bus-frequency", bd->bi_busfreq, 1); -	do_fixup_u32(blob, cpu_path, "clock-frequency", bd->bi_intfreq, 1); -	do_fixup_u32(blob, "/" OF_SOC, "bus-frequency", bd->bi_ipbfreq, 1); -	do_fixup_u32(blob, "/" OF_SOC, "system-frequency", -			bd->bi_busfreq*div, 1); -	do_fixup(blob, eth_path, "mac-address", bd->bi_enetaddr, 6, 0); -	do_fixup(blob, eth_path, "local-mac-address", bd->bi_enetaddr, 6, 0); +	do_fixup_by_path_u32(blob, cpu_path, "timebase-frequency", OF_TBCLK, 1); +	do_fixup_by_path_u32(blob, cpu_path, "bus-frequency", bd->bi_busfreq, 1); +	do_fixup_by_path_u32(blob, cpu_path, "clock-frequency", bd->bi_intfreq, 1); +	do_fixup_by_path_u32(blob, "/" OF_SOC, "bus-frequency", bd->bi_ipbfreq, 1); +	do_fixup_by_path_u32(blob, "/" OF_SOC, "system-frequency", +				bd->bi_busfreq*div, 1); +	do_fixup_by_path(blob, eth_path, "mac-address", bd->bi_enetaddr, 6, 0); +	do_fixup_by_path(blob, eth_path, "local-mac-address", bd->bi_enetaddr, 6, 0);  }  #endif diff --git a/cpu/mpc8260/cpu.c b/cpu/mpc8260/cpu.c index c2b753d6b..55e61a188 100644 --- a/cpu/mpc8260/cpu.c +++ b/cpu/mpc8260/cpu.c @@ -50,6 +50,7 @@  #if defined(CONFIG_OF_LIBFDT)  #include <libfdt.h>  #include <libfdt_env.h> +#include <fdt_support.h>  #endif  DECLARE_GLOBAL_DATA_PTR; @@ -300,35 +301,12 @@ void watchdog_reset (void)  /* ------------------------------------------------------------------------- */  #if defined(CONFIG_OF_LIBFDT) -static void do_fixup(void *fdt, const char *node, const char *prop, -			const void *val, int len, int create) -{ -#if defined(DEBUG) -	int i; -	debug("Updating property '%s/%s' = ", node, prop); -	for (i = 0; i < len; i++) -		debug(" %.2x", *(u8*)(val+i)); -	debug("\n"); -#endif -	int rc = fdt_find_and_setprop(fdt, node, prop, val, len, create); -	if (rc) -		printf("Unable to update property %s:%s, err=%s\n", -			node, prop, fdt_strerror(rc)); -} - -static void do_fixup_u32(void *fdt, const char *node, const char *prop, -			 u32 val, int create) -{ -	val = cpu_to_fdt32(val); -	do_fixup(fdt, node, prop, &val, sizeof(val), create); -} -  void ft_cpu_setup (void *blob, bd_t *bd)  {  	char * cpu_path = "/cpus/" OF_CPU; -	do_fixup_u32(blob, cpu_path, "bus-frequency", bd->bi_busfreq, 1); -	do_fixup_u32(blob, cpu_path, "timebase-frequency", OF_TBCLK, 1); -	do_fixup_u32(blob, cpu_path, "clock-frequency", bd->bi_intfreq, 1); +	do_fixup_by_path_u32(blob, cpu_path, "bus-frequency", bd->bi_busfreq, 1); +	do_fixup_by_path_u32(blob, cpu_path, "timebase-frequency", OF_TBCLK, 1); +	do_fixup_by_path_u32(blob, cpu_path, "clock-frequency", bd->bi_intfreq, 1);  }  #endif /* CONFIG_OF_LIBFDT */ diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index e634f0a25..b2c35d300 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -529,7 +529,7 @@ ft_cpu_setup(void *blob, bd_t *bd)  	int tmp[2];  	for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) { -		nodeoffset = fdt_find_node_by_path(blob, fixup_props[j].node); +		nodeoffset = fdt_path_offset(blob, fixup_props[j].node);  		if (nodeoffset >= 0) {  			err = fixup_props[j].set_fn(blob, nodeoffset,  						    fixup_props[j].prop, bd); @@ -544,7 +544,7 @@ ft_cpu_setup(void *blob, bd_t *bd)  	}  	/* update, or add and update /memory node */ -	nodeoffset = fdt_find_node_by_path(blob, "/memory"); +	nodeoffset = fdt_path_offset(blob, "/memory");  	if (nodeoffset < 0) {  		nodeoffset = fdt_add_subnode(blob, 0, "memory");  		if (nodeoffset < 0) diff --git a/cpu/mpc83xx/pci.c b/cpu/mpc83xx/pci.c index 5675afe97..0defb0ec8 100644 --- a/cpu/mpc83xx/pci.c +++ b/cpu/mpc83xx/pci.c @@ -179,7 +179,7 @@ void ft_pci_setup(void *blob, bd_t *bd)  	if (pci_num_buses < 1)  		return; -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8500");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(pci_hose[0].first_busno);  		tmp[1] = cpu_to_be32(pci_hose[0].last_busno); @@ -194,7 +194,7 @@ void ft_pci_setup(void *blob, bd_t *bd)  	if (pci_num_buses < 2)  		return; -	nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8600"); +	nodeoffset = fdt_path_offset(blob, "/" OF_SOC "/pci@8600");  	if (nodeoffset >= 0) {  		tmp[0] = cpu_to_be32(pci_hose[0].first_busno);  		tmp[1] = cpu_to_be32(pci_hose[0].last_busno); diff --git a/include/fdt.h b/include/fdt.h index 3dd3aca3b..e00559ad6 100644 --- a/include/fdt.h +++ b/include/fdt.h @@ -1,44 +1,25 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -  #ifndef _FDT_H  #define _FDT_H  #ifndef __ASSEMBLY__  struct fdt_header { -	uint32_t magic;			 /* magic word FDT_MAGIC */ -	uint32_t totalsize;		 /* total size of DT block */ -	uint32_t off_dt_struct;		 /* offset to structure */ -	uint32_t off_dt_strings;	 /* offset to strings */ -	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */ -	uint32_t version;		 /* format version */ -	uint32_t last_comp_version;	 /* last compatible version */ +	uint32_t magic;                  /* magic word FDT_MAGIC */ +	uint32_t totalsize;              /* total size of DT block */ +	uint32_t off_dt_struct;          /* offset to structure */ +	uint32_t off_dt_strings;         /* offset to strings */ +	uint32_t off_mem_rsvmap;         /* offset to memory reserve map */ +	uint32_t version;                /* format version */ +	uint32_t last_comp_version;      /* last compatible version */ -	/* version 2 fields below */ -	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're +        /* version 2 fields below */ +	uint32_t boot_cpuid_phys;        /* Which physical CPU id we're  					    booting on */  	/* version 3 fields below */ -	uint32_t size_dt_strings;	 /* size of the strings block */ +        uint32_t size_dt_strings;        /* size of the strings block */  	/* version 17 fields below */ -	uint32_t size_dt_struct;	 /* size of the structure block */ +	uint32_t size_dt_struct;         /* size of the structure block */  };  struct fdt_reserve_entry { @@ -60,12 +41,12 @@ struct fdt_property {  #endif /* !__ASSEMBLY */ -#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */ +#define FDT_MAGIC	0xd00dfeed      /* 4: version, 4: total size */  #define FDT_TAGSIZE	sizeof(uint32_t) -#define FDT_BEGIN_NODE	0x1		/* Start node: full name */ -#define FDT_END_NODE	0x2		/* End node */ -#define FDT_PROP	0x3		/* Property: name off, +#define FDT_BEGIN_NODE	0x1             /* Start node: full name */ +#define FDT_END_NODE	0x2             /* End node */ +#define FDT_PROP	0x3             /* Property: name off,  					   size, content */  #define FDT_NOP		0x4		/* nop */  #define FDT_END		0x9 diff --git a/include/fdt_support.h b/include/fdt_support.h index 60fa423b3..8f781d440 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -29,6 +29,22 @@  #include <fdt.h>  int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force); +void do_fixup_by_path(void *fdt, const char *path, const char *prop, +		      const void *val, int len, int create); +void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, +			  u32 val, int create); +void do_fixup_by_prop(void *fdt, +		      const char *pname, const void *pval, int plen, +		      const char *prop, const void *val, int len, +		      int create); +void do_fixup_by_prop_u32(void *fdt, +			  const char *pname, const void *pval, int plen, +			  const char *prop, u32 val, int create); +void do_fixup_by_compat(void *fdt, const char *compat, +			const char *prop, const void *val, int len, int create); +void do_fixup_by_compat_u32(void *fdt, const char *compat, +			    const char *prop, u32 val, int create); +void fdt_fixup_ethernet(void *fdt, bd_t *bd);  #ifdef CONFIG_OF_HAS_UBOOT_ENV  int fdt_env(void *fdt); diff --git a/include/libfdt.h b/include/libfdt.h index 38c65a989..6b2fb92ea 100644 --- a/include/libfdt.h +++ b/include/libfdt.h @@ -1,154 +1,721 @@ +#ifndef _LIBFDT_H +#define _LIBFDT_H  /*   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library 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 library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met:   * - * This library 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 - * Lesser General Public License for more details. + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#ifndef _LIBFDT_H -#define _LIBFDT_H - -#include <fdt.h>  #include <libfdt_env.h> +#include <fdt.h>  #define FDT_FIRST_SUPPORTED_VERSION	0x10  #define FDT_LAST_SUPPORTED_VERSION	0x11  /* Error codes: informative error codes */  #define FDT_ERR_NOTFOUND	1 +	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */  #define FDT_ERR_EXISTS		2 +	/* FDT_ERR_EXISTS: Attemped to create a node or property which +	 * already exists */  #define FDT_ERR_NOSPACE		3 +	/* FDT_ERR_NOSPACE: Operation needed to expand the device +	 * tree, but its buffer did not have sufficient space to +	 * contain the expanded tree. Use fdt_open_into() to move the +	 * device tree to a buffer with more space. */  /* Error codes: codes for bad parameters */  #define FDT_ERR_BADOFFSET	4 +	/* FDT_ERR_BADOFFSET: Function was passed a structure block +	 * offset which is out-of-bounds, or which points to an +	 * unsuitable part of the structure for the operation. */  #define FDT_ERR_BADPATH		5 -#define FDT_ERR_BADSTATE	6 +	/* FDT_ERR_BADPATH: Function was passed a badly formatted path +	 * (e.g. missing a leading / for a function which requires an +	 * absolute path) */ +#define FDT_ERR_BADPHANDLE	6 +	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle +	 * value.  phandle values of 0 and -1 are not permitted. */ +#define FDT_ERR_BADSTATE	7 +	/* FDT_ERR_BADSTATE: Function was passed an incomplete device +	 * tree created by the sequential-write functions, which is +	 * not sufficiently complete for the requested operation. */  /* Error codes: codes for bad device tree blobs */ -#define FDT_ERR_TRUNCATED	7 -#define FDT_ERR_BADMAGIC	8 -#define FDT_ERR_BADVERSION	9 -#define FDT_ERR_BADSTRUCTURE	10 -#define FDT_ERR_BADLAYOUT	11 +#define FDT_ERR_TRUNCATED	8 +	/* FDT_ERR_TRUNCATED: Structure block of the given device tree +	 * ends without an FDT_END tag. */ +#define FDT_ERR_BADMAGIC	9 +	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a +	 * device tree at all - it is missing the flattened device +	 * tree magic number. */ +#define FDT_ERR_BADVERSION	10 +	/* FDT_ERR_BADVERSION: Given device tree has a version which +	 * can't be handled by the requested operation.  For +	 * read-write functions, this may mean that fdt_open_into() is +	 * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE	11 +	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt +	 * structure block or other serious error (e.g. misnested +	 * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT	12 +	/* FDT_ERR_BADLAYOUT: For read-write functions, the given +	 * device tree has it's sub-blocks in an order that the +	 * function can't handle (memory reserve map, then structure, +	 * then strings).  Use fdt_open_into() to reorganize the tree +	 * into a form suitable for the read-write operations. */ + +/* "Can't happen" error indicating a bug in libfdt */ +#define FDT_ERR_INTERNAL	13 +	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. +	 * Should never be returned, if it is, it indicates a bug in +	 * libfdt itself. */ -#define FDT_ERR_MAX		11 +#define FDT_ERR_MAX		13 + +/**********************************************************************/ +/* Low-level functions (you probably don't need these)                */ +/**********************************************************************/ + +const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); +static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) +{ +	return (void *)fdt_offset_ptr(fdt, offset, checklen); +} + +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); + +/**********************************************************************/ +/* General functions                                                  */ +/**********************************************************************/  #define fdt_get_header(fdt, field) \ -	(fdt32_to_cpu(((struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt)			(fdt_get_header(fdt, magic)) +	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic))  #define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))  #define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))  #define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))  #define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))  #define fdt_version(fdt)		(fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt)	(fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt)	(fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt)	(fdt_get_header(fdt, size_dt_strings)) +#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings))  #define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct)) -#define fdt_set_header(fdt, field, val) \ -	((struct fdt_header *)(fdt))->field = cpu_to_fdt32(val) +#define __fdt_set_hdr(name) \ +	static inline void fdt_set_##name(void *fdt, uint32_t val) \ +	{ \ +		struct fdt_header *fdth = fdt; \ +		fdth->name = cpu_to_fdt32(val); \ +	} +__fdt_set_hdr(magic); +__fdt_set_hdr(totalsize); +__fdt_set_hdr(off_dt_struct); +__fdt_set_hdr(off_dt_strings); +__fdt_set_hdr(off_mem_rsvmap); +__fdt_set_hdr(version); +__fdt_set_hdr(last_comp_version); +__fdt_set_hdr(boot_cpuid_phys); +__fdt_set_hdr(size_dt_strings); +__fdt_set_hdr(size_dt_struct); +#undef __fdt_set_hdr +/** + * fdt_check_header - sanity check a device tree or possible device tree + * @fdt: pointer to data which might be a flattened device tree + * + * fdt_check_header() checks that the given buffer contains what + * appears to be a flattened device tree with sane information in its + * header. + * + * returns: + *     0, if the buffer appears to contain a valid device tree + *     -FDT_ERR_BADMAGIC, + *     -FDT_ERR_BADVERSION, + *     -FDT_ERR_BADSTATE, standard meanings, as above + */  int fdt_check_header(const void *fdt); -void *fdt_offset_ptr(const void *fdt, int offset, int checklen); +/** + * fdt_move - move a device tree around in memory + * @fdt: pointer to the device tree to move + * @buf: pointer to memory where the device is to be moved + * @bufsize: size of the memory space at buf + * + * fdt_move() relocates, if possible, the device tree blob located at + * fdt to the buffer at buf of size bufsize.  The buffer may overlap + * with the existing device tree blob at fdt.  Therefore, + *     fdt_move(fdt, fdt, fdt_totalsize(fdt)) + * should always succeed. + * + * returns: + *     0, on success + *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree + *     -FDT_ERR_BADMAGIC, + *     -FDT_ERR_BADVERSION, + *     -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_move(const void *fdt, void *buf, int bufsize); -#define fdt_offset_ptr_typed(fdt, offset, var) \ -	((typeof(var))(fdt_offset_ptr((fdt), (offset), sizeof(*(var))))) +/**********************************************************************/ +/* Read-only functions                                                */ +/**********************************************************************/ -int fdt_move(const void *fdt, void *buf, int bufsize); +/** + * fdt_string - retreive a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * + * fdt_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt. + * + * returns: + *     a pointer to the string, on success + *     NULL, if stroffset is out of bounds + */ +const char *fdt_string(const void *fdt, int stroffset); -/* Read-only functions */ -char *fdt_string(const void *fdt, int stroffset); +/** + * fdt_num_mem_rsv - retreive the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * + * Returns the number of entries in the device tree blob's memory + * reservation map.  This does not include the terminating 0,0 entry + * or any other (0,0) entries reserved for expansion. + * + * returns: + *     the number of entries + */ +int fdt_num_mem_rsv(const void *fdt); +/** + * fdt_get_mem_rsv - retreive one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: pointers to 64-bit variables + * + * On success, *address and *size will contain the address and size of + * the n-th reserve map entry from the device tree blob, in + * native-endian format. + * + * returns: + *     0, on success + *     -FDT_ERR_BADMAGIC, + *     -FDT_ERR_BADVERSION, + *     -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + +/** + * fdt_subnode_offset_namelen - find a subnode based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_subnode_offset(), but only examine the first + * namelen characters of name for matching the subnode name.  This is + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */  int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,  			       const char *name, int namelen); +/** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node at structure block + * offset parentoffset with the given name.  name may include a unit + * address, in which case fdt_subnode_offset() will find the subnode + * with that unit address, or the unit address may be omitted, in + * which case fdt_subnode_offset() will find an arbitrary subnode + * whose name excluding unit address matches the given name. + * + * returns: + *	structure block offset of the requested subnode (>=0), on success + *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist + *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + *      -FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings. + */  int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); -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); +/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * + * fdt_path_offset() finds a node of a given path in the device tree. + * Each path component may omit the unit address portion, but the + * results of this are undefined if any such path component is + * ambiguous (that is if there are multiple nodes at the relevant + * level matching the given component, differentiated only by unit + * address). + * + * returns: + *	structure block offset of the node with the requested path (>=0), on success + *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + *	-FDT_ERR_NOTFOUND, if the requested node does not exist + *      -FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_path_offset(const void *fdt, const char *path); -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); +/** + * fdt_get_name - retreive the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the starting node + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_name() retrieves the name (including unit address) of the + * device tree node at structure block offset nodeoffset.  If lenp is + * non-NULL, the length of this name is also returned, in the integer + * pointed to by lenp. + * + * returns: + *	pointer to the node's name, on success + *		If lenp is non-NULL, *lenp contains the length of that name (>=0) + *	NULL, on error + *		if lenp is non-NULL *lenp contains an error code (<0): + *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *		-FDT_ERR_BADMAGIC, + *		-FDT_ERR_BADVERSION, + *		-FDT_ERR_BADSTATE, standard meanings + */ +const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); -struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, -				      const char *name, int *lenp); -void *fdt_getprop(const void *fdt, int nodeoffset, -		  const char *name, int *lenp); +/** + * fdt_get_property - find a given property in a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property() retrieves a pointer to the fdt_property + * structure within the device tree blob corresponding to the property + * named 'name' of the node at offset nodeoffset.  If lenp is + * non-NULL, the length of the property value also returned, in the + * integer pointed to by lenp. + * + * returns: + *	pointer to the structure representing the property + *		if lenp is non-NULL, *lenp contains the length of the property + *		value (>=0) + *	NULL, on error + *		if lenp is non-NULL, *lenp contains an error code (<0): + *		-FDT_ERR_NOTFOUND, node does not have named property + *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *		-FDT_ERR_BADMAGIC, + *		-FDT_ERR_BADVERSION, + *		-FDT_ERR_BADSTATE, + *		-FDT_ERR_BADSTRUCTURE, + *		-FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, +					    const char *name, int *lenp); +static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, +						      const char *name, +						      int *lenp) +{ +	return (struct fdt_property *)fdt_get_property(fdt, nodeoffset, +						       name, lenp); +} -uint32_t fdt_next_tag(const void *fdt, int offset, -		      int *nextoffset, char **namep); -int fdt_num_reservemap(void *fdt, int *used, int *total); -int fdt_get_reservemap(void *fdt, int n, struct fdt_reserve_entry *re); +/** + * fdt_getprop - retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop() retrieves a pointer to the value of the property + * named 'name' of the node at offset nodeoffset (this will be a + * pointer to within the device blob itself, not a copy of the value). + * If lenp is non-NULL, the length of the property value also + * returned, in the integer pointed to by lenp. + * + * returns: + *	pointer to the property's value + *		if lenp is non-NULL, *lenp contains the length of the property + *		value (>=0) + *	NULL, on error + *		if lenp is non-NULL, *lenp contains an error code (<0): + *		-FDT_ERR_NOTFOUND, node does not have named property + *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *		-FDT_ERR_BADMAGIC, + *		-FDT_ERR_BADVERSION, + *		-FDT_ERR_BADSTATE, + *		-FDT_ERR_BADSTRUCTURE, + *		-FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop(const void *fdt, int nodeoffset, +			const char *name, int *lenp); +static inline void *fdt_getprop_w(void *fdt, int nodeoffset, +				  const char *name, int *lenp) +{ +	return (void *)fdt_getprop(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_get_phandle - retreive the phandle of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the node + * + * fdt_get_phandle() retrieves the phandle of the device tree node at + * structure block offset nodeoffset. + * + * returns: + *	the phandle of the node at nodeoffset, on succes (!= 0, != -1) + *	0, if the node has no phandle, or another error occurs + */ +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + +/** + * fdt_get_path - determine the full path of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose path to find + * @buf: character buffer to contain the returned path (will be overwritten) + * @buflen: size of the character buffer at buf + * + * fdt_get_path() computes the full path of the node at offset + * nodeoffset, and records that path in the buffer at buf. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + *	0, on success + *		buf contains the absolute path of the node at + *		nodeoffset, as a NUL-terminated string. + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + *		characters and will not fit in the given buffer. + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + +/** + * fdt_supernode_atdepth_offset - find a specific ancestor of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * @supernodedepth: depth of the ancestor to find + * @nodedepth: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_supernode_atdepth_offset() finds an ancestor of the given node + * at a specific depth from the root (where the root itself has depth + * 0, its immediate subnodes depth 1 and so forth).  So + *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * will always return 0, the offset of the root node.  If the node at + * nodeoffset has depth D, then: + *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * will return nodeoffset itself. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + + *	structure block offset of the node at node offset's ancestor + *		of depth supernodedepth (>=0), on success + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag +*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, +				 int supernodedepth, int *nodedepth); + +/** + * fdt_node_depth - find the depth of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_node_depth() finds the depth of a given node.  The root node + * has depth 0, its immediate subnodes depth 1 and so forth. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + *	depth of the node at nodeoffset (>=0), on success + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_depth(const void *fdt, int nodeoffset); + +/** + * fdt_parent_offset - find the parent of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_parent_offset() locates the parent node of a given node (that + * is, it finds the offset of the node which contains the node at + * nodeoffset as a subnode). + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset, *twice*. + * + * returns: + *	stucture block offset of the parent of the node at nodeoffset + *		(>=0), on success + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_parent_offset(const void *fdt, int nodeoffset); + +/** + * fdt_node_offset_by_prop_value - find nodes with a given property value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @propname: property name to check + * @propval: property value to search for + * @proplen: length of the value in propval + * + * fdt_node_offset_by_prop_value() returns the offset of the first + * node after startoffset, which has a property named propname whose + * value is of length proplen and has value equal to propval; or if + * startoffset is -1, the very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + *					       propval, proplen); + *	while (offset != -FDT_ERR_NOTFOUND) { + *		// other code here + *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + *						       propval, proplen); + *	} + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + *	structure block offset of the located node (>= 0, >startoffset), + *		 on success + *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the + *		tree after startoffset + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, +				  const char *propname, +				  const void *propval, int proplen); + +/** + * fdt_node_offset_by_phandle - find the node with a given phandle + * @fdt: pointer to the device tree blob + * @phandle: phandle value + * + * fdt_node_offset_by_prop_value() returns the offset of the node + * which has the given phandle value.  If there is more than one node + * in the tree with the given phandle (an invalid tree), results are + * undefined. + * + * returns: + *	structure block offset of the located node (>= 0), on success + *	-FDT_ERR_NOTFOUND, no node with that phandle exists + *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + +/** + * fdt_node_check_compatible: check a node's compatible property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @compatible: string to match against + * + * + * fdt_node_check_compatible() returns 0 if the given node contains a + * 'compatible' property with the given string as one of its elements, + * it returns non-zero otherwise, or on error. + * + * returns: + *	0, if the node has a 'compatible' property listing the given string + *	1, if the node has a 'compatible' property, but it does not list + *		the given string + *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property + * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_check_compatible(const void *fdt, int nodeoffset, +			      const char *compatible); + +/** + * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @compatible: 'compatible' string to match against + * + * fdt_node_offset_by_compatible() returns the offset of the first + * node after startoffset, which has a 'compatible' property which + * lists the given compatible string; or if startoffset is -1, the + * very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + *	while (offset != -FDT_ERR_NOTFOUND) { + *		// other code here + *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + *	} + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + *	structure block offset of the located node (>= 0, >startoffset), + *		 on success + *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the + *		tree after startoffset + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, +				  const char *compatible); + +/**********************************************************************/ +/* Write-in-place functions                                           */ +/**********************************************************************/ -/* Write-in-place functions */  int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,  			const void *val, int len); - -#define fdt_setprop_inplace_typed(fdt, nodeoffset, name, val) \ -	({ \ -		typeof(val) x = val; \ -		fdt_setprop_inplace(fdt, nodeoffset, name, &x, sizeof(x)); \ -	}) +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, +					   const char *name, uint32_t val) +{ +	val = cpu_to_fdt32(val); +	return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); +}  int fdt_nop_property(void *fdt, int nodeoffset, const char *name);  int fdt_nop_node(void *fdt, int nodeoffset); -int fdt_insert_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size); +/**********************************************************************/ +/* Sequential write functions                                         */ +/**********************************************************************/ -/* Sequential-write functions */  int fdt_create(void *buf, int bufsize);  int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);  int fdt_finish_reservemap(void *fdt);  int fdt_begin_node(void *fdt, const char *name);  int fdt_property(void *fdt, const char *name, const void *val, int len); -#define fdt_property_typed(fdt, name, val) \ -	({ \ -		typeof(val) x = (val); \ -		fdt_property((fdt), (name), &x, sizeof(x)); \ -	}) +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ +	val = cpu_to_fdt32(val); +	return fdt_property(fdt, name, &val, sizeof(val)); +}  #define fdt_property_string(fdt, name, str) \  	fdt_property(fdt, name, str, strlen(str)+1)  int fdt_end_node(void *fdt);  int fdt_finish(void *fdt); -int fdt_replace_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size); -/* Read-write functions */ -int fdt_open_into(void *fdt, void *buf, int bufsize); +/**********************************************************************/ +/* Read-write functions                                               */ +/**********************************************************************/ + +int fdt_open_into(const void *fdt, void *buf, int bufsize);  int fdt_pack(void *fdt); +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); +int fdt_del_mem_rsv(void *fdt, int n); +  int fdt_setprop(void *fdt, int nodeoffset, const char *name,  		const void *val, int len); -#define fdt_setprop_typed(fdt, nodeoffset, name, val) \ -	({ \ -		typeof(val) x = (val); \ -		fdt_setprop((fdt), (nodeoffset), (name), &x, sizeof(x)); \ -	}) +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, +				   uint32_t val) +{ +	val = cpu_to_fdt32(val); +	return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); +}  #define fdt_setprop_string(fdt, nodeoffset, name, str) \  	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) -int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, -			 const void *val, int len, int create);  int fdt_delprop(void *fdt, int nodeoffset, const char *name);  int fdt_add_subnode_namelen(void *fdt, int parentoffset,  			    const char *name, int namelen);  int fdt_add_subnode(void *fdt, int parentoffset, const char *name);  int fdt_del_node(void *fdt, int nodeoffset); -/* Extra functions */ +/**********************************************************************/ +/* Debugging / informational functions                                */ +/**********************************************************************/ +  const char *fdt_strerror(int errval);  #endif /* _LIBFDT_H */ diff --git a/libfdt/Makefile b/libfdt/Makefile index 126fa2c02..d166cce79 100644 --- a/libfdt/Makefile +++ b/libfdt/Makefile @@ -27,7 +27,7 @@ LIB	= $(obj)libfdt.a  SOBJS	= -COBJS-y += fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o fdt_wip.o +COBJS-$(CONFIG_OF_LIBFDT) += fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o fdt_wip.o  COBJS	:= $(COBJS-y)  SRCS 	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 1ee67ad19..586a36136 100644 --- a/libfdt/fdt.c +++ b/libfdt/fdt.c @@ -2,23 +2,52 @@   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option.   * - * This library 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 - * Lesser General Public License for more details. + *  a) This library 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.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     This library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include "config.h" -#if CONFIG_OF_LIBFDT -  #include "libfdt_env.h"  #include <fdt.h> @@ -45,9 +74,9 @@ int fdt_check_header(const void *fdt)  	return 0;  } -void *fdt_offset_ptr(const void *fdt, int offset, int len) +const void *fdt_offset_ptr(const void *fdt, int offset, int len)  { -	void *p; +	const void *p;  	if (fdt_version(fdt) >= 0x11)  		if (((offset + len) < offset) @@ -61,6 +90,45 @@ void *fdt_offset_ptr(const void *fdt, int offset, int len)  	return p;  } +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) +{ +	const uint32_t *tagp, *lenp; +	uint32_t tag; +	const char *p; + +	if (offset % FDT_TAGSIZE) +		return -1; + +	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); +	if (! tagp) +		return FDT_END; /* premature end */ +	tag = fdt32_to_cpu(*tagp); +	offset += FDT_TAGSIZE; + +	switch (tag) { +	case FDT_BEGIN_NODE: +		/* skip name */ +		do { +			p = fdt_offset_ptr(fdt, offset++, 1); +		} while (p && (*p != '\0')); +		if (! p) +			return FDT_END; +		break; +	case FDT_PROP: +		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); +		if (! lenp) +			return FDT_END; +		/* skip name offset, length and value */ +		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); +		break; +	} + +	if (nextoffset) +		*nextoffset = ALIGN(offset, FDT_TAGSIZE); + +	return tag; +} +  const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)  {  	int len = strlen(s) + 1; @@ -86,5 +154,3 @@ 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 46d525db1..12a37d59f 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -2,23 +2,52 @@   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option.   * - * This library 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 - * Lesser General Public License for more details. + *  a) This library 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.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     This library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include "config.h" -#if CONFIG_OF_LIBFDT -  #include "libfdt_env.h"  #include <fdt.h> @@ -26,14 +55,15 @@  #include "libfdt_internal.h" -#define CHECK_HEADER(fdt)	{ \ -	int err; \ -	if ((err = fdt_check_header(fdt)) != 0) \ -		return err; \ -} +#define CHECK_HEADER(fdt) \ +	{ \ +		int err; \ +		if ((err = fdt_check_header(fdt)) != 0) \ +			return err; \ +	} -static int offset_streq(const void *fdt, int offset, -			const char *s, int len) +static int nodename_eq(const void *fdt, int offset, +		       const char *s, int len)  {  	const char *p = fdt_offset_ptr(fdt, offset, len+1); @@ -44,169 +74,36 @@ static int offset_streq(const void *fdt, int offset,  	if (memcmp(p, s, len) != 0)  		return 0; -	if (p[len] != '\0') +	if (p[len] == '\0') +		return 1; +	else if (!memchr(s, '@', len) && (p[len] == '@')) +		return 1; +	else  		return 0; - -	return 1;  } -/* - * 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) +const char *fdt_string(const void *fdt, int stroffset)  {  	return (char *)fdt + fdt_off_dt_strings(fdt) + 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 fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)  { -	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; -		} -	} +	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); +	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); +	return 0;  } -/* - * 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 fdt_num_mem_rsv(const void *fdt)  { -	int offset; - -	offset = fdt_find_node_by_type(fdt, nodeoffset, type); -	if (offset < 0 || fdt_node_is_compatible(fdt, offset, compat)) -		return offset; +	int i = 0; -	return -FDT_ERR_NOTFOUND; +	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) +		i++; +	return i;  } -/* - * Return the node offset of the node specified by: - *   parentoffset - starting place (0 to start at the root) - *   name         - name being searched for - *   namelen      - length of the name: typically strlen(name) - * - * Notes: - *   If the start node has subnodes, the subnodes are _not_ searched for the - *     requested name. - */  int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,  			       const char *name, int namelen)  { @@ -216,13 +113,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,  	CHECK_HEADER(fdt); -	tag = fdt_next_tag(fdt, parentoffset, &nextoffset, NULL); +	tag = fdt_next_tag(fdt, parentoffset, &nextoffset);  	if (tag != FDT_BEGIN_NODE)  		return -FDT_ERR_BADOFFSET;  	do {  		offset = nextoffset; -		tag = fdt_next_tag(fdt, offset, &nextoffset, NULL); +		tag = fdt_next_tag(fdt, offset, &nextoffset);  		switch (tag) {  		case FDT_END: @@ -230,15 +127,10 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,  		case FDT_BEGIN_NODE:  			level++; -			/* -			 * If we are nested down levels, ignore the strings -			 * until we get back to the proper level. -			 */  			if (level != 1)  				continue; - -			/* Return the offset if this is "our" string. */ -			if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen)) +			if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen)) +				/* Found it! */  				return offset;  			break; @@ -258,20 +150,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,  	return -FDT_ERR_NOTFOUND;  } -/* - * See fdt_subnode_offset_namelen() - */  int fdt_subnode_offset(const void *fdt, int parentoffset,  		       const char *name)  {  	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));  } -/* - * Searches for the node corresponding to the given path and returns the - * offset of that node. - */ -int fdt_find_node_by_path(const void *fdt, const char *path) +int fdt_path_offset(const void *fdt, const char *path)  {  	const char *end = path + strlen(path);  	const char *p = path; @@ -279,37 +164,21 @@ int fdt_find_node_by_path(const void *fdt, const char *path)  	CHECK_HEADER(fdt); -	/* Paths must be absolute */  	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; -		/* Skip path separator(s) */  		while (*p == '/')  			p++;  		if (! *p) -			return -FDT_ERR_BADPATH; - -		/* -		 * Find the next path separator.  The characters between -		 * p and q are the next segment of the the path to find. -		 */ +			return offset;  		q = strchr(p, '/');  		if (! q)  			q = end; -		/* -		 * Find the offset corresponding to the this path segment. -		 */  		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); - -		/* Oops, error, abort abort abort */  		if (offset < 0)  			return offset; @@ -319,17 +188,37 @@ int fdt_find_node_by_path(const void *fdt, const char *path)  	return offset;  } -/* - * Given the offset of a node and a name of a property in that node, return - * a pointer to the property struct. - */ -struct fdt_property *fdt_get_property(const void *fdt, -				      int nodeoffset, -				      const char *name, int *lenp) +const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) +{ +	const struct fdt_node_header *nh; +	int err; + +	if ((err = fdt_check_header(fdt)) != 0) +		goto fail; + +	err = -FDT_ERR_BADOFFSET; +	nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh)); +	if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE)) +		goto fail; + +	if (len) +		*len = strlen(nh->name); + +	return nh->name; + + fail: +	if (len) +		*len = err; +	return NULL; +} + +const struct fdt_property *fdt_get_property(const void *fdt, +					    int nodeoffset, +					    const char *name, int *lenp)  { -	int level = 0;  	uint32_t tag; -	struct fdt_property *prop; +	const struct fdt_property *prop; +	int namestroff;  	int offset, nextoffset;  	int err; @@ -340,63 +229,59 @@ struct fdt_property *fdt_get_property(const void *fdt,  	if (nodeoffset % FDT_TAGSIZE)  		goto fail; -	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL); +	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);  	if (tag != FDT_BEGIN_NODE)  		goto fail;  	do {  		offset = nextoffset; -		tag = fdt_next_tag(fdt, offset, &nextoffset, NULL); +		tag = fdt_next_tag(fdt, offset, &nextoffset);  		switch (tag) {  		case FDT_END:  			err = -FDT_ERR_TRUNCATED;  			goto fail;  		case FDT_BEGIN_NODE: -			level++; -			break; -  		case FDT_END_NODE: -			level--; +		case FDT_NOP:  			break;  		case FDT_PROP: -			/* -			 * If we are nested down levels, ignore the strings -			 * until we get back to the proper level. -			 */ -			if (level != 0) -				continue; - -			err = prop_name_eq(fdt, offset, name, &prop, lenp); -			if (err > 0) -				return prop; -			else if (err < 0) +			err = -FDT_ERR_BADSTRUCTURE; +			prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); +			if (! prop)  				goto fail; -			break; +			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; -		case FDT_NOP: +				if (lenp) +					*lenp = len; + +				return prop; +			}  			break;  		default:  			err = -FDT_ERR_BADSTRUCTURE;  			goto fail;  		} -	} while (level >= 0); +	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));  	err = -FDT_ERR_NOTFOUND; -fail: + fail:  	if (lenp)  		*lenp = err;  	return NULL;  } -/* - * Given the offset of a node and a name of a property in that node, return - * a pointer to the property data (ONLY). - */ -void *fdt_getprop(const void *fdt, int nodeoffset, +const void *fdt_getprop(const void *fdt, int nodeoffset,  		  const char *name, int *lenp)  {  	const struct fdt_property *prop; @@ -405,132 +290,294 @@ void *fdt_getprop(const void *fdt, int nodeoffset,  	if (! prop)  		return NULL; -	return (void *)prop->data; +	return prop->data;  } +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) +{ +	const uint32_t *php; +	int len; + +	php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); +	if (!php || (len != sizeof(*php))) +		return 0; + +	return fdt32_to_cpu(*php); +} -uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset, char **namep) +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)  { -	const uint32_t *tagp, *lenp;  	uint32_t tag; -	const char *p; +	int p = 0, overflow = 0; +	int offset, nextoffset, namelen; +	const char *name; -	if (offset % FDT_TAGSIZE) -		return -1; +	CHECK_HEADER(fdt); -	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); -	if (! tagp) -		return FDT_END; /* premature end */ -	tag = fdt32_to_cpu(*tagp); -	offset += FDT_TAGSIZE; +	tag = fdt_next_tag(fdt, 0, &nextoffset); +	if (tag != FDT_BEGIN_NODE) +		return -FDT_ERR_BADSTRUCTURE; -	switch (tag) { -	case FDT_BEGIN_NODE: -		if(namep) -			*namep = fdt_offset_ptr(fdt, offset, 1); +	if (buflen < 2) +		return -FDT_ERR_NOSPACE; +	buf[0] = '/'; +	p = 1; -		/* skip name */ -		do { -			p = fdt_offset_ptr(fdt, offset++, 1); -		} while (p && (*p != '\0')); -		if (! p) -			return FDT_END; -		break; -	case FDT_PROP: -		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); -		if (! lenp) -			return FDT_END; -		/* -		 * Get the property and set the namep to the name. -		 */ -		if(namep) { -			struct fdt_property *prop; +	while (nextoffset <= nodeoffset) { +		offset = nextoffset; +		tag = fdt_next_tag(fdt, offset, &nextoffset); +		switch (tag) { +		case FDT_END: +			return -FDT_ERR_BADOFFSET; -			prop = fdt_offset_ptr_typed(fdt, offset - FDT_TAGSIZE, prop); -			if (! prop) -				return -FDT_ERR_BADSTRUCTURE; -			*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); +		case FDT_BEGIN_NODE: +			name = fdt_get_name(fdt, offset, &namelen); +			if (!name) +				return namelen; +			if (overflow || ((p + namelen + 1) > buflen)) { +				overflow++; +				break; +			} +			memcpy(buf + p, name, namelen); +			p += namelen; +			buf[p++] = '/'; +			break; + +		case FDT_END_NODE: +			if (overflow) { +				overflow--; +				break; +			} +			do { +				p--; +			} while  (buf[p-1] != '/'); +			break; + +		case FDT_PROP: +		case FDT_NOP: +			break; + +		default: +			return -FDT_ERR_BADSTRUCTURE;  		} -		/* skip name offset, length and value */ -		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); -		break;  	} -	if (nextoffset) -		*nextoffset = ALIGN(offset, FDT_TAGSIZE); +	if (overflow) +		return -FDT_ERR_NOSPACE; -	return tag; +	if (p > 1) /* special case so that root path is "/", not "" */ +		p--; +	buf[p] = '\0'; +	return p;  } -/* - * Return the number of used reserve map entries and total slots available. - */ -int fdt_num_reservemap(void *fdt, int *used, int *total) +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, +				 int supernodedepth, int *nodedepth)  { -	struct fdt_reserve_entry *re; -	int  start; -	int  end; -	int  err = fdt_check_header(fdt); +	int level = -1; +	uint32_t tag; +	int offset, nextoffset = 0; +	int supernodeoffset = -FDT_ERR_INTERNAL; + +	CHECK_HEADER(fdt); -	if (err != 0) -		return err; +	if (supernodedepth < 0) +		return -FDT_ERR_NOTFOUND; -	start = fdt_off_mem_rsvmap(fdt); +	do { +		offset = nextoffset; +		tag = fdt_next_tag(fdt, offset, &nextoffset); +		switch (tag) { +		case FDT_END: +			return -FDT_ERR_BADOFFSET; -	/* -	 * Convention is that the reserve map is before the dt_struct, -	 * but it does not have to be. -	 */ -	end = fdt_totalsize(fdt); -	if (end > fdt_off_dt_struct(fdt)) -		end = fdt_off_dt_struct(fdt); -	if (end > fdt_off_dt_strings(fdt)) -		end = fdt_off_dt_strings(fdt); +		case FDT_BEGIN_NODE: +			level++; +			if (level == supernodedepth) +				supernodeoffset = offset; +			break; -	/* -	 * Since the reserved area list is zero terminated, you get one fewer. -	 */ -	if (total) -		*total = ((end - start) / sizeof(struct fdt_reserve_entry)) - 1; +		case FDT_END_NODE: +			level--; +			break; -	if (used) { -		*used = 0; -		while (start < end) { -			re = (struct fdt_reserve_entry *)(fdt + start); -			if (re->size == 0) -				return 0;	/* zero size terminates the list */ +		case FDT_PROP: +		case FDT_NOP: +			break; -			*used += 1; -			start += sizeof(struct fdt_reserve_entry); +		default: +			return -FDT_ERR_BADSTRUCTURE;  		} -		/* -		 * If we get here, there was no zero size termination. -		 */ -		return -FDT_ERR_BADLAYOUT; +	} while (offset < nodeoffset); + +	if (nodedepth) +		*nodedepth = level; + +	if (supernodedepth > level) +		return -FDT_ERR_NOTFOUND; +	return supernodeoffset; +} + +int fdt_node_depth(const void *fdt, int nodeoffset) +{ +	int nodedepth; +	int err; + +	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); +	if (err) +		return (err < 0) ? err : -FDT_ERR_INTERNAL; +	return nodedepth; +} + +int fdt_parent_offset(const void *fdt, int nodeoffset) +{ +	int nodedepth = fdt_node_depth(fdt, nodeoffset); + +	if (nodedepth < 0) +		return nodedepth; +	return fdt_supernode_atdepth_offset(fdt, nodeoffset, +					    nodedepth - 1, NULL); +} + +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, +				  const char *propname, +				  const void *propval, int proplen) +{ +	uint32_t tag; +	int offset, nextoffset; +	const void *val; +	int len; + +	CHECK_HEADER(fdt); + +	if (startoffset >= 0) { +		tag = fdt_next_tag(fdt, startoffset, &nextoffset); +		if (tag != FDT_BEGIN_NODE) +			return -FDT_ERR_BADOFFSET; +	} else { +		nextoffset = 0;  	} -	return 0; + +	/* FIXME: The algorithm here is pretty horrible: we scan each +	 * property of a node in fdt_getprop(), then if that didn't +	 * find what we want, we scan over them again making our way +	 * to the next node.  Still it's the easiest to implement +	 * approach; performance can come later. */ +	do { +		offset = nextoffset; +		tag = fdt_next_tag(fdt, offset, &nextoffset); + +		switch (tag) { +		case FDT_BEGIN_NODE: +			val = fdt_getprop(fdt, offset, propname, &len); +			if (val +			    && (len == proplen) +			    && (memcmp(val, propval, len) == 0)) +				return offset; +			break; + +		case FDT_PROP: +		case FDT_END: +		case FDT_END_NODE: +		case FDT_NOP: +			break; + +		default: +			return -FDT_ERR_BADSTRUCTURE; +		} +	} while (tag != FDT_END); + +	return -FDT_ERR_NOTFOUND;  } -/* - * Return the nth reserve map entry. - */ -int fdt_get_reservemap(void *fdt, int n, struct fdt_reserve_entry *re) +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)  { -	int  used; -	int  total; -	int  err; +	if ((phandle == 0) || (phandle == -1)) +		return -FDT_ERR_BADPHANDLE; +	phandle = cpu_to_fdt32(phandle); +	return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", +					     &phandle, sizeof(phandle)); +} -	err = fdt_num_reservemap(fdt, &used, &total); -	if (err != 0) -		return err; +int _stringlist_contains(const void *strlist, int listlen, const char *str) +{ +	int len = strlen(str); +	const void *p; -	if (n >= total) -		return -FDT_ERR_NOSPACE; -	if (re) { -		*re = *(struct fdt_reserve_entry *) -			_fdt_offset_ptr(fdt, n * sizeof(struct fdt_reserve_entry)); +	while (listlen >= len) { +		if (memcmp(str, strlist, len+1) == 0) +			return 1; +		p = memchr(strlist, '\0', listlen); +		if (!p) +			return 0; /* malformed strlist.. */ +		listlen -= (p-strlist) + 1; +		strlist = p + 1;  	}  	return 0;  } -#endif /* CONFIG_OF_LIBFDT */ +int fdt_node_check_compatible(const void *fdt, int nodeoffset, +			      const char *compatible) +{ +	const void *prop; +	int len; + +	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); +	if (!prop) +		return len; +	if (_stringlist_contains(prop, len, compatible)) +		return 0; +	else +		return 1; +} + +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, +				  const char *compatible) +{ +	uint32_t tag; +	int offset, nextoffset; +	int err; + +	CHECK_HEADER(fdt); + +	if (startoffset >= 0) { +		tag = fdt_next_tag(fdt, startoffset, &nextoffset); +		if (tag != FDT_BEGIN_NODE) +			return -FDT_ERR_BADOFFSET; +	} else { +		nextoffset = 0; +	} + +	/* FIXME: The algorithm here is pretty horrible: we scan each +	 * property of a node in fdt_node_check_compatible(), then if +	 * that didn't find what we want, we scan over them again +	 * making our way to the next node.  Still it's the easiest to +	 * implement approach; performance can come later. */ +	do { +		offset = nextoffset; +		tag = fdt_next_tag(fdt, offset, &nextoffset); + +		switch (tag) { +		case FDT_BEGIN_NODE: +			err = fdt_node_check_compatible(fdt, offset, +							compatible); +			if ((err < 0) +			    && (err != -FDT_ERR_NOTFOUND)) +				return err; +			else if (err == 0) +				return offset; +			break; + +		case FDT_PROP: +		case FDT_END: +		case FDT_END_NODE: +		case FDT_NOP: +			break; + +		default: +			return -FDT_ERR_BADSTRUCTURE; +		} +	} while (tag != FDT_END); + +	return -FDT_ERR_NOTFOUND; +} diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 55fcc41d1..dfe5628a3 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -2,23 +2,52 @@   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option.   * - * This library 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 - * Lesser General Public License for more details. + *  a) This library 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.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     This library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include "config.h" -#if CONFIG_OF_LIBFDT -  #include "libfdt_env.h"  #include <fdt.h> @@ -26,25 +55,32 @@  #include "libfdt_internal.h" +static int _blocks_misordered(const void *fdt, +			      int mem_rsv_size, int struct_size) +{ +	return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8)) +		|| (fdt_off_dt_struct(fdt) < +		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) +		|| (fdt_off_dt_strings(fdt) < +		    (fdt_off_dt_struct(fdt) + struct_size)) +		|| (fdt_totalsize(fdt) < +		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} +  static int rw_check_header(void *fdt)  {  	int err;  	if ((err = fdt_check_header(fdt)))  		return err; -	if (fdt_version(fdt) < 0x11) +	if (fdt_version(fdt) < 17)  		return -FDT_ERR_BADVERSION; -	if (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8)) -		return -FDT_ERR_BADLAYOUT; -	if (fdt_off_dt_struct(fdt) < -	    (fdt_off_mem_rsvmap(fdt) + sizeof(struct fdt_reserve_entry))) -		return -FDT_ERR_BADLAYOUT; -	if (fdt_off_dt_strings(fdt) < -	    (fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))) -		return -FDT_ERR_BADLAYOUT; -	if (fdt_totalsize(fdt) < -	    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))) +	if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), +			       fdt_size_dt_struct(fdt)))  		return -FDT_ERR_BADLAYOUT; +	if (fdt_version(fdt) > 17) +		fdt_set_version(fdt, 17); +  	return 0;  } @@ -72,6 +108,19 @@ static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)  	return 0;  } +static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, +				int oldn, int newn) +{ +	int delta = (newn - oldn) * sizeof(*p); +	int err; +	err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); +	if (err) +		return err; +	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); +	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); +	return 0; +} +  static int _blob_splice_struct(void *fdt, void *p,  			       int oldlen, int newlen)  { @@ -81,8 +130,8 @@ static int _blob_splice_struct(void *fdt, void *p,  	if ((err = _blob_splice(fdt, p, oldlen, newlen)))  		return err; -	fdt_set_header(fdt, size_dt_struct, fdt_size_dt_struct(fdt) + delta); -	fdt_set_header(fdt, off_dt_strings, fdt_off_dt_strings(fdt) + delta); +	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); +	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);  	return 0;  } @@ -94,7 +143,7 @@ static int _blob_splice_string(void *fdt, int newlen)  	if ((err = _blob_splice(fdt, p, 0, newlen)))  		return err; -	fdt_set_header(fdt, size_dt_strings, fdt_size_dt_strings(fdt) + newlen); +	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);  	return 0;  } @@ -120,13 +169,47 @@ static int _find_add_string(void *fdt, const char *s)  	return (new - strtab);  } +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ +	struct fdt_reserve_entry *re; +	int err; + +	if ((err = rw_check_header(fdt))) +		return err; + +	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); +	err = _blob_splice_mem_rsv(fdt, re, 0, 1); +	if (err) +		return err; + +	re->address = cpu_to_fdt64(address); +	re->size = cpu_to_fdt64(size); +	return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ +	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); +	int err; + +	if ((err = rw_check_header(fdt))) +		return err; +	if (n >= fdt_num_mem_rsv(fdt)) +		return -FDT_ERR_NOTFOUND; + +	err = _blob_splice_mem_rsv(fdt, re, 1, 0); +	if (err) +		return err; +	return 0; +} +  static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,  			    struct fdt_property **prop)  {  	int oldlen;  	int err; -	*prop = fdt_get_property(fdt, nodeoffset, name, &oldlen); +	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);  	if (! (*prop))  		return oldlen; @@ -148,7 +231,7 @@ static int _add_property(void *fdt, int nodeoffset, const char *name, int len,  	int namestroff;  	int err; -	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL); +	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);  	if (tag != FDT_BEGIN_NODE)  		return -FDT_ERR_BADOFFSET; @@ -156,7 +239,7 @@ static int _add_property(void *fdt, int nodeoffset, const char *name, int len,  	if (namestroff < 0)  		return namestroff; -	*prop = _fdt_offset_ptr(fdt, nextoffset); +	*prop = _fdt_offset_ptr_w(fdt, nextoffset);  	proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);  	err = _blob_splice_struct(fdt, *prop, 0, proplen); @@ -188,32 +271,6 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,  	return 0;  } -/** - * fdt_find_and_setprop: Find a node and set it's property - * - * @fdt: ptr to device tree - * @node: path of node - * @prop: property name - * @val: ptr to new value - * @len: length of new property value - * @create: flag to create the property if it doesn't exist - * - * Convenience function to directly set a property given the path to the node. - */ -int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, -			 const void *val, int len, int create) -{ -	int nodeoff = fdt_find_node_by_path(fdt, node); - -	if (nodeoff < 0) -		return nodeoff; - -	if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL)) -		return 0; /* create flag not set; so exit quietly */ - -	return fdt_setprop(fdt, nodeoff, prop, val, len); -} -  int fdt_delprop(void *fdt, int nodeoffset, const char *name)  {  	struct fdt_property *prop; @@ -221,7 +278,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)  	RW_CHECK_HEADER(fdt); -	prop = fdt_get_property(fdt, nodeoffset, name, &len); +	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);  	if (! prop)  		return len; @@ -248,13 +305,13 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,  		return offset;  	/* Try to place the new node after the parent's properties */ -	fdt_next_tag(fdt, parentoffset, &nextoffset, NULL); /* skip the BEGIN_NODE */ +	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */  	do {  		offset = nextoffset; -		tag = fdt_next_tag(fdt, offset, &nextoffset, NULL); +		tag = fdt_next_tag(fdt, offset, &nextoffset);  	} while (tag == FDT_PROP); -	nh = _fdt_offset_ptr(fdt, offset); +	nh = _fdt_offset_ptr_w(fdt, offset);  	nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;  	err = _blob_splice_struct(fdt, nh, 0, nodelen); @@ -279,46 +336,112 @@ int fdt_del_node(void *fdt, int nodeoffset)  {  	int endoffset; +	RW_CHECK_HEADER(fdt); +  	endoffset = _fdt_node_end_offset(fdt, nodeoffset);  	if (endoffset < 0)  		return endoffset; -	return _blob_splice_struct(fdt, _fdt_offset_ptr(fdt, nodeoffset), +	return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),  				   endoffset - nodeoffset, 0);  } -int fdt_open_into(void *fdt, void *buf, int bufsize) +static void _packblocks(const void *fdt, void *buf, +		       int mem_rsv_size, int struct_size) +{ +	int mem_rsv_off, struct_off, strings_off; + +	mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8); +	struct_off = mem_rsv_off + mem_rsv_size; +	strings_off = struct_off + struct_size; + +	memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size); +	fdt_set_off_mem_rsvmap(buf, mem_rsv_off); + +	memcpy(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size); +	fdt_set_off_dt_struct(buf, struct_off); +	fdt_set_size_dt_struct(buf, struct_size); + +	memcpy(buf + strings_off, fdt + fdt_off_dt_strings(fdt), +	       fdt_size_dt_strings(fdt)); +	fdt_set_off_dt_strings(buf, strings_off); +	fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize)  {  	int err; +	int mem_rsv_size, struct_size; +	int newsize; +	void *tmp; -	err = fdt_move(fdt, buf, bufsize); +	err = fdt_check_header(fdt);  	if (err)  		return err; -	fdt = buf; +	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) +		* sizeof(struct fdt_reserve_entry); -	fdt_set_header(fdt, totalsize, bufsize); +	if (fdt_version(fdt) >= 17) { +		struct_size = fdt_size_dt_struct(fdt); +	} else { +		struct_size = 0; +		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) +			; +	} -	/* FIXME: re-order if necessary */ +	if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) { +		/* no further work necessary */ +		err = fdt_move(fdt, buf, bufsize); +		if (err) +			return err; +		fdt_set_version(buf, 17); +		fdt_set_size_dt_struct(buf, struct_size); +		fdt_set_totalsize(buf, bufsize); +		return 0; +	} -	err = rw_check_header(fdt); -	if (err) -		return err; +	/* Need to reorder */ +	newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size +		+ struct_size + fdt_size_dt_strings(fdt); + +	if (bufsize < newsize) +		return -FDT_ERR_NOSPACE; + +	if (((buf + newsize) <= fdt) +	    || (buf >= (fdt + fdt_totalsize(fdt)))) { +		tmp = buf; +	} else { +		tmp = (void *)fdt + fdt_totalsize(fdt); +		if ((tmp + newsize) > (buf + bufsize)) +			return -FDT_ERR_NOSPACE; +	} + +	_packblocks(fdt, tmp, mem_rsv_size, struct_size); +	memmove(buf, tmp, newsize); + +	fdt_set_magic(buf, FDT_MAGIC); +	fdt_set_totalsize(buf, bufsize); +	fdt_set_version(buf, 17); +	fdt_set_last_comp_version(buf, 16); +	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));  	return 0;  }  int fdt_pack(void *fdt)  { +	int mem_rsv_size;  	int err;  	err = rw_check_header(fdt);  	if (err)  		return err; -	/* FIXME: pack components */ -	fdt_set_header(fdt, totalsize, _blob_data_size(fdt)); +	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) +		* sizeof(struct fdt_reserve_entry); +	_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); +	fdt_set_totalsize(fdt, _blob_data_size(fdt)); +  	return 0;  } - -#endif /* CONFIG_OF_LIBFDT */ diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c index b49c952f3..f9d32ef53 100644 --- a/libfdt/fdt_strerror.c +++ b/libfdt/fdt_strerror.c @@ -2,23 +2,52 @@   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option.   * - * This library 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 - * Lesser General Public License for more details. + *  a) This library 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.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     This library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include "config.h" -#if CONFIG_OF_LIBFDT -  #include "libfdt_env.h"  #include <fdt.h> @@ -65,5 +94,3 @@ 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 c7eea8ff3..dda2de34b 100644 --- a/libfdt/fdt_sw.c +++ b/libfdt/fdt_sw.c @@ -2,23 +2,52 @@   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option.   * - * This library 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 - * Lesser General Public License for more details. + *  a) This library 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.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     This library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include "config.h" -#if CONFIG_OF_LIBFDT -  #include "libfdt_env.h"  #include <fdt.h> @@ -44,8 +73,8 @@ static void *grab_space(void *fdt, int len)  	if ((offset + len < offset) || (offset + len > spaceleft))  		return NULL; -	fdt_set_header(fdt, size_dt_struct, offset + len); -	return fdt_offset_ptr(fdt, offset, len); +	fdt_set_size_dt_struct(fdt, offset + len); +	return fdt_offset_ptr_w(fdt, offset, len);  }  int fdt_create(void *buf, int bufsize) @@ -57,15 +86,15 @@ int fdt_create(void *buf, int bufsize)  	memset(buf, 0, bufsize); -	fdt_set_header(fdt, magic, SW_MAGIC); -	fdt_set_header(fdt, version, FDT_LAST_SUPPORTED_VERSION); -	fdt_set_header(fdt, last_comp_version, FDT_FIRST_SUPPORTED_VERSION); -	fdt_set_header(fdt, totalsize, bufsize); +	fdt_set_magic(fdt, SW_MAGIC); +	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); +	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); +	fdt_set_totalsize(fdt,  bufsize); -	fdt_set_header(fdt, off_mem_rsvmap, ALIGN(sizeof(struct fdt_header), -					      sizeof(struct fdt_reserve_entry))); -	fdt_set_header(fdt, off_dt_struct, fdt_off_mem_rsvmap(fdt)); -	fdt_set_header(fdt, off_dt_strings, bufsize); +	fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header), +					  sizeof(struct fdt_reserve_entry))); +	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); +	fdt_set_off_dt_strings(fdt, bufsize);  	return 0;  } @@ -85,11 +114,11 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)  	if ((offset + sizeof(*re)) > fdt_totalsize(fdt))  		return -FDT_ERR_NOSPACE; -	re = (struct fdt_reserve_entry *)((void *)fdt + offset); +	re = (struct fdt_reserve_entry *)(fdt + offset);  	re->address = cpu_to_fdt64(addr);  	re->size = cpu_to_fdt64(size); -	fdt_set_header(fdt, off_dt_struct, offset + sizeof(*re)); +	fdt_set_off_dt_struct(fdt, offset + sizeof(*re));  	return 0;  } @@ -152,7 +181,7 @@ static int find_add_string(void *fdt, const char *s)  		return 0; /* no more room :( */  	memcpy(strtab + offset, s, len); -	fdt_set_header(fdt, size_dt_strings, strtabsize + len); +	fdt_set_size_dt_strings(fdt, strtabsize + len);  	return offset;  } @@ -202,14 +231,14 @@ int fdt_finish(void *fdt)  	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);  	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);  	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); -	fdt_set_header(fdt, off_dt_strings, newstroffset); +	fdt_set_off_dt_strings(fdt, newstroffset);  	/* Walk the structure, correcting string offsets */  	offset = 0; -	while ((tag = fdt_next_tag(fdt, offset, &nextoffset, NULL)) != FDT_END) { +	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {  		if (tag == FDT_PROP) { -			struct fdt_property *prop = fdt_offset_ptr(fdt, offset, -								   sizeof(*prop)); +			struct fdt_property *prop = +				fdt_offset_ptr_w(fdt, offset, sizeof(*prop));  			int nameoff;  			if (! prop) @@ -223,9 +252,7 @@ int fdt_finish(void *fdt)  	}  	/* Finally, adjust the header */ -	fdt_set_header(fdt, totalsize, newstroffset + fdt_size_dt_strings(fdt)); -	fdt_set_header(fdt, magic, FDT_MAGIC); +	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); +	fdt_set_magic(fdt, FDT_MAGIC);  	return 0;  } - -#endif /* CONFIG_OF_LIBFDT */ diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index 2d39aabe1..88e24b831 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -2,23 +2,52 @@   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option.   * - * This library 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 - * Lesser General Public License for more details. + *  a) This library 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.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     This library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include "config.h" -#if CONFIG_OF_LIBFDT -  #include "libfdt_env.h"  #include <fdt.h> @@ -32,7 +61,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,  	void *propval;  	int proplen; -	propval = fdt_getprop(fdt, nodeoffset, name, &proplen); +	propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);  	if (! propval)  		return proplen; @@ -56,7 +85,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)  	struct fdt_property *prop;  	int len; -	prop = fdt_get_property(fdt, nodeoffset, name, &len); +	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);  	if (! prop)  		return len; @@ -71,12 +100,12 @@ int _fdt_node_end_offset(void *fdt, int nodeoffset)  	uint32_t tag;  	int offset, nextoffset; -	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL); +	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);  	if (tag != FDT_BEGIN_NODE)  		return -FDT_ERR_BADOFFSET;  	do {  		offset = nextoffset; -		tag = fdt_next_tag(fdt, offset, &nextoffset, NULL); +		tag = fdt_next_tag(fdt, offset, &nextoffset);  		switch (tag) {  		case FDT_END: @@ -110,33 +139,6 @@ int fdt_nop_node(void *fdt, int nodeoffset)  	if (endoffset < 0)  		return endoffset; -	nop_region(fdt_offset_ptr(fdt, nodeoffset, 0), endoffset - nodeoffset); +	nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);  	return 0;  } - -/* - * Replace a reserve map entry in the nth slot. - */ -int fdt_replace_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size) -{ -	struct fdt_reserve_entry *re; -	int  used; -	int  total; -	int  err; - -	err = fdt_num_reservemap(fdt, &used, &total); -	if (err != 0) -		return err; - -	if (n >= total) -		return -FDT_ERR_NOSPACE; -	re = (struct fdt_reserve_entry *) -		(fdt + fdt_off_mem_rsvmap(fdt) + -		 (n * sizeof(struct fdt_reserve_entry))); -	re->address = cpu_to_fdt64(addr); -	re->size    = cpu_to_fdt64(size); - -	return 0; -} - -#endif /* CONFIG_OF_LIBFDT */ diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h index cc9633c9e..1e60936be 100644 --- a/libfdt/libfdt_internal.h +++ b/libfdt/libfdt_internal.h @@ -4,19 +4,51 @@   * libfdt - Flat Device Tree manipulation   * Copyright (C) 2006 David Gibson, IBM Corporation.   * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option.   * - * This library 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 - * Lesser General Public License for more details. + *  a) This library 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.   * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + *     This library 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 library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */  #include <fdt.h> @@ -26,13 +58,30 @@  #define memeq(p, q, n)	(memcmp((p), (q), (n)) == 0)  #define streq(p, q)	(strcmp((p), (q)) == 0) -int _fdt_check_header(const void *fdt); +uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);  const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);  int _fdt_node_end_offset(void *fdt, int nodeoffset); -static inline void *_fdt_offset_ptr(const struct fdt_header *fdt, int offset) +static inline const void *_fdt_offset_ptr(const void *fdt, int offset) +{ +	return fdt + fdt_off_dt_struct(fdt) + offset; +} + +static inline void *_fdt_offset_ptr_w(void *fdt, int offset) +{ +	return (void *)_fdt_offset_ptr(fdt, offset); +} + +static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) +{ +	const struct fdt_reserve_entry *rsv_table = +		fdt + fdt_off_mem_rsvmap(fdt); + +	return rsv_table + n; +} +static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)  { -	return (void *)fdt + fdt_off_dt_struct(fdt) + offset; +	return (void *)_fdt_mem_rsv(fdt, n);  }  #define SW_MAGIC		(~FDT_MAGIC) |