Merge branch 'master' of git://www.denx.de/git/u-boot-fdt
diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c
index 9cd22ee..14c3fa0 100644
--- a/common/cmd_fdt.c
+++ b/common/cmd_fdt.c
@@ -260,7 +260,7 @@
 	/********************************************************************
 	 * Remove a property/node
 	 ********************************************************************/
-	} else if (argv[1][0] == 'r') {
+	} else if ((argv[1][0] == 'r') && (argv[1][1] == 'm')) {
 		int  nodeoffset;	/* node offset from libfdt */
 		int  err;
 
@@ -296,6 +296,111 @@
 				return err;
 			}
 		}
+
+	/********************************************************************
+	 * Display header info
+	 ********************************************************************/
+	} else if (argv[1][0] == 'h') {
+		u32 version = fdt_version(fdt);
+		printf("magic:\t\t\t0x%x\n", fdt_magic(fdt));
+		printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(fdt), fdt_totalsize(fdt));
+		printf("off_dt_struct:\t\t0x%x\n", fdt_off_dt_struct(fdt));
+		printf("off_dt_strings:\t\t0x%x\n", fdt_off_dt_strings(fdt));
+		printf("off_mem_rsvmap:\t\t0x%x\n", fdt_off_mem_rsvmap(fdt));
+		printf("version:\t\t%d\n", version);
+		printf("last_comp_version:\t%d\n", fdt_last_comp_version(fdt));
+		if (version >= 2)
+			printf("boot_cpuid_phys:\t0x%x\n",
+				fdt_boot_cpuid_phys(fdt));
+		if (version >= 3)
+			printf("size_dt_strings:\t0x%x\n",
+				fdt_size_dt_strings(fdt));
+		if (version >= 17)
+			printf("size_dt_struct:\t\t0x%x\n",
+				fdt_size_dt_struct(fdt));
+		printf("number mem_rsv:\t\t0x%x\n", fdt_num_mem_rsv(fdt));
+		printf("\n");
+
+	/********************************************************************
+	 * Set boot cpu id
+	 ********************************************************************/
+	} else if ((argv[1][0] == 'b') && (argv[1][1] == 'o') &&
+		   (argv[1][2] == 'o')) {
+		unsigned long tmp = simple_strtoul(argv[2], NULL, 16);
+		fdt_set_boot_cpuid_phys(fdt, tmp);
+
+	/********************************************************************
+	 * memory command
+	 ********************************************************************/
+	} else if ((argv[1][0] == 'm') && (argv[1][1] == 'e')) {
+		uint64_t addr, size;
+		int err;
+#ifdef CFG_64BIT_STRTOUL
+			addr = simple_strtoull(argv[2], NULL, 16);
+			size = simple_strtoull(argv[3], NULL, 16);
+#else
+			addr = simple_strtoul(argv[2], NULL, 16);
+			size = simple_strtoul(argv[3], NULL, 16);
+#endif
+		err = fdt_fixup_memory(fdt, addr, size);
+		if (err < 0)
+			return err;
+
+	/********************************************************************
+	 * mem reserve commands
+	 ********************************************************************/
+	} else if ((argv[1][0] == 'r') && (argv[1][1] == 's')) {
+		if (argv[2][0] == 'p') {
+			uint64_t addr, size;
+			int total = fdt_num_mem_rsv(fdt);
+			int j, err;
+			printf("index\t\t   start\t\t    size\n");
+			printf("-------------------------------"
+				"-----------------\n");
+			for (j = 0; j < total; j++) {
+				err = fdt_get_mem_rsv(fdt, j, &addr, &size);
+				if (err < 0) {
+					printf("libfdt fdt_get_mem_rsv():  %s\n",
+							fdt_strerror(err));
+					return err;
+				}
+				printf("    %x\t%08x%08x\t%08x%08x\n", j,
+					(u32)(addr >> 32),
+					(u32)(addr & 0xffffffff),
+					(u32)(size >> 32),
+					(u32)(size & 0xffffffff));
+			}
+		} else if (argv[2][0] == 'a') {
+			uint64_t addr, size;
+			int err;
+#ifdef CFG_64BIT_STRTOUL
+			addr = simple_strtoull(argv[3], NULL, 16);
+			size = simple_strtoull(argv[4], NULL, 16);
+#else
+			addr = simple_strtoul(argv[3], NULL, 16);
+			size = simple_strtoul(argv[4], NULL, 16);
+#endif
+			err = fdt_add_mem_rsv(fdt, addr, size);
+
+			if (err < 0) {
+				printf("libfdt fdt_add_mem_rsv():  %s\n",
+					fdt_strerror(err));
+				return err;
+			}
+		} else if (argv[2][0] == 'd') {
+			unsigned long idx = simple_strtoul(argv[3], NULL, 16);
+			int err = fdt_del_mem_rsv(fdt, idx);
+
+			if (err < 0) {
+				printf("libfdt fdt_del_mem_rsv():  %s\n",
+					fdt_strerror(err));
+				return err;
+			}
+		} else {
+			/* Unrecognized command */
+			printf ("Usage:\n%s\n", cmdtp->usage);
+			return 1;
+		}
 	}
 #ifdef CONFIG_OF_BOARD_SETUP
 	/* Call the board-specific fixup routine */
