Ejemplo n.º 1
0
/*
 * Flattened Device Tree command, see the help for parameter definitions.
 */
int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	char		op;

	if (argc < 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	/*
	 * Figure out which subcommand was given
	 */
	op = argv[1][0];
	/********************************************************************
	 * Set the address of the fdt
	 ********************************************************************/
	if (op == 'a') {
		/*
		 * Set the address [and length] of the fdt.
		 */
		fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);

		if (!fdt_valid()) {
			return 1;
		}

		if (argc >= 4) {
			int  len;
			int  err;
			/*
			 * Optional new length
			 */
			len =  simple_strtoul(argv[3], NULL, 16);
			if (len < fdt_totalsize(fdt)) {
				printf ("New length %d < existing length %d, ignoring.\n",
					len, fdt_totalsize(fdt));
			} else {
				/*
				 * Open in place with a new length.
				 */
				err = fdt_open_into(fdt, fdt, len);
				if (err != 0) {
					printf ("libfdt: %s\n", fdt_strerror(err));
				}
			}
		}

	/********************************************************************
	 * Move the fdt
	 ********************************************************************/
	} else if (op == 'm' && argv[1][1] == 'o') {
		struct fdt_header *newaddr;
		int  len;
		int  err;

		if (argc != 5) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		/*
		 * Set the address and length of the fdt.
		 */
		fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
		if (!fdt_valid()) {
			return 1;
		}

		newaddr = (struct fdt_header *)simple_strtoul(argv[3], NULL, 16);
		len     =  simple_strtoul(argv[4], NULL, 16);
		if (len < fdt_totalsize(fdt)) {
			printf ("New length %d < existing length %d, aborting.\n",
				len, fdt_totalsize(fdt));
			return 1;
		}

		/*
		 * Copy to the new location.
		 */
		err = fdt_open_into(fdt, newaddr, len);
		if (err != 0) {
			printf ("libfdt: %s\n", fdt_strerror(err));
			return 1;
		}
		fdt = newaddr;

	/********************************************************************
	 * mknode 
	 ********************************************************************/
	} else if (op == 'm' && argv[1][1] == 'k') {
		char *pathp = argv[2];
		char *node = argv[3];
		int nodeoffset;

		if (argc != 4) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}
			
		/*
		 * See if the node already exists
		 */
		if (strcmp(pathp, "/") == 0)
			nodeoffset = 0;
		else
			nodeoffset = fdt_path_offset (fdt, pathp);

		if (nodeoffset < 0) {
			printf("parent node %s doesn't exist\n", pathp);
			return 1;
		}

		/*
		 * Create the new node
		 */
		nodeoffset = fdt_add_subnode(fdt, nodeoffset, node);
		if (nodeoffset < 0) {
			printf("libfdt: %s\n", fdt_strerror(nodeoffset));
			return 1;
		}

	/********************************************************************
	 * Set the value of a node in the fdt.
	 ********************************************************************/
	} else if (op == 's') {
		char *pathp;		/* path */
		char *prop;			/* property */
		struct fdt_property *nodep;	/* node struct pointer */
		char *newval;		/* value from the user (as a string) */
		char *vp;			/* temporary value pointer */
		char *cp;			/* temporary char pointer */
		int  nodeoffset;	/* node offset from libfdt */
		int  len;			/* new length of the property */
		int  oldlen;		/* original length of the property */
		unsigned long tmp;	/* holds converted values */
		int  ret;			/* return value */

		/*
		 * Parameters: Node path, property, value.
		 */
		if (argc < 5) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		pathp  = argv[2];
		prop   = argv[3];
		newval = argv[4];

		if (strcmp(pathp, "/") == 0) {
			nodeoffset = 0;
		} else {
			nodeoffset = fdt_path_offset (fdt, pathp);
			if (nodeoffset < 0) {
				/*
			 	 * Not found or something else bad happened.
			 	 */
				printf ("libfdt: %s\n", fdt_strerror(nodeoffset));
				return 1;
			}
		}
		nodep = fdt_getprop (fdt, nodeoffset, prop, &oldlen);
		if (oldlen == 0) {
			/*
			 * The specified property has no value
			 */
			printf("%s has no value, cannot set one (yet).\n", prop);
			return 1;
		} else {
			/*
			 * Convert the new property
			 */
			vp = data;
			if (*newval == '<') {
				/*
				 * Bigger values than bytes.
				 */
				len = 0;
				newval++;
				while ((*newval != '>') && (*newval != '\0')) {
					cp = newval;
					tmp = simple_strtoul(cp, &newval, 16);
					if ((newval - cp) <= 2) {
						*vp = tmp & 0xFF;
						vp  += 1;
						len += 1;
					} else if ((newval - cp) <= 4) {
						*(uint16_t *)vp = __cpu_to_be16(tmp);
						vp  += 2;
						len += 2;
					} else if ((newval - cp) <= 8) {
						*(uint32_t *)vp = __cpu_to_be32(tmp);
						vp  += 4;
						len += 4;
					} else {
						printf("Sorry, I could not convert \"%s\"\n", cp);
						return 1;
					}
					while (*newval == ' ')
						newval++;
				}
				if (*newval != '>') {
					printf("Unexpected character '%c'\n", *newval);
					return 1;
				}
			} else if (*newval == '[') {
				/*
				 * Byte stream.  Convert the values.
				 */
				len = 0;
				newval++;
				while ((*newval != ']') && (*newval != '\0')) {
					tmp = simple_strtoul(newval, &newval, 16);
					*vp++ = tmp & 0xFF;
					len++;
					while (*newval == ' ')
						newval++;
				}
				if (*newval != ']') {
					printf("Unexpected character '%c'\n", *newval);
					return 1;
				}
			} else {
				/*
				 * Assume it is a string.  Copy it into our data area for
				 * convenience (including the terminating '\0').
				 */
				len = strlen(newval) + 1;
				strcpy(data, newval);
			}

			ret = fdt_setprop(fdt, nodeoffset, prop, data, len);
			if (ret < 0) {
				printf ("libfdt %s\n", fdt_strerror(ret));
				return 1;
			}
		}

	/********************************************************************
	 * Print (recursive) / List (single level)
	 ********************************************************************/
	} else if ((op == 'p') || (op == 'l')) {
		/*
		 * Recursively print (a portion of) the fdt.
		 */
		static int offstack[MAX_LEVEL];
		static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
		int depth = MAX_LEVEL;	/* how deep to print */
		char *pathp;		/* path */
		char *prop;			/* property */
		void *nodep;		/* property node pointer */
		int  nodeoffset;	/* node offset from libfdt */
		int  nextoffset;	/* next node offset from libfdt */
		uint32_t tag;		/* tag */
		int  len;			/* length of the property */
		int  level = 0;		/* keep track of nesting level */

		/*
		 * list is an alias for print, but limited to 1 level
		 */
		if (op == 'l') {
			depth = 1;
		}

		/*
		 * Get the starting path.  The root node is an oddball,
		 * the offset is zero and has no name.
		 */
		pathp = argv[2];
		if (argc > 3)
			prop = argv[3];
		else
			prop = NULL;

		if (strcmp(pathp, "/") == 0) {
			nodeoffset = 0;
			printf("/");
		} else {
			nodeoffset = fdt_path_offset (fdt, pathp);
			if (nodeoffset < 0) {
				/*
				 * Not found or something else bad happened.
				 */
				printf ("libfdt %s\n", fdt_strerror(nodeoffset));
				return 1;
			}
		}
		/*
		 * The user passed in a property as well as node path.  Print only
		 * the given property and then return.
		 */
		if (prop) {
			nodep = fdt_getprop (fdt, nodeoffset, prop, &len);
			if (len == 0) {
				printf("%s %s\n", pathp, prop);	/* no property value */
				return 0;
			} else if (len > 0) {
				printf("%s=", prop);
				print_data (nodep, len);
				printf("\n");
				return 0;
			} else {
				printf ("libfdt %s\n", fdt_strerror(len));
				return 1;
			}
		}

		/*
		 * The user passed in a node path and no property, print the node
		 * and all subnodes.
		 */
		offstack[0] = nodeoffset;

		while(level >= 0) {
			tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, &pathp);
			switch(tag) {
			case FDT_BEGIN_NODE:
				if(level <= depth)
					printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp);
				level++;
				offstack[level] = nodeoffset;
				if (level >= MAX_LEVEL) {
					printf("Aaaiii <splat> nested too deep.\n");
					return 1;
				}
				break;
			case FDT_END_NODE:
				level--;
				if(level <= depth)
					printf("%s};\n", &tabs[MAX_LEVEL - level]);
				if (level == 0) {
					level = -1;		/* exit the loop */
				}
				break;
			case FDT_PROP:
				nodep = fdt_getprop (fdt, offstack[level], pathp, &len);
				if (len < 0) {
					printf ("libfdt %s\n", fdt_strerror(len));
					return 1;
				} else if (len == 0) {
					/* the property has no value */
					if(level <= depth)
						printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp);
				} else {
					if(level <= depth) {
						printf("%s%s=", &tabs[MAX_LEVEL - level], pathp);
						print_data (nodep, len);
						printf(";\n");
					}
				}
				break;
			case FDT_NOP:
				break;
			case FDT_END:
				return 1;
			default:
				if(level <= depth)
					printf("Unknown tag 0x%08X\n", tag);
				return 1;
			}
			nodeoffset = nextoffset;
		}

	/********************************************************************
	 * Remove a property/node
	 ********************************************************************/
	} else if (op == 'r') {
		int  nodeoffset;	/* node offset from libfdt */
		int  err;

		/*
		 * Get the path.  The root node is an oddball, the offset
		 * is zero and has no name.
		 */
		if (strcmp(argv[2], "/") == 0) {
			nodeoffset = 0;
		} else {
			nodeoffset = fdt_path_offset (fdt, argv[2]);
			if (nodeoffset < 0) {
				/*
				 * Not found or something else bad happened.
				 */
				printf ("libfdt %s\n", fdt_strerror(nodeoffset));
				return 1;
			}
		}
		/*
		 * Do the delete.  A fourth parameter means delete a property,
		 * otherwise delete the node.
		 */
		if (argc > 3) {
			err = fdt_delprop(fdt, nodeoffset, argv[3]);
			if (err < 0) {
				printf("fdt_delprop libfdt: %s\n", fdt_strerror(err));
				return err;
			}
		} else {
			err = fdt_del_node(fdt, nodeoffset);
			if (err < 0) {
				printf("fdt_del_node libfdt: %s\n", fdt_strerror(err));
				return err;
			}
		}

	/********************************************************************
	 * Create a chosen node
	 ********************************************************************/
	} else if (op == 'c') {
		fdt_chosen(fdt, 0, 0, 1);

#ifdef CONFIG_OF_HAS_UBOOT_ENV
	/********************************************************************
	 * Create a u-boot-env node
	 ********************************************************************/
	} else if (op == 'e') {
		fdt_env(fdt);
#endif 
#ifdef CONFIG_OF_HAS_BD_T
	/********************************************************************
	 * Create a bd_t node
	 ********************************************************************/
	} else if (op == 'b') {
		fdt_bd_t(fdt);
#endif
	/********************************************************************
	 * Unrecognized command
	 ********************************************************************/
	} else {
		printf ("Usage:\n%s\n", cmdtp->usage);
		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 *argv[])
{
	if (argc < 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	/********************************************************************
	 * Set the address of the fdt
	 ********************************************************************/
	if (argv[1][0] == 'a') {
		/*
		 * Set the address [and length] of the fdt.
		 */
		fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);

		if (!fdt_valid()) {
			return 1;
		}

		if (argc >= 4) {
			int  len;
			int  err;
			/*
			 * Optional new length
			 */
			len = simple_strtoul(argv[3], NULL, 16);
			if (len < fdt_totalsize(fdt)) {
				printf ("New length %d < existing length %d, "
					"ignoring.\n",
					len, fdt_totalsize(fdt));
			} else {
				/*
				 * Open in place with a new length.
				 */
				err = fdt_open_into(fdt, fdt, len);
				if (err != 0) {
					printf ("libfdt fdt_open_into(): %s\n",
						fdt_strerror(err));
				}
			}
		}

	/********************************************************************
	 * Move the fdt
	 ********************************************************************/
	} else if ((argv[1][0] == 'm') && (argv[1][1] == 'o')) {
		struct fdt_header *newaddr;
		int  len;
		int  err;

		if (argc < 4) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		/*
		 * Set the address and length of the fdt.
		 */
		fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
		if (!fdt_valid()) {
			return 1;
		}

		newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16);

		/*
		 * If the user specifies a length, use that.  Otherwise use the
		 * current length.
		 */
		if (argc <= 4) {
			len = fdt_totalsize(fdt);
		} else {
			len = simple_strtoul(argv[4], NULL, 16);
			if (len < fdt_totalsize(fdt)) {
				printf ("New length 0x%X < existing length "
					"0x%X, aborting.\n",
					len, fdt_totalsize(fdt));
				return 1;
			}
		}

		/*
		 * Copy to the new location.
		 */
		err = fdt_open_into(fdt, newaddr, len);
		if (err != 0) {
			printf ("libfdt fdt_open_into(): %s\n",
				fdt_strerror(err));
			return 1;
		}
		fdt = newaddr;

	/********************************************************************
	 * Make a new node
	 ********************************************************************/
	} else if ((argv[1][0] == 'm') && (argv[1][1] == 'k')) {
		char *pathp;		/* path */
		char *nodep;		/* new node to add */
		int  nodeoffset;	/* node offset from libfdt */
		int  err;

		/*
		 * Parameters: Node path, new node to be appended to the path.
		 */
		if (argc < 4) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		pathp = argv[2];
		nodep = argv[3];

		nodeoffset = fdt_path_offset (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;
		}
		err = fdt_add_subnode(fdt, nodeoffset, nodep);
		if (err < 0) {
			printf ("libfdt fdt_add_subnode(): %s\n",
				fdt_strerror(err));
			return 1;
		}

	/********************************************************************
	 * Set the value of a property in the fdt.
	 ********************************************************************/
	} else if (argv[1][0] == 's') {
		char *pathp;		/* path */
		char *prop;		/* property */
		char *newval;		/* value from the user (as a string) */
		int  nodeoffset;	/* node offset from libfdt */
		static char data[SCRATCHPAD];	/* storage for the property */
		int  len;		/* new length of the property */
		int  ret;		/* return value */

		/*
		 * Parameters: Node path, property, value.
		 */
		if (argc < 5) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		pathp  = argv[2];
		prop   = argv[3];
		newval = argv[4];

		nodeoffset = fdt_path_offset (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;
		}
		ret = fdt_parse_prop(pathp, prop, newval, data, &len);
		if (ret != 0)
			return ret;

		ret = fdt_setprop(fdt, nodeoffset, prop, data, len);
		if (ret < 0) {
			printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret));
			return 1;
		}

	/********************************************************************
	 * Print (recursive) / List (single level)
	 ********************************************************************/
	} else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) {
		int depth = MAX_LEVEL;	/* how deep to print */
		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
		 */
		if (argv[1][0] == 'l') {
			depth = 1;
		}

		/*
		 * Get the starting path.  The root node is an oddball,
		 * the offset is zero and has no name.
		 */
		if (argc == 2)
			pathp = root;
		else
			pathp = argv[2];
		if (argc > 3)
			prop = argv[3];
		else
			prop = NULL;

		ret = fdt_print(pathp, prop, depth);
		if (ret != 0)
			return ret;

	/********************************************************************
	 * Remove a property/node
	 ********************************************************************/
	} else if (argv[1][0] == 'r') {
		int  nodeoffset;	/* node offset from libfdt */
		int  err;

		/*
		 * Get the path.  The root node is an oddball, the offset
		 * is zero and has no name.
		 */
		nodeoffset = fdt_path_offset (fdt, argv[2]);
		if (nodeoffset < 0) {
			/*
			 * Not found or something else bad happened.
			 */
			printf ("libfdt fdt_path_offset() returned %s\n",
				fdt_strerror(nodeoffset));
			return 1;
		}
		/*
		 * Do the delete.  A fourth parameter means delete a property,
		 * otherwise delete the node.
		 */
		if (argc > 3) {
			err = fdt_delprop(fdt, nodeoffset, argv[3]);
			if (err < 0) {
				printf("libfdt fdt_delprop():  %s\n",
					fdt_strerror(err));
				return err;
			}
		} else {
			err = fdt_del_node(fdt, nodeoffset);
			if (err < 0) {
				printf("libfdt fdt_del_node():  %s\n",
					fdt_strerror(err));
				return err;
			}
		}
	}
#ifdef CONFIG_OF_BOARD_SETUP
	/* Call the board-specific fixup routine */
	else if (argv[1][0] == 'b')
		ft_board_setup(fdt, gd->bd);
#endif
	/* Create a chosen node */
	else if (argv[1][0] == 'c')
		fdt_chosen(fdt, 0, 0, 1);

#ifdef CONFIG_OF_HAS_UBOOT_ENV
	/* Create a u-boot-env node */
	else if (argv[1][0] == 'e')
		fdt_env(fdt);
#endif
#ifdef CONFIG_OF_HAS_BD_T
	/* Create a bd_t node */
	else if (argv[1][0] == 'b')
		fdt_bd_t(fdt);
#endif
	else {
		/* Unrecognized command */
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	return 0;
}