diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2017-04-07 09:59:38 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2017-04-07 09:59:38 +0200 |
commit | 53adf0648c330357103e4a7103c3d7f05c0c4bcf (patch) | |
tree | 78d038c2761e3c0694eac9bc3386436a8d6c3b1c /drivers | |
parent | 8b30a8a77612b728bf664a9e9827af7ebdbcd3ba (diff) | |
parent | 12960a57841d5e6ea04fd523611e15a9a4170c89 (diff) | |
download | barebox-53adf0648c330357103e4a7103c3d7f05c0c4bcf.tar.gz barebox-53adf0648c330357103e4a7103c3d7f05c0c4bcf.tar.xz |
Merge branch 'for-next/ofpart'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/driver.c | 2 | ||||
-rw-r--r-- | drivers/eeprom/at24.c | 1 | ||||
-rw-r--r-- | drivers/eeprom/at25.c | 2 | ||||
-rw-r--r-- | drivers/mci/mci-core.c | 4 | ||||
-rw-r--r-- | drivers/mtd/core.c | 65 | ||||
-rw-r--r-- | drivers/mtd/partition.c | 2 | ||||
-rw-r--r-- | drivers/of/base.c | 24 | ||||
-rw-r--r-- | drivers/of/of_path.c | 107 | ||||
-rw-r--r-- | drivers/of/partition.c | 176 | ||||
-rw-r--r-- | drivers/video/simplefb.c | 12 |
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) |