diff options
| author | Anatolij Gustschin <agust@denx.de> | 2010-03-16 17:10:05 +0100 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2010-03-21 22:44:59 +0100 | 
| commit | 3c950e2ebfde083084cc926b020e3a22a536bf85 (patch) | |
| tree | 50a4b0b6b2f5c03272216a7d9414052d8e3e9496 | |
| parent | d611295032c30e6c533cb356005fa82ab7992824 (diff) | |
| download | olio-uboot-2014.01-3c950e2ebfde083084cc926b020e3a22a536bf85.tar.xz olio-uboot-2014.01-3c950e2ebfde083084cc926b020e3a22a536bf85.zip | |
fdt_support: add partitions fixup in mtd node
Allow overwriting defined partitions in the device tree blob
using partition info defined in the 'mtdparts' environment
variable.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Gerald Van Baren <vanbaren@cideas.com>
| -rw-r--r-- | common/cmd_mtdparts.c | 2 | ||||
| -rw-r--r-- | common/fdt_support.c | 219 | ||||
| -rw-r--r-- | include/fdt_support.h | 2 | ||||
| -rw-r--r-- | include/jffs2/load_kernel.h | 1 | ||||
| -rw-r--r-- | include/mtd_node.h | 11 | 
5 files changed, 234 insertions, 1 deletions
| diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c index 20fed2aad..0b5f74714 100644 --- a/common/cmd_mtdparts.c +++ b/common/cmd_mtdparts.c @@ -776,7 +776,7 @@ static int device_del(struct mtd_device *dev)   * @param num device number   * @return NULL if requested device does not exist   */ -static struct mtd_device* device_find(u8 type, u8 num) +struct mtd_device *device_find(u8 type, u8 num)  {  	struct list_head *entry;  	struct mtd_device *dev_tmp; diff --git a/common/fdt_support.c b/common/fdt_support.c index f89a3eef6..b7d4fe506 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -757,3 +757,222 @@ int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size)  	return -1;  }  #endif + +#ifdef CONFIG_FDT_FIXUP_PARTITIONS +#include <jffs2/load_kernel.h> +#include <mtd_node.h> + +struct reg_cell { +	unsigned int r0; +	unsigned int r1; +}; + +int fdt_del_subnodes(const void *blob, int parent_offset) +{ +	int off, ndepth; +	int ret; + +	for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth); +	     (off >= 0) && (ndepth > 0); +	     off = fdt_next_node(blob, off, &ndepth)) { +		if (ndepth == 1) { +			debug("delete %s: offset: %x\n", +				fdt_get_name(blob, off, 0), off); +			ret = fdt_del_node((void *)blob, off); +			if (ret < 0) { +				printf("Can't delete node: %s\n", +					fdt_strerror(ret)); +				return ret; +			} else { +				ndepth = 0; +				off = parent_offset; +			} +		} +	} +	return 0; +} + +int fdt_increase_size(void *fdt, int add_len) +{ +	int newlen; + +	newlen = fdt_totalsize(fdt) + add_len; + +	/* Open in place with a new len */ +	return fdt_open_into(fdt, fdt, newlen); +} + +int fdt_del_partitions(void *blob, int parent_offset) +{ +	const void *prop; +	int ndepth = 0; +	int off; +	int ret; + +	off = fdt_next_node(blob, parent_offset, &ndepth); +	if (off > 0 && ndepth == 1) { +		prop = fdt_getprop(blob, off, "label", NULL); +		if (prop == NULL) { +			/* +			 * Could not find label property, nand {}; node? +			 * Check subnode, delete partitions there if any. +			 */ +			return fdt_del_partitions(blob, off); +		} else { +			ret = fdt_del_subnodes(blob, parent_offset); +			if (ret < 0) { +				printf("Can't remove subnodes: %s\n", +					fdt_strerror(ret)); +				return ret; +			} +		} +	} +	return 0; +} + +int fdt_node_set_part_info(void *blob, int parent_offset, +			   struct mtd_device *dev) +{ +	struct list_head *pentry; +	struct part_info *part; +	struct reg_cell cell; +	int off, ndepth = 0; +	int part_num, ret; +	char buf[64]; + +	ret = fdt_del_partitions(blob, parent_offset); +	if (ret < 0) +		return ret; + +	/* +	 * Check if it is nand {}; subnode, adjust +	 * the offset in this case +	 */ +	off = fdt_next_node(blob, parent_offset, &ndepth); +	if (off > 0 && ndepth == 1) +		parent_offset = off; + +	part_num = 0; +	list_for_each_prev(pentry, &dev->parts) { +		int newoff; + +		part = list_entry(pentry, struct part_info, link); + +		debug("%2d: %-20s0x%08x\t0x%08x\t%d\n", +			part_num, part->name, part->size, +			part->offset, part->mask_flags); + +		sprintf(buf, "partition@%x", part->offset); +add_sub: +		ret = fdt_add_subnode(blob, parent_offset, buf); +		if (ret == -FDT_ERR_NOSPACE) { +			ret = fdt_increase_size(blob, 512); +			if (!ret) +				goto add_sub; +			else +				goto err_size; +		} else if (ret < 0) { +			printf("Can't add partition node: %s\n", +				fdt_strerror(ret)); +			return ret; +		} +		newoff = ret; + +		/* Check MTD_WRITEABLE_CMD flag */ +		if (part->mask_flags & 1) { +add_ro: +			ret = fdt_setprop(blob, newoff, "read_only", NULL, 0); +			if (ret == -FDT_ERR_NOSPACE) { +				ret = fdt_increase_size(blob, 512); +				if (!ret) +					goto add_ro; +				else +					goto err_size; +			} else if (ret < 0) +				goto err_prop; +		} + +		cell.r0 = cpu_to_fdt32(part->offset); +		cell.r1 = cpu_to_fdt32(part->size); +add_reg: +		ret = fdt_setprop(blob, newoff, "reg", &cell, sizeof(cell)); +		if (ret == -FDT_ERR_NOSPACE) { +			ret = fdt_increase_size(blob, 512); +			if (!ret) +				goto add_reg; +			else +				goto err_size; +		} else if (ret < 0) +			goto err_prop; + +add_label: +		ret = fdt_setprop_string(blob, newoff, "label", part->name); +		if (ret == -FDT_ERR_NOSPACE) { +			ret = fdt_increase_size(blob, 512); +			if (!ret) +				goto add_label; +			else +				goto err_size; +		} else if (ret < 0) +			goto err_prop; + +		part_num++; +	} +	return 0; +err_size: +	printf("Can't increase blob size: %s\n", fdt_strerror(ret)); +	return ret; +err_prop: +	printf("Can't add property: %s\n", fdt_strerror(ret)); +	return ret; +} + +/* + * Update partitions in nor/nand nodes using info from + * mtdparts environment variable. The nodes to update are + * specified by node_info structure which contains mtd device + * type and compatible string: E. g. the board code in + * ft_board_setup() could use: + * + *	struct node_info nodes[] = { + *		{ "fsl,mpc5121-nfc",    MTD_DEV_TYPE_NAND, }, + *		{ "cfi-flash",          MTD_DEV_TYPE_NOR,  }, + *	}; + * + *	fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); + */ +void fdt_fixup_mtdparts(void *blob, void *node_info, int node_info_size) +{ +	struct node_info *ni = node_info; +	struct mtd_device *dev; +	char *parts; +	int i, idx; +	int noff; + +	parts = getenv("mtdparts"); +	if (!parts) +		return; + +	if (mtdparts_init() != 0) +		return; + +	for (i = 0; i < node_info_size; i++) { +		idx = 0; +		noff = fdt_node_offset_by_compatible(blob, -1, ni[i].compat); +		while (noff != -FDT_ERR_NOTFOUND) { +			debug("%s: %s, mtd dev type %d\n", +				fdt_get_name(blob, noff, 0), +				ni[i].compat, ni[i].type); +			dev = device_find(ni[i].type, idx++); +			if (dev) { +				if (fdt_node_set_part_info(blob, noff, dev)) +					return; /* return on error */ +			} + +			/* Jump to next flash node */ +			noff = fdt_node_offset_by_compatible(blob, noff, +							     ni[i].compat); +		} +	} +} +#endif diff --git a/include/fdt_support.h b/include/fdt_support.h index 0a9dd0dd8..a3d5f8cbf 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -81,5 +81,7 @@ int fdt_resize(void *blob);  int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size); +void fdt_fixup_mtdparts(void *fdt, void *node_info, int node_info_size); +  #endif /* ifdef CONFIG_OF_LIBFDT */  #endif /* ifndef __FDT_SUPPORT_H */ diff --git a/include/jffs2/load_kernel.h b/include/jffs2/load_kernel.h index 8b2720e95..906eb3d3c 100644 --- a/include/jffs2/load_kernel.h +++ b/include/jffs2/load_kernel.h @@ -78,5 +78,6 @@ struct mtdids {  extern int mtdparts_init(void);  extern int find_dev_and_part(const char *id, struct mtd_device **dev,  				u8 *part_num, struct part_info **part); +extern struct mtd_device *device_find(u8 type, u8 num);  #endif /* load_kernel_h */ diff --git a/include/mtd_node.h b/include/mtd_node.h new file mode 100644 index 000000000..5aae0859d --- /dev/null +++ b/include/mtd_node.h @@ -0,0 +1,11 @@ +#ifndef _NODE_INFO +#define _NODE_INFO + +/* + * Info we use to search for a flash node in DTB. + */ +struct node_info { +	const char *compat;	/* compatible string */ +	int type;		/* mtd flash type */ +}; +#endif |