summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2017-04-07 09:59:38 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2017-04-07 09:59:38 +0200
commit53adf0648c330357103e4a7103c3d7f05c0c4bcf (patch)
tree78d038c2761e3c0694eac9bc3386436a8d6c3b1c /drivers
parent8b30a8a77612b728bf664a9e9827af7ebdbcd3ba (diff)
parent12960a57841d5e6ea04fd523611e15a9a4170c89 (diff)
downloadbarebox-53adf0648c330357103e4a7103c3d7f05c0c4bcf.tar.gz
barebox-53adf0648c330357103e4a7103c3d7f05c0c4bcf.tar.xz
Merge branch 'for-next/ofpart'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/driver.c2
-rw-r--r--drivers/eeprom/at24.c1
-rw-r--r--drivers/eeprom/at25.c2
-rw-r--r--drivers/mci/mci-core.c4
-rw-r--r--drivers/mtd/core.c65
-rw-r--r--drivers/mtd/partition.c2
-rw-r--r--drivers/of/base.c24
-rw-r--r--drivers/of/of_path.c107
-rw-r--r--drivers/of/partition.c176
-rw-r--r--drivers/video/simplefb.c12
10 files changed, 318 insertions, 77 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 5867fe45d0..83260990af 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -221,7 +221,7 @@ int unregister_device(struct device_d *old_dev)
}
list_for_each_entry_safe(cdev, ct, &old_dev->cdevs, devices_list) {
- if (cdev->flags & DEVFS_IS_PARTITION) {
+ if (cdev->master) {
dev_dbg(old_dev, "unregister part %s\n", cdev->name);
devfs_del_partition(cdev->name);
}
diff --git a/drivers/eeprom/at24.c b/drivers/eeprom/at24.c
index 4ae3776554..1227286fbe 100644
--- a/drivers/eeprom/at24.c
+++ b/drivers/eeprom/at24.c
@@ -500,6 +500,7 @@ static int at24_probe(struct device_d *dev)
goto err_devfs_create;
of_parse_partitions(&at24->cdev, dev->device_node);
+ of_partitions_register_fixup(&at24->cdev);
return 0;
diff --git a/drivers/eeprom/at25.c b/drivers/eeprom/at25.c
index f7f8368c4b..1caaebd371 100644
--- a/drivers/eeprom/at25.c
+++ b/drivers/eeprom/at25.c
@@ -360,6 +360,8 @@ static int at25_probe(struct device_d *dev)
dev_dbg(dev, "%s probed\n", at25->cdev.name);
of_parse_partitions(&at25->cdev, dev->device_node);
+ of_partitions_register_fixup(&at25->cdev);
+
return 0;
fail:
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 928277a924..b173a173b1 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1621,8 +1621,10 @@ static int mci_register_partition(struct mci_part *part)
rc = 0; /* it's not a failure */
}
- if (np)
+ if (np) {
of_parse_partitions(&part->blk.cdev, np);
+ of_partitions_register_fixup(&part->blk.cdev);
+ }
return 0;
}
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 4e7bfdb3da..1eb8dd36d8 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -556,67 +556,6 @@ static int mtd_part_compare(struct list_head *a, struct list_head *b)
return 0;
}
-static int of_mtd_fixup(struct device_node *root, void *ctx)
-{
- struct mtd_info *mtd = ctx, *partmtd;
- struct device_node *np, *part, *tmp;
- int ret;
-
- 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",
- mtd->of_path);
- return -EINVAL;
- }
-
- for_each_child_of_node_safe(np, tmp, part) {
- if (of_get_property(part, "compatible", NULL))
- continue;
- of_delete_node(part);
- }
-
- list_for_each_entry(partmtd, &mtd->partitions, partitions_entry) {
- int na, ns, len = 0;
- char *name = basprintf("partition@%0llx",
- partmtd->master_offset);
- void *p;
- u8 tmp[16 * 16]; /* Up to 64-bit address + 64-bit size */
-
- if (!name)
- return -ENOMEM;
-
- part = of_new_node(np, name);
- free(name);
- if (!part)
- return -ENOMEM;
-
- p = of_new_property(part, "label", partmtd->cdev.partname,
- strlen(partmtd->cdev.partname) + 1);
- if (!p)
- return -ENOMEM;
-
- na = of_n_addr_cells(part);
- ns = of_n_size_cells(part);
-
- of_write_number(tmp + len, partmtd->master_offset, na);
- len += na * 4;
- of_write_number(tmp + len, partmtd->size, ns);
- len += ns * 4;
-
- ret = of_set_property(part, "reg", tmp, len, 1);
- if (ret)
- return ret;
-
- if (partmtd->cdev.flags & DEVFS_PARTITION_READONLY) {
- ret = of_set_property(part, "read-only", NULL, 0, 1);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
static int mtd_detect(struct device_d *dev)
{
struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
@@ -732,7 +671,9 @@ int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id)
of_parse_partitions(&mtd->cdev, mtd->parent->device_node);
if (IS_ENABLED(CONFIG_OFDEVICE) && mtd->parent->device_node) {
mtd->of_path = xstrdup(mtd->parent->device_node->full_name);
- of_register_fixup(of_mtd_fixup, mtd);
+ ret = of_partitions_register_fixup(&mtd->cdev);
+ if (ret)
+ goto err1;
}
}
diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c
index 777cb758ce..013697732d 100644
--- a/drivers/mtd/partition.c
+++ b/drivers/mtd/partition.c
@@ -225,6 +225,8 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
if (ret)
goto err;
+ part->cdev.master = &part->master->cdev;
+
return part;
err:
free(part->cdev.partname);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index bef8f1de1a..6632f4d9dd 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1217,6 +1217,28 @@ int of_property_write_u64_array(struct device_node *np,
}
/**
+ * of_property_write_string - Write a string to a property. If
+ * the property does not exist, it will be created and appended to the given
+ * device node.
+ *
+ * @np: device node to which the property value is to be written.
+ * @propname: name of the property to be written.
+ * value: pointer to the string to write
+ *
+ * Search for a property in a device node and write a string to
+ * it. If the property does not exist, it will be created and appended to
+ * the device node. Returns 0 on success, -ENOMEM if the property or array
+ * of elements cannot be created.
+ */
+int of_property_write_string(struct device_node *np,
+ const char *propname, const char *value)
+{
+ size_t len = strlen(value);
+
+ return of_set_property(np, propname, value, len + 1, 1);
+}
+
+/**
* of_parse_phandle_from - Resolve a phandle property to a device_node pointer from
* a given root node
* @np: Pointer to device node holding phandle property
@@ -2093,7 +2115,7 @@ int of_device_enable_path(const char *path)
*/
int of_device_disable(struct device_node *node)
{
- return of_set_property(node, "status", "disabled", sizeof("disabled"), 1);
+ return of_property_write_string(node, "status", "disabled");
}
/**
diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c
index e0b2dc1247..a5886dffac 100644
--- a/drivers/of/of_path.c
+++ b/drivers/of/of_path.c
@@ -104,6 +104,113 @@ int of_find_path_by_node(struct device_node *node, char **outpath, unsigned flag
}
/**
+ * of_find_node_by_devpath - translate a device path to a device tree node
+ *
+ * @root: The device tree root. Can be NULL, in this case the internal tree is used
+ * @path: The path to look the node up for. Can be "/dev/cdevname" or "cdevname" directly.
+ *
+ * This is the counterpart of of_find_path_by_node(). Given a path this function tries
+ * to find the corresponding node in the given device tree.
+ *
+ * We first have to find the hardware device in the tree we are passed and then find
+ * a partition matching offset/size in this tree. This is necessary because the
+ * passed tree may use another partition binding (legacy vs. fixed-partitions). Also
+ * the node names may differ (some device trees have partition@<num> instead of
+ * partition@<offset>.
+ */
+struct device_node *of_find_node_by_devpath(struct device_node *root, const char *path)
+{
+ struct cdev *cdev;
+ bool is_partition = false;
+ struct device_node *np, *partnode, *rnp;
+ loff_t part_offset = 0, part_size = 0;
+
+ pr_debug("%s: looking for path %s\n", __func__, path);
+
+ if (!strncmp(path, "/dev/", 5))
+ path += 5;
+
+ cdev = cdev_by_name(path);
+ if (!cdev) {
+ pr_debug("%s: cdev %s not found\n", __func__, path);
+ return NULL;
+ }
+
+ /*
+ * Look for the device node of the master device (the one of_parse_partitions() has
+ * been called with
+ */
+ if (cdev->master) {
+ is_partition = true;
+ part_offset = cdev->offset;
+ part_size = cdev->size;
+ pr_debug("%s path %s: is a partition with offset 0x%08llx, size 0x%08llx\n",
+ __func__, path, part_offset, part_size);
+ np = cdev->master->device_node;
+ } else {
+ np = cdev->device_node;
+ }
+
+ /*
+ * Now find the device node of the master device in the device tree we have
+ * been passed.
+ */
+ rnp = of_find_node_by_path_from(root, np->full_name);
+ if (!rnp) {
+ pr_debug("%s path %s: %s not found in passed tree\n", __func__, path,
+ np->full_name);
+ return NULL;
+ }
+
+ if (!is_partition) {
+ pr_debug("%s path %s: returning full device node %s\n", __func__, path,
+ rnp->full_name);
+ return rnp;
+ }
+
+ /*
+ * Look for a partition with matching offset/size in the device node of
+ * the tree we have been passed.
+ */
+ partnode = of_get_child_by_name(rnp, "partitions");
+ if (!partnode) {
+ pr_debug("%s path %s: using legacy partition binding\n", __func__, path);
+ partnode = rnp;
+ }
+
+ for_each_child_of_node(partnode, np) {
+ const __be32 *reg;
+ int na, ns, len;
+ loff_t offset, size;
+
+ reg = of_get_property(np, "reg", &len);
+ if (!reg)
+ return NULL;
+
+ na = of_n_addr_cells(np);
+ ns = of_n_size_cells(np);
+
+ if (len < (na + ns) * sizeof(__be32)) {
+ pr_err("reg property too small in %s\n", np->full_name);
+ continue;
+ }
+
+ offset = of_read_number(reg, na);
+ size = of_read_number(reg + na, ns);
+
+ if (part_offset == offset && part_size == size) {
+ pr_debug("%s path %s: found matching partition in %s\n", __func__, path,
+ np->full_name);
+ return np;
+ }
+ }
+
+ pr_debug("%s path %s: no matching node found\n", __func__, path);
+
+ return NULL;
+}
+
+/**
* of_find_path - translate a path description in the devicetree to a barebox
* path
*
diff --git a/drivers/of/partition.c b/drivers/of/partition.c
index 8c2aef2326..25b41cb012 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)
{
@@ -30,10 +40,11 @@ struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node)
char *filename;
struct cdev *new;
const __be32 *reg;
- unsigned long offset, size;
+ u64 offset, size;
const char *name;
int len;
unsigned long flags = 0;
+ int na, ns;
if (!node)
return NULL;
@@ -42,8 +53,16 @@ struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node)
if (!reg)
return NULL;
- offset = be32_to_cpu(reg[0]);
- size = be32_to_cpu(reg[1]);
+ na = of_n_addr_cells(node);
+ ns = of_n_size_cells(node);
+
+ if (len < (na + ns) * sizeof(__be32)) {
+ pr_err("reg property too small in %s\n", node->full_name);
+ return NULL;
+ }
+
+ offset = of_read_number(reg, na);
+ size = of_read_number(reg + na, ns);
partname = of_get_property(node, "label", &len);
if (!partname)
@@ -53,7 +72,7 @@ struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node)
name = (char *)partname;
- debug("add partition: %s.%s 0x%08lx 0x%08lx\n", cdev->name, partname, offset, size);
+ debug("add partition: %s.%s 0x%08llx 0x%08llx\n", cdev->name, partname, offset, size);
if (of_get_property(node, "read-only", &len))
flags = DEVFS_PARTITION_READONLY;
@@ -79,6 +98,8 @@ int of_parse_partitions(struct cdev *cdev, struct device_node *node)
if (!node)
return -EINVAL;
+ cdev->device_node = node;
+
subnode = of_get_child_by_name(node, "partitions");
if (subnode) {
if (!of_device_is_compatible(subnode, "fixed-partitions"))
@@ -92,3 +113,150 @@ 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_partition_fixup(struct device_node *root, void *ctx)
+{
+ struct cdev *cdev = ctx, *partcdev;
+ struct device_node *np, *part, *partnode;
+ int ret;
+ int n_cells, n_parts = 0;
+
+ if (of_partition_binding == MTD_OF_BINDING_DONTTOUCH)
+ return 0;
+
+ if (!cdev->device_node)
+ return -EINVAL;
+
+ list_for_each_entry(partcdev, &cdev->partitions, partition_entry) {
+ if (partcdev->flags & DEVFS_PARTITION_FROM_TABLE)
+ continue;
+ n_parts++;
+ }
+
+ if (!n_parts)
+ return 0;
+
+ if (cdev->size >= 0x100000000)
+ n_cells = 2;
+ else
+ n_cells = 1;
+
+ np = of_find_node_by_path_from(root, cdev->device_node->full_name);
+ if (!np) {
+ dev_err(cdev->dev, "Cannot find nodepath %s, cannot fixup\n",
+ cdev->device_node->full_name);
+ return -EINVAL;
+ }
+
+ 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(partcdev, &cdev->partitions, partition_entry) {
+ int na, ns, len = 0;
+ char *name;
+ void *p;
+ u8 tmp[16 * 16]; /* Up to 64-bit address + 64-bit size */
+ loff_t partoffset;
+
+ if (partcdev->flags & DEVFS_PARTITION_FROM_TABLE)
+ continue;
+
+ if (partcdev->mtd)
+ partoffset = partcdev->mtd->master_offset;
+ else
+ partoffset = partcdev->offset;
+
+ name = basprintf("partition@%0llx", partoffset);
+ if (!name)
+ return -ENOMEM;
+
+ part = of_new_node(partnode, name);
+ free(name);
+ if (!part)
+ return -ENOMEM;
+
+ p = of_new_property(part, "label", partcdev->partname,
+ strlen(partcdev->partname) + 1);
+ if (!p)
+ return -ENOMEM;
+
+ na = of_n_addr_cells(part);
+ ns = of_n_size_cells(part);
+
+ of_write_number(tmp + len, partoffset, na);
+ len += na * 4;
+ of_write_number(tmp + len, partcdev->size, ns);
+ len += ns * 4;
+
+ ret = of_set_property(part, "reg", tmp, len, 1);
+ if (ret)
+ return ret;
+
+ if (partcdev->flags & DEVFS_PARTITION_READONLY) {
+ ret = of_set_property(part, "read-only", NULL, 0, 1);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int of_partitions_register_fixup(struct cdev *cdev)
+{
+ return of_register_fixup(of_partition_fixup, cdev);
+}
+
+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);
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
index 357262988e..a2c59de364 100644
--- a/drivers/video/simplefb.c
+++ b/drivers/video/simplefb.c
@@ -89,9 +89,6 @@ static const struct simplefb_mode *simplefb_find_mode(const struct fb_info *fbi)
static int simplefb_create_node(struct device_node *root,
const struct fb_info *fbi, const char *format)
{
- const char *compat = "simple-framebuffer";
- const char *disabled = "disabled";
- const char *okay = "okay";
struct device_node *node;
u32 cells[2];
int ret;
@@ -100,12 +97,11 @@ static int simplefb_create_node(struct device_node *root,
if (!node)
return -ENOMEM;
- ret = of_set_property(node, "status", disabled,
- strlen(disabled) + 1, 1);
+ ret = of_property_write_string(node, "status", "disabled");
if (ret < 0)
return ret;
- ret = of_set_property(node, "compatible", compat, strlen(compat) + 1, 1);
+ ret = of_property_write_string(node, "compatible", "simple-framebuffer");
if (ret)
return ret;
@@ -130,14 +126,14 @@ static int simplefb_create_node(struct device_node *root,
if (ret < 0)
return ret;
- ret = of_set_property(node, "format", format, strlen(format) + 1, 1);
+ ret = of_property_write_string(node, "format", format);
if (ret < 0)
return ret;
of_add_reserve_entry((u32)fbi->screen_base,
(u32)fbi->screen_base + fbi->screen_size);
- return of_set_property(node, "status", okay, strlen(okay) + 1, 1);
+ return of_property_write_string(node, "status", "okay");
}
static int simplefb_of_fixup(struct device_node *root, void *ctx)