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