@@ -689,6 +794,12 @@
 	"fdt set    <path> <prop> [<val>]    - Set <property> [to <val>]\n"
 	"fdt mknode <path> <node>            - Create a new node after <path>\n"
 	"fdt rm     <path> [<prop>]          - Delete the node or <property>\n"
+	"fdt header                          - Display header info\n"
+	"fdt bootcpu <id>                    - Set boot cpuid\n"
+	"fdt memory <addr> <size>            - Add/Update memory node\n"
+	"fdt rsvmem print                    - Show current mem reserves\n"
+	"fdt rsvmem add <addr> <size>        - Add a mem reserve\n"
+	"fdt rsvmem delete <index>           - Delete a mem reserves\n"
 	"fdt chosen - Add/update the /chosen branch in the tree\n"
 #ifdef CONFIG_OF_HAS_UBOOT_ENV
 	"fdt env    - Add/replace the /u-boot-env branch in the tree\n"
diff --git a/include/libfdt.h b/include/libfdt.h
index 6c05236..beeacb2 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -131,6 +131,12 @@
 uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
 
 /**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
 /* General functions                                                  */
 /**********************************************************************/
 
@@ -846,6 +852,32 @@
 int fdt_del_mem_rsv(void *fdt, int n);
 
 /**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
  * fdt_setprop - create or change a property
  * @fdt: pointer to the device tree blob
  * @nodeoffset: offset of the node whose property to change
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index 586a361..bd91712 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -129,6 +129,47 @@
 	return tag;
 }
 
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+	int nextoffset = 0;
+	uint32_t tag;
+
+	if (offset >= 0) {
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		if (tag != FDT_BEGIN_NODE)
+			return -FDT_ERR_BADOFFSET;
+	}
+
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		case FDT_BEGIN_NODE:
+			if (depth)
+				(*depth)++;
+			break;
+
+		case FDT_END_NODE:
+			if (depth)
+				(*depth)--;
+			break;
+
+		case FDT_END:
+			return -FDT_ERR_NOTFOUND;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (tag != FDT_BEGIN_NODE);
+
+	return offset;
+}
+
 const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
 {
 	int len = strlen(s) + 1;
@@ -143,10 +184,7 @@
 
 int fdt_move(const void *fdt, void *buf, int bufsize)
 {
-	int err = fdt_check_header(fdt);
-
-	if (err)
-		return err;
+	CHECK_HEADER(fdt);
 
 	if (fdt_totalsize(fdt) > bufsize)
 		return -FDT_ERR_NOSPACE;
diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
index 12a37d5..63fa129 100644
--- a/libfdt/fdt_ro.c
+++ b/libfdt/fdt_ro.c
@@ -55,17 +55,10 @@
 
 #include "libfdt_internal.h"
 
-#define CHECK_HEADER(fdt) \
-	{ \
-		int err; \
-		if ((err = fdt_check_header(fdt)) != 0) \
-			return err; \
-	}
-
 static int nodename_eq(const void *fdt, int offset,
 		       const char *s, int len)
 {
-	const char *p = fdt_offset_ptr(fdt, offset, len+1);
+	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
 
 	if (! p)
 		/* short match */
@@ -104,50 +97,24 @@
 	return i;
 }
 
