* [PATCH V6 08/13] boot_constraint: Manage deferrable constraints
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
It is possible that some of the resources aren't available at the time
constraints are getting set and the boot constraints core will return
-EPROBE_DEFER for them. In order to retry adding the constraints at a
later point of time (after the resource is added and before any of its
users come up), this patch proposes two things:
- Each constraint is represented by a virtual platform device, so that
it is re-probed again until the time all the dependencies aren't met.
The platform device is removed along with the constraint, with help of
the free_resources() callback.
- Enable early defer probing support by calling
driver_enable_deferred_probe(), so that the core retries probing
deferred devices every time any device is bound to a driver. This
makes sure that the constraint is set before any of the users of the
resources come up.
This is tested on ARM64 Hikey board where probe was deferred for a
device.
Tested-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/base/dd.c | 12 ++
drivers/boot_constraint/Makefile | 2 +-
drivers/boot_constraint/deferrable_dev.c | 241 +++++++++++++++++++++++++++++++
include/linux/boot_constraint.h | 27 ++++
4 files changed, 281 insertions(+), 1 deletion(-)
create mode 100644 drivers/boot_constraint/deferrable_dev.c
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index dc89f98a2487..48a9945ff206 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -227,6 +227,18 @@ void device_unblock_probing(void)
driver_deferred_probe_trigger();
}
+/**
+ * driver_enable_deferred_probe() - Enable probing of deferred devices
+ *
+ * We don't want to get in the way when the bulk of drivers are getting probed
+ * and so deferred probe is disabled in the beginning. Enable it now because we
+ * need it.
+ */
+void driver_enable_deferred_probe(void)
+{
+ driver_deferred_probe_enable = true;
+}
+
/**
* deferred_probe_initcall() - Enable probing of deferred devices
*
diff --git a/drivers/boot_constraint/Makefile b/drivers/boot_constraint/Makefile
index b7ade1a7afb5..a765094623a3 100644
--- a/drivers/boot_constraint/Makefile
+++ b/drivers/boot_constraint/Makefile
@@ -1,3 +1,3 @@
# Makefile for device boot constraints
-obj-y := clk.o core.o pm.o supply.o
+obj-y := clk.o deferrable_dev.o core.o pm.o supply.o
diff --git a/drivers/boot_constraint/deferrable_dev.c b/drivers/boot_constraint/deferrable_dev.c
new file mode 100644
index 000000000000..158c04d41e09
--- /dev/null
+++ b/drivers/boot_constraint/deferrable_dev.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "core.h"
+
+static DEFINE_IDA(pdev_index);
+
+void driver_enable_deferred_probe(void);
+
+struct boot_constraint_pdata {
+ struct device *dev;
+ struct dev_boot_constraint constraint;
+ int probe_failed;
+ int index;
+};
+
+static void boot_constraint_remove(void *data)
+{
+ struct platform_device *pdev = data;
+ struct boot_constraint_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+ ida_simple_remove(&pdev_index, pdata->index);
+ kfree(pdata->constraint.data);
+ platform_device_unregister(pdev);
+}
+
+/*
+ * A platform device is added for each and every constraint, to handle
+ * -EPROBE_DEFER properly.
+ */
+static int boot_constraint_probe(struct platform_device *pdev)
+{
+ struct boot_constraint_pdata *pdata = dev_get_platdata(&pdev->dev);
+ struct dev_boot_constraint_info info;
+ int ret;
+
+ if (WARN_ON(!pdata))
+ return -EINVAL;
+
+ info.constraint = pdata->constraint;
+ info.free_resources = boot_constraint_remove;
+ info.free_resources_data = pdev;
+
+ ret = dev_boot_constraint_add(pdata->dev, &info);
+ if (ret) {
+ if (ret == -EPROBE_DEFER)
+ driver_enable_deferred_probe();
+ else
+ pdata->probe_failed = ret;
+ }
+
+ return ret;
+}
+
+static struct platform_driver boot_constraint_driver = {
+ .driver = {
+ .name = "boot-constraints-dev",
+ },
+ .probe = boot_constraint_probe,
+};
+
+static int __init boot_constraint_init(void)
+{
+ return platform_driver_register(&boot_constraint_driver);
+}
+core_initcall(boot_constraint_init);
+
+static int boot_constraint_add_dev(struct device *dev,
+ struct dev_boot_constraint *constraint)
+{
+ struct boot_constraint_pdata pdata = {
+ .dev = dev,
+ .constraint.type = constraint->type,
+ };
+ struct platform_device *pdev;
+ struct boot_constraint_pdata *pdev_pdata;
+ int size, ret;
+
+ switch (constraint->type) {
+ case DEV_BOOT_CONSTRAINT_CLK:
+ size = sizeof(struct dev_boot_constraint_clk_info);
+ break;
+ case DEV_BOOT_CONSTRAINT_PM:
+ size = 0;
+ break;
+ case DEV_BOOT_CONSTRAINT_SUPPLY:
+ size = sizeof(struct dev_boot_constraint_supply_info);
+ break;
+ default:
+ dev_err(dev, "%s: Constraint type (%d) not supported\n",
+ __func__, constraint->type);
+ return -EINVAL;
+ }
+
+ /* Will be freed from boot_constraint_remove() */
+ pdata.constraint.data = kmemdup(constraint->data, size, GFP_KERNEL);
+ if (!pdata.constraint.data)
+ return -ENOMEM;
+
+ ret = ida_simple_get(&pdev_index, 0, 256, GFP_KERNEL);
+ if (ret < 0) {
+ dev_err(dev, "failed to allocate index (%d)\n", ret);
+ goto free;
+ }
+
+ pdata.index = ret;
+
+ pdev = platform_device_register_data(NULL, "boot-constraints-dev", ret,
+ &pdata, sizeof(pdata));
+ if (IS_ERR(pdev)) {
+ dev_err(dev, "%s: Failed to create pdev (%ld)\n", __func__,
+ PTR_ERR(pdev));
+ ret = PTR_ERR(pdev);
+ goto ida_remove;
+ }
+
+ /* Release resources if probe has failed */
+ pdev_pdata = dev_get_platdata(&pdev->dev);
+ if (pdev_pdata->probe_failed) {
+ ret = pdev_pdata->probe_failed;
+ goto remove_pdev;
+ }
+
+ return 0;
+
+remove_pdev:
+ platform_device_unregister(pdev);
+ida_remove:
+ ida_simple_remove(&pdev_index, pdata.index);
+free:
+ kfree(pdata.constraint.data);
+
+ return ret;
+}
+
+static int dev_boot_constraint_add_deferrable(struct device *dev,
+ struct dev_boot_constraint *constraints, int count)
+{
+ int ret, i;
+
+ for (i = 0; i < count; i++) {
+ ret = boot_constraint_add_dev(dev, &constraints[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* This only creates platform devices for now */
+static void add_deferrable_of_single(struct device_node *np,
+ struct dev_boot_constraint *constraints,
+ int count)
+{
+ struct device *dev;
+ int ret;
+
+ if (!of_device_is_available(np))
+ return;
+
+ ret = of_platform_bus_create(np, NULL, NULL, NULL, false);
+ if (ret)
+ return;
+
+ dev = of_find_any_device_by_node(np);
+ if (!dev) {
+ pr_err("Boot Constraints: Failed to find dev: %pOF\n", np);
+ return;
+ }
+
+ ret = dev_boot_constraint_add_deferrable(dev, constraints, count);
+ if (ret)
+ dev_err(dev, "Failed to add boot constraint (%d)\n", ret);
+}
+
+/* Not all compatible device nodes may have boot constraints */
+static bool node_has_boot_constraints(struct device_node *np,
+ struct dev_boot_constraint_of *oconst)
+{
+ int i;
+
+ if (!oconst->dev_names)
+ return true;
+
+ for (i = 0; i < oconst->dev_names_count; i++) {
+ if (!strcmp(oconst->dev_names[i], kbasename(np->full_name)))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * dev_boot_constraint_add_deferrable_of: Adds all constraints for a platform.
+ *
+ * @oconst: This is an array of 'struct dev_boot_constraint_of', where each
+ * entry of the array is used to add one or more boot constraints across one or
+ * more devices having the same compatibility in the device tree.
+ * @count: Size of the 'oconst' array.
+ *
+ * This helper routine provides an easy way to add all boot constraints for a
+ * machine or platform. Just like dev_boot_constraint_add(), this must be called
+ * before the devices (to which we want to add constraints) are probed by their
+ * drivers, otherwise the boot constraint will never get removed for those
+ * devices and may result in unwanted behavior of the hardware. The boot
+ * constraints are removed by the driver core automatically after the devices
+ * are probed (successfully or unsuccessfully).
+ *
+ * This adds the boot constraints in a deferrable way and the caller need not
+ * worry about the availability of the resources required by the constraint.
+ * This routine will return successfully and the constraint will be added by the
+ * boot constraint core as soon as the resource is available at a later point in
+ * time.
+ */
+void dev_boot_constraint_add_deferrable_of(struct dev_boot_constraint_of *oconst,
+ int count)
+{
+ struct device_node *np;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ for_each_compatible_node(np, NULL, oconst[i].compat) {
+ if (!node_has_boot_constraints(np, &oconst[i]))
+ continue;
+
+ add_deferrable_of_single(np, oconst[i].constraints,
+ oconst[i].count);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(dev_boot_constraint_add_deferrable_of);
diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h
index 12fac0d565b0..ab752e19bfd0 100644
--- a/include/linux/boot_constraint.h
+++ b/include/linux/boot_constraint.h
@@ -79,16 +79,43 @@ struct dev_boot_constraint_info {
void *free_resources_data;
};
+/**
+ * struct dev_boot_constraint_of - This is used to add one or more boot
+ * constraints across one or more devices having the same compatibility in the
+ * device tree.
+ *
+ * @compat: This must match the compatible string of the devices to which we
+ * want to apply constraints.
+ * @constraints: This points to one or more boot constraints.
+ * @count: This contains the number of boot constraints pointed by the
+ * 'constraints' field.
+ * @dev_names: This is used to limit the application of boot constraints to only
+ * a subset of devices with matching compatibility.
+ * @dev_names_count: This is the number of devices pointed by the 'dev_names'
+ * array.
+ */
+struct dev_boot_constraint_of {
+ const char *compat;
+ struct dev_boot_constraint *constraints;
+ unsigned int count;
+
+ const char * const *dev_names;
+ unsigned int dev_names_count;
+};
+
#ifdef CONFIG_DEV_BOOT_CONSTRAINT
int dev_boot_constraint_add(struct device *dev,
struct dev_boot_constraint_info *info);
void dev_boot_constraints_remove(struct device *dev);
+void dev_boot_constraint_add_deferrable_of(struct dev_boot_constraint_of *oconst,
+ int count);
#else
static inline
int dev_boot_constraint_add(struct device *dev,
struct dev_boot_constraint_info *info)
{ return 0; }
static inline void dev_boot_constraints_remove(struct device *dev) {}
+static inline void dev_boot_constraint_add_deferrable_of(struct dev_boot_constraint_of *oconst, int count) {}
#endif /* CONFIG_DEV_BOOT_CONSTRAINT */
#endif /* _LINUX_BOOT_CONSTRAINT_H */
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 07/13] boot_constraint: Add debugfs support
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
This patch adds debugfs support for boot constraints. This is how it
looks for a "vmmc-supply" constraint for the MMC device.
$ ls -R /sys/kernel/debug/boot_constraints/
/sys/kernel/debug/boot_constraints/:
f723d000.dwmmc0
/sys/kernel/debug/boot_constraints/f723d000.dwmmc0:
clk-ciu pm-domain supply-vmmc supply-vmmcaux
/sys/kernel/debug/boot_constraints/f723d000.dwmmc0/clk-ciu:
/sys/kernel/debug/boot_constraints/f723d000.dwmmc0/pm-domain:
/sys/kernel/debug/boot_constraints/f723d000.dwmmc0/supply-vmmc:
u_volt_max u_volt_min
/sys/kernel/debug/boot_constraints/f723d000.dwmmc0/supply-vmmcaux:
u_volt_max u_volt_min
Tested-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/boot_constraint/clk.c | 3 ++
drivers/boot_constraint/core.c | 59 ++++++++++++++++++++++++++++++++++++++++
drivers/boot_constraint/core.h | 6 ++++
drivers/boot_constraint/pm.c | 11 ++++++--
drivers/boot_constraint/supply.c | 9 ++++++
5 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/drivers/boot_constraint/clk.c b/drivers/boot_constraint/clk.c
index db22acff43e6..ebc871c29a83 100644
--- a/drivers/boot_constraint/clk.c
+++ b/drivers/boot_constraint/clk.c
@@ -46,6 +46,8 @@ int constraint_clk_add(struct constraint *constraint, void *data)
cclk->clk_info.name = kstrdup_const(clk_info->name, GFP_KERNEL);
constraint->private = cclk;
+ constraint_add_debugfs(constraint, clk_info->name);
+
return 0;
put_clk:
@@ -60,6 +62,7 @@ void constraint_clk_remove(struct constraint *constraint)
{
struct constraint_clk *cclk = constraint->private;
+ constraint_remove_debugfs(constraint);
kfree_const(cclk->clk_info.name);
clk_disable_unprepare(cclk->clk);
clk_put(cclk->clk);
diff --git a/drivers/boot_constraint/core.c b/drivers/boot_constraint/core.c
index b36c02aa50c5..0350c5057ee5 100644
--- a/drivers/boot_constraint/core.c
+++ b/drivers/boot_constraint/core.c
@@ -21,6 +21,63 @@
static LIST_HEAD(constraint_devices);
static DEFINE_MUTEX(constraint_devices_mutex);
+/* Debugfs */
+
+static struct dentry *rootdir;
+
+static void constraint_device_add_debugfs(struct constraint_dev *cdev)
+{
+ struct device *dev = cdev->dev;
+
+ cdev->dentry = debugfs_create_dir(dev_name(dev), rootdir);
+}
+
+static void constraint_device_remove_debugfs(struct constraint_dev *cdev)
+{
+ debugfs_remove_recursive(cdev->dentry);
+}
+
+void constraint_add_debugfs(struct constraint *constraint, const char *suffix)
+{
+ struct device *dev = constraint->cdev->dev;
+ const char *prefix;
+ char name[NAME_MAX];
+
+ switch (constraint->type) {
+ case DEV_BOOT_CONSTRAINT_CLK:
+ prefix = "clk";
+ break;
+ case DEV_BOOT_CONSTRAINT_PM:
+ prefix = "pm";
+ break;
+ case DEV_BOOT_CONSTRAINT_SUPPLY:
+ prefix = "supply";
+ break;
+ default:
+ dev_err(dev, "%s: Constraint type (%d) not supported\n",
+ __func__, constraint->type);
+ return;
+ }
+
+ snprintf(name, NAME_MAX, "%s-%s", prefix, suffix);
+
+ constraint->dentry = debugfs_create_dir(name, constraint->cdev->dentry);
+}
+
+void constraint_remove_debugfs(struct constraint *constraint)
+{
+ debugfs_remove_recursive(constraint->dentry);
+}
+
+static int __init constraint_debugfs_init(void)
+{
+ rootdir = debugfs_create_dir("boot_constraints", NULL);
+
+ return 0;
+}
+core_initcall(constraint_debugfs_init);
+
+
/* Boot constraints core */
static struct constraint_dev *constraint_device_find(struct device *dev)
@@ -48,12 +105,14 @@ static struct constraint_dev *constraint_device_allocate(struct device *dev)
INIT_LIST_HEAD(&cdev->constraints);
list_add(&cdev->node, &constraint_devices);
+ constraint_device_add_debugfs(cdev);
return cdev;
}
static void constraint_device_free(struct constraint_dev *cdev)
{
+ constraint_device_remove_debugfs(cdev);
list_del(&cdev->node);
kfree(cdev);
}
diff --git a/drivers/boot_constraint/core.h b/drivers/boot_constraint/core.h
index c5b27617b4ae..9dd481d38b99 100644
--- a/drivers/boot_constraint/core.h
+++ b/drivers/boot_constraint/core.h
@@ -7,6 +7,7 @@
#define _CORE_H
#include <linux/boot_constraint.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/list.h>
@@ -14,6 +15,7 @@ struct constraint_dev {
struct device *dev;
struct list_head node;
struct list_head constraints;
+ struct dentry *dentry;
};
struct constraint {
@@ -22,12 +24,16 @@ struct constraint {
enum dev_boot_constraint_type type;
void (*free_resources)(void *data);
void *free_resources_data;
+ struct dentry *dentry;
int (*add)(struct constraint *constraint, void *data);
void (*remove)(struct constraint *constraint);
void *private;
};
+void constraint_add_debugfs(struct constraint *constraint, const char *suffix);
+void constraint_remove_debugfs(struct constraint *constraint);
+
/* Forward declarations of constraint specific callbacks */
int constraint_clk_add(struct constraint *constraint, void *data);
void constraint_clk_remove(struct constraint *constraint);
diff --git a/drivers/boot_constraint/pm.c b/drivers/boot_constraint/pm.c
index 4950ec6b248b..584d3d46ef65 100644
--- a/drivers/boot_constraint/pm.c
+++ b/drivers/boot_constraint/pm.c
@@ -11,11 +11,18 @@
int constraint_pm_add(struct constraint *constraint, void *data)
{
struct device *dev = constraint->cdev->dev;
+ int ret;
- return dev_pm_domain_attach(dev, true);
+ ret = dev_pm_domain_attach(dev, true);
+ if (ret)
+ return ret;
+
+ constraint_add_debugfs(constraint, "domain");
+
+ return 0;
}
void constraint_pm_remove(struct constraint *constraint)
{
- /* Nothing to do for now */
+ constraint_remove_debugfs(constraint);
}
diff --git a/drivers/boot_constraint/supply.c b/drivers/boot_constraint/supply.c
index 916e5d6848d5..28fda60a0711 100644
--- a/drivers/boot_constraint/supply.c
+++ b/drivers/boot_constraint/supply.c
@@ -57,6 +57,14 @@ int constraint_supply_add(struct constraint *constraint, void *data)
csupply->supply.name = kstrdup_const(supply->name, GFP_KERNEL);
constraint->private = csupply;
+ constraint_add_debugfs(constraint, supply->name);
+
+ debugfs_create_u32("u_volt_min", 0444, constraint->dentry,
+ &csupply->supply.u_volt_min);
+
+ debugfs_create_u32("u_volt_max", 0444, constraint->dentry,
+ &csupply->supply.u_volt_max);
+
return 0;
remove_voltage:
@@ -77,6 +85,7 @@ void constraint_supply_remove(struct constraint *constraint)
struct device *dev = constraint->cdev->dev;
int ret;
+ constraint_remove_debugfs(constraint);
kfree_const(supply->name);
ret = regulator_disable(csupply->reg);
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 06/13] boot_constraint: Add support for PM constraints
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
This patch adds the PM constraint type.
The constraint is set by attaching the power domain for the device,
which will also enable the power domain. This guarantees that the power
domain doesn't get shut down while being used.
We don't need to detach the power domain to remove the constraint as the
domain is attached only once, from here or before driver probe.
Tested-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/boot_constraint/Makefile | 2 +-
drivers/boot_constraint/core.c | 4 ++++
drivers/boot_constraint/core.h | 3 +++
drivers/boot_constraint/pm.c | 21 +++++++++++++++++++++
include/linux/boot_constraint.h | 2 ++
5 files changed, 31 insertions(+), 1 deletion(-)
create mode 100644 drivers/boot_constraint/pm.c
diff --git a/drivers/boot_constraint/Makefile b/drivers/boot_constraint/Makefile
index 3424379fd1e4..b7ade1a7afb5 100644
--- a/drivers/boot_constraint/Makefile
+++ b/drivers/boot_constraint/Makefile
@@ -1,3 +1,3 @@
# Makefile for device boot constraints
-obj-y := clk.o core.o supply.o
+obj-y := clk.o core.o pm.o supply.o
diff --git a/drivers/boot_constraint/core.c b/drivers/boot_constraint/core.c
index df9e0bddbfbe..b36c02aa50c5 100644
--- a/drivers/boot_constraint/core.c
+++ b/drivers/boot_constraint/core.c
@@ -95,6 +95,10 @@ static struct constraint *constraint_allocate(struct constraint_dev *cdev,
add = constraint_clk_add;
remove = constraint_clk_remove;
break;
+ case DEV_BOOT_CONSTRAINT_PM:
+ add = constraint_pm_add;
+ remove = constraint_pm_remove;
+ break;
case DEV_BOOT_CONSTRAINT_SUPPLY:
add = constraint_supply_add;
remove = constraint_supply_remove;
diff --git a/drivers/boot_constraint/core.h b/drivers/boot_constraint/core.h
index 720bda0a0f44..c5b27617b4ae 100644
--- a/drivers/boot_constraint/core.h
+++ b/drivers/boot_constraint/core.h
@@ -32,6 +32,9 @@ struct constraint {
int constraint_clk_add(struct constraint *constraint, void *data);
void constraint_clk_remove(struct constraint *constraint);
+int constraint_pm_add(struct constraint *constraint, void *data);
+void constraint_pm_remove(struct constraint *constraint);
+
int constraint_supply_add(struct constraint *constraint, void *data);
void constraint_supply_remove(struct constraint *constraint);
diff --git a/drivers/boot_constraint/pm.c b/drivers/boot_constraint/pm.c
new file mode 100644
index 000000000000..4950ec6b248b
--- /dev/null
+++ b/drivers/boot_constraint/pm.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#include <linux/pm_domain.h>
+
+#include "core.h"
+
+int constraint_pm_add(struct constraint *constraint, void *data)
+{
+ struct device *dev = constraint->cdev->dev;
+
+ return dev_pm_domain_attach(dev, true);
+}
+
+void constraint_pm_remove(struct constraint *constraint)
+{
+ /* Nothing to do for now */
+}
diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h
index d798355fd93f..12fac0d565b0 100644
--- a/include/linux/boot_constraint.h
+++ b/include/linux/boot_constraint.h
@@ -17,10 +17,12 @@ struct device;
* enum dev_boot_constraint_type - This defines different boot constraint types.
*
* @DEV_BOOT_CONSTRAINT_CLK: This represents a clock boot constraint.
+ * @DEV_BOOT_CONSTRAINT_PM: This represents a power domain boot constraint.
* @DEV_BOOT_CONSTRAINT_SUPPLY: This represents a power supply boot constraint.
*/
enum dev_boot_constraint_type {
DEV_BOOT_CONSTRAINT_CLK,
+ DEV_BOOT_CONSTRAINT_PM,
DEV_BOOT_CONSTRAINT_SUPPLY,
};
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 05/13] boot_constraint: Add support for clk constraints
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
This patch adds the clk constraint type.
The constraint is set by enabling the clk for the device. Once the
device is probed, the clk is disabled and the constraint is removed.
We may want to do clk_set_rate() from here, but lets wait for some real
users that really want it.
Tested-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/boot_constraint/Makefile | 2 +-
drivers/boot_constraint/clk.c | 67 ++++++++++++++++++++++++++++++++++++++++
drivers/boot_constraint/core.c | 4 +++
drivers/boot_constraint/core.h | 3 ++
include/linux/boot_constraint.h | 11 +++++++
5 files changed, 86 insertions(+), 1 deletion(-)
create mode 100644 drivers/boot_constraint/clk.c
diff --git a/drivers/boot_constraint/Makefile b/drivers/boot_constraint/Makefile
index a45616f0c3b0..3424379fd1e4 100644
--- a/drivers/boot_constraint/Makefile
+++ b/drivers/boot_constraint/Makefile
@@ -1,3 +1,3 @@
# Makefile for device boot constraints
-obj-y := core.o supply.o
+obj-y := clk.o core.o supply.o
diff --git a/drivers/boot_constraint/clk.c b/drivers/boot_constraint/clk.c
new file mode 100644
index 000000000000..db22acff43e6
--- /dev/null
+++ b/drivers/boot_constraint/clk.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "core.h"
+
+struct constraint_clk {
+ struct dev_boot_constraint_clk_info clk_info;
+ struct clk *clk;
+};
+
+int constraint_clk_add(struct constraint *constraint, void *data)
+{
+ struct dev_boot_constraint_clk_info *clk_info = data;
+ struct constraint_clk *cclk;
+ struct device *dev = constraint->cdev->dev;
+ int ret;
+
+ cclk = kzalloc(sizeof(*cclk), GFP_KERNEL);
+ if (!cclk)
+ return -ENOMEM;
+
+ cclk->clk = clk_get(dev, clk_info->name);
+ if (IS_ERR(cclk->clk)) {
+ ret = PTR_ERR(cclk->clk);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(dev, "clk_get() failed for %s (%d)\n",
+ clk_info->name, ret);
+ }
+ goto free;
+ }
+
+ ret = clk_prepare_enable(cclk->clk);
+ if (ret) {
+ dev_err(dev, "clk_prepare_enable() %s failed (%d)\n",
+ clk_info->name, ret);
+ goto put_clk;
+ }
+
+ cclk->clk_info.name = kstrdup_const(clk_info->name, GFP_KERNEL);
+ constraint->private = cclk;
+
+ return 0;
+
+put_clk:
+ clk_put(cclk->clk);
+free:
+ kfree(cclk);
+
+ return ret;
+}
+
+void constraint_clk_remove(struct constraint *constraint)
+{
+ struct constraint_clk *cclk = constraint->private;
+
+ kfree_const(cclk->clk_info.name);
+ clk_disable_unprepare(cclk->clk);
+ clk_put(cclk->clk);
+ kfree(cclk);
+}
diff --git a/drivers/boot_constraint/core.c b/drivers/boot_constraint/core.c
index 63a4b1a2fa2c..df9e0bddbfbe 100644
--- a/drivers/boot_constraint/core.c
+++ b/drivers/boot_constraint/core.c
@@ -91,6 +91,10 @@ static struct constraint *constraint_allocate(struct constraint_dev *cdev,
void (*remove)(struct constraint *constraint);
switch (type) {
+ case DEV_BOOT_CONSTRAINT_CLK:
+ add = constraint_clk_add;
+ remove = constraint_clk_remove;
+ break;
case DEV_BOOT_CONSTRAINT_SUPPLY:
add = constraint_supply_add;
remove = constraint_supply_remove;
diff --git a/drivers/boot_constraint/core.h b/drivers/boot_constraint/core.h
index d0d3e7bf7d57..720bda0a0f44 100644
--- a/drivers/boot_constraint/core.h
+++ b/drivers/boot_constraint/core.h
@@ -29,6 +29,9 @@ struct constraint {
};
/* Forward declarations of constraint specific callbacks */
+int constraint_clk_add(struct constraint *constraint, void *data);
+void constraint_clk_remove(struct constraint *constraint);
+
int constraint_supply_add(struct constraint *constraint, void *data);
void constraint_supply_remove(struct constraint *constraint);
diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h
index 1db24d53b622..d798355fd93f 100644
--- a/include/linux/boot_constraint.h
+++ b/include/linux/boot_constraint.h
@@ -16,12 +16,23 @@ struct device;
/**
* enum dev_boot_constraint_type - This defines different boot constraint types.
*
+ * @DEV_BOOT_CONSTRAINT_CLK: This represents a clock boot constraint.
* @DEV_BOOT_CONSTRAINT_SUPPLY: This represents a power supply boot constraint.
*/
enum dev_boot_constraint_type {
+ DEV_BOOT_CONSTRAINT_CLK,
DEV_BOOT_CONSTRAINT_SUPPLY,
};
+/**
+ * struct dev_boot_constraint_clk_info - Clock boot constraint information.
+ *
+ * @name: This must match the connection-id of the clock for the device.
+ */
+struct dev_boot_constraint_clk_info {
+ const char *name;
+};
+
/**
* struct dev_boot_constraint_supply_info - Power supply boot constraint
* information.
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 04/13] boot_constraint: Add support for supply constraints
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
This patch adds the first constraint type: power-supply.
The constraint is set by enabling the regulator and setting a voltage
range (if required) for the respective regulator device, which will be
honored by the regulator core even if more users turn up. Once the
device is probed, the regulator is released and the constraint is
removed.
Tested-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/boot_constraint/Makefile | 2 +-
drivers/boot_constraint/core.c | 4 ++
drivers/boot_constraint/core.h | 5 +++
drivers/boot_constraint/supply.c | 95 ++++++++++++++++++++++++++++++++++++++++
include/linux/boot_constraint.h | 17 ++++++-
5 files changed, 121 insertions(+), 2 deletions(-)
create mode 100644 drivers/boot_constraint/supply.c
diff --git a/drivers/boot_constraint/Makefile b/drivers/boot_constraint/Makefile
index 0f2680177974..a45616f0c3b0 100644
--- a/drivers/boot_constraint/Makefile
+++ b/drivers/boot_constraint/Makefile
@@ -1,3 +1,3 @@
# Makefile for device boot constraints
-obj-y := core.o
+obj-y := core.o supply.o
diff --git a/drivers/boot_constraint/core.c b/drivers/boot_constraint/core.c
index 45a0fbed1b11..63a4b1a2fa2c 100644
--- a/drivers/boot_constraint/core.c
+++ b/drivers/boot_constraint/core.c
@@ -91,6 +91,10 @@ static struct constraint *constraint_allocate(struct constraint_dev *cdev,
void (*remove)(struct constraint *constraint);
switch (type) {
+ case DEV_BOOT_CONSTRAINT_SUPPLY:
+ add = constraint_supply_add;
+ remove = constraint_supply_remove;
+ break;
default:
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/boot_constraint/core.h b/drivers/boot_constraint/core.h
index 1e87125de531..d0d3e7bf7d57 100644
--- a/drivers/boot_constraint/core.h
+++ b/drivers/boot_constraint/core.h
@@ -27,4 +27,9 @@ struct constraint {
void (*remove)(struct constraint *constraint);
void *private;
};
+
+/* Forward declarations of constraint specific callbacks */
+int constraint_supply_add(struct constraint *constraint, void *data);
+void constraint_supply_remove(struct constraint *constraint);
+
#endif /* _CORE_H */
diff --git a/drivers/boot_constraint/supply.c b/drivers/boot_constraint/supply.c
new file mode 100644
index 000000000000..916e5d6848d5
--- /dev/null
+++ b/drivers/boot_constraint/supply.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include "core.h"
+
+struct constraint_supply {
+ struct dev_boot_constraint_supply_info supply;
+ struct regulator *reg;
+};
+
+int constraint_supply_add(struct constraint *constraint, void *data)
+{
+ struct dev_boot_constraint_supply_info *supply = data;
+ struct constraint_supply *csupply;
+ struct device *dev = constraint->cdev->dev;
+ int ret;
+
+ csupply = kzalloc(sizeof(*csupply), GFP_KERNEL);
+ if (!csupply)
+ return -ENOMEM;
+
+ csupply->reg = regulator_get(dev, supply->name);
+ if (IS_ERR(csupply->reg)) {
+ ret = PTR_ERR(csupply->reg);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(dev, "regulator_get() failed for %s (%d)\n",
+ supply->name, ret);
+ }
+ goto free;
+ }
+
+ if (supply->u_volt_min != 0 && supply->u_volt_max != 0) {
+ ret = regulator_set_voltage(csupply->reg, supply->u_volt_min,
+ supply->u_volt_max);
+ if (ret) {
+ dev_err(dev, "regulator_set_voltage %s failed (%d)\n",
+ supply->name, ret);
+ goto free_regulator;
+ }
+ }
+
+ ret = regulator_enable(csupply->reg);
+ if (ret) {
+ dev_err(dev, "regulator_enable %s failed (%d)\n",
+ supply->name, ret);
+ goto remove_voltage;
+ }
+
+ memcpy(&csupply->supply, supply, sizeof(*supply));
+ csupply->supply.name = kstrdup_const(supply->name, GFP_KERNEL);
+ constraint->private = csupply;
+
+ return 0;
+
+remove_voltage:
+ if (supply->u_volt_min != 0 && supply->u_volt_max != 0)
+ regulator_set_voltage(csupply->reg, 0, INT_MAX);
+free_regulator:
+ regulator_put(csupply->reg);
+free:
+ kfree(csupply);
+
+ return ret;
+}
+
+void constraint_supply_remove(struct constraint *constraint)
+{
+ struct constraint_supply *csupply = constraint->private;
+ struct dev_boot_constraint_supply_info *supply = &csupply->supply;
+ struct device *dev = constraint->cdev->dev;
+ int ret;
+
+ kfree_const(supply->name);
+
+ ret = regulator_disable(csupply->reg);
+ if (ret)
+ dev_err(dev, "regulator_disable failed (%d)\n", ret);
+
+ if (supply->u_volt_min != 0 && supply->u_volt_max != 0) {
+ ret = regulator_set_voltage(csupply->reg, 0, INT_MAX);
+ if (ret)
+ dev_err(dev, "regulator_set_voltage failed (%d)\n",
+ ret);
+ }
+
+ regulator_put(csupply->reg);
+ kfree(csupply);
+}
diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h
index 2ce62b7b3cc6..1db24d53b622 100644
--- a/include/linux/boot_constraint.h
+++ b/include/linux/boot_constraint.h
@@ -16,9 +16,24 @@ struct device;
/**
* enum dev_boot_constraint_type - This defines different boot constraint types.
*
+ * @DEV_BOOT_CONSTRAINT_SUPPLY: This represents a power supply boot constraint.
*/
enum dev_boot_constraint_type {
- DEV_BOOT_CONSTRAINT_NONE,
+ DEV_BOOT_CONSTRAINT_SUPPLY,
+};
+
+/**
+ * struct dev_boot_constraint_supply_info - Power supply boot constraint
+ * information.
+ *
+ * @name: This must match the power supply name for the device.
+ * @u_volt_min: This is the minimum microvolts value supported by the device.
+ * @u_volt_max: This is the maximum microvolts value supported by the device.
+ */
+struct dev_boot_constraint_supply_info {
+ const char *name;
+ unsigned int u_volt_min;
+ unsigned int u_volt_max;
};
/**
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 03/13] drivers: Add boot constraints core
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
Some devices are powered ON by the bootloader before the bootloader
handovers control to Linux. It maybe important for those devices to keep
working until the time a Linux device driver probes the device and
reconfigure its resources.
A typical example of that can be the LCD controller, which is used by
the bootloaders to show image(s) while the platform is booting into
Linux. The LCD controller can be using some resources, like clk,
regulators, PM domain, etc, that are shared between several devices.
These shared resources should be configured to satisfy need of all the
users. If another device's (X) driver gets probed before the LCD
controller driver in this case, then it may end up reconfiguring these
resources to ranges satisfying the current users (only device X) and
that can make the LCD screen unstable.
This patch introduces the concept of boot-constraints, which will be set
by the bootloaders and the kernel will satisfy them until the time
driver for such a device is probed (successfully or unsuccessfully).
The list of boot constraint types is empty for now, and will be
incrementally updated by later patches.
Only two routines are exposed by the boot constraints core for now:
- dev_boot_constraint_add(): This shall be called by parts of the kernel
(before the device is probed) to set the constraints.
- dev_boot_constraints_remove(): This is called only by the driver core
after a device is probed successfully or unsuccessfully. Special
handling is done here for deferred probing.
Tested-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/base/dd.c | 20 ++--
drivers/boot_constraint/Kconfig | 9 ++
drivers/boot_constraint/Makefile | 3 +
drivers/boot_constraint/core.c | 219 +++++++++++++++++++++++++++++++++++++++
drivers/boot_constraint/core.h | 30 ++++++
include/linux/boot_constraint.h | 66 ++++++++++++
8 files changed, 343 insertions(+), 7 deletions(-)
create mode 100644 drivers/boot_constraint/Kconfig
create mode 100644 drivers/boot_constraint/Makefile
create mode 100644 drivers/boot_constraint/core.c
create mode 100644 drivers/boot_constraint/core.h
create mode 100644 include/linux/boot_constraint.h
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 152744c5ef0f..6aa1629423d4 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -5,6 +5,8 @@ source "drivers/amba/Kconfig"
source "drivers/base/Kconfig"
+source "drivers/boot_constraint/Kconfig"
+
source "drivers/bus/Kconfig"
source "drivers/connector/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index e06f7f633f73..3a2774672e29 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
obj-$(CONFIG_NVM) += lightnvm/
obj-y += base/ block/ misc/ mfd/ nfc/
+obj-$(CONFIG_DEV_BOOT_CONSTRAINT) += boot_constraint/
obj-$(CONFIG_LIBNVDIMM) += nvdimm/
obj-$(CONFIG_DAX) += dax/
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 533c82f55cea..dc89f98a2487 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -16,6 +16,7 @@
* Copyright (c) 2007-2009 Novell Inc.
*/
+#include <linux/boot_constraint.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -419,15 +420,20 @@ static int really_probe(struct device *dev, struct device_driver *drv)
*/
devices_kset_move_last(dev);
- if (dev->bus->probe) {
+ if (dev->bus->probe)
ret = dev->bus->probe(dev);
- if (ret)
- goto probe_failed;
- } else if (drv->probe) {
+ else if (drv->probe)
ret = drv->probe(dev);
- if (ret)
- goto probe_failed;
- }
+
+ /*
+ * Remove boot constraints for both successful and unsuccessful probe(),
+ * except for the case where EPROBE_DEFER is returned by probe().
+ */
+ if (ret != -EPROBE_DEFER)
+ dev_boot_constraints_remove(dev);
+
+ if (ret)
+ goto probe_failed;
if (test_remove) {
test_remove = false;
diff --git a/drivers/boot_constraint/Kconfig b/drivers/boot_constraint/Kconfig
new file mode 100644
index 000000000000..9195f9a39fe2
--- /dev/null
+++ b/drivers/boot_constraint/Kconfig
@@ -0,0 +1,9 @@
+config DEV_BOOT_CONSTRAINT
+ bool "Boot constraints for devices"
+ help
+ This enables boot constraints detection for devices. These constraints
+ are (normally) set by the Bootloader and must be satisfied by the
+ kernel until the relevant device driver is probed. Once the driver is
+ probed, the constraint is dropped.
+
+ If unsure, say N.
diff --git a/drivers/boot_constraint/Makefile b/drivers/boot_constraint/Makefile
new file mode 100644
index 000000000000..0f2680177974
--- /dev/null
+++ b/drivers/boot_constraint/Makefile
@@ -0,0 +1,3 @@
+# Makefile for device boot constraints
+
+obj-y := core.o
diff --git a/drivers/boot_constraint/core.c b/drivers/boot_constraint/core.c
new file mode 100644
index 000000000000..45a0fbed1b11
--- /dev/null
+++ b/drivers/boot_constraint/core.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This takes care of boot time device constraints, normally set by the
+ * Bootloader.
+ *
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include "core.h"
+
+#define for_each_constraint(_constraint, _temp, _cdev) \
+ list_for_each_entry_safe(_constraint, _temp, &_cdev->constraints, node)
+
+/* Global list of all constraint devices currently registered */
+static LIST_HEAD(constraint_devices);
+static DEFINE_MUTEX(constraint_devices_mutex);
+
+/* Boot constraints core */
+
+static struct constraint_dev *constraint_device_find(struct device *dev)
+{
+ struct constraint_dev *cdev;
+
+ list_for_each_entry(cdev, &constraint_devices, node) {
+ if (cdev->dev == dev)
+ return cdev;
+ }
+
+ return NULL;
+}
+
+static struct constraint_dev *constraint_device_allocate(struct device *dev)
+{
+ struct constraint_dev *cdev;
+
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ if (!cdev)
+ return ERR_PTR(-ENOMEM);
+
+ cdev->dev = dev;
+ INIT_LIST_HEAD(&cdev->node);
+ INIT_LIST_HEAD(&cdev->constraints);
+
+ list_add(&cdev->node, &constraint_devices);
+
+ return cdev;
+}
+
+static void constraint_device_free(struct constraint_dev *cdev)
+{
+ list_del(&cdev->node);
+ kfree(cdev);
+}
+
+static struct constraint_dev *constraint_device_get(struct device *dev)
+{
+ struct constraint_dev *cdev;
+
+ cdev = constraint_device_find(dev);
+ if (cdev)
+ return cdev;
+
+ cdev = constraint_device_allocate(dev);
+ if (IS_ERR(cdev)) {
+ dev_err(dev, "Failed to add constraint dev (%ld)\n",
+ PTR_ERR(cdev));
+ }
+
+ return cdev;
+}
+
+static void constraint_device_put(struct constraint_dev *cdev)
+{
+ if (!list_empty(&cdev->constraints))
+ return;
+
+ constraint_device_free(cdev);
+}
+
+static struct constraint *constraint_allocate(struct constraint_dev *cdev,
+ enum dev_boot_constraint_type type)
+{
+ struct constraint *constraint;
+ int (*add)(struct constraint *constraint, void *data);
+ void (*remove)(struct constraint *constraint);
+
+ switch (type) {
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ constraint = kzalloc(sizeof(*constraint), GFP_KERNEL);
+ if (!constraint)
+ return ERR_PTR(-ENOMEM);
+
+ constraint->cdev = cdev;
+ constraint->type = type;
+ constraint->add = add;
+ constraint->remove = remove;
+ INIT_LIST_HEAD(&constraint->node);
+
+ list_add(&constraint->node, &cdev->constraints);
+
+ return constraint;
+}
+
+static void constraint_free(struct constraint *constraint)
+{
+ list_del(&constraint->node);
+ kfree(constraint);
+}
+
+/**
+ * dev_boot_constraint_add: Adds a boot constraint.
+ *
+ * @dev: Device for which the boot constraint is getting added.
+ * @info: Structure representing the boot constraint.
+ *
+ * This routine adds a single boot constraint for the device. This must be
+ * called before the device is probed by its driver, otherwise the boot
+ * constraint will never get removed and may result in unwanted behavior of the
+ * hardware. The boot constraint is removed by the driver core automatically
+ * after the device is probed (successfully or unsuccessfully).
+ *
+ * Return: 0 on success, and a negative error otherwise.
+ */
+int dev_boot_constraint_add(struct device *dev,
+ struct dev_boot_constraint_info *info)
+{
+ struct constraint_dev *cdev;
+ struct constraint *constraint;
+ int ret;
+
+ mutex_lock(&constraint_devices_mutex);
+
+ /* Find or add the cdev type first */
+ cdev = constraint_device_get(dev);
+ if (IS_ERR(cdev)) {
+ ret = PTR_ERR(cdev);
+ goto unlock;
+ }
+
+ constraint = constraint_allocate(cdev, info->constraint.type);
+ if (IS_ERR(constraint)) {
+ dev_err(dev, "Failed to add constraint type: %d (%ld)\n",
+ info->constraint.type, PTR_ERR(constraint));
+ ret = PTR_ERR(constraint);
+ goto put_cdev;
+ }
+
+ constraint->free_resources = info->free_resources;
+ constraint->free_resources_data = info->free_resources_data;
+
+ /* Set constraint */
+ ret = constraint->add(constraint, info->constraint.data);
+ if (ret)
+ goto free_constraint;
+
+ dev_dbg(dev, "Added boot constraint-type (%d)\n",
+ info->constraint.type);
+
+ mutex_unlock(&constraint_devices_mutex);
+
+ return 0;
+
+free_constraint:
+ constraint_free(constraint);
+put_cdev:
+ constraint_device_put(cdev);
+unlock:
+ mutex_unlock(&constraint_devices_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_boot_constraint_add);
+
+static void constraint_remove(struct constraint *constraint)
+{
+ constraint->remove(constraint);
+
+ if (constraint->free_resources)
+ constraint->free_resources(constraint->free_resources_data);
+
+ constraint_free(constraint);
+}
+
+/**
+ * dev_boot_constraints_remove: Removes all boot constraints of a device.
+ *
+ * @dev: Device for which the boot constraints are getting removed.
+ *
+ * This routine removes all the boot constraints that were previously added for
+ * the device. This is called directly by the driver core and should not be
+ * called by platform specific code.
+ */
+void dev_boot_constraints_remove(struct device *dev)
+{
+ struct constraint_dev *cdev;
+ struct constraint *constraint, *temp;
+
+ mutex_lock(&constraint_devices_mutex);
+
+ cdev = constraint_device_find(dev);
+ if (!cdev)
+ goto unlock;
+
+ for_each_constraint(constraint, temp, cdev)
+ constraint_remove(constraint);
+
+ constraint_device_put(cdev);
+unlock:
+ mutex_unlock(&constraint_devices_mutex);
+}
diff --git a/drivers/boot_constraint/core.h b/drivers/boot_constraint/core.h
new file mode 100644
index 000000000000..1e87125de531
--- /dev/null
+++ b/drivers/boot_constraint/core.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ */
+#ifndef _CORE_H
+#define _CORE_H
+
+#include <linux/boot_constraint.h>
+#include <linux/device.h>
+#include <linux/list.h>
+
+struct constraint_dev {
+ struct device *dev;
+ struct list_head node;
+ struct list_head constraints;
+};
+
+struct constraint {
+ struct constraint_dev *cdev;
+ struct list_head node;
+ enum dev_boot_constraint_type type;
+ void (*free_resources)(void *data);
+ void *free_resources_data;
+
+ int (*add)(struct constraint *constraint, void *data);
+ void (*remove)(struct constraint *constraint);
+ void *private;
+};
+#endif /* _CORE_H */
diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h
new file mode 100644
index 000000000000..2ce62b7b3cc6
--- /dev/null
+++ b/include/linux/boot_constraint.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Boot constraints header.
+ *
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ */
+#ifndef _LINUX_BOOT_CONSTRAINT_H
+#define _LINUX_BOOT_CONSTRAINT_H
+
+#include <linux/err.h>
+#include <linux/types.h>
+
+struct device;
+
+/**
+ * enum dev_boot_constraint_type - This defines different boot constraint types.
+ *
+ */
+enum dev_boot_constraint_type {
+ DEV_BOOT_CONSTRAINT_NONE,
+};
+
+/**
+ * struct dev_boot_constraint - This represents a single boot constraint.
+ *
+ * @type: This is boot constraint type (like: clk, supply, etc.).
+ * @data: This points to constraint type specific data (like:
+ * dev_boot_constraint_clk_info).
+ */
+struct dev_boot_constraint {
+ enum dev_boot_constraint_type type;
+ void *data;
+};
+
+/**
+ * struct dev_boot_constraint_info - This is used to add a single boot
+ * constraint.
+ *
+ * @constraint: This represents a single boot constraint.
+ * @free_resources: This callback is called by the boot constraint core after
+ * the constraint is removed. This is an optional field.
+ * @free_resources_data: This is data to be passed to free_resources() callback.
+ * This is an optional field.
+ */
+struct dev_boot_constraint_info {
+ struct dev_boot_constraint constraint;
+
+ /* This will be called just before the constraint is removed */
+ void (*free_resources)(void *data);
+ void *free_resources_data;
+};
+
+#ifdef CONFIG_DEV_BOOT_CONSTRAINT
+int dev_boot_constraint_add(struct device *dev,
+ struct dev_boot_constraint_info *info);
+void dev_boot_constraints_remove(struct device *dev);
+#else
+static inline
+int dev_boot_constraint_add(struct device *dev,
+ struct dev_boot_constraint_info *info)
+{ return 0; }
+static inline void dev_boot_constraints_remove(struct device *dev) {}
+#endif /* CONFIG_DEV_BOOT_CONSTRAINT */
+
+#endif /* _LINUX_BOOT_CONSTRAINT_H */
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 02/13] of: platform: Make of_platform_bus_create() global
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
The boot constraints core needs to create platform or AMBA devices
corresponding to a compatible string and not for rest of the nodes in
DT. of_platform_bus_create() fits in the best to achieve that.
Allow it to be used outside of platform.c.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/of/platform.c | 8 ++++----
include/linux/of_platform.h | 11 +++++++++++
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 61a4a81bea9f..6f707bfb348f 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -397,10 +397,10 @@ static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *l
* Creates a platform_device for the provided device_node, and optionally
* recursively create devices for all the child nodes.
*/
-static int of_platform_bus_create(struct device_node *bus,
- const struct of_device_id *matches,
- const struct of_dev_auxdata *lookup,
- struct device *parent, bool strict)
+int of_platform_bus_create(struct device_node *bus,
+ const struct of_device_id *matches,
+ const struct of_dev_auxdata *lookup,
+ struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 4909d1aa47ec..ff80fba79c41 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -81,6 +81,10 @@ extern int of_platform_bus_probe(struct device_node *root,
const struct of_device_id *matches,
struct device *parent);
#ifdef CONFIG_OF_ADDRESS
+extern int of_platform_bus_create(struct device_node *bus,
+ const struct of_device_id *matches,
+ const struct of_dev_auxdata *lookup,
+ struct device *parent, bool strict);
extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
@@ -94,6 +98,13 @@ extern int devm_of_platform_populate(struct device *dev);
extern void devm_of_platform_depopulate(struct device *dev);
#else
+static inline int of_platform_bus_create(struct device_node *bus,
+ const struct of_device_id *matches,
+ const struct of_dev_auxdata *lookup,
+ struct device *parent, bool strict)
+{
+ return -ENODEV;
+}
static inline int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 01/13] of: platform: Add of_find_any_device_by_node()
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515554879.git.viresh.kumar@linaro.org>
This creates a new helper that returns the struct device corresponding
to a struct device_node. This currently works only for amba and platform
devices, but can be easily extended to include other bus types.
This also creates an internal of_find_amba_device_by_node() helper,
which isn't exported as of now.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/of/platform.c | 55 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_platform.h | 5 +++++
2 files changed, 60 insertions(+)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index b7cf84b29737..61a4a81bea9f 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -60,6 +60,61 @@ struct platform_device *of_find_device_by_node(struct device_node *np)
}
EXPORT_SYMBOL(of_find_device_by_node);
+#ifdef CONFIG_ARM_AMBA
+/**
+ * of_find_amba_device_by_node - Find the amba_device associated with a node
+ * @np: Pointer to device tree node
+ *
+ * Takes a reference to the embedded struct device which needs to be dropped
+ * after use.
+ *
+ * Returns amba_device pointer, or NULL if not found
+ */
+static struct amba_device *of_find_amba_device_by_node(struct device_node *np)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&amba_bustype, NULL, np, of_dev_node_match);
+ return dev ? to_amba_device(dev) : NULL;
+}
+#else
+static inline struct amba_device *of_find_amba_device_by_node(struct device_node *np)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * of_find_any_device_by_node - Find the struct device associated with a node
+ * @np: Pointer to device tree node
+ *
+ * Takes a reference to the embedded struct device which needs to be dropped
+ * after use.
+ *
+ * This currently supports only AMBA and platform devices.
+ *
+ * Returns struct device pointer, or NULL if not found
+ */
+struct device *of_find_any_device_by_node(struct device_node *np)
+{
+ struct device *dev = NULL;
+
+ if (of_device_is_compatible(np, "arm,primecell")) {
+ struct amba_device *adev = of_find_amba_device_by_node(np);
+
+ if (adev)
+ dev = &adev->dev;
+ } else {
+ struct platform_device *pdev = of_find_device_by_node(np);
+
+ if (pdev)
+ dev = &pdev->dev;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL(of_find_any_device_by_node);
+
#ifdef CONFIG_OF_ADDRESS
/*
* The following routines scan a subtree and registers a device for
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index fb908e598348..4909d1aa47ec 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -59,11 +59,16 @@ extern struct platform_device *of_device_alloc(struct device_node *np,
struct device *parent);
#ifdef CONFIG_OF
extern struct platform_device *of_find_device_by_node(struct device_node *np);
+extern struct device *of_find_any_device_by_node(struct device_node *np);
#else
static inline struct platform_device *of_find_device_by_node(struct device_node *np)
{
return NULL;
}
+static inline struct device *of_find_any_device_by_node(struct device_node *np)
+{
+ return NULL;
+}
#endif
/* Platform devices and busses creation */
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply related
* [PATCH V6 Resend 00/13] drivers: Boot Constraint core
From: Viresh Kumar @ 2018-01-10 3:47 UTC (permalink / raw)
To: linux-arm-kernel
Hi Greg,
I am re-sending V6 as you suggested. There is no change from the patches
sent on 14/15th of December, apart from rebasing on driver-core-next.
I have tested the Hisilicon patches (again) on hikey 9660 board, IMX
stuff was earlier tested by Sascha (Pengutronix) on i.MX6 and Qualcomm
stuff was earlier tested by Rajendra (Qualcomm) on Dragonboard 410C
(This required some more patches related to display driver which
Rajendra should be sending separately later on).
Problem statement:
Some devices are powered ON by the bootloader before the bootloader
handovers control to Linux. It maybe important for those devices to keep
working until the time a Linux device driver probes the device and
reconfigure its resources.
A typical example of that can be the LCD controller, which is used by
the bootloaders to show image(s) while the platform is booting into
Linux. The LCD controller can be using some resources, like clk,
regulators, etc, that are shared between several devices. These shared
resources should be configured to satisfy need of all the users. If
another device's (X) driver gets probed before the LCD controller driver
in this case, then it may end up disabling or reconfiguring these
resources to ranges satisfying the current users (only device X) and
that can make the LCD screen unstable.
Another case can be a debug serial port enabled from the bootloader.
Of course we can have more complex cases where the same resource is
getting used by two devices while the kernel boots and the order in
which devices get probed wouldn't matter as the other device will surely
break then.
There are also cases where the resources may not be shared, but the
kernel will disable them forcefully as no users may have appeared until
a certain point in kernel boot. This makes sure that the resources stay
enabled. A wide variety of constraints can be satisfied using the new
framework.
Proposed solution:
This series introduces the concept of "boot-constraint", which are set
by platform specific drivers (for now at least) at early init (like
subsys_initcall) and the kernel will keep satisfying them until the time
driver for such a device is probed (successfully or unsuccessfully).
Once the driver is probed, the driver core removes the constraints set
for the device. This series implements clk, regulator and PM domain
constraints currently.
Pushed here:
git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/linux.git boot-constraints
V5->V6:
- Fix a build error reported by build bot for !CONFIG_OF_ADDRESS. This
was already sent on 15th December.
- Rebased over latest driver-core-next.
V4->V5:
- SPDX Licence format used.
- arm,primecell stuff removed from boot constraint core and added a
helper in OF core (which already handles amba and platform devices).
- Removed a bunch of BUG_ON(), pr_fmt(), comments.
- Changed directory and other names from
boot_constraints/boot_constraint.
- Removed serial.o file and moved the code to hikey and imx files.
- Don't return error from dummy helper.
- Added documentation and corresponding kernel doc comments in the code.
- Updated MAINTAINERS.
V3->V4:
- Added support for imx, hikey and Qcom usecases.
- Enhanced boot constraints core to make drivers code easy and handle
complex cases.
- Two new patches for OF included to provide APIs to boot constraint
core.
- Removed the kernel parameter patch for now.
- Don't check return values of debugfs routines.
- Moved the boot constraints core from drivers/base/ to drivers/.
V2->V3:
- Removed DT support as we aren't sure about how to define the bindings
yet.
- Added CLK and PM domain constraint types.
- A new directory is added for boot constraints, which will also contain
platform specific drivers in future.
- Deferred devices are still supported, just that it wouldn't be called
from generic code anymore but platform specific code.
- Tested on Qcom 410c dragonboard with display flash screen (Rajendra).
- Usual renaming/commit-log-updates/etc changes done.
V1->V2:
- Add support for setting constraints for devices created from DT.
- Allow handling deferred devices earlier then late_init.
- Remove 'default y' line from kconfig.
- Drop '=" after boot_constraints_disable kernel param.
- Dropped the dummy testing patch now.
--
viresh
Rajendra Nayak (1):
boot_constraint: Add Qualcomm display controller constraints
Viresh Kumar (12):
of: platform: Add of_find_any_device_by_node()
of: platform: Make of_platform_bus_create() global
drivers: Add boot constraints core
boot_constraint: Add support for supply constraints
boot_constraint: Add support for clk constraints
boot_constraint: Add support for PM constraints
boot_constraint: Add debugfs support
boot_constraint: Manage deferrable constraints
boot_constraint: Add support for Hisilicon platforms
boot_constraint: Add support for IMX platform
boot_constraint: Update MAINTAINERS
boot_constraint: Add documentation
.../driver-api/boot-constraint/constraints.rst | 98 +++++++
Documentation/driver-api/boot-constraint/index.rst | 4 +
Documentation/driver-api/index.rst | 1 +
MAINTAINERS | 9 +
arch/arm/mach-imx/Kconfig | 1 +
arch/arm64/Kconfig.platforms | 2 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/base/dd.c | 32 ++-
drivers/boot_constraint/Kconfig | 9 +
drivers/boot_constraint/Makefile | 7 +
drivers/boot_constraint/clk.c | 70 +++++
drivers/boot_constraint/core.c | 290 +++++++++++++++++++++
drivers/boot_constraint/core.h | 47 ++++
drivers/boot_constraint/deferrable_dev.c | 241 +++++++++++++++++
drivers/boot_constraint/hikey.c | 158 +++++++++++
drivers/boot_constraint/imx.c | 126 +++++++++
drivers/boot_constraint/pm.c | 28 ++
drivers/boot_constraint/qcom.c | 122 +++++++++
drivers/boot_constraint/supply.c | 104 ++++++++
drivers/clk/imx/clk-imx25.c | 12 -
drivers/clk/imx/clk-imx27.c | 13 -
drivers/clk/imx/clk-imx31.c | 12 -
drivers/clk/imx/clk-imx35.c | 10 -
drivers/clk/imx/clk-imx51-imx53.c | 16 --
drivers/clk/imx/clk-imx6q.c | 8 -
drivers/clk/imx/clk-imx6sl.c | 8 -
drivers/clk/imx/clk-imx6sx.c | 8 -
drivers/clk/imx/clk-imx7d.c | 14 -
drivers/clk/imx/clk.c | 38 ---
drivers/clk/imx/clk.h | 1 -
drivers/of/platform.c | 63 ++++-
include/linux/boot_constraint.h | 121 +++++++++
include/linux/of_platform.h | 16 ++
34 files changed, 1541 insertions(+), 151 deletions(-)
create mode 100644 Documentation/driver-api/boot-constraint/constraints.rst
create mode 100644 Documentation/driver-api/boot-constraint/index.rst
create mode 100644 drivers/boot_constraint/Kconfig
create mode 100644 drivers/boot_constraint/Makefile
create mode 100644 drivers/boot_constraint/clk.c
create mode 100644 drivers/boot_constraint/core.c
create mode 100644 drivers/boot_constraint/core.h
create mode 100644 drivers/boot_constraint/deferrable_dev.c
create mode 100644 drivers/boot_constraint/hikey.c
create mode 100644 drivers/boot_constraint/imx.c
create mode 100644 drivers/boot_constraint/pm.c
create mode 100644 drivers/boot_constraint/qcom.c
create mode 100644 drivers/boot_constraint/supply.c
create mode 100644 include/linux/boot_constraint.h
--
2.15.0.194.g9af6a3dea062
^ permalink raw reply
* [PATCH 3/4] bcm2835-gpio-exp: Driver for GPIO expander via mailbox service
From: Baruch Siach @ 2018-01-10 3:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkdb73jGGRm5OrXLGYSOjMni-NsOwdC7TXH2k+iAEnAvL2g@mail.gmail.com>
Hi Linus,
On Wed, Jan 03, 2018 at 11:08:15AM +0100, Linus Walleij wrote:
> On Tue, Jan 2, 2018 at 2:19 PM, Baruch Siach <baruch@tkos.co.il> wrote:
> > +#include <linux/err.h>
> > +#include <linux/gpio.h>
>
> Just use
>
> #include <linux/driver.h>
You mean linux/gpio/driver.h, right?
I still need linux/gpio.h for GPIOF_DIR_*.
baruch
--
http://baruch.siach.name/blog/ ~. .~ Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
- baruch at tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -
^ permalink raw reply
* [PATCH V5 00/13] drivers: Boot Constraint core
From: Viresh Kumar @ 2018-01-10 3:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180109184733.GB28273@kroah.com>
On 09-01-18, 19:47, Greg Kroah-Hartman wrote:
> Can you resend this? As you can tell, I've been a bit busy for the past
> month or so :(
Sure.
> Also, why is there no signed-off-by on the OF core patches?
A bit confused, sorry. Are you looking for my signed-off ? They are already
there.
Or are you looking for Rob's (OF maintainer) signed-off ?
--
viresh
^ permalink raw reply
* [PATCH v5 01/44] dt-bindings: clock: Add new bindings for TI Davinci PLL clocks
From: David Lechner @ 2018-01-10 3:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0f90b5f7-f21e-5f81-1154-9a815bbb786d@ti.com>
On 01/09/2018 06:35 AM, Sekhar Nori wrote:
> On Monday 08 January 2018 09:59 PM, David Lechner wrote:
>> On 01/08/2018 08:00 AM, Sekhar Nori wrote:
>>> On Monday 08 January 2018 07:47 AM, David Lechner wrote:
>>>> This adds a new binding for the PLL IP blocks in the mach-davinci family
>>>> of processors. Currently, only the SYSCLKn and AUXCLK outputs are
>>>> needed,
>>>> but in the future additional child nodes could be added for OBSCLK and
>>>> BPDIV.
>>>>
>>>> Note: Although these PLL controllers are very similar to the TI Keystone
>>>> SoCs, we are not re-using those bindings. The Keystone bindings use a
>>>> legacy one-node-per-clock binding. Furthermore, the mach-davinici SoCs
>>>
>>> Not sure what is meant by "legacy one-node-per-clock binding"
>>
>> It's a term I picked up from of_clk_detect_critical()
>>
>> ?* Do not use this function. It exists only for legacy Device Tree
>> ?* bindings, such as the one-clock-per-node style that are outdated.
>> ?* Those bindings typically put all clock data into .dts and the Linux
>> ?* driver has no clock data, thus making it impossible to set this flag
>> ?* correctly from the driver. Only those drivers may call
>> ?* of_clk_detect_critical from their setup functions.
>
> Okay, I still don't understand the outdated style. I looked at clocks
> defined in arch/arm/boot/dts/stih407-clock.dtsi which is the only file
> that uses clock-critical and don't particularly see anything wrong with
> the way clocks are defined there.
>
> Anyway, I guess we digress. As long as this patch series is not using
> the "legacy style", we are good :)
>
>>>> have a slightly different PLL register layout and a number of quirks
>>>> that
>>>> can't be handled by the existing bindings, so the keystone bindings
>>>> could
>>>> not be used as-is anyway.
>>>
>>> Right, I think different register layout between the processors is the
>>> main reason for a new driver. This should be sufficient reason IMO.
>>>
>>>>
>>>> Signed-off-by: David Lechner <david@lechnology.com>
>>>> ---
>>>> ? .../devicetree/bindings/clock/ti/davinci/pll.txt?? | 47
>>>> ++++++++++++++++++++++
>>>> ? 1 file changed, 47 insertions(+)
>>>> ? create mode 100644
>>>> Documentation/devicetree/bindings/clock/ti/davinci/pll.txt
>>>>
>>>> diff --git
>>>> a/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt
>>>> b/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt
>>>> new file mode 100644
>>>> index 0000000..99bf5da
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt
>>>> @@ -0,0 +1,47 @@
>>>> +Binding for TI DaVinci PLL Controllers
>>>> +
>>>> +The PLL provides clocks to most of the components on the SoC. In
>>>> addition
>>>> +to the PLL itself, this controller also contains bypasses, gates,
>>>> dividers,
>>>> +an multiplexers for various clock signals.
>>>> +
>>>> +Required properties:
>>>> +- compatible: shall be one of:
>>>> +??? - "ti,da850-pll0" for PLL0 on DA850/OMAP-L138/AM18XX
>>>> +??? - "ti,da850-pll1" for PLL1 on DA850/OMAP-L138/AM18XX
>>>
>>> These PLLs are same IP so they should use the same compatible. You can
>>> initialize both PLLs for DA850 based on the same compatible.
>>>
>>
>> But they are not exactly the same. For example, PLL0 has 7 PLLDIV clocks
>> while
>> PLL1 only has 3. PLL0 has PREDIV while PLL1 does not. PLL0 has certain
>> SYSCLKs
>> that are fixed-ratio but PLL1 does not have any of these. There are even
>> more
>> differences, but these are the ones we are actually using.
>
> We need each element of the PLLC to be modeled individually as a clock
> node.
I gave this a good think while I have been working on this series
and I came to the conclusion that we really don't need to do this.
These components are all internal to the PLL IP block, so the
compatible string is enough to tell us what we have. They only
thing we need really in the device tree bindings are the connections
that are external to the IP block.
> That is, PLL should only model the multiplier, the dividers
> including post and prediv should be modeled as divider clocks (hopefully
> being able to use the clk-divider.c library). The sysclks can be
> fixed-factor-clock type clocks.
>
> Without this flexible mechanism, we cannot (at least later) model things
> like DIV4.5 clock which is the only clock which derives from the output
> of PLL multiplier before the post divider is applied.
>
> Since with DT there are are no retakes, we need to get this right the
> first time and modifying later will not be an option.
>
So, the full device tree binding would look something like this:
+
+ pll0: clock-controller at 11000 {
+ compatible = "ti,da850-pll0";
+ reg = <0x11000 0x1000>;
+ clocks = <&ref_clk>, <&pll1_sysclk 3>, <&pll1_obsclk>;
+ clock-names = "oscin", pll1_sysclk3", "pll1_osbclk";
+ oscin-square-wave;
+
+ pll0_sysclk: sysclk {
+ #clock-cells = <1>;
+ };
+
+ pll0_auxclk: auxclk {
+ #clock-cells = <0>;
+ };
+
+ pll0_div45: div4.5 {
+ #clock-cells = <0>;
+ };
+
+ pll0_obsclk: obsclk {
+ #clock-cells = <0>;
+ assigned-clocks = <&pll0_sysclk 1>;
+ assigned-clock-names = "ocsrc";
+ };
+ };
There are three clocks coming into the IP block and there are 11 clocks
going out (sysclk is 7 clocks). And you can specify the board-specific
configuration, like having the "oscin-square-wave" flag when a square wave
is used instead of a crystal oscillator and you can assign the multiplexer
input that will be used by obsclk. (And, this binding is totally compatible
with the binding I have already proposed - although, I see now it would
be better to go ahead and add the clocks-names property.)
How everything connects together is all implemented in the driver and the
driver will be able to know what to do just by looking at the compatible
string.
Part of my motivation for doing things this way comes from my recent
experience with writing some bindings for some LCD panels. These
device tree bindings were notorious for trying to be one-size-fits
all will lots of properties to try to describe all of the internal
workings. And it turns out that just having a new compatible string
for each device or variant and pushing all of details of the quirks
into the driver is much simpler and cleaner and will make it easier
for other projects to reuse the bindings.
^ permalink raw reply
* [PATCH 0/2] pinctrl: meson: use one uniform 'function' name
From: Yixun Lan @ 2018-01-10 2:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515401544.5048.67.camel@baylibre.com>
On 01/08/18 16:52, Jerome Brunet wrote:
> On Mon, 2018-01-08 at 15:33 +0800, Yixun Lan wrote:
>> These two patches are general improvement for meson pinctrl driver.
>> It make the two pinctrl trees (ee/ao) to share one uniform 'function' name for
>> one hardware block even its pin groups live inside two differet hardware domains,
>> which for example EE vs AO domain here.
>>
>> This idea is motivated by Martin's question at [1]
>>
>> [1]
>> http://lkml.kernel.org/r/CAFBinCCuQ-NK747+GHDkhZty_UMMgzCYOYFcNTrRDJgU8OM=Gw at mail.gmail.com
>>
>>
>> Yixun Lan (2):
>> pinctrl: meson: introduce a macro to have name/groups seperated
>> pinctrl: meson-axg: correct the pin expansion of UART_AO_B
>>
>> drivers/pinctrl/meson/pinctrl-meson-axg.c | 4 ++--
>> drivers/pinctrl/meson/pinctrl-meson.h | 8 +++++---
>> 2 files changed, 7 insertions(+), 5 deletions(-)
>
> Hi Yixun,
>
> Honestly, I don't like the idea. I think it adds an unnecessary complexity.
> I don't see the point of FUNCTION_EX(uart_ao_b, _z) when you could simply write
> FUNCTION(uart_ao_b_z) ... especially when there is just a couple of function per
> SoC available on different domains.
>
> A pinctrl driver can already be challenging to understand at first, let's keep
> it simple and avoid adding more macros.
>
Hi Jerome?
In my opinion, the idea of keeping one uniform 'function' in DT (thus
introducing another macro) is worth considering. It would make the DT
part much clean.
And yes, it's a trade-off here, either we 1) do more in code to make
DT clean or 2) do nothing in the code level to make DT live with it.
Yixun
^ permalink raw reply
* [PATCH 3/3] pinctrl: qcom: Don't allow protected pins to be requested
From: Stephen Boyd @ 2018-01-10 1:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110015848.11480-1-sboyd@codeaurora.org>
Some qcom platforms make some GPIOs or pins unavailable for use
by non-secure operating systems, and thus reading or writing the
registers for those pins will cause access control issues and
reset the device. With a DT/ACPI property to describe the set of
pins that are available for use, parse the available pins and set
the irq valid bits for gpiolib to know what to consider 'valid'.
This should avoid any issues with gpiolib. Furthermore, implement
the pinmux_ops::request function so that pinmux can also make
sure to not use pins that are unavailable.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
drivers/pinctrl/qcom/pinctrl-msm.c | 98 ++++++++++++++++++++++++++++++++++++--
1 file changed, 94 insertions(+), 4 deletions(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 7a960590ecaa..4a251268ebc4 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -105,6 +105,17 @@ static const struct pinctrl_ops msm_pinctrl_ops = {
.dt_free_map = pinctrl_utils_free_map,
};
+static int msm_pinmux_request(struct pinctrl_dev *pctldev, unsigned offset)
+{
+ struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct gpio_chip *chip = &pctrl->chip;
+
+ if (gpiochip_irqchip_irq_valid(chip, offset))
+ return 0;
+
+ return -EINVAL;
+}
+
static int msm_get_functions_count(struct pinctrl_dev *pctldev)
{
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -166,6 +177,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
}
static const struct pinmux_ops msm_pinmux_ops = {
+ .request = msm_pinmux_request,
.get_functions_count = msm_get_functions_count,
.get_function_name = msm_get_function_name,
.get_function_groups = msm_get_function_groups,
@@ -506,6 +518,9 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
"pull up"
};
+ if (!gpiochip_irqchip_irq_valid(chip, offset))
+ return;
+
g = &pctrl->soc->groups[offset];
ctl_reg = readl(pctrl->regs + g->ctl_reg);
@@ -516,7 +531,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
seq_printf(s, " %dmA", msm_regval_to_drive(drive));
- seq_printf(s, " %s", pulls[pull]);
+ seq_printf(s, " %s\n", pulls[pull]);
}
static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
@@ -524,10 +539,8 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
unsigned gpio = chip->base;
unsigned i;
- for (i = 0; i < chip->ngpio; i++, gpio++) {
+ for (i = 0; i < chip->ngpio; i++, gpio++)
msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
- seq_puts(s, "\n");
- }
}
#else
@@ -808,6 +821,76 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+static int msm_gpio_init_irq_valid_mask(struct gpio_chip *chip,
+ struct msm_pinctrl *pctrl)
+{
+ int ret;
+ unsigned int len, i;
+ unsigned int max_gpios = pctrl->soc->ngpios;
+ struct device_node *np = pctrl->dev->of_node;
+
+ /* The number of GPIOs in the ACPI tables */
+ ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
+ if (ret > 0 && ret < max_gpios) {
+ u16 *tmp;
+
+ len = ret;
+ tmp = kmalloc_array(len, sizeof(tmp[0]), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp,
+ len);
+ if (ret < 0) {
+ dev_err(pctrl->dev, "could not read list of GPIOs\n");
+ kfree(tmp);
+ return ret;
+ }
+
+ bitmap_zero(chip->irq_valid_mask, max_gpios);
+ for (i = 0; i < len; i++)
+ set_bit(tmp[i], chip->irq_valid_mask);
+
+ return 0;
+ }
+
+ /* If there's a DT ngpios-ranges property then add those ranges */
+ ret = of_property_count_u32_elems(np, "ngpios-ranges");
+ if (ret > 0 && ret % 2 == 0 && ret / 2 < max_gpios) {
+ u32 start;
+ u32 count;
+
+ len = ret / 2;
+ bitmap_zero(chip->irq_valid_mask, max_gpios);
+
+ for (i = 0; i < len; i++) {
+ of_property_read_u32_index(np, "ngpios-ranges",
+ i * 2, &start);
+ of_property_read_u32_index(np, "ngpios-ranges",
+ i * 2 + 1, &count);
+ bitmap_set(chip->irq_valid_mask, start, count);
+ }
+ }
+
+ return 0;
+}
+
+static bool msm_gpio_needs_irq_valid_mask(struct msm_pinctrl *pctrl)
+{
+ int ret;
+ struct device_node *np = pctrl->dev->of_node;
+
+ ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
+ if (ret > 0)
+ return true;
+
+ ret = of_property_count_u32_elems(np, "ngpios-ranges");
+ if (ret > 0 && ret % 2 == 0)
+ return true;
+
+ return false;
+}
+
static int msm_gpio_init(struct msm_pinctrl *pctrl)
{
struct gpio_chip *chip;
@@ -824,6 +907,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
chip->parent = pctrl->dev;
chip->owner = THIS_MODULE;
chip->of_node = pctrl->dev->of_node;
+ chip->irq_need_valid_mask = msm_gpio_needs_irq_valid_mask(pctrl);
ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
@@ -831,6 +915,12 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
return ret;
}
+ ret = msm_gpio_init_irq_valid_mask(chip, pctrl);
+ if (ret) {
+ dev_err(pctrl->dev, "Failed to setup irq valid bits\n");
+ return ret;
+ }
+
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
if (ret) {
dev_err(pctrl->dev, "Failed to add pin range\n");
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* [PATCH 2/3] dt-bindings: pinctrl: Add a ngpios-ranges property
From: Stephen Boyd @ 2018-01-10 1:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110015848.11480-1-sboyd@codeaurora.org>
Some qcom platforms make some GPIOs or pins unavailable for use
by non-secure operating systems, and thus reading or writing the
registers for those pins will cause access control issues.
Introduce a DT property to describe the set of GPIOs that are
available for use so that higher level OSes are able to know what
pins to avoid reading/writing.
Cc: <devicetree@vger.kernel.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
I stuck this inside msm8996, but maybe it can go somewhere more generic?
Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt
index aaf01e929eea..8354ab270486 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt
@@ -40,6 +40,12 @@ MSM8996 platform.
Definition: must be 2. Specifying the pin number and flags, as defined
in <dt-bindings/gpio/gpio.h>
+- ngpios-ranges:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Tuples of GPIO ranges (base, size) indicating
+ GPIOs available for use.
+
Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
a general description of GPIO and interrupt bindings.
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* [PATCH 1/3] gpiolib: Export gpiochip_irqchip_irq_valid() to drivers
From: Stephen Boyd @ 2018-01-10 1:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110015848.11480-1-sboyd@codeaurora.org>
Some pinctrl drivers can use the gpiochip irq valid information
to figure out if certain gpios are exposed to the kernel for
usage or not. Expose this API so we can use it in the
pinmux_ops::request ops.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
drivers/gpio/gpiolib.c | 5 +++--
include/linux/gpio/driver.h | 3 +++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b80936a25caa..c18b7b60ea1d 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1503,14 +1503,15 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
gpiochip->irq.valid_mask = NULL;
}
-static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
- unsigned int offset)
+bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
+ unsigned int offset)
{
/* No mask means all valid */
if (likely(!gpiochip->irq.valid_mask))
return true;
return test_bit(offset, gpiochip->irq.valid_mask);
}
+EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
/**
* gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 7258cd676df4..1ba9a331ec51 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -436,6 +436,9 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
struct lock_class_key *lock_key,
struct lock_class_key *request_key);
+bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
+ unsigned int offset);
+
#ifdef CONFIG_LOCKDEP
/*
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* [PATCH 0/3] Support qcom pinctrl protected pins
From: Stephen Boyd @ 2018-01-10 1:58 UTC (permalink / raw)
To: linux-arm-kernel
This patchset proposes a solution to describing the valid
pins for a pin controller in a semi-generic way so that qcom
platforms can expose the pins that are really available.
Typically, this has been done by having drivers and firmware
descriptions only use pins they know they have access to, and that
still works now because we no longer read the pin direction at
boot. But there are still some userspace drivers and debugfs facilities
that don't know what pins are available and attempt to read everything
they can. On qcom platforms, this may lead to a system hang, which isn't
very nice behavior, even if root is the only user that can trigger it.
The proposal is to describe the valid pins and then not allow things to
cause problems by using the invalid pins. Obviously, the firmware may
mess this up, so this is mostly a nice to have feature or a safety net
so that things don't blow up easily.
Stephen Boyd (3):
gpiolib: Export gpiochip_irqchip_irq_valid() to drivers
dt-bindings: pinctrl: Add a ngpios-ranges property
pinctrl: qcom: Don't allow protected pins to be requested
.../bindings/pinctrl/qcom,msm8996-pinctrl.txt | 6 ++
drivers/gpio/gpiolib.c | 5 +-
drivers/pinctrl/qcom/pinctrl-msm.c | 98 +++++++++++++++++++++-
include/linux/gpio/driver.h | 3 +
4 files changed, 106 insertions(+), 6 deletions(-)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH 2/2] MAINTAINERS: mtd/nand: update Microchip nand entry
From: Yang, Wenyou @ 2018-01-10 1:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d8a6b8a3fe05c57972de1c374fcdeb933717396b.1515503733.git.nicolas.ferre@microchip.com>
On 2018/1/9 21:46, Nicolas Ferre wrote:
> Update Wenyou Yang email address.
> Take advantage of this update to move this entry to the MICROCHIP / ATMEL
> location and add the DT binding documentation link.
>
> Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Acked-by: Wenyou Yang <wenyou.yang@microchip.com>
> ---
> Hi,
>
> Patch against next-20180109.
> This patch is somehow dependent on the previous one in the series
> ("MAINTAINERS: linux-media: update Microchip ISI and ISC entries") but can be
> rebased easily.
>
> I don't know if it's better to have them added at the end of the development
> cycle or just after rc1: let me know if you plan to take them or if I need to
> rebase them for next cycle.
>
> Best regards,
> Nicolas
>
>
> MAINTAINERS | 15 ++++++++-------
> 1 file changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 65c4b59b582f..b48e217d41fb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2373,13 +2373,6 @@ F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt
> F: drivers/input/touchscreen/atmel_mxt_ts.c
> F: include/linux/platform_data/atmel_mxt_ts.h
>
> -ATMEL NAND DRIVER
> -M: Wenyou Yang <wenyou.yang@atmel.com>
> -M: Josh Wu <rainyfeeling@outlook.com>
> -L: linux-mtd at lists.infradead.org
> -S: Supported
> -F: drivers/mtd/nand/atmel/*
> -
> ATMEL SAMA5D2 ADC DRIVER
> M: Ludovic Desroches <ludovic.desroches@microchip.com>
> L: linux-iio at vger.kernel.org
> @@ -9110,6 +9103,14 @@ F: drivers/media/platform/atmel/atmel-isi.c
> F: include/media/atmel-isi.h
> F: Documentation/devicetree/bindings/media/atmel-isi.txt
>
> +MICROCHIP / ATMEL NAND DRIVER
> +M: Wenyou Yang <wenyou.yang@microchip.com>
> +M: Josh Wu <rainyfeeling@outlook.com>
> +L: linux-mtd at lists.infradead.org
> +S: Supported
> +F: drivers/mtd/nand/atmel/*
> +F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
> +
> MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
> M: Woojung Huh <Woojung.Huh@microchip.com>
> M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
Best Regards,
Wenyou Yang
^ permalink raw reply
* [PATCH 1/2] MAINTAINERS: linux-media: update Microchip ISI and ISC entries
From: Yang, Wenyou @ 2018-01-10 1:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <eb6b3cbe8e48faee7e88eca0649e42cbde91ffa6.1515503733.git.nicolas.ferre@microchip.com>
On 2018/1/9 21:46, Nicolas Ferre wrote:
> These two image capture interface drivers are now handled
> by Wenyou Yang.
> I benefit from this change to update the two entries by correcting the
> binding documentation link for ISC and moving the ISI to the new
> MICROCHIP / ATMEL location.
>
> Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Acked-by: Wenyou Yang <wenyou.yang@microchip.com>
> ---
> Hi,
>
> Patch against next-20180109.
> Note that I didn't find it useful to have several patches for these changes.
> Tell me if you feel differently.
>
> I would like to have the Ack from Ludovic and Wenyou obviously. I don't know if
> Songjun can answer as he's not with Microchip anymore.
>
> Best regards,
> Nicolas
>
> MAINTAINERS | 19 ++++++++++---------
> 1 file changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a7d10a2bb980..65c4b59b582f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2353,13 +2353,6 @@ L: linux-i2c at vger.kernel.org
> S: Supported
> F: drivers/i2c/busses/i2c-at91.c
>
> -ATMEL ISI DRIVER
> -M: Ludovic Desroches <ludovic.desroches@microchip.com>
> -L: linux-media at vger.kernel.org
> -S: Supported
> -F: drivers/media/platform/atmel/atmel-isi.c
> -F: include/media/atmel-isi.h
> -
> ATMEL LCDFB DRIVER
> M: Nicolas Ferre <nicolas.ferre@microchip.com>
> L: linux-fbdev at vger.kernel.org
> @@ -9102,12 +9095,20 @@ S: Maintained
> F: drivers/crypto/atmel-ecc.*
>
> MICROCHIP / ATMEL ISC DRIVER
> -M: Songjun Wu <songjun.wu@microchip.com>
> +M: Wenyou Yang <wenyou.yang@microchip.com>
> L: linux-media at vger.kernel.org
> S: Supported
> F: drivers/media/platform/atmel/atmel-isc.c
> F: drivers/media/platform/atmel/atmel-isc-regs.h
> -F: devicetree/bindings/media/atmel-isc.txt
> +F: Documentation/devicetree/bindings/media/atmel-isc.txt
> +
> +MICROCHIP / ATMEL ISI DRIVER
> +M: Wenyou Yang <wenyou.yang@microchip.com>
> +L: linux-media at vger.kernel.org
> +S: Supported
> +F: drivers/media/platform/atmel/atmel-isi.c
> +F: include/media/atmel-isi.h
> +F: Documentation/devicetree/bindings/media/atmel-isi.txt
>
> MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
> M: Woojung Huh <Woojung.Huh@microchip.com>
Best Regards,
Wenyou Yang
^ permalink raw reply
* [PATCH 3/9] soc: samsung: pmu: Add the PMU data of exynos5433 to support low-power state
From: Chanwoo Choi @ 2018-01-10 1:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <b639da18-a069-aeb7-ceca-30c79b1c25c8@arm.com>
On 2018? 01? 09? 23:11, Sudeep Holla wrote:
>
>
> On 09/01/18 07:59, Chanwoo Choi wrote:
>> This patch adds the PMU (Power Management Unit) data of exynos5433 SoC
>> in order to support the various power modes. Each power mode has
>> the different value for reducing the power-consumption.
>>
>> Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
>> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
>> ---
>> arch/arm/mach-exynos/common.h | 2 -
>> drivers/soc/samsung/Makefile | 3 +-
>> drivers/soc/samsung/exynos-pmu.c | 1 +
>> drivers/soc/samsung/exynos-pmu.h | 2 +
>> drivers/soc/samsung/exynos5433-pmu.c | 286 ++++++++++++++++++++++++++++
>> include/linux/soc/samsung/exynos-regs-pmu.h | 148 ++++++++++++++
>> 6 files changed, 439 insertions(+), 3 deletions(-)
>> create mode 100644 drivers/soc/samsung/exynos5433-pmu.c
>>
>
>> diff --git a/drivers/soc/samsung/exynos5433-pmu.c b/drivers/soc/samsung/exynos5433-pmu.c
>> new file mode 100644
>> index 000000000000..2571e61522f0
>> --- /dev/null
>> +++ b/drivers/soc/samsung/exynos5433-pmu.c
>> @@ -0,0 +1,286 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +//
>> +// Copyright (c) 2018 Samsung Electronics Co., Ltd.
>> +// Copyright (c) Jonghwa Lee <jonghwa3.lee@samsung.com>
>> +// Copyright (c) Chanwoo Choi <cw00.choi@samsung.com>
>> +//
>> +// EXYNOS5433 - CPU PMU (Power Management Unit) support
>> +
>> +#include <linux/soc/samsung/exynos-regs-pmu.h>
>> +#include <linux/soc/samsung/exynos-pmu.h>
>> +
>> +#include "exynos-pmu.h"
>> +
>> +static struct exynos_pmu_conf exynos5433_pmu_config[] = {
>> + /* { .offset = address, .val = { AFTR, LPA, SLEEP } } */
>> + { EXYNOS5433_ATLAS_CPU0_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_ATLAS_CPU0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_ATLAS_CPU1_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_ATLAS_CPU1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_ATLAS_CPU2_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_ATLAS_CPU2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_ATLAS_CPU3_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_ATLAS_CPU3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_APOLLO_CPU0_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_APOLLO_CPU0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_APOLLO_CPU1_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_APOLLO_CPU1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_APOLLO_CPU2_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_APOLLO_CPU2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_APOLLO_CPU3_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_DIS_IRQ_APOLLO_CPU3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0 } },
>> + { EXYNOS5433_ATLAS_NONCPU_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>> + { EXYNOS5433_APOLLO_NONCPU_SYS_PWR_REG, { 0x0, 0x0, 0x8 } },
>
>
> 1. First of all why do you need any of these CPU related PMU config
> registers in kernel ? From the information I gathered this is ARM64
> SoC using PSCI. These are needed just in PSCI implementation and not
> in kernel. So can you elaborate on why there are present here ?
The 32bit Exynos used the 'smc' call to enter the suspend mode
and need to handle the PMU registers.
Even if PSCI replaces the 'smc' call on the Exynos5433,
the Exynos5433's document requires the handling of PMU config
related to CPU for the suspend mode.
IMHO, If the secure OS implemented the all something related to CPU,
it might be unnecessary to handle the PMU registers. I think that
it depend on how to design the SoC by H/W Architect. This is just my opinion.
>
> 2. Are there any public documents that these names map to ?
There is no public document. It is confidential.
> If there is none, please replace these codenames(ATLAS, APOLLO) with
> appropriately.
In the Exynos5433, 'apollo' indicates the LITTLE cores (cpu0-3, cortex-a53)
and 'atlas' indicates the big cores (cpu4-7, cortex-a57)
Exynos5433 already used the 'apollo' and 'atlas' on clk-exynos5433.c driver
and thermal device-tree node. It is better to use the original register name
in the document in order to reduce the confusion of the change of register name
even if document is not public.
Also, exynos7 used the 'atlas' word for big cores.
>
> Sorry if these are already answered, just point me to those threads.
>
--
Best Regards,
Chanwoo Choi
Samsung Electronics
^ permalink raw reply
* [PATCH v2 4/6] arm: Add icache invalidation on switch_mm for Cortex-A15
From: Florian Fainelli @ 2018-01-10 1:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3ab22cbc-76a2-01c6-d016-61bc874cd003@arm.com>
On 01/09/2018 05:33 PM, Andr? Przywara wrote:
> On 10/01/18 01:28, Florian Fainelli wrote:
>> On 01/08/2018 10:55 AM, Marc Zyngier wrote:
>>> In order to avoid aliasing attacks against the branch predictor,
>>> Cortex-A15 require to invalidate the BTB when switching
>>> from one user context to another. The only way to do so on this
>>> CPU is to perform an ICIALLU, having set ACTLR[0] to 1 from secure
>>> mode.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> ---
>>
>> [snip]
>>
>>> diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
>>> index f6adfe88ead2..0a2245b309e5 100644
>>> --- a/arch/arm/mm/proc-v7-3level.S
>>> +++ b/arch/arm/mm/proc-v7-3level.S
>>> @@ -71,6 +71,22 @@ ENTRY(cpu_v7_switch_mm)
>>> ENDPROC(cpu_v7_switch_mm)
>>> ENDPROC(cpu_v7_btbinv_switch_mm)
>>>
>>> +/*
>>> + * Cortex-A15 requires ACTLR[0] to be set from secure in order
>>> + * for the icache invalidation to also invalidate the BTB.
>>
>> Considering that writes are ignored when we don't have the correct
>> permission level, how about set try to set this bit from the
>> __v7_ca15mp_setup and __v7_b15mp_setup labels just like we are setting
>> the SMP_EN bit for the poor bastards out there stuck with possibly
>> frozen bootloaders/ATF?
>
> Even when writes to ACTLR are allowed by secure world, this only
> actually applies to the SMP bit:
> ARM DDI0438H ARM Cortex-A15 TRM, 4.3.28 Auxiliary Control Register:
> "-- Read/write in Non-secure PL1 and PL2 modes if NSACR.NS_SMP is 1. In
> this case, all bits are write-ignored except for the SMP bit."
>
> So: good idea, but no luck here :-(
Looks like I failed basic reading exercise here, thanks ;)
--
Florian
^ permalink raw reply
* [PATCH v2 4/6] arm: Add icache invalidation on switch_mm for Cortex-A15
From: André Przywara @ 2018-01-10 1:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <a11193e5-0f0b-3280-e2b2-c0665676d230@gmail.com>
On 10/01/18 01:28, Florian Fainelli wrote:
> On 01/08/2018 10:55 AM, Marc Zyngier wrote:
>> In order to avoid aliasing attacks against the branch predictor,
>> Cortex-A15 require to invalidate the BTB when switching
>> from one user context to another. The only way to do so on this
>> CPU is to perform an ICIALLU, having set ACTLR[0] to 1 from secure
>> mode.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>
> [snip]
>
>> diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
>> index f6adfe88ead2..0a2245b309e5 100644
>> --- a/arch/arm/mm/proc-v7-3level.S
>> +++ b/arch/arm/mm/proc-v7-3level.S
>> @@ -71,6 +71,22 @@ ENTRY(cpu_v7_switch_mm)
>> ENDPROC(cpu_v7_switch_mm)
>> ENDPROC(cpu_v7_btbinv_switch_mm)
>>
>> +/*
>> + * Cortex-A15 requires ACTLR[0] to be set from secure in order
>> + * for the icache invalidation to also invalidate the BTB.
>
> Considering that writes are ignored when we don't have the correct
> permission level, how about set try to set this bit from the
> __v7_ca15mp_setup and __v7_b15mp_setup labels just like we are setting
> the SMP_EN bit for the poor bastards out there stuck with possibly
> frozen bootloaders/ATF?
Even when writes to ACTLR are allowed by secure world, this only
actually applies to the SMP bit:
ARM DDI0438H ARM Cortex-A15 TRM, 4.3.28 Auxiliary Control Register:
"-- Read/write in Non-secure PL1 and PL2 modes if NSACR.NS_SMP is 1. In
this case, all bits are write-ignored except for the SMP bit."
So: good idea, but no luck here :-(
Cheers,
Andre.
^ permalink raw reply
* [PATCH v2 4/6] arm: Add icache invalidation on switch_mm for Cortex-A15
From: Florian Fainelli @ 2018-01-10 1:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180108185533.9698-5-marc.zyngier@arm.com>
On 01/08/2018 10:55 AM, Marc Zyngier wrote:
> In order to avoid aliasing attacks against the branch predictor,
> Cortex-A15 require to invalidate the BTB when switching
> from one user context to another. The only way to do so on this
> CPU is to perform an ICIALLU, having set ACTLR[0] to 1 from secure
> mode.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
[snip]
> diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
> index f6adfe88ead2..0a2245b309e5 100644
> --- a/arch/arm/mm/proc-v7-3level.S
> +++ b/arch/arm/mm/proc-v7-3level.S
> @@ -71,6 +71,22 @@ ENTRY(cpu_v7_switch_mm)
> ENDPROC(cpu_v7_switch_mm)
> ENDPROC(cpu_v7_btbinv_switch_mm)
>
> +/*
> + * Cortex-A15 requires ACTLR[0] to be set from secure in order
> + * for the icache invalidation to also invalidate the BTB.
Considering that writes are ignored when we don't have the correct
permission level, how about set try to set this bit from the
__v7_ca15mp_setup and __v7_b15mp_setup labels just like we are setting
the SMP_EN bit for the poor bastards out there stuck with possibly
frozen bootloaders/ATF?
--
Florian
^ permalink raw reply
* [PATCH v3 2/2] dt-bindings: mailbox: Add Xilinx IPI Mailbox
From: Jiaying Liang @ 2018-01-10 1:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABb+yY00n6fLiQXftj-TMhT6q=KopZMkLYr6DpYE8CvxH-gz8Q@mail.gmail.com>
> -----Original Message-----
> From: Jassi Brar [mailto:jassisinghbrar at gmail.com]
> Sent: Tuesday, January 09, 2018 12:00 AM
> To: Jiaying Liang <jliang@xilinx.com>
> Cc: Michal Simek <michal.simek@xilinx.com>; Rob Herring
> <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>; linux-arm-
> kernel at lists.infradead.org; Devicetree List <devicetree@vger.kernel.org>;
> Linux Kernel Mailing List <linux-kernel@vger.kernel.org>; Jiaying Liang
> <jliang@xilinx.com>
> Subject: Re: [PATCH v3 2/2] dt-bindings: mailbox: Add Xilinx IPI Mailbox
>
> On Fri, Jan 5, 2018 at 5:21 AM, Wendy Liang <wendy.liang@xilinx.com> wrote:
> > Xilinx ZynqMP IPI(Inter Processor Interrupt) is a hardware block in
> > ZynqMP SoC used for the communication between various processor
> > systems.
> >
> > Signed-off-by: Wendy Liang <jliang@xilinx.com>
> > ---
> > .../bindings/mailbox/xlnx,zynqmp-ipi-mailbox.txt | 104
> +++++++++++++++++++++
> > 1 file changed, 104 insertions(+)
> > create mode 100644
> > Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.txt
> >
> > diff --git
> > a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.tx
> > t
> > b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-
> mailbox.tx
> > t
> > new file mode 100644
> > index 0000000..5e270a3
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-
> mailbo
> > +++ x.txt
> > @@ -0,0 +1,104 @@
> > +Xilinx IPI Mailbox Controller
> > +========================================
> > +
> > +The Xilinx IPI(Inter Processor Interrupt) mailbox controller is to
> > +manage messaging between two Xilinx Zynq UltraScale+ MPSoC IPI
> > +agents. Each IPI agent owns registers used for notification and buffers for
> message.
> > +
> > + +-------------------------------------+
> > + | Xilinx ZynqMP IPI Controller |
> > + +-------------------------------------+
> > + +--------------------------------------------------+
> > +ATF | |
> > + | |
> > + | |
> > + +--------------------------+ |
> > + | |
> > + | |
> > + +--------------------------------------------------+
> > + +------------------------------------------+
> > + | +----------------+ +----------------+ |
> > +Hardware | | IPI Agent | | IPI Buffers | |
> > + | | Registers | | | |
> > + | | | | | |
> > + | +----------------+ +----------------+ |
> > + | |
> > + | Xilinx IPI Agent Block |
> > + +------------------------------------------+
> > +
> > +
> > +Controller Device Node:
> > +===========================
> > +Required properties:
> > +--------------------
> > +- compatible: Shall be: "xlnx,zynqmp-ipi-mailbox"
> > +- reg: IPI buffers address ranges
> > +- reg-names: Names of the reg resources. It should have:
> > + * local_request_region
> > + - IPI request msg buffer written by local and read
> > + by remote
> > + * local_response_region
> > + - IPI response msg buffer written by local and read
> > + by remote
> > + * remote_request_region
> > + - IPI request msg buffer written by remote and read
> > + by local
> > + * remote_response_region
> > + - IPI response msg buffer written by remote and read
> > + by local
> >
> shmem is option and external to the controller. It should be passed via
> client's binding.
> Please have a look at Sudeep's proposed patch
> https://www.spinics.net/lists/arm-kernel/msg626120.html
[Wendy] thanks for the link, but those 'buffers" are registers in the hardware
but not memory. It looks like a bit hacky to access them as memory.
>
> > +- #mbox-cells: Shall be 1. It contains:
> > + * tx(0) or rx(1) channel
> > +- xlnx,ipi-ids: Xilinx IPI agent IDs of the two peers of the
> > + Xilinx IPI communication channel.
> > +- interrupt-parent: Phandle for the interrupt controller
> > +- interrupts: Interrupt information corresponding to the
> > + interrupt-names property.
> > +
> > +Optional properties:
> > +--------------------
> > +- method: The method of accessing the IPI agent registers.
> > + Permitted values are: "smc" and "hvc". Default is
> > + "smc".
> > +
> Andre almost implemented the generic driver. Can you please have a look at
> https://www.spinics.net/lists/arm-kernel/msg595416.html
> and see if you can just finish it off?
[Wendy] This mailbox controller is about to use Xilinx IPI hardware as mailbox.
We use it to send notification/short request to firmware (usually running on
another core on SoC), and also to receive notification/short request from firmware.
Interrupt is used in the receiving direction. It looks different to the usage of
mailbox driver from the link. Is there a plan to extend the ARM SMC mailbox driver
to both trigger firmware actions and receive request from firmware?
Thanks,
Wendy
>
> Thanks
^ permalink raw reply
* [PATCH v2 1/7] PCI: aardvark: fix logic in PCI configuration read/write functions
From: Bjorn Helgaas @ 2018-01-10 1:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180109174918.5c4b9ee6@windsurf.lan>
[+cc Lorenzo, since he takes care of this now]
On Tue, Jan 09, 2018 at 05:49:18PM +0100, Thomas Petazzoni wrote:
> Hello Bjorn,
>
> Again, reviving this very old thread :-)
>
> On Thu, 5 Oct 2017 12:23:30 -0500, Bjorn Helgaas wrote:
>
> > > - if (PCI_SLOT(devfn) != 0) {
> > > + if ((bus->number == pcie->root_bus_nr) && (PCI_SLOT(devfn) != 0)) {
> >
> > I'm fine with this, but please take a look at these:
> >
> > 8e7ca8ca5fd8 PCI: xilinx: Relax device number checking to allow SR-IOV
> > e18934b5e9c7 PCI: designware: Relax device number checking to allow SR-IOV
> > d99e30b7936a PCI: altera: Relax device number checking to allow SR-IOV
> >
> > and make sure that reasoning doesn't apply here, too.
> >
> > http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=8e7ca8ca5fd8
> > http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=e18934b5e9c7
> > http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d99e30b7936a
>
> The original code for xilinx/designware/altera was doing:
>
> if (bus->number == port->root_busno && devfn > 0)
> return false;
>
> if (bus->primary == port->root_busno && devfn > 0)
> return false;
>
> I.e, it was checking both if bus->number *and* bus->primary were equal
> to port->root_busno.
>
> The commit you points removed the check on bus->primary, keeping the
> check on bus->number.
>
> Your patch for the Aadvark driver only adds a check on bus->number, i.e
> exactly what the xilinx/designware/altera code is still doing today:
This is a long time ago and I could have forgotten, but I don't think
this is *my* patch, is it?
> Altera:
>
> /* access only one slot on each root port */
> if (bus->number == pcie->root_bus_nr && dev > 0)
> return false;
>
> Designware:
>
> /* access only one slot on each root port */
> if (bus->number == pp->root_bus_nr && dev > 0)
> return 0;
>
> Xilinx:
>
> /* Only one device down on each root port */
> if (bus->number == port->root_busno && devfn > 0)
> return false;
>
> Aardvark (with our patch):
>
> if ((bus->number == pcie->root_bus_nr) && (PCI_SLOT(devfn) != 0)) {
> *val = 0xffffffff;
> return PCIBIOS_DEVICE_NOT_FOUND;
> }
>
> So we're doing exactly the same thing.
>
> Do you agree ?
I do agree. I can't remember what I was thinking when I first
responded.
I *would* suggest making an advk_pcie_valid_device() so your structure
matches the other drivers. I know it seems trivial when you're mostly
looking at one driver, but it really helps those who pay attention to
all of them.
Bjorn
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox