[PATCH 8/9] Add configurability via devicetree
Jean-Christophe PLAGNIOL-VILLARD
plagnioj at jcrosoft.com
Wed Jul 10 09:17:03 EDT 2013
On Jul 10, 2013, at 6:52 PM, Sascha Hauer <s.hauer at pengutronix.de> wrote:
> This adds the possibility to configure the place for the environment
> from the devicetree and to partition devices from the devicetree.
>
> Configuration has the general form of devices with a regular compatible
> property. This allows to later add additional drivers or drivers with
> different behaviour (for example to add support for redundant environment).
>
> The configuration is all in the /chosen/barebox/ hierarchy of the
> devicetree. This separates the configuration from the hardware
> description. Also it makes it possible to store the configuration
> in a completely separate devicetree (or devicetree overlay). For
> the same reason all configuration is done using nodepathes rather
> than phandles.
>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
> Documentation/devicetree/bindings/barebox.txt | 10 ++
> .../bindings/barebox/barebox,environment.txt | 24 +++
> .../bindings/barebox/barebox,partition.txt | 42 +++++
> drivers/of/Kconfig | 9 +
> drivers/of/Makefile | 1 +
> drivers/of/barebox.c | 191 +++++++++++++++++++++
> drivers/of/of_path.c | 155 +++++++++++++++++
> fs/devfs-core.c | 2 +
> include/driver.h | 5 +
> include/of.h | 11 ++
> 10 files changed, 450 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/barebox.txt
> create mode 100644 Documentation/devicetree/bindings/barebox/barebox,environment.txt
> create mode 100644 Documentation/devicetree/bindings/barebox/barebox,partition.txt
> create mode 100644 drivers/of/barebox.c
> create mode 100644 drivers/of/of_path.c
>
> diff --git a/Documentation/devicetree/bindings/barebox.txt b/Documentation/devicetree/bindings/barebox.txt
> new file mode 100644
> index 0000000..906c4bc
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/barebox.txt
> @@ -0,0 +1,10 @@
> +barebox specific devicetree bindings
> +====================================
> +
> +barebox uses some barebox specific devicetree bindings. All of these
> +are under the /chosen/barebox/ hierarchy in the devicetree.
> +
> +The bindings have the form of a device with regular 'compatible' properties.
> +drivers matching these devices do not handle physical devices but instead
> +influence / configure certain behaviours of barebox like the place where to
> +find the persistent environment or the partitioning of devices.
> diff --git a/Documentation/devicetree/bindings/barebox/barebox,environment.txt b/Documentation/devicetree/bindings/barebox/barebox,environment.txt
> new file mode 100644
> index 0000000..48fd376
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/barebox/barebox,environment.txt
> @@ -0,0 +1,24 @@
> +barebox environment
> +
> +This driver provides an environment for barebox from the devicetree.
> +
> +Required properties:
> +- compatible: should be "barebox,environment"
> +- device-path: path to the environment
> +
> +The device-path is a multistring property. The first string should be a
> +nodepath to the node containing the physical device of the environment.
> +The subsequent strings are of the form <type>:<options> to further describe
> +the path to the environment. Supported values for <type>:
> +
> +partname:<partname> This describes a partition on a device. <partname> can
> + be the label for mtd partitions, the number for DOS
> + partitions (beginning with 0) or the name for GPT
> + partitions
> +
> +Example:
> +
> +environment at 0 {
> + compatible = "barebox,environment";
> + device-path = &flash, "partname:barebox-environment";
> +};
> diff --git a/Documentation/devicetree/bindings/barebox/barebox,partition.txt b/Documentation/devicetree/bindings/barebox/barebox,partition.txt
> new file mode 100644
> index 0000000..f38e76d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/barebox/barebox,partition.txt
> @@ -0,0 +1,42 @@
> +partition provider
> +
> +Driver to provide a partitioning for mtd devices. barebox provides a
> +separate driver for this instead of positioning the partitions under
> +the devicenode which actually provides the partitions. The reason for
> +this is that the devicetree contains the hardware description whereas
> +the partitioning of a device is not hardware specific. Having a separate
> +driver makes it possible to separate the hardware devicetree from the
> +configuration.
> +
> +Required properties:
> +
> +- compatible: should be "barebox,partition"
> +- device-path: should contain a nodepath to the physical device for which
> + this device provides a partitioning
> +- #address-cells, #size-cells: number of cells for size/addresses in the
> + partitions
> +
> +Partition properties:
> +
> +- reg: The partition's offset and size
> +- label: The label/name for this partition
> +- read-only: if present, the partition is read-only
> +
> +Example:
> +
> +nor-partitions {
> + compatible = "barebox,partition";
> + device-path = &flash;
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + partition at 0 {
> + label = "barebox";
> + reg = <0x0 0x80000>;
> + };
> +
> + partition at 1 {
> + label = "barebox-environment";
> + reg = <0x80000 0x80000>;
> + };
> +};
This is duplicate with the mtd partition, isn't?
Best Regards,
J.
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index 03ae599..ab5eac8 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -18,3 +18,12 @@ config OFDEVICE
> config OF_NET
> depends on NET
> def_bool y
> +
> +config OF_BAREBOX_DRIVERS
> + depends on OFDEVICE
> + bool "Enable barebox specific devicetree configuration drivers"
> + help
> + barebox supports being configured from devicetree. This enables
> + support for this feature. This currently allows to configure the
> + environment path from devicetree and to partition devices. See
> + Documentation/devicetree/bindings/barebox/ for more information.
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index e7d0733..97fea9d 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -3,3 +3,4 @@ obj-$(CONFIG_OFTREE_MEM_GENERIC) += mem_generic.o
> obj-$(CONFIG_GPIOLIB) += of_gpio.o
> obj-y += partition.o
> obj-y += of_net.o
> +obj-$(CONFIG_OF_BAREBOX_DRIVERS) += barebox.o of_path.o
> diff --git a/drivers/of/barebox.c b/drivers/of/barebox.c
> new file mode 100644
> index 0000000..4d178a8
> --- /dev/null
> +++ b/drivers/of/barebox.c
> @@ -0,0 +1,191 @@
> +/*
> + * barebox.c
> + *
> + * Copyright (c) 2013 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <io.h>
> +#include <of.h>
> +#include <malloc.h>
> +#include <partition.h>
> +#include <envfs.h>
> +
> +struct of_partition {
> + struct list_head list;
> + char *nodepath;
> + struct device_d *dev;
> +};
> +
> +static LIST_HEAD(of_partition_list);
> +
> +static struct device_node *cdev_find_node(struct cdev *cdev)
> +{
> + struct device_d *dev = cdev->dev;
> +
> + while (dev) {
> + if (dev->device_node)
> + return dev->device_node;
> +
> + dev = dev->parent;
> + }
> +
> + return NULL;
> +}
> +
> +void of_cdev_register(struct cdev *cdev)
> +{
> + struct device_node *np, *child;
> + struct of_partition *op;
> +
> + if (cdev->flags & DEVFS_IS_PARTITION)
> + return;
> +
> + if (cdev->partname)
> + return;
> +
> + np = cdev_find_node(cdev);
> + if (!np)
> + return;
> +
> + list_for_each_entry(op, &of_partition_list, list)
> + if (!strcmp(np->full_name, op->nodepath))
> + goto found;
> +
> + return;
> +
> +found:
> + for_each_child_of_node(op->dev->device_node, child) {
> + dev_dbg(op->dev, "adding partition %s to %s\n", child->name,
> + cdev->name);
> + of_parse_partition(cdev, child);
> + }
> +
> + list_del(&op->list);
> + free(op);
> +}
> +
> +struct device_d *of_find_device_by_node_path(const char *path)
> +{
> + struct device_d *dev;
> +
> + for_each_device(dev) {
> + if (!dev->device_node)
> + continue;
> + if (!strcmp(path, dev->device_node->full_name))
> + return dev;
> + }
> +
> + return NULL;
> +}
> +
> +static int partition_probe(struct device_d *dev)
> +{
> + const char *path;
> + struct device_node *node = dev->device_node;
> + int len;
> + struct of_partition *op;
> + struct cdev *cdev;
> +
> + path = of_get_property(node, "device-path", &len);
> + if (!path) {
> + dev_err(dev, "cannot find 'device-path' property\n");
> + return -EINVAL;
> + }
> +
> + node = of_find_node_by_path(path);
> + if (!node) {
> + dev_err(dev, "cannot find node with path '%s'\n", path);
> + return -ENODEV;
> + }
> +
> + op = xzalloc(sizeof(*op));
> + op->nodepath = xstrdup(path);
> + op->dev = dev;
> +
> + list_add_tail(&op->list, &of_partition_list);
> +
> + cdev_for_each(cdev)
> + of_cdev_register(cdev);
> +
> + return 0;
> +}
> +
> +static struct of_device_id partition_dt_ids[] = {
> + {
> + .compatible = "barebox,partition",
> + }, {
> + /* sentinel */
> + }
> +};
> +
> +static struct driver_d partition_driver = {
> + .name = "barebox-partition",
> + .probe = partition_probe,
> + .of_compatible = partition_dt_ids,
> +};
> +
> +static int environment_probe(struct device_d *dev)
> +{
> + char *path;
> + int ret;
> +
> + ret = of_find_path(dev->device_node, "device-path", &path);
> + if (ret)
> + return ret;
> +
> + dev_info(dev, "setting default environment path to %s\n", path);
> +
> + default_environment_path = path;
> +
> + return 0;
> +}
> +
> +static struct of_device_id environment_dt_ids[] = {
> + {
> + .compatible = "barebox,environment",
> + }, {
> + /* sentinel */
> + }
> +};
> +
> +static struct driver_d environment_driver = {
> + .name = "barebox-environment",
> + .probe = environment_probe,
> + .of_compatible = environment_dt_ids,
> +};
> +
> +static int barebox_of_driver_init(void)
> +{
> + struct device_node *node;
> +
> + node = of_get_root_node();
> + if (!node)
> + return 0;
> +
> + node = of_find_node_by_path("/chosen/barebox");
> + if (!node)
> + return 0;
> +
> + of_platform_populate(node, of_default_bus_match_table, NULL);
> +
> + platform_driver_register(&partition_driver);
> + platform_driver_register(&environment_driver);
> +
> + return 0;
> +}
> +late_initcall(barebox_of_driver_init);
> diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c
> new file mode 100644
> index 0000000..ab8618e
> --- /dev/null
> +++ b/drivers/of/of_path.c
> @@ -0,0 +1,155 @@
> +/*
> + * of_path.c
> + *
> + * Copyright (c) 2013 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <common.h>
> +#include <malloc.h>
> +#include <of.h>
> +
> +struct of_path {
> + struct cdev *cdev;
> + struct device_d *dev;
> +};
> +
> +struct of_path_type {
> + const char *name;
> + int (*parse)(struct of_path *op, const char *str);
> +};
> +
> +/**
> + * of_path_type_partname - find a partition based on physical device and
> + * partition name
> + * @op: of_path context
> + * @name: the partition name to find
> + */
> +static int of_path_type_partname(struct of_path *op, const char *name)
> +{
> + if (!op->dev)
> + return -EINVAL;
> +
> + op->cdev = device_find_partition(op->dev, name);
> + if (op->cdev) {
> + pr_debug("%s: found part '%s'\n", __func__, name);
> + return 0;
> + } else {
> + pr_debug("%s: cannot find part '%s'\n", __func__, name);
> + return -ENODEV;
> + }
> +}
> +
> +static struct of_path_type of_path_types[] = {
> + {
> + .name = "partname",
> + .parse = of_path_type_partname,
> + },
> +};
> +
> +static int of_path_parse_one(struct of_path *op, const char *str)
> +{
> + int i, ret;
> + char *name, *desc;
> +
> + pr_debug("parsing: %s\n", str);
> +
> + name = xstrdup(str);
> + desc = strchr(name, ':');
> + if (!desc) {
> + free(name);
> + return -EINVAL;
> + }
> +
> + *desc = 0;
> + desc++;
> +
> + for (i = 0; i < ARRAY_SIZE(of_path_types); i++) {
> + if (!strcmp(of_path_types[i].name, name)) {
> + ret = of_path_types[i].parse(op, desc);
> + goto out;
> + }
> + }
> +
> + ret = -EINVAL;
> +out:
> + free(name);
> +
> + return ret;
> +}
> +
> +/**
> + * of_find_path - translate a path description in the devicetree to a barebox
> + * path
> + *
> + * @node: the node containing the property with the path description
> + * @propname: the property name of the path description
> + * @outpath: if this function returns 0 outpath will contain the path belonging
> + * to the input path description. Must be freed with free().
> + *
> + * pathes in the devicetree have the form of a multistring property. The first
> + * string contains the full path to the physical device containing the path.
> + * The remaining strings have the form "<type>:<options>". Currently supported
> + * for <type> are:
> + *
> + * partname:<partname> - find a partition by its partition name. For mtd
> + * partitions this is the label. For DOS partitions
> + * this is the number beginning with 0.
> + *
> + * examples:
> + *
> + * device-path = &mmc0, "partname:0";
> + * device-path = &norflash, "partname:barebox-environment";
> + */
> +int of_find_path(struct device_node *node, const char *propname, char **outpath)
> +{
> + struct of_path op = {};
> + struct device_node *rnode;
> + const char *path, *str;
> + int i, len, ret;
> +
> + path = of_get_property(node, propname, &len);
> + if (!path)
> + return -EINVAL;
> +
> + rnode = of_find_node_by_path(path);
> + if (!rnode)
> + return -ENODEV;
> +
> + op.dev = of_find_device_by_node_path(rnode->full_name);
> + if (!op.dev)
> + return -ENODEV;
> +
> + device_detect(op.dev);
> +
> + i = 1;
> +
> + while (1) {
> + ret = of_property_read_string_index(node, propname, i++, &str);
> + if (ret)
> + break;
> +
> + ret = of_path_parse_one(&op, str);
> + if (ret)
> + return ret;
> + }
> +
> + if (!op.cdev)
> + return -ENOENT;
> +
> + *outpath = asprintf("/dev/%s", op.cdev->name);
> +
> + return 0;
> +}
> diff --git a/fs/devfs-core.c b/fs/devfs-core.c
> index a92d434..b41ae53 100644
> --- a/fs/devfs-core.c
> +++ b/fs/devfs-core.c
> @@ -244,6 +244,8 @@ int devfs_create(struct cdev *new)
> if (new->dev)
> list_add_tail(&new->devices_list, &new->dev->cdevs);
>
> + of_cdev_register(new);
> +
> return 0;
> }
>
> diff --git a/include/driver.h b/include/driver.h
> index f95c93c..9abd41c 100644
> --- a/include/driver.h
> +++ b/include/driver.h
> @@ -455,6 +455,11 @@ struct cdev {
> struct mtd_info *mtd;
> };
>
> +extern struct list_head cdev_list;
> +
> +#define cdev_for_each(cdev) \
> + list_for_each_entry(cdev, &cdev_list, list)
> +
> int devfs_create(struct cdev *);
> int devfs_remove(struct cdev *);
> int cdev_find_free_index(const char *);
> diff --git a/include/of.h b/include/of.h
> index 710383c..e977e23 100644
> --- a/include/of.h
> +++ b/include/of.h
> @@ -229,6 +229,8 @@ void *of_flatten_dtb(struct device_node *node);
> int of_add_memory(struct device_node *node, bool dump);
> void of_add_memory_bank(struct device_node *node, bool dump, int r,
> u64 base, u64 size);
> +struct device_d *of_find_device_by_node_path(const char *path);
> +int of_find_path(struct device_node *node, const char *propname, char **outpath);
> #else
> static inline int of_parse_partitions(struct cdev *cdev,
> struct device_node *node)
> @@ -560,6 +562,7 @@ static inline struct device_d *of_find_device_by_node(struct device_node *np)
> {
> return NULL;
> }
> +
> #endif
>
> #define for_each_node_by_name(dn, name) \
> @@ -682,4 +685,12 @@ static inline int of_property_write_u64(struct device_node *np,
>
> extern const struct of_device_id of_default_bus_match_table[];
>
> +#ifdef CONFIG_OF_BAREBOX_DRIVERS
> +void of_cdev_register(struct cdev *cdev);
> +#else
> +static inline void of_cdev_register(struct cdev *cdev)
> +{
> +}
> +#endif
> +
> #endif /* __OF_H */
> --
> 1.8.3.2
>
>
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
More information about the barebox
mailing list