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@xxxxxxxxxxxxxx> --- drivers/base/Kconfig | 3 + drivers/base/Makefile | 1 + drivers/base/featctrl.c | 120 ++++++++++++++++++++++++++++++++++++++++ include/featctrl.h | 29 ++++++++++ 4 files changed, 153 insertions(+) create mode 100644 drivers/base/featctrl.c create mode 100644 include/featctrl.h diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 5bc70aa1e525..eebb60ce9193 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 59645c6f5359..e8e354cdaabc 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 000000000000..a5d06323c221 --- /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); diff --git a/include/featctrl.h b/include/featctrl.h new file mode 100644 index 000000000000..fb9e4156bdc2 --- /dev/null +++ b/include/featctrl.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __FEATCTRL_H_ +#define __FEATCTRL_H_ + +#include <linux/list.h> + +struct feature_controller; +struct device_node; + +struct feature_controller { + struct device_d *dev; + int (*check)(struct feature_controller *, int idx); + struct list_head list; +}; + +enum { FEATCTRL_GATED = 0, FEATCTRL_OKAY = 1 }; + +int feature_controller_register(struct feature_controller *); + +#ifdef CONFIG_FEATURE_CONTROLLER +int of_feature_controller_check(struct device_node *np); +#else +static inline int of_feature_controller_check(struct device_node *np) +{ + return FEATCTRL_OKAY; +} +#endif + +#endif /* PINCTRL_H */ -- 2.30.2