-int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
 			       const char *name, int namelen)
 {
-	int level = 0;
-	uint32_t tag;
-	int offset, nextoffset;
+	int depth;
 
 	CHECK_HEADER(fdt);
 
-	tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
-	if (tag != FDT_BEGIN_NODE)
-		return -FDT_ERR_BADOFFSET;
+	for (depth = 0;
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth < 0)
+			return -FDT_ERR_NOTFOUND;
+		else if ((depth == 1)
+			 && nodename_eq(fdt, offset, name, namelen))
+			return offset;
+	}
 
-	do {
-		offset = nextoffset;
-		tag = fdt_next_tag(fdt, offset, &nextoffset);
-
-		switch (tag) {
-		case FDT_END:
-			return -FDT_ERR_TRUNCATED;
-
-		case FDT_BEGIN_NODE:
-			level++;
-			if (level != 1)
-				continue;
-			if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen))
-				/* Found it! */
-				return offset;
-			break;
-
-		case FDT_END_NODE:
-			level--;
-			break;
-
-		case FDT_PROP:
-		case FDT_NOP:
-			break;
-
-		default:
-			return -FDT_ERR_BADSTRUCTURE;
-		}
-	} while (level >= 0);
-
-	return -FDT_ERR_NOTFOUND;
+	return offset; /* error */
 }
 
 int fdt_subnode_offset(const void *fdt, int parentoffset,
@@ -307,76 +274,61 @@
 
 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
 {
-	uint32_t tag;
-	int p = 0, overflow = 0;
-	int offset, nextoffset, namelen;
+	int pdepth = 0, p = 0;
+	int offset, depth, namelen;
 	const char *name;
 
 	CHECK_HEADER(fdt);
 
-	tag = fdt_next_tag(fdt, 0, &nextoffset);
-	if (tag != FDT_BEGIN_NODE)
-		return -FDT_ERR_BADSTRUCTURE;
-
 	if (buflen < 2)
 		return -FDT_ERR_NOSPACE;
-	buf[0] = '/';
-	p = 1;
 
-	while (nextoffset <= nodeoffset) {
-		offset = nextoffset;
-		tag = fdt_next_tag(fdt, offset, &nextoffset);
-		switch (tag) {
-		case FDT_END:
-			return -FDT_ERR_BADOFFSET;
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (pdepth < depth)
+			continue; /* overflowed buffer */
 
-		case FDT_BEGIN_NODE:
-			name = fdt_get_name(fdt, offset, &namelen);
-			if (!name)
-				return namelen;
-			if (overflow || ((p + namelen + 1) > buflen)) {
-				overflow++;
-				break;
-			}
+		while (pdepth > depth) {
+			do {
+				p--;
+			} while (buf[p-1] != '/');
+			pdepth--;
+		}
+
+		name = fdt_get_name(fdt, offset, &namelen);
+		if (!name)
+			return namelen;
+		if ((p + namelen + 1) <= buflen) {
 			memcpy(buf + p, name, namelen);
 			p += namelen;
 			buf[p++] = '/';
-			break;
+			pdepth++;
+		}
 
-		case FDT_END_NODE:
-			if (overflow) {
-				overflow--;
-				break;
-			}
-			do {
+		if (offset == nodeoffset) {
+			if (pdepth < (depth + 1))
+				return -FDT_ERR_NOSPACE;
+
+			if (p > 1) /* special case so that root path is "/", not "" */
 				p--;
-			} while  (buf[p-1] != '/');
-			break;
-
-		case FDT_PROP:
-		case FDT_NOP:
-			break;
-
-		default:
-			return -FDT_ERR_BADSTRUCTURE;
+			buf[p] = '\0';
+			return p;
 		}
 	}
 
-	if (overflow)
-		return -FDT_ERR_NOSPACE;
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
 
-	if (p > 1) /* special case so that root path is "/", not "" */
-		p--;
-	buf[p] = '\0';
-	return p;
+	return offset; /* error from fdt_next_node() */
 }
 
 int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
 				 int supernodedepth, int *nodedepth)
 {
-	int level = -1;
-	uint32_t tag;
-	int offset, nextoffset = 0;
+	int offset, depth;
 	int supernodeoffset = -FDT_ERR_INTERNAL;
 
 	CHECK_HEADER(fdt);
@@ -384,38 +336,29 @@
 	if (supernodedepth < 0)
 		return -FDT_ERR_NOTFOUND;
 
-	do {
-		offset = nextoffset;
-		tag = fdt_next_tag(fdt, offset, &nextoffset);
-		switch (tag) {
-		case FDT_END:
-			return -FDT_ERR_BADOFFSET;
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth == supernodedepth)
+			supernodeoffset = offset;
 
-		case FDT_BEGIN_NODE:
-			level++;
-			if (level == supernodedepth)
-				supernodeoffset = offset;
-			break;
+		if (offset == nodeoffset) {
+			if (nodedepth)
+				*nodedepth = depth;
 
-		case FDT_END_NODE:
-			level--;
-			break;
-
-		case FDT_PROP:
-		case FDT_NOP:
-			break;
-
-		default:
-			return -FDT_ERR_BADSTRUCTURE;
+			if (supernodedepth > depth)
+				return -FDT_ERR_NOTFOUND;
+			else
+				return supernodeoffset;
 		}
-	} while (offset < nodeoffset);
+	}
 
-	if (nodedepth)
-		*nodedepth = level;
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
 
-	if (supernodedepth > level)
-		return -FDT_ERR_NOTFOUND;
-	return supernodeoffset;
+	return offset; /* error from fdt_next_node() */
 }
 
 int fdt_node_depth(const void *fdt, int nodeoffset)
