Merge tag 'gcc-plugins-v5.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / hwtracing / coresight / of_coresight.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2012, The Linux Foundation. All rights reserved.
4  */
5
6 #include <linux/types.h>
7 #include <linux/err.h>
8 #include <linux/slab.h>
9 #include <linux/clk.h>
10 #include <linux/of.h>
11 #include <linux/of_address.h>
12 #include <linux/of_graph.h>
13 #include <linux/of_platform.h>
14 #include <linux/platform_device.h>
15 #include <linux/amba/bus.h>
16 #include <linux/coresight.h>
17 #include <linux/cpumask.h>
18 #include <asm/smp_plat.h>
19
20
21 static int of_dev_node_match(struct device *dev, void *data)
22 {
23         return dev->of_node == data;
24 }
25
26 static struct device *
27 of_coresight_get_endpoint_device(struct device_node *endpoint)
28 {
29         struct device *dev = NULL;
30
31         /*
32          * If we have a non-configurable replicator, it will be found on the
33          * platform bus.
34          */
35         dev = bus_find_device(&platform_bus_type, NULL,
36                               endpoint, of_dev_node_match);
37         if (dev)
38                 return dev;
39
40         /*
41          * We have a configurable component - circle through the AMBA bus
42          * looking for the device that matches the endpoint node.
43          */
44         return bus_find_device(&amba_bustype, NULL,
45                                endpoint, of_dev_node_match);
46 }
47
48 static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
49 {
50         return of_property_read_bool(ep, "slave-mode");
51 }
52
53 static void of_coresight_get_ports_legacy(const struct device_node *node,
54                                           int *nr_inport, int *nr_outport)
55 {
56         struct device_node *ep = NULL;
57         int in = 0, out = 0;
58
59         do {
60                 ep = of_graph_get_next_endpoint(node, ep);
61                 if (!ep)
62                         break;
63
64                 if (of_coresight_legacy_ep_is_input(ep))
65                         in++;
66                 else
67                         out++;
68
69         } while (ep);
70
71         *nr_inport = in;
72         *nr_outport = out;
73 }
74
75 static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
76 {
77         struct device_node *parent = of_graph_get_port_parent(ep);
78
79         /*
80          * Skip one-level up to the real device node, if we
81          * are using the new bindings.
82          */
83         if (of_node_name_eq(parent, "in-ports") ||
84             of_node_name_eq(parent, "out-ports"))
85                 parent = of_get_next_parent(parent);
86
87         return parent;
88 }
89
90 static inline struct device_node *
91 of_coresight_get_input_ports_node(const struct device_node *node)
92 {
93         return of_get_child_by_name(node, "in-ports");
94 }
95
96 static inline struct device_node *
97 of_coresight_get_output_ports_node(const struct device_node *node)
98 {
99         return of_get_child_by_name(node, "out-ports");
100 }
101
102 static inline int
103 of_coresight_count_ports(struct device_node *port_parent)
104 {
105         int i = 0;
106         struct device_node *ep = NULL;
107
108         while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
109                 i++;
110         return i;
111 }
112
113 static void of_coresight_get_ports(const struct device_node *node,
114                                    int *nr_inport, int *nr_outport)
115 {
116         struct device_node *input_ports = NULL, *output_ports = NULL;
117
118         input_ports = of_coresight_get_input_ports_node(node);
119         output_ports = of_coresight_get_output_ports_node(node);
120
121         if (input_ports || output_ports) {
122                 if (input_ports) {
123                         *nr_inport = of_coresight_count_ports(input_ports);
124                         of_node_put(input_ports);
125                 }
126                 if (output_ports) {
127                         *nr_outport = of_coresight_count_ports(output_ports);
128                         of_node_put(output_ports);
129                 }
130         } else {
131                 /* Fall back to legacy DT bindings parsing */
132                 of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
133         }
134 }
135
136 static int of_coresight_alloc_memory(struct device *dev,
137                         struct coresight_platform_data *pdata)
138 {
139         if (pdata->nr_outport) {
140                 pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
141                                             sizeof(*pdata->conns),
142                                             GFP_KERNEL);
143                 if (!pdata->conns)
144                         return -ENOMEM;
145         }
146
147         return 0;
148 }
149
150 int of_coresight_get_cpu(const struct device_node *node)
151 {
152         int cpu;
153         struct device_node *dn;
154
155         dn = of_parse_phandle(node, "cpu", 0);
156         /* Affinity defaults to CPU0 */
157         if (!dn)
158                 return 0;
159         cpu = of_cpu_node_to_id(dn);
160         of_node_put(dn);
161
162         /* Affinity to CPU0 if no cpu nodes are found */
163         return (cpu < 0) ? 0 : cpu;
164 }
165 EXPORT_SYMBOL_GPL(of_coresight_get_cpu);
166
167 /*
168  * of_coresight_parse_endpoint : Parse the given output endpoint @ep
169  * and fill the connection information in @conn
170  *
171  * Parses the local port, remote device name and the remote port.
172  *
173  * Returns :
174  *       1      - If the parsing is successful and a connection record
175  *                was created for an output connection.
176  *       0      - If the parsing completed without any fatal errors.
177  *      -Errno  - Fatal error, abort the scanning.
178  */
179 static int of_coresight_parse_endpoint(struct device *dev,
180                                        struct device_node *ep,
181                                        struct coresight_connection *conn)
182 {
183         int ret = 0;
184         struct of_endpoint endpoint, rendpoint;
185         struct device_node *rparent = NULL;
186         struct device_node *rep = NULL;
187         struct device *rdev = NULL;
188
189         do {
190                 /* Parse the local port details */
191                 if (of_graph_parse_endpoint(ep, &endpoint))
192                         break;
193                 /*
194                  * Get a handle on the remote endpoint and the device it is
195                  * attached to.
196                  */
197                 rep = of_graph_get_remote_endpoint(ep);
198                 if (!rep)
199                         break;
200                 rparent = of_coresight_get_port_parent(rep);
201                 if (!rparent)
202                         break;
203                 if (of_graph_parse_endpoint(rep, &rendpoint))
204                         break;
205
206                 /* If the remote device is not available, defer probing */
207                 rdev = of_coresight_get_endpoint_device(rparent);
208                 if (!rdev) {
209                         ret = -EPROBE_DEFER;
210                         break;
211                 }
212
213                 conn->outport = endpoint.port;
214                 conn->child_name = devm_kstrdup(dev,
215                                                 dev_name(rdev),
216                                                 GFP_KERNEL);
217                 conn->child_port = rendpoint.port;
218                 /* Connection record updated */
219                 ret = 1;
220         } while (0);
221
222         of_node_put(rparent);
223         of_node_put(rep);
224         put_device(rdev);
225
226         return ret;
227 }
228
229 struct coresight_platform_data *
230 of_get_coresight_platform_data(struct device *dev,
231                                const struct device_node *node)
232 {
233         int ret = 0;
234         struct coresight_platform_data *pdata;
235         struct coresight_connection *conn;
236         struct device_node *ep = NULL;
237         const struct device_node *parent = NULL;
238         bool legacy_binding = false;
239
240         pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
241         if (!pdata)
242                 return ERR_PTR(-ENOMEM);
243
244         /* Use device name as sysfs handle */
245         pdata->name = dev_name(dev);
246         pdata->cpu = of_coresight_get_cpu(node);
247
248         /* Get the number of input and output port for this component */
249         of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
250
251         /* If there are no output connections, we are done */
252         if (!pdata->nr_outport)
253                 return pdata;
254
255         ret = of_coresight_alloc_memory(dev, pdata);
256         if (ret)
257                 return ERR_PTR(ret);
258
259         parent = of_coresight_get_output_ports_node(node);
260         /*
261          * If the DT uses obsoleted bindings, the ports are listed
262          * under the device and we need to filter out the input
263          * ports.
264          */
265         if (!parent) {
266                 legacy_binding = true;
267                 parent = node;
268                 dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
269         }
270
271         conn = pdata->conns;
272
273         /* Iterate through each output port to discover topology */
274         while ((ep = of_graph_get_next_endpoint(parent, ep))) {
275                 /*
276                  * Legacy binding mixes input/output ports under the
277                  * same parent. So, skip the input ports if we are dealing
278                  * with legacy binding, as they processed with their
279                  * connected output ports.
280                  */
281                 if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
282                         continue;
283
284                 ret = of_coresight_parse_endpoint(dev, ep, conn);
285                 switch (ret) {
286                 case 1:
287                         conn++;         /* Fall through */
288                 case 0:
289                         break;
290                 default:
291                         return ERR_PTR(ret);
292                 }
293         }
294
295         return pdata;
296 }
297 EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);