163 lines
5.2 KiB
Diff
163 lines
5.2 KiB
Diff
|
From c97db7cc7778e34a53b42d58c766f0ec0e30d580 Mon Sep 17 00:00:00 2001
|
||
|
From: Arnd Bergmann <arnd@arndb.de>
|
||
|
Date: Wed, 21 Sep 2016 14:57:19 +0800
|
||
|
Subject: [PATCH] base: soc: Introduce soc_device_match() interface
|
||
|
|
||
|
We keep running into cases where device drivers want to know the exact
|
||
|
version of the a SoC they are currently running on. In the past, this has
|
||
|
usually been done through a vendor specific API that can be called by a
|
||
|
driver, or by directly accessing some kind of version register that is
|
||
|
not part of the device itself but that belongs to a global register area
|
||
|
of the chip.
|
||
|
|
||
|
Common reasons for doing this include:
|
||
|
|
||
|
- A machine is not using devicetree or similar for passing data about
|
||
|
on-chip devices, but just announces their presence using boot-time
|
||
|
platform devices, and the machine code itself does not care about the
|
||
|
revision.
|
||
|
|
||
|
- There is existing firmware or boot loaders with existing DT binaries
|
||
|
with generic compatible strings that do not identify the particular
|
||
|
revision of each device, but the driver knows which SoC revisions
|
||
|
include which part.
|
||
|
|
||
|
- A prerelease version of a chip has some quirks and we are using the same
|
||
|
version of the bootloader and the DT blob on both the prerelease and the
|
||
|
final version. An update of the DT binding seems inappropriate because
|
||
|
that would involve maintaining multiple copies of the dts and/or
|
||
|
bootloader.
|
||
|
|
||
|
This patch introduces the soc_device_match() interface that is meant to
|
||
|
work like of_match_node() but instead of identifying the version of a
|
||
|
device, it identifies the SoC itself using a vendor-agnostic interface.
|
||
|
|
||
|
Unlike of_match_node(), we do not do an exact string compare but instead
|
||
|
use glob_match() to allow wildcards in strings.
|
||
|
|
||
|
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||
|
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
|
||
|
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
|
||
|
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||
|
---
|
||
|
drivers/base/Kconfig | 1 +
|
||
|
drivers/base/soc.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
include/linux/sys_soc.h | 3 +++
|
||
|
3 files changed, 70 insertions(+)
|
||
|
|
||
|
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
|
||
|
index fdf44cac08e6..991b21e1f89b 100644
|
||
|
--- a/drivers/base/Kconfig
|
||
|
+++ b/drivers/base/Kconfig
|
||
|
@@ -235,6 +235,7 @@ config GENERIC_CPU_AUTOPROBE
|
||
|
|
||
|
config SOC_BUS
|
||
|
bool
|
||
|
+ select GLOB
|
||
|
|
||
|
source "drivers/base/regmap/Kconfig"
|
||
|
|
||
|
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
|
||
|
index 028cef377fd4..04ee597fc3a3 100644
|
||
|
--- a/drivers/base/soc.c
|
||
|
+++ b/drivers/base/soc.c
|
||
|
@@ -13,6 +13,7 @@
|
||
|
#include <linux/spinlock.h>
|
||
|
#include <linux/sys_soc.h>
|
||
|
#include <linux/err.h>
|
||
|
+#include <linux/glob.h>
|
||
|
|
||
|
static DEFINE_IDA(soc_ida);
|
||
|
|
||
|
@@ -168,3 +169,68 @@ static int __init soc_bus_register(void)
|
||
|
return bus_register(&soc_bus_type);
|
||
|
}
|
||
|
core_initcall(soc_bus_register);
|
||
|
+
|
||
|
+static int soc_device_match_one(struct device *dev, void *arg)
|
||
|
+{
|
||
|
+ struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
||
|
+ const struct soc_device_attribute *match = arg;
|
||
|
+
|
||
|
+ if (match->machine &&
|
||
|
+ !glob_match(match->machine, soc_dev->attr->machine))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (match->family &&
|
||
|
+ !glob_match(match->family, soc_dev->attr->family))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (match->revision &&
|
||
|
+ !glob_match(match->revision, soc_dev->attr->revision))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (match->soc_id &&
|
||
|
+ !glob_match(match->soc_id, soc_dev->attr->soc_id))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * soc_device_match - identify the SoC in the machine
|
||
|
+ * @matches: zero-terminated array of possible matches
|
||
|
+ *
|
||
|
+ * returns the first matching entry of the argument array, or NULL
|
||
|
+ * if none of them match.
|
||
|
+ *
|
||
|
+ * This function is meant as a helper in place of of_match_node()
|
||
|
+ * in cases where either no device tree is available or the information
|
||
|
+ * in a device node is insufficient to identify a particular variant
|
||
|
+ * by its compatible strings or other properties. For new devices,
|
||
|
+ * the DT binding should always provide unique compatible strings
|
||
|
+ * that allow the use of of_match_node() instead.
|
||
|
+ *
|
||
|
+ * The calling function can use the .data entry of the
|
||
|
+ * soc_device_attribute to pass a structure or function pointer for
|
||
|
+ * each entry.
|
||
|
+ */
|
||
|
+const struct soc_device_attribute *soc_device_match(
|
||
|
+ const struct soc_device_attribute *matches)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ if (!matches)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ while (!ret) {
|
||
|
+ if (!(matches->machine || matches->family ||
|
||
|
+ matches->revision || matches->soc_id))
|
||
|
+ break;
|
||
|
+ ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
|
||
|
+ soc_device_match_one);
|
||
|
+ if (!ret)
|
||
|
+ matches++;
|
||
|
+ else
|
||
|
+ return matches;
|
||
|
+ }
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(soc_device_match);
|
||
|
diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
|
||
|
index 2739ccb69571..9f5eb06f9fd8 100644
|
||
|
--- a/include/linux/sys_soc.h
|
||
|
+++ b/include/linux/sys_soc.h
|
||
|
@@ -13,6 +13,7 @@ struct soc_device_attribute {
|
||
|
const char *family;
|
||
|
const char *revision;
|
||
|
const char *soc_id;
|
||
|
+ const void *data;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
@@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev);
|
||
|
*/
|
||
|
struct device *soc_device_to_device(struct soc_device *soc);
|
||
|
|
||
|
+const struct soc_device_attribute *soc_device_match(
|
||
|
+ const struct soc_device_attribute *matches);
|
||
|
#endif /* __SOC_BUS_H */
|
||
|
--
|
||
|
2.11.1
|
||
|
|