diff options
Diffstat (limited to 'common/cmd_fdt.c')
| -rw-r--r-- | common/cmd_fdt.c | 144 | 
1 files changed, 144 insertions, 0 deletions
| diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 699441b51..299745237 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -47,6 +47,7 @@ DECLARE_GLOBAL_DATA_PTR;  static int fdt_valid(void);  static int fdt_parse_prop(char *const*newval, int count, char *data, int *len);  static int fdt_print(const char *pathp, char *prop, int depth); +static int is_printable_string(const void *data, int len);  /*   * The working_fdt points to our working flattened device tree. @@ -64,6 +65,34 @@ void set_working_fdt_addr(void *addr)  }  /* + * Get a value from the fdt and format it to be set in the environment + */ +static int fdt_value_setenv(const void *nodep, int len, const char *var) +{ +	if (is_printable_string(nodep, len)) +		setenv(var, (void *)nodep); +	else if (len == 4) { +		char buf[11]; + +		sprintf(buf, "0x%08X", *(uint32_t *)nodep); +		setenv(var, buf); +	} else if (len%4 == 0 && len <= 20) { +		/* Needed to print things like sha1 hashes. */ +		char buf[41]; +		int i; + +		for (i = 0; i < len; i += sizeof(unsigned int)) +			sprintf(buf + (i * 2), "%08x", +				*(unsigned int *)(nodep + i)); +		setenv(var, buf); +	} else { +		printf("error: unprintable value\n"); +		return 1; +	} +	return 0; +} + +/*   * Flattened Device Tree command, see the help for parameter definitions.   */  int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) @@ -253,6 +282,117 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  			return 1;  		} +	/******************************************************************** +	 * Get the value of a property in the working_fdt. +	 ********************************************************************/ +	} else if (argv[1][0] == 'g') { +		char *subcmd;		/* sub-command */ +		char *pathp;		/* path */ +		char *prop;		/* property */ +		char *var;		/* variable to store result */ +		int  nodeoffset;	/* node offset from libfdt */ +		const void *nodep;	/* property node pointer */ +		int  len = 0;		/* new length of the property */ + +		/* +		 * Parameters: Node path, property, optional value. +		 */ +		if (argc < 5) +			return CMD_RET_USAGE; + +		subcmd = argv[2]; + +		if (argc < 6 && subcmd[0] != 's') +			return CMD_RET_USAGE; + +		var    = argv[3]; +		pathp  = argv[4]; +		prop   = argv[5]; + +		nodeoffset = fdt_path_offset(working_fdt, pathp); +		if (nodeoffset < 0) { +			/* +			 * Not found or something else bad happened. +			 */ +			printf("libfdt fdt_path_offset() returned %s\n", +				fdt_strerror(nodeoffset)); +			return 1; +		} + +		if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) { +			int reqIndex = -1; +			int startDepth = fdt_node_depth( +				working_fdt, nodeoffset); +			int curDepth = startDepth; +			int curIndex = -1; +			int nextNodeOffset = fdt_next_node( +				working_fdt, nodeoffset, &curDepth); + +			if (subcmd[0] == 'n') +				reqIndex = simple_strtoul(argv[5], NULL, 16); + +			while (curDepth > startDepth) { +				if (curDepth == startDepth + 1) +					curIndex++; +				if (subcmd[0] == 'n' && curIndex == reqIndex) { +					const char *nodeName = fdt_get_name( +					    working_fdt, nextNodeOffset, NULL); + +					setenv(var, (char *)nodeName); +					return 0; +				} +				nextNodeOffset = fdt_next_node( +					working_fdt, nextNodeOffset, &curDepth); +				if (nextNodeOffset < 0) +					break; +			} +			if (subcmd[0] == 's') { +				/* get the num nodes at this level */ +				char buf[11]; + +				sprintf(buf, "%d", curIndex + 1); +				setenv(var, buf); +			} else { +				/* node index not found */ +				printf("libfdt node not found\n"); +				return 1; +			} +		} else { +			nodep = fdt_getprop( +				working_fdt, nodeoffset, prop, &len); +			if (len == 0) { +				/* no property value */ +				setenv(var, ""); +				return 0; +			} else if (len > 0) { +				if (subcmd[0] == 'v') { +					int ret; + +					ret = fdt_value_setenv(nodep, len, var); +					if (ret != 0) +						return ret; +				} else if (subcmd[0] == 'a') { +					/* Get address */ +					char buf[11]; + +					sprintf(buf, "0x%08X", (uint32_t)nodep); +					setenv(var, buf); +				} else if (subcmd[0] == 's') { +					/* Get size */ +					char buf[11]; + +					sprintf(buf, "0x%08X", len); +					setenv(var, buf); +				} else +					return CMD_RET_USAGE; +				return 0; +			} else { +				printf("libfdt fdt_getprop(): %s\n", +					fdt_strerror(len)); +				return 1; +			} +		} +  	/*  	 * Print (recursive) / List (single level)  	 */ @@ -836,6 +976,10 @@ U_BOOT_CMD(  	"fdt resize                          - Resize fdt to size + padding to 4k addr\n"  	"fdt print  <path> [<prop>]          - Recursive print starting at <path>\n"  	"fdt list   <path> [<prop>]          - Print one level starting at <path>\n" +	"fdt get value <var> <path> <prop>   - Get <property> and store in <var>\n" +	"fdt get name <var> <path> <index>   - Get name of node <index> and store in <var>\n" +	"fdt get addr <var> <path> <prop>    - Get start address of <property> and store in <var>\n" +	"fdt get size <var> <path> [<prop>]  - Get size of [<property>] or num nodes and store in <var>\n"  	"fdt set    <path> <prop> [<val>]    - Set <property> [to <val>]\n"  	"fdt mknode <path> <node>            - Create a new node after <path>\n"  	"fdt rm     <path> [<prop>]          - Delete the node or <property>\n" |