@@ -443,51 +386,27 @@
 				  const char *propname,
 				  const void *propval, int proplen)
 {
-	uint32_t tag;
-	int offset, nextoffset;
+	int offset;
 	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;
-	}
-
 	/* 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);
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		val = fdt_getprop(fdt, offset, propname, &len);
+		if (val && (len == proplen)
+		    && (memcmp(val, propval, len) == 0))
+			return offset;
+	}
 
-		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 offset; /* error from fdt_next_node() */
 }
 
 int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
@@ -534,50 +453,24 @@
 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
 				  const char *compatible)
 {
-	uint32_t tag;
-	int offset, nextoffset;
-	int err;
+	int offset, 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);
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		err = fdt_node_check_compatible(fdt, offset, compatible);
+		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+			return err;
+		else if (err == 0)
+			return offset;
+	}
 
-		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;
+	return offset; /* error from fdt_next_node() */
 }
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index 6673f8e..0df472b 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -69,10 +69,8 @@
 
 static int rw_check_header(void *fdt)
 {
-	int err;
+	CHECK_HEADER(fdt);
 
-	if ((err = fdt_check_header(fdt)))
-		return err;
 	if (fdt_version(fdt) < 17)
 		return -FDT_ERR_BADVERSION;
 	if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
@@ -252,6 +250,30 @@
 	return 0;
 }
 
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+	char *namep;
+	int oldlen, newlen;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	namep = (char *)fdt_get_name(fdt, nodeoffset, &oldlen);
+	if (!namep)
+		return oldlen;
+
+	newlen = strlen(name);
+
+	err = _blob_splice_struct(fdt, namep, ALIGN(oldlen+1, FDT_TAGSIZE),
+				  ALIGN(newlen+1, FDT_TAGSIZE));
+	if (err)
+		return err;
+
+	memcpy(namep, name, newlen+1);
+	return 0;
+}
+
 int fdt_setprop(void *fdt, int nodeoffset, const char *name,
 		const void *val, int len)
 {
@@ -309,7 +331,7 @@
 	do {
 		offset = nextoffset;
 		tag = fdt_next_tag(fdt, offset, &nextoffset);
-	} while (tag == FDT_PROP);
+	} while ((tag == FDT_PROP) || (tag == FDT_NOP));
 
 	nh = _fdt_offset_ptr_w(fdt, offset);
 	nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
@@ -375,9 +397,7 @@
 	int newsize;
 	void *tmp;
 
-	err = fdt_check_header(fdt);
-	if (err)
-		return err;
+	CHECK_HEADER(fdt);
 
 	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
 		* sizeof(struct fdt_reserve_entry);
diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
index 1e60936..52e1b8d 100644
--- a/libfdt/libfdt_internal.h
+++ b/libfdt/libfdt_internal.h
@@ -58,6 +58,13 @@
 #define memeq(p, q, n)	(memcmp((p), (q), (n)) == 0)
 #define streq(p, q)	(strcmp((p), (q)) == 0)
 
+#define CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = fdt_check_header(fdt)) != 0) \
+			return err; \
+	}
+
 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);