summaryrefslogtreecommitdiffstats
path: root/drivers/of/partition.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/partition.c')
-rw-r--r--drivers/of/partition.c84
1 files changed, 77 insertions, 7 deletions
diff --git a/drivers/of/partition.c b/drivers/of/partition.c
index 68f3812ed6..f4d6c3322c 100644
--- a/drivers/of/partition.c
+++ b/drivers/of/partition.c
@@ -23,6 +23,16 @@
#include <linux/mtd/mtd.h>
#include <linux/err.h>
#include <nand.h>
+#include <init.h>
+#include <globalvar.h>
+
+static unsigned int of_partition_binding;
+
+enum of_binding_name {
+ MTD_OF_BINDING_NEW,
+ MTD_OF_BINDING_LEGACY,
+ MTD_OF_BINDING_DONTTOUCH,
+};
struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node)
{
@@ -93,15 +103,36 @@ int of_parse_partitions(struct cdev *cdev, struct device_node *node)
return 0;
}
+static void delete_subnodes(struct device_node *np)
+{
+ struct device_node *part, *tmp;
+
+ for_each_child_of_node_safe(np, tmp, part) {
+ if (of_get_property(part, "compatible", NULL))
+ continue;
+
+ of_delete_node(part);
+ }
+}
+
static int of_mtd_fixup(struct device_node *root, void *ctx)
{
struct cdev *cdev = ctx;
struct mtd_info *mtd, *partmtd;
- struct device_node *np, *part, *tmp;
+ struct device_node *np, *part, *partnode;
int ret;
+ int n_cells;
mtd = container_of(cdev, struct mtd_info, cdev);
+ if (of_partition_binding == MTD_OF_BINDING_DONTTOUCH)
+ return 0;
+
+ if (mtd->size >= 0x100000000)
+ n_cells = 2;
+ else
+ n_cells = 1;
+
np = of_find_node_by_path_from(root, mtd->of_path);
if (!np) {
dev_err(&mtd->class_dev, "Cannot find nodepath %s, cannot fixup\n",
@@ -109,12 +140,37 @@ static int of_mtd_fixup(struct device_node *root, void *ctx)
return -EINVAL;
}
- for_each_child_of_node_safe(np, tmp, part) {
- if (of_get_property(part, "compatible", NULL))
- continue;
- of_delete_node(part);
+ partnode = of_get_child_by_name(np, "partitions");
+ if (partnode) {
+ if (of_partition_binding == MTD_OF_BINDING_LEGACY) {
+ of_delete_node(partnode);
+ partnode = np;
+ }
+ delete_subnodes(partnode);
+ } else {
+ delete_subnodes(np);
+
+ if (of_partition_binding == MTD_OF_BINDING_LEGACY)
+ partnode = np;
+ else
+ partnode = of_new_node(np, "partitions");
+ }
+
+ if (of_partition_binding == MTD_OF_BINDING_NEW) {
+ ret = of_property_write_string(partnode, "compatible",
+ "fixed-partitions");
+ if (ret)
+ return ret;
}
+ of_property_write_u32(partnode, "#size-cells", n_cells);
+ if (ret)
+ return ret;
+
+ of_property_write_u32(partnode, "#addres-cells", n_cells);
+ if (ret)
+ return ret;
+
list_for_each_entry(partmtd, &mtd->partitions, partitions_entry) {
int na, ns, len = 0;
char *name = basprintf("partition@%0llx",
@@ -125,7 +181,7 @@ static int of_mtd_fixup(struct device_node *root, void *ctx)
if (!name)
return -ENOMEM;
- part = of_new_node(np, name);
+ part = of_new_node(partnode, name);
free(name);
if (!part)
return -ENOMEM;
@@ -160,4 +216,18 @@ static int of_mtd_fixup(struct device_node *root, void *ctx)
int of_partitions_register_fixup(struct cdev *cdev)
{
return of_register_fixup(of_mtd_fixup, cdev);
-} \ No newline at end of file
+}
+
+static const char *of_binding_names[] = {
+ "new", "legacy", "donttouch"
+};
+
+static int of_partition_init(void)
+{
+ dev_add_param_enum(&global_device, "of_partition_binding", NULL, NULL,
+ &of_partition_binding, of_binding_names,
+ ARRAY_SIZE(of_binding_names), NULL);
+
+ return 0;
+}
+device_initcall(of_partition_init); \ No newline at end of file