brcm47xx: fix switch port mapping on Asus RT-N16
[openwrt/openwrt.git] / target / linux / layerscape / patches-4.9 / 820-base-soc-Introduce-soc_device_match-interface.patch
1 From c97db7cc7778e34a53b42d58c766f0ec0e30d580 Mon Sep 17 00:00:00 2001
2 From: Arnd Bergmann <arnd@arndb.de>
3 Date: Wed, 21 Sep 2016 14:57:19 +0800
4 Subject: [PATCH] base: soc: Introduce soc_device_match() interface
5
6 We keep running into cases where device drivers want to know the exact
7 version of the a SoC they are currently running on. In the past, this has
8 usually been done through a vendor specific API that can be called by a
9 driver, or by directly accessing some kind of version register that is
10 not part of the device itself but that belongs to a global register area
11 of the chip.
12
13 Common reasons for doing this include:
14
15 - A machine is not using devicetree or similar for passing data about
16 on-chip devices, but just announces their presence using boot-time
17 platform devices, and the machine code itself does not care about the
18 revision.
19
20 - There is existing firmware or boot loaders with existing DT binaries
21 with generic compatible strings that do not identify the particular
22 revision of each device, but the driver knows which SoC revisions
23 include which part.
24
25 - A prerelease version of a chip has some quirks and we are using the same
26 version of the bootloader and the DT blob on both the prerelease and the
27 final version. An update of the DT binding seems inappropriate because
28 that would involve maintaining multiple copies of the dts and/or
29 bootloader.
30
31 This patch introduces the soc_device_match() interface that is meant to
32 work like of_match_node() but instead of identifying the version of a
33 device, it identifies the SoC itself using a vendor-agnostic interface.
34
35 Unlike of_match_node(), we do not do an exact string compare but instead
36 use glob_match() to allow wildcards in strings.
37
38 Signed-off-by: Arnd Bergmann <arnd@arndb.de>
39 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
40 Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
41 Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
42 ---
43 drivers/base/Kconfig | 1 +
44 drivers/base/soc.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
45 include/linux/sys_soc.h | 3 +++
46 3 files changed, 70 insertions(+)
47
48 diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
49 index fdf44cac08e6..991b21e1f89b 100644
50 --- a/drivers/base/Kconfig
51 +++ b/drivers/base/Kconfig
52 @@ -235,6 +235,7 @@ config GENERIC_CPU_AUTOPROBE
53
54 config SOC_BUS
55 bool
56 + select GLOB
57
58 source "drivers/base/regmap/Kconfig"
59
60 diff --git a/drivers/base/soc.c b/drivers/base/soc.c
61 index 028cef377fd4..04ee597fc3a3 100644
62 --- a/drivers/base/soc.c
63 +++ b/drivers/base/soc.c
64 @@ -13,6 +13,7 @@
65 #include <linux/spinlock.h>
66 #include <linux/sys_soc.h>
67 #include <linux/err.h>
68 +#include <linux/glob.h>
69
70 static DEFINE_IDA(soc_ida);
71
72 @@ -168,3 +169,68 @@ static int __init soc_bus_register(void)
73 return bus_register(&soc_bus_type);
74 }
75 core_initcall(soc_bus_register);
76 +
77 +static int soc_device_match_one(struct device *dev, void *arg)
78 +{
79 + struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
80 + const struct soc_device_attribute *match = arg;
81 +
82 + if (match->machine &&
83 + !glob_match(match->machine, soc_dev->attr->machine))
84 + return 0;
85 +
86 + if (match->family &&
87 + !glob_match(match->family, soc_dev->attr->family))
88 + return 0;
89 +
90 + if (match->revision &&
91 + !glob_match(match->revision, soc_dev->attr->revision))
92 + return 0;
93 +
94 + if (match->soc_id &&
95 + !glob_match(match->soc_id, soc_dev->attr->soc_id))
96 + return 0;
97 +
98 + return 1;
99 +}
100 +
101 +/*
102 + * soc_device_match - identify the SoC in the machine
103 + * @matches: zero-terminated array of possible matches
104 + *
105 + * returns the first matching entry of the argument array, or NULL
106 + * if none of them match.
107 + *
108 + * This function is meant as a helper in place of of_match_node()
109 + * in cases where either no device tree is available or the information
110 + * in a device node is insufficient to identify a particular variant
111 + * by its compatible strings or other properties. For new devices,
112 + * the DT binding should always provide unique compatible strings
113 + * that allow the use of of_match_node() instead.
114 + *
115 + * The calling function can use the .data entry of the
116 + * soc_device_attribute to pass a structure or function pointer for
117 + * each entry.
118 + */
119 +const struct soc_device_attribute *soc_device_match(
120 + const struct soc_device_attribute *matches)
121 +{
122 + int ret = 0;
123 +
124 + if (!matches)
125 + return NULL;
126 +
127 + while (!ret) {
128 + if (!(matches->machine || matches->family ||
129 + matches->revision || matches->soc_id))
130 + break;
131 + ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
132 + soc_device_match_one);
133 + if (!ret)
134 + matches++;
135 + else
136 + return matches;
137 + }
138 + return NULL;
139 +}
140 +EXPORT_SYMBOL_GPL(soc_device_match);
141 diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
142 index 2739ccb69571..9f5eb06f9fd8 100644
143 --- a/include/linux/sys_soc.h
144 +++ b/include/linux/sys_soc.h
145 @@ -13,6 +13,7 @@ struct soc_device_attribute {
146 const char *family;
147 const char *revision;
148 const char *soc_id;
149 + const void *data;
150 };
151
152 /**
153 @@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev);
154 */
155 struct device *soc_device_to_device(struct soc_device *soc);
156
157 +const struct soc_device_attribute *soc_device_match(
158 + const struct soc_device_attribute *matches);
159 #endif /* __SOC_BUS_H */
160 --
161 2.11.1
162