1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2019, The Linaro Limited. All rights reserved.
5 #include <linux/coresight.h>
6 #include <linux/device.h>
9 #include <linux/property.h>
10 #include <linux/slab.h>
12 #include <dt-bindings/arm/coresight-cti-dt.h>
14 #include "coresight-cti.h"
15 #include "coresight-priv.h"
17 /* Number of CTI signals in the v8 architecturally defined connection */
18 #define NR_V8PE_IN_SIGS 2
19 #define NR_V8PE_OUT_SIGS 3
20 #define NR_V8ETM_INOUT_SIGS 4
22 /* CTI device tree trigger connection node keyword */
23 #define CTI_DT_CONNS "trig-conns"
25 /* CTI device tree connection property keywords */
26 #define CTI_DT_V8ARCH_COMPAT "arm,coresight-cti-v8-arch"
27 #define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc"
28 #define CTI_DT_TRIGIN_SIGS "arm,trig-in-sigs"
29 #define CTI_DT_TRIGOUT_SIGS "arm,trig-out-sigs"
30 #define CTI_DT_TRIGIN_TYPES "arm,trig-in-types"
31 #define CTI_DT_TRIGOUT_TYPES "arm,trig-out-types"
32 #define CTI_DT_FILTER_OUT_SIGS "arm,trig-filters"
33 #define CTI_DT_CONN_NAME "arm,trig-conn-name"
34 #define CTI_DT_CTM_ID "arm,cti-ctm-id"
38 * CTI can be bound to a CPU, or a system device.
39 * CPU can be declared at the device top level or in a connections node
40 * so need to check relative to node not device.
42 static int of_cti_get_cpu_at_node(const struct device_node
*node
)
45 struct device_node
*dn
;
50 dn
= of_parse_phandle(node
, "cpu", 0);
51 /* CTI affinity defaults to no cpu */
54 cpu
= of_cpu_node_to_id(dn
);
57 /* No Affinity if no cpu nodes are found */
58 return (cpu
< 0) ? -1 : cpu
;
62 static int of_cti_get_cpu_at_node(const struct device_node
*node
)
70 * CTI can be bound to a CPU, or a system device.
71 * CPU can be declared at the device top level or in a connections node
72 * so need to check relative to node not device.
74 static int cti_plat_get_cpu_at_node(struct fwnode_handle
*fwnode
)
76 if (is_of_node(fwnode
))
77 return of_cti_get_cpu_at_node(to_of_node(fwnode
));
81 const char *cti_plat_get_node_name(struct fwnode_handle
*fwnode
)
83 if (is_of_node(fwnode
))
84 return of_node_full_name(to_of_node(fwnode
));
89 * Extract a name from the fwnode.
90 * If the device associated with the node is a coresight_device, then return
91 * that name and the coresight_device pointer, otherwise return the node name.
94 cti_plat_get_csdev_or_node_name(struct fwnode_handle
*fwnode
,
95 struct coresight_device
**csdev
)
97 const char *name
= NULL
;
98 *csdev
= coresight_find_csdev_by_fwnode(fwnode
);
100 name
= dev_name(&(*csdev
)->dev
);
102 name
= cti_plat_get_node_name(fwnode
);
106 static bool cti_plat_node_name_eq(struct fwnode_handle
*fwnode
,
109 if (is_of_node(fwnode
))
110 return of_node_name_eq(to_of_node(fwnode
), name
);
114 static int cti_plat_create_v8_etm_connection(struct device
*dev
,
115 struct cti_drvdata
*drvdata
)
117 int ret
= -ENOMEM
, i
;
118 struct fwnode_handle
*root_fwnode
, *cs_fwnode
;
119 const char *assoc_name
= NULL
;
120 struct coresight_device
*csdev
;
121 struct cti_trig_con
*tc
= NULL
;
123 root_fwnode
= dev_fwnode(dev
);
124 if (IS_ERR_OR_NULL(root_fwnode
))
127 /* Can optionally have an etm node - return if not */
128 cs_fwnode
= fwnode_find_reference(root_fwnode
, CTI_DT_CSDEV_ASSOC
, 0);
129 if (IS_ERR(cs_fwnode
))
132 /* allocate memory */
133 tc
= cti_allocate_trig_con(dev
, NR_V8ETM_INOUT_SIGS
,
134 NR_V8ETM_INOUT_SIGS
);
136 goto create_v8_etm_out
;
138 /* build connection data */
139 tc
->con_in
->used_mask
= 0xF0; /* sigs <4,5,6,7> */
140 tc
->con_out
->used_mask
= 0xF0; /* sigs <4,5,6,7> */
143 * The EXTOUT type signals from the ETM are connected to a set of input
144 * triggers on the CTI, the EXTIN being connected to output triggers.
146 for (i
= 0; i
< NR_V8ETM_INOUT_SIGS
; i
++) {
147 tc
->con_in
->sig_types
[i
] = ETM_EXTOUT
;
148 tc
->con_out
->sig_types
[i
] = ETM_EXTIN
;
152 * We look to see if the ETM coresight device associated with this
153 * handle has been registered with the system - i.e. probed before
154 * this CTI. If so csdev will be non NULL and we can use the device
155 * name and pass the csdev to the connection entry function where
156 * the association will be recorded.
157 * If not, then simply record the name in the connection data, the
158 * probing of the ETM will call into the CTI driver API to update the
161 assoc_name
= cti_plat_get_csdev_or_node_name(cs_fwnode
, &csdev
);
162 ret
= cti_add_connection_entry(dev
, drvdata
, tc
, csdev
, assoc_name
);
165 fwnode_handle_put(cs_fwnode
);
170 * Create an architecturally defined v8 connection
171 * must have a cpu, can have an ETM.
173 static int cti_plat_create_v8_connections(struct device
*dev
,
174 struct cti_drvdata
*drvdata
)
176 struct cti_device
*cti_dev
= &drvdata
->ctidev
;
177 struct cti_trig_con
*tc
= NULL
;
179 char cpu_name_str
[16];
182 /* Must have a cpu node */
183 cpuid
= cti_plat_get_cpu_at_node(dev_fwnode(dev
));
186 "ARM v8 architectural CTI connection: missing cpu\n");
189 cti_dev
->cpu
= cpuid
;
191 /* Allocate the v8 cpu connection memory */
192 tc
= cti_allocate_trig_con(dev
, NR_V8PE_IN_SIGS
, NR_V8PE_OUT_SIGS
);
194 goto of_create_v8_out
;
196 /* Set the v8 PE CTI connection data */
197 tc
->con_in
->used_mask
= 0x3; /* sigs <0 1> */
198 tc
->con_in
->sig_types
[0] = PE_DBGTRIGGER
;
199 tc
->con_in
->sig_types
[1] = PE_PMUIRQ
;
200 tc
->con_out
->used_mask
= 0x7; /* sigs <0 1 2 > */
201 tc
->con_out
->sig_types
[0] = PE_EDBGREQ
;
202 tc
->con_out
->sig_types
[1] = PE_DBGRESTART
;
203 tc
->con_out
->sig_types
[2] = PE_CTIIRQ
;
204 scnprintf(cpu_name_str
, sizeof(cpu_name_str
), "cpu%d", cpuid
);
206 ret
= cti_add_connection_entry(dev
, drvdata
, tc
, NULL
, cpu_name_str
);
208 goto of_create_v8_out
;
210 /* Create the v8 ETM associated connection */
211 ret
= cti_plat_create_v8_etm_connection(dev
, drvdata
);
213 goto of_create_v8_out
;
215 /* filter pe_edbgreq - PE trigout sig <0> */
216 drvdata
->config
.trig_out_filter
|= 0x1;
222 static int cti_plat_check_v8_arch_compatible(struct device
*dev
)
224 struct fwnode_handle
*fwnode
= dev_fwnode(dev
);
226 if (is_of_node(fwnode
))
227 return of_device_is_compatible(to_of_node(fwnode
),
228 CTI_DT_V8ARCH_COMPAT
);
232 static int cti_plat_count_sig_elements(const struct fwnode_handle
*fwnode
,
235 int nr_elem
= fwnode_property_count_u32(fwnode
, name
);
237 return (nr_elem
< 0 ? 0 : nr_elem
);
240 static int cti_plat_read_trig_group(struct cti_trig_grp
*tgrp
,
241 const struct fwnode_handle
*fwnode
,
242 const char *grp_name
)
250 values
= kcalloc(tgrp
->nr_sigs
, sizeof(u32
), GFP_KERNEL
);
254 err
= fwnode_property_read_u32_array(fwnode
, grp_name
,
255 values
, tgrp
->nr_sigs
);
258 /* set the signal usage mask */
259 for (idx
= 0; idx
< tgrp
->nr_sigs
; idx
++)
260 tgrp
->used_mask
|= BIT(values
[idx
]);
267 static int cti_plat_read_trig_types(struct cti_trig_grp
*tgrp
,
268 const struct fwnode_handle
*fwnode
,
269 const char *type_name
)
271 int items
, err
= 0, nr_sigs
;
272 u32
*values
= NULL
, i
;
274 /* allocate an array according to number of signals in connection */
275 nr_sigs
= tgrp
->nr_sigs
;
279 /* see if any types have been included in the device description */
280 items
= cti_plat_count_sig_elements(fwnode
, type_name
);
284 /* need an array to store the values iff there are any */
286 values
= kcalloc(items
, sizeof(u32
), GFP_KERNEL
);
290 err
= fwnode_property_read_u32_array(fwnode
, type_name
,
293 goto read_trig_types_out
;
297 * Match type id to signal index, 1st type to 1st index etc.
298 * If fewer types than signals default remainder to GEN_IO.
300 for (i
= 0; i
< nr_sigs
; i
++) {
303 values
[i
] < CTI_TRIG_MAX
? values
[i
] : GEN_IO
;
305 tgrp
->sig_types
[i
] = GEN_IO
;
314 static int cti_plat_process_filter_sigs(struct cti_drvdata
*drvdata
,
315 const struct fwnode_handle
*fwnode
)
317 struct cti_trig_grp
*tg
= NULL
;
318 int err
= 0, nr_filter_sigs
;
320 nr_filter_sigs
= cti_plat_count_sig_elements(fwnode
,
321 CTI_DT_FILTER_OUT_SIGS
);
322 if (nr_filter_sigs
== 0)
325 if (nr_filter_sigs
> drvdata
->config
.nr_trig_max
)
328 tg
= kzalloc(sizeof(*tg
), GFP_KERNEL
);
332 err
= cti_plat_read_trig_group(tg
, fwnode
, CTI_DT_FILTER_OUT_SIGS
);
334 drvdata
->config
.trig_out_filter
|= tg
->used_mask
;
340 static int cti_plat_create_connection(struct device
*dev
,
341 struct cti_drvdata
*drvdata
,
342 struct fwnode_handle
*fwnode
)
344 struct cti_trig_con
*tc
= NULL
;
345 int cpuid
= -1, err
= 0;
346 struct fwnode_handle
*cs_fwnode
= NULL
;
347 struct coresight_device
*csdev
= NULL
;
348 const char *assoc_name
= "unknown";
349 char cpu_name_str
[16];
350 int nr_sigs_in
, nr_sigs_out
;
352 /* look to see how many in and out signals we have */
353 nr_sigs_in
= cti_plat_count_sig_elements(fwnode
, CTI_DT_TRIGIN_SIGS
);
354 nr_sigs_out
= cti_plat_count_sig_elements(fwnode
, CTI_DT_TRIGOUT_SIGS
);
356 if ((nr_sigs_in
> drvdata
->config
.nr_trig_max
) ||
357 (nr_sigs_out
> drvdata
->config
.nr_trig_max
))
360 tc
= cti_allocate_trig_con(dev
, nr_sigs_in
, nr_sigs_out
);
364 /* look for the signals properties. */
365 err
= cti_plat_read_trig_group(tc
->con_in
, fwnode
,
370 err
= cti_plat_read_trig_types(tc
->con_in
, fwnode
,
371 CTI_DT_TRIGIN_TYPES
);
375 err
= cti_plat_read_trig_group(tc
->con_out
, fwnode
,
376 CTI_DT_TRIGOUT_SIGS
);
380 err
= cti_plat_read_trig_types(tc
->con_out
, fwnode
,
381 CTI_DT_TRIGOUT_TYPES
);
385 err
= cti_plat_process_filter_sigs(drvdata
, fwnode
);
389 /* read the connection name if set - may be overridden by later */
390 fwnode_property_read_string(fwnode
, CTI_DT_CONN_NAME
, &assoc_name
);
392 /* associated cpu ? */
393 cpuid
= cti_plat_get_cpu_at_node(fwnode
);
395 drvdata
->ctidev
.cpu
= cpuid
;
396 scnprintf(cpu_name_str
, sizeof(cpu_name_str
), "cpu%d", cpuid
);
397 assoc_name
= cpu_name_str
;
399 /* associated device ? */
400 cs_fwnode
= fwnode_find_reference(fwnode
,
401 CTI_DT_CSDEV_ASSOC
, 0);
402 if (!IS_ERR(cs_fwnode
)) {
403 assoc_name
= cti_plat_get_csdev_or_node_name(cs_fwnode
,
405 fwnode_handle_put(cs_fwnode
);
408 /* set up a connection */
409 err
= cti_add_connection_entry(dev
, drvdata
, tc
, csdev
, assoc_name
);
415 static int cti_plat_create_impdef_connections(struct device
*dev
,
416 struct cti_drvdata
*drvdata
)
419 struct fwnode_handle
*fwnode
= dev_fwnode(dev
);
420 struct fwnode_handle
*child
= NULL
;
422 if (IS_ERR_OR_NULL(fwnode
))
425 fwnode_for_each_child_node(fwnode
, child
) {
426 if (cti_plat_node_name_eq(child
, CTI_DT_CONNS
))
427 rc
= cti_plat_create_connection(dev
, drvdata
,
432 fwnode_handle_put(child
);
437 /* get the hardware configuration & connection data. */
438 static int cti_plat_get_hw_data(struct device
*dev
, struct cti_drvdata
*drvdata
)
441 struct cti_device
*cti_dev
= &drvdata
->ctidev
;
443 /* get any CTM ID - defaults to 0 */
444 device_property_read_u32(dev
, CTI_DT_CTM_ID
, &cti_dev
->ctm_id
);
446 /* check for a v8 architectural CTI device */
447 if (cti_plat_check_v8_arch_compatible(dev
))
448 rc
= cti_plat_create_v8_connections(dev
, drvdata
);
450 rc
= cti_plat_create_impdef_connections(dev
, drvdata
);
454 /* if no connections, just add a single default based on max IN-OUT */
455 if (cti_dev
->nr_trig_con
== 0)
456 rc
= cti_add_default_connection(dev
, drvdata
);
460 struct coresight_platform_data
*
461 coresight_cti_get_platform_data(struct device
*dev
)
464 struct coresight_platform_data
*pdata
= NULL
;
465 struct fwnode_handle
*fwnode
= dev_fwnode(dev
);
466 struct cti_drvdata
*drvdata
= dev_get_drvdata(dev
);
468 if (IS_ERR_OR_NULL(fwnode
))
472 * Alloc platform data but leave it zero init. CTI does not use the
473 * same connection infrastructuree as trace path components but an
474 * empty struct enables us to use the standard coresight component
477 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
483 /* get some CTI specifics */
484 ret
= cti_plat_get_hw_data(dev
, drvdata
);