[PATCH] of: Overlay manager

From: dimitrysh
Date: Thu Sep 08 2016 - 17:02:08 EST


From e14eb45fa5a93c1bff8a6dfe7b6756e4ad72c579 Mon Sep 17 00:00:00 2001
From: Dmitry Shmidt <dimitrysh@xxxxxxxxxx>
Date: Wed, 24 Aug 2016 13:25:52 -0700
Subject: [PATCH] of: Overlay manager

Overlay manager processes DT entries on demand.
It is chosen by CONFIG_OF_OVERLAY_MGR option.
These entries can be chosen from kernel command line:
overlay_mgr.overlay_dt_entry=hardware_cfg_0
DT contains main overlay_mng entry with all possible
HW config setups. And then kernel command line option
will allow to choose between them.

Kernel DT entry:
overlay_mgr {
compatible = "linux,overlay_manager";
hardware_cfg_0 {
overlay@0 {
fragment@0 {
__overlay__ {
};
};
};
overlay@1 {
fragment@0 {
__overlay__ {
};
};
};
};
};

Signed-off-by: Dmitry Shmidt <dimitrysh@xxxxxxxxxx>
Tested-by: John Stultz <john.stultz@xxxxxxxxxx>
Acked-by: John Stultz <john.stultz@xxxxxxxxxx>
---
.../devicetree/bindings/of/overlay_mgr.txt | 32 ++++++++
drivers/of/Kconfig | 10 +++
drivers/of/Makefile | 1 +
drivers/of/overlay_mgr.c | 90 ++++++++++++++++++++++
4 files changed, 133 insertions(+)
create mode 100644 Documentation/devicetree/bindings/of/overlay_mgr.txt
create mode 100644 drivers/of/overlay_mgr.c

diff --git a/Documentation/devicetree/bindings/of/overlay_mgr.txt b/Documentation/devicetree/bindings/of/overlay_mgr.txt
new file mode 100644
index 0000000..5f3ce4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/of/overlay_mgr.txt
@@ -0,0 +1,32 @@
+overlay_mgr
+
+Required properties:
+- compatible: "linux,overlay_manager";
+
+Optional properties:
+- starts from the word "hardware": hardware_cfg_0
+
+These properties can be chosen from kernel command line:
+overlay_mgr.overlay_dt_entry=hardware_cfg_0
+DT contains main overlay_mng entry with all possible
+HW config setups. And then kernel command line option
+will allow to choose between them.
+
+Example:
+ overlay_mgr {
+ compatible = "linux,overlay_manager";
+ hardware_cfg_0 {
+ overlay@0 {
+ fragment@0 {
+ __overlay__ {
+ };
+ };
+ };
+ overlay@1 {
+ fragment@0 {
+ __overlay__ {
+ };
+ };
+ };
+ };
+ };
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index e2a4841..e3eb06d 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -112,4 +112,14 @@ config OF_OVERLAY
While this option is selected automatically when needed, you can
enable it manually to improve device tree unit test coverage.

+config OF_OVERLAY_MGR
+ bool "Enable Overlay manager"
+ default n
+ depends on OF_OVERLAY
+ help
+ Enables Overlay manager - it accepts DT entry from command line
+ overlay_mgr.overlay_dt_entry=<name> and applies all overlays in
+ it to current DT. It is also possible to apply predefined DT
+ entry on the fly by writing it to 'current_overlay' sysfs entry.
+
endif # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 156c072..3bddd19 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
+obj-$(CONFIG_OF_OVERLAY_MGR) += overlay_mgr.o

obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/overlay_mgr.c b/drivers/of/overlay_mgr.c
new file mode 100644
index 0000000..1fdeb0a
--- /dev/null
+++ b/drivers/of/overlay_mgr.c
@@ -0,0 +1,90 @@
+/*
+ * Overlay manager that allows to apply list of overlays from DT entry
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+static char *of_overlay_dt_entry;
+module_param_named(overlay_dt_entry, of_overlay_dt_entry, charp, 0644);
+
+static int of_overlay_mgr_apply_overlay(struct device_node *onp)
+{
+ int ret;
+
+ ret = of_overlay_create(onp);
+ if (ret < 0) {
+ pr_err("overlay_mgr: fail to create overlay: %d\n", ret);
+ of_node_put(onp);
+ return ret;
+ }
+ pr_info("overlay_mgr: %s overlay applied\n", onp->name);
+ return 0;
+}
+
+static int of_overlay_mgr_apply_dt(struct device *dev, char *dt_entry)
+{
+ struct device_node *enp = dev->of_node;
+ struct device_node *next;
+ struct device_node *prev = NULL;
+
+ if (!enp) {
+ pr_err("overlay_mgr: no dt entry\n");
+ return -ENODEV;
+ }
+
+ enp = of_get_child_by_name(enp, dt_entry);
+ if (!enp) {
+ pr_err("overlay_mgr: dt entry %s not found\n", dt_entry);
+ return -ENODEV;
+ }
+ pr_info("overlay_mgr: apply %s dt entry\n", enp->name);
+ while ((next = of_get_next_available_child(enp, prev)) != NULL) {
+ if (strncmp(next->name, "overlay", 7) == 0)
+ of_overlay_mgr_apply_overlay(next);
+ prev = next;
+ }
+ return 0;
+}
+
+static int of_overlay_mgr_probe(struct platform_device *pdev)
+{
+ if (!of_overlay_dt_entry)
+ return 0;
+ of_overlay_mgr_apply_dt(&pdev->dev, of_overlay_dt_entry);
+ return 0;
+}
+
+static const struct of_device_id of_overlay_mgr_match[] = {
+ { .compatible = "linux,overlay_manager", },
+ {}
+};
+
+static struct platform_driver of_overlay_mgr_driver = {
+ .probe = of_overlay_mgr_probe,
+ .driver = {
+ .name = "overlay_manager",
+ .of_match_table = of_match_ptr(of_overlay_mgr_match),
+ },
+};
+
+static int __init of_overlay_mgr_init(void)
+{
+ return platform_driver_register(&of_overlay_mgr_driver);
+}
+
+postcore_initcall(of_overlay_mgr_init);
--
2.8.0.rc3.226.g39d4020