fdtput: add delete node and property function

add the delete node and property function for fdtput.

usage:
1) delete nodes
   fdtput -r <options> <dt file> [<node>...]
2) delete properties
   fdtput -d <options> <dt file> <node> [<property>...]

Signed-off-by: Wang Long <long.wanglong@huawei.com>
diff --git a/fdtput.c b/fdtput.c
index 2a8d674..9b15c53 100644
--- a/fdtput.c
+++ b/fdtput.c
@@ -32,6 +32,8 @@
 enum oper_type {
 	OPER_WRITE_PROP,		/* Write a property in a node */
 	OPER_CREATE_NODE,		/* Create a new node */
+	OPER_REMOVE_NODE,		/* Delete a node */
+	OPER_DELETE_PROP,		/* Delete a property in a node */
 };
 
 struct display_info {
@@ -270,11 +272,65 @@
 	return 0;
 }
 
+/**
+ * Delete a property of a node in the fdt.
+ *
+ * @param blob		FDT blob to write into
+ * @param node_name	Path to node containing the property to delete
+ * @param prop_name	Name of property to delete
+ * @return 0 on success, or -1 on failure
+ */
+static int delete_prop(char *blob, const char *node_name, const char *prop_name)
+{
+	int node = 0;
+
+	node = fdt_path_offset(blob, node_name);
+	if (node < 0) {
+		report_error(node_name, -1, node);
+		return -1;
+	}
+
+	node = fdt_delprop(blob, node, prop_name);
+	if (node < 0) {
+		report_error(node_name, -1, node);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Delete a node in the fdt.
+ *
+ * @param blob		FDT blob to write into
+ * @param node_name	Name of node to delete
+ * @return 0 on success, or -1 on failure
+ */
+static int delete_node(char *blob, const char *node_name)
+{
+	int node = 0;
+
+	node = fdt_path_offset(blob, node_name);
+	if (node < 0) {
+		report_error(node_name, -1, node);
+		return -1;
+	}
+
+	node = fdt_del_node(blob, node);
+	if (node < 0) {
+		report_error(node_name, -1, node);
+		return -1;
+	}
+
+	return 0;
+}
+
 static int do_fdtput(struct display_info *disp, const char *filename,
 		    char **arg, int arg_count)
 {
 	char *value;
 	char *blob;
+	char *node;
 	int len, ret = 0;
 
 	blob = utilfdt_read(filename);
@@ -302,6 +358,15 @@
 				ret = create_node(&blob, *arg);
 		}
 		break;
+	case OPER_REMOVE_NODE:
+		for (; ret >= 0 && arg_count--; arg++)
+			ret = delete_node(blob, *arg);
+		break;
+	case OPER_DELETE_PROP:
+		node = *arg;
+		for (arg++; ret >= 0 && arg_count-- > 1; arg++)
+			ret = delete_prop(blob, node, *arg);
+		break;
 	}
 	if (ret >= 0) {
 		fdt_pack(blob);
@@ -317,12 +382,16 @@
 	"write a property value to a device tree\n"
 	"	fdtput <options> <dt file> <node> <property> [<value>...]\n"
 	"	fdtput -c <options> <dt file> [<node>...]\n"
+	"	fdtput -r <options> <dt file> [<node>...]\n"
+	"	fdtput -d <options> <dt file> <node> [<property>...]\n"
 	"\n"
 	"The command line arguments are joined together into a single value.\n"
 	USAGE_TYPE_MSG;
-static const char usage_short_opts[] = "cpt:v" USAGE_COMMON_SHORT_OPTS;
+static const char usage_short_opts[] = "crdpt:v" USAGE_COMMON_SHORT_OPTS;
 static struct option const usage_long_opts[] = {
 	{"create",           no_argument, NULL, 'c'},
+	{"remove",	     no_argument, NULL, 'r'},
+	{"delete",	     no_argument, NULL, 'd'},
 	{"auto-path",        no_argument, NULL, 'p'},
 	{"type",              a_argument, NULL, 't'},
 	{"verbose",          no_argument, NULL, 'v'},
@@ -330,6 +399,8 @@
 };
 static const char * const usage_opts_help[] = {
 	"Create nodes if they don't already exist",
+	"Delete nodes (and any subnodes) if they already exist",
+	"Delete properties if they already exist",
 	"Automatically create nodes as needed for the node path",
 	"Type of data",
 	"Display each value decoded from command line",
@@ -348,8 +419,6 @@
 	while ((opt = util_getopt_long()) != EOF) {
 		/*
 		 * TODO: add options to:
-		 * - delete property
-		 * - delete node (optionally recursively)
 		 * - rename node
 		 * - pack fdt before writing
 		 * - set amount of free space when writing
@@ -360,6 +429,12 @@
 		case 'c':
 			disp.oper = OPER_CREATE_NODE;
 			break;
+		case 'r':
+			disp.oper = OPER_REMOVE_NODE;
+			break;
+		case 'd':
+			disp.oper = OPER_DELETE_PROP;
+			break;
 		case 'p':
 			disp.auto_path = 1;
 			break;
@@ -390,6 +465,10 @@
 			usage("missing property");
 	}
 
+	if (disp.oper == OPER_DELETE_PROP)
+		if (argc < 1)
+			usage("missing node");
+
 	if (do_fdtput(&disp, filename, argv, argc))
 		return 1;
 	return 0;
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index ace6e4f..c5856d9 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -610,6 +610,28 @@
     run_wrap_test $DTPUT $dtb -cp /chosen
     run_wrap_test $DTPUT $dtb -cp /chosen/son
 
+    # Start again with a fresh dtb
+    run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
+
+    # Node delete
+    run_wrap_test $DTPUT $dtb -c /chosen/node1 /chosen/node2 /chosen/node3
+    run_fdtget_test "node3\nnode2\nnode1" $dtb -l  /chosen
+    run_wrap_test $DTPUT $dtb -r /chosen/node1 /chosen/node2
+    run_fdtget_test "node3" $dtb -l  /chosen
+
+    # Delete the non-existent node
+    run_wrap_error_test $DTPUT $dtb -r /non-existent/node
+
+    # Property delete
+    run_fdtput_test "eva" $dtb /chosen/ name "" -ts "eva"
+    run_fdtput_test "016" $dtb /chosen/ age  "" -ts "016"
+    run_fdtget_test "age\nname\nbootargs\nlinux,platform" $dtb -p  /chosen
+    run_wrap_test $DTPUT $dtb -d /chosen/ name age
+    run_fdtget_test "bootargs\nlinux,platform" $dtb -p  /chosen
+
+    # Delete the non-existent property
+    run_wrap_error_test $DTPUT $dtb -d /chosen   non-existent-prop
+
     # TODO: Add tests for verbose mode?
 }