Even if a platform doesn't use a device tree during its boot process it can be useful to enable CONFIG_OF and get an empty device tree. Then, devices can use device tree overlays to populate this default tree. Signed-off-by: Franck Jullien <franck.jullien@xxxxxxxxxxxxxxxxxxx> --- drivers/of/Kconfig | 9 +++++++++ drivers/of/Makefile | 3 +++ drivers/of/base.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/of/default.dts | 4 ++++ drivers/of/unittest.c | 33 +++++---------------------------- include/linux/of.h | 2 ++ 6 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 drivers/of/default.dts diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index b3bec3a..ed60af7 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -11,6 +11,15 @@ menuconfig OF if OF +config OF_DEFAULT_DTB + bool "Load default empty Device Tree" + depends on OF_IRQ + select OF_EARLY_FLATTREE + select OF_RESOLVE + help + This option builds in an empty device tree. + If unsure, say N here, but this option is safe to enable. + config OF_UNITTEST bool "Device Tree runtime unit tests" depends on OF_IRQ diff --git a/drivers/of/Makefile b/drivers/of/Makefile index d7efd9d..e611dc0 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -15,4 +15,7 @@ obj-$(CONFIG_OF_RESOLVE) += resolver.o obj-$(CONFIG_OF_OVERLAY) += overlay.o obj-$(CONFIG_OF_NUMA) += of_numa.o +obj-y += default.dtb.o +targets += default.dtb default.dtb.S + obj-$(CONFIG_OF_UNITTEST) += unittest-data/ diff --git a/drivers/of/base.c b/drivers/of/base.c index ebf84e3..43ebf5f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> +#include <linux/of_fdt.h> #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/string.h> @@ -189,10 +190,55 @@ int __of_attach_node_sysfs(struct device_node *np) return 0; } +int of_get_builtin_dtb(uint8_t *dtb_begin, uint8_t *dtb_end, struct device_node **dtb_node) +{ + const int size = dtb_end - dtb_begin; + void *dtb; + struct device_node *node; + int rc; + + if (!size) { + pr_warn("%s: No DTB to attach\n", __func__); + return -ENODATA; + } + + dtb = kmemdup(dtb_begin, size, GFP_KERNEL); + + if (!dtb_begin) { + pr_warn("%s: Failed to allocate memory for built-in dtb\n", __func__); + return -ENOMEM; + } + + of_fdt_unflatten_tree(dtb, NULL, &node); + if (!node) { + pr_warn("%s: No tree to attach\n", __func__); + return -ENODATA; + } + + of_node_set_flag(node, OF_DETACHED); + rc = of_resolve_phandles(node); + if (rc) { + pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc); + return -EINVAL; + } + + *dtb_node = node; + + return 0; +} +EXPORT_SYMBOL_GPL(of_get_builtin_dtb); + void __init of_core_init(void) { struct device_node *np; + /* + * __dtb_default_begin[] and __dtb_default_end[] are magically + * created by cmd_dt_S_dtb in scripts/Makefile.lib + */ + extern uint8_t __dtb_default_begin[]; + extern uint8_t __dtb_default_end[]; + /* Create the kset, and register existing nodes */ mutex_lock(&of_mutex); of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); @@ -201,6 +247,10 @@ void __init of_core_init(void) pr_err("devicetree: failed to register existing nodes\n"); return; } + + if (!of_root && IS_ENABLED(CONFIG_OF_DEFAULT_DTB)) + of_get_builtin_dtb(__dtb_default_begin, __dtb_default_end, &of_root); + for_each_of_allnodes(np) __of_attach_node_sysfs(np); mutex_unlock(&of_mutex); diff --git a/drivers/of/default.dts b/drivers/of/default.dts new file mode 100644 index 0000000..fc387fb --- /dev/null +++ b/drivers/of/default.dts @@ -0,0 +1,4 @@ +/dts-v1/; +/ { + +}; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index f34ed93..2400e78 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -895,42 +895,19 @@ static int attach_node_and_children(struct device_node *np) */ static int __init unittest_data_add(void) { - void *unittest_data; struct device_node *unittest_data_node, *np; + int rc; + /* * __dtb_testcases_begin[] and __dtb_testcases_end[] are magically * created by cmd_dt_S_dtb in scripts/Makefile.lib */ extern uint8_t __dtb_testcases_begin[]; extern uint8_t __dtb_testcases_end[]; - const int size = __dtb_testcases_end - __dtb_testcases_begin; - int rc; - - if (!size) { - pr_warn("%s: No testcase data to attach; not running tests\n", - __func__); - return -ENODATA; - } - - /* creating copy */ - unittest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL); - if (!unittest_data) { - pr_warn("%s: Failed to allocate memory for unittest_data; " - "not running tests\n", __func__); - return -ENOMEM; - } - of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node); - if (!unittest_data_node) { - pr_warn("%s: No tree to attach; not running tests\n", __func__); - return -ENODATA; - } - of_node_set_flag(unittest_data_node, OF_DETACHED); - rc = of_resolve_phandles(unittest_data_node); - if (rc) { - pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc); - return -EINVAL; - } + rc = of_get_builtin_dtb(__dtb_testcases_begin, __dtb_testcases_end, &unittest_data_node); + if (rc) + return rc; if (!of_root) { of_root = unittest_data_node; diff --git a/include/linux/of.h b/include/linux/of.h index 74eb28c..5cab2b5 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -406,6 +406,8 @@ const char *of_prop_next_string(struct property *prop, const char *cur); bool of_console_check(struct device_node *dn, char *name, int index); +int of_get_builtin_dtb(uint8_t *dtb_begin, uint8_t *dtb_end, struct device_node **dtb_node); + #else /* CONFIG_OF */ static inline void of_core_init(void) -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html