summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2022-08-18 07:19:46 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2022-09-01 10:40:49 +0200
commitdc5f9e74316aac7eac45dbe88060cc1a7ea8d834 (patch)
treece90ec555d9d4c7a5762f04cf6ba00897a41ee50 /drivers
parent72017e24f20eee7558fd0615069a2ea382ccc9f9 (diff)
downloadbarebox-dc5f9e74316aac7eac45dbe88060cc1a7ea8d834.tar.gz
barebox-dc5f9e74316aac7eac45dbe88060cc1a7ea8d834.tar.xz
driver: add feature controller framework
Many SoCs feature hardware that controls or reports access restrictions to specific devices, e.g. a TrustZone firewall controller can limit which devices are accessible to the non-secure world and a fusebank can report that some peripherals are gated and unusable. A feature controller is an abstraction that covers both cases. Nodes that are dependent on a feature (e.g. exception level or SoC type) get a barebox,feature-gates property that references a feature controller with a feature index. The feature controller registers a callback with the framework that checks whether a device is accessible. Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Link: https://lore.barebox.org/20220818051955.2088238-2-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/Kconfig3
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/featctrl.c120
3 files changed, 124 insertions, 0 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5bc70aa1e5..eebb60ce91 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -2,3 +2,6 @@
config PM_GENERIC_DOMAINS
bool
+
+config FEATURE_CONTROLLER
+ bool "Feature controller support" if COMPILE_TEST
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 59645c6f53..e8e354cdaa 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -6,3 +6,4 @@ obj-y += resource.o
obj-y += regmap/
obj-$(CONFIG_PM_GENERIC_DOMAINS) += power.o
+obj-$(CONFIG_FEATURE_CONTROLLER) += featctrl.o
diff --git a/drivers/base/featctrl.c b/drivers/base/featctrl.c
new file mode 100644
index 0000000000..a5d06323c2
--- /dev/null
+++ b/drivers/base/featctrl.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2022 Ahmad Fatoum, Pengutronix
+
+#define pr_fmt(fmt) "featctrl: " fmt
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <of.h>
+
+#include <featctrl.h>
+
+/* List of registered feature controllers */
+static LIST_HEAD(of_feature_controllers);
+
+/**
+ * feature_controller_register() - Register a feature controller
+ * @feat: Pointer to feature controller
+ */
+int feature_controller_register(struct feature_controller *feat)
+{
+ struct device_node *np = dev_of_node(feat->dev);
+
+ if (!np)
+ return -EINVAL;
+
+ list_add(&feat->list, &of_feature_controllers);
+ dev_dbg(feat->dev, "Registering feature controller\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(feature_controller_register);
+
+/**
+ * featctrl_get_from_provider() - Look-up feature gate
+ * @spec: OF phandle args to use for look-up
+ * @gateid: ID of feature controller gate populated on successful lookup
+ *
+ * Looks for a feature controller under the node specified by @spec.
+ *
+ * Returns a valid pointer to struct feature_controller on success or ERR_PTR()
+ * on failure.
+ */
+static struct feature_controller *featctrl_get_from_provider(struct of_phandle_args *spec,
+ unsigned *gateid)
+{
+ struct feature_controller *featctrl;
+ int ret;
+
+ if (!spec)
+ return ERR_PTR(-EINVAL);
+
+ ret = of_device_ensure_probed(spec->np);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ /* Check if we have such a controller in our array */
+ list_for_each_entry(featctrl, &of_feature_controllers, list) {
+ if (dev_of_node(featctrl->dev) == spec->np) {
+ *gateid = spec->args[0];
+ return featctrl;
+ }
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+/**
+ * of_feature_controller_check - Check whether a feature controller gates the device
+ * @np: Device node to check
+ *
+ * Parse device's OF node to find a feature controller specifier. If such is
+ * found, checks it to determine whether device is gated.
+ *
+ * Returns FEATCTRL_GATED if a specified feature controller gates the device
+ * and FEATCTRL_OKAY if none do. On error a negative error code is returned.
+ */
+int of_feature_controller_check(struct device_node *np)
+{
+ struct of_phandle_args featctrl_args;
+ struct feature_controller *featctrl;
+ int ret, err = 0, i, ngates;
+
+ ngates = of_count_phandle_with_args(np, "barebox,feature-gates",
+ "#feature-cells");
+ if (ngates <= 0)
+ return FEATCTRL_OKAY;
+
+ for (i = 0; i < ngates; i++) {
+ unsigned gateid = 0;
+
+ ret = of_parse_phandle_with_args(np, "barebox,feature-gates",
+ "#feature-cells", i, &featctrl_args);
+ if (ret < 0)
+ return ret;
+
+ featctrl = featctrl_get_from_provider(&featctrl_args, &gateid);
+ if (IS_ERR(featctrl)) {
+ ret = PTR_ERR(featctrl);
+ pr_debug("%s() failed to find feature controller: %pe\n",
+ __func__, ERR_PTR(ret));
+ /*
+ * Assume that missing featctrls are unresolved
+ * dependency are report them as deferred
+ */
+ return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
+ }
+
+ ret = featctrl->check(featctrl, gateid);
+
+ dev_dbg(featctrl->dev, "checking %s: %d\n", np->full_name, ret);
+
+ if (ret == FEATCTRL_OKAY)
+ return FEATCTRL_OKAY;
+ if (ret != FEATCTRL_GATED)
+ err = ret;
+ }
+
+ return err ?: FEATCTRL_GATED;
+}
+EXPORT_SYMBOL_GPL(of_feature_controller_check);