[U-Boot] [PATCH 5/6] fdt_support: add partitions fixup in mtd node

Anatolij Gustschin agust at denx.de
Tue Feb 23 23:37:09 CET 2010


Allow overriding defined partitions in the device tree blob
using partition info defined in the 'mtdparts' environment
variable.

Signed-off-by: Anatolij Gustschin <agust at denx.de>
Cc: Gerald Van Baren <vanbaren at cideas.com>
---
 common/cmd_mtdparts.c       |    2 +-
 common/fdt_support.c        |  214 +++++++++++++++++++++++++++++++++++++++++++
 include/fdt_support.h       |    2 +
 include/jffs2/load_kernel.h |    1 +
 include/mtd_node.h          |   11 ++
 5 files changed, 229 insertions(+), 1 deletions(-)
 create mode 100644 include/mtd_node.h

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index b375fea..80c548b 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 f89a3ee..b6abf38 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -757,3 +757,217 @@ 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;
+	int i, idx;
+	int noff;
+
+	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 0a9dd0d..a3d5f8c 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 8b2720e..906eb3d 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 0000000..5aae085
--- /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
-- 
1.6.3.3



More information about the U-Boot mailing list