1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2019, The Linaro Limited. All rights reserved. 4 */ 5 6 #include <dt-bindings/arm/coresight-cti-dt.h> 7 #include <linux/of.h> 8 9 #include "coresight-cti.h" 10 11 /* Number of CTI signals in the v8 architecturally defined connection */ 12 #define NR_V8PE_IN_SIGS 2 13 #define NR_V8PE_OUT_SIGS 3 14 #define NR_V8ETM_INOUT_SIGS 4 15 16 /* CTI device tree trigger connection node keyword */ 17 #define CTI_DT_CONNS "trig-conns" 18 19 /* CTI device tree connection property keywords */ 20 #define CTI_DT_V8ARCH_COMPAT "arm,coresight-cti-v8-arch" 21 #define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc" 22 #define CTI_DT_TRIGIN_SIGS "arm,trig-in-sigs" 23 #define CTI_DT_TRIGOUT_SIGS "arm,trig-out-sigs" 24 #define CTI_DT_TRIGIN_TYPES "arm,trig-in-types" 25 #define CTI_DT_TRIGOUT_TYPES "arm,trig-out-types" 26 #define CTI_DT_FILTER_OUT_SIGS "arm,trig-filters" 27 #define CTI_DT_CONN_NAME "arm,trig-conn-name" 28 #define CTI_DT_CTM_ID "arm,cti-ctm-id" 29 30 #ifdef CONFIG_OF 31 /* 32 * CTI can be bound to a CPU, or a system device. 33 * CPU can be declared at the device top level or in a connections node 34 * so need to check relative to node not device. 35 */ 36 static int of_cti_get_cpu_at_node(const struct device_node *node) 37 { 38 int cpu; 39 struct device_node *dn; 40 41 if (node == NULL) 42 return -1; 43 44 dn = of_parse_phandle(node, "cpu", 0); 45 /* CTI affinity defaults to no cpu */ 46 if (!dn) 47 return -1; 48 cpu = of_cpu_node_to_id(dn); 49 of_node_put(dn); 50 51 /* No Affinity if no cpu nodes are found */ 52 return (cpu < 0) ? -1 : cpu; 53 } 54 55 #else 56 static int of_cti_get_cpu_at_node(const struct device_node *node) 57 { 58 return -1; 59 } 60 61 #endif 62 63 /* 64 * CTI can be bound to a CPU, or a system device. 65 * CPU can be declared at the device top level or in a connections node 66 * so need to check relative to node not device. 67 */ 68 static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode) 69 { 70 if (is_of_node(fwnode)) 71 return of_cti_get_cpu_at_node(to_of_node(fwnode)); 72 return -1; 73 } 74 75 const char *cti_plat_get_node_name(struct fwnode_handle *fwnode) 76 { 77 if (is_of_node(fwnode)) 78 return of_node_full_name(to_of_node(fwnode)); 79 return "unknown"; 80 } 81 82 /* 83 * Extract a name from the fwnode. 84 * If the device associated with the node is a coresight_device, then return 85 * that name and the coresight_device pointer, otherwise return the node name. 86 */ 87 static const char * 88 cti_plat_get_csdev_or_node_name(struct fwnode_handle *fwnode, 89 struct coresight_device **csdev) 90 { 91 const char *name = NULL; 92 *csdev = coresight_find_csdev_by_fwnode(fwnode); 93 if (*csdev) 94 name = dev_name(&(*csdev)->dev); 95 else 96 name = cti_plat_get_node_name(fwnode); 97 return name; 98 } 99 100 static bool cti_plat_node_name_eq(struct fwnode_handle *fwnode, 101 const char *name) 102 { 103 if (is_of_node(fwnode)) 104 return of_node_name_eq(to_of_node(fwnode), name); 105 return false; 106 } 107 108 static int cti_plat_create_v8_etm_connection(struct device *dev, 109 struct cti_drvdata *drvdata) 110 { 111 int ret = -ENOMEM, i; 112 struct fwnode_handle *root_fwnode, *cs_fwnode; 113 const char *assoc_name = NULL; 114 struct coresight_device *csdev; 115 struct cti_trig_con *tc = NULL; 116 117 root_fwnode = dev_fwnode(dev); 118 if (IS_ERR_OR_NULL(root_fwnode)) 119 return -EINVAL; 120 121 /* Can optionally have an etm node - return if not */ 122 cs_fwnode = fwnode_find_reference(root_fwnode, CTI_DT_CSDEV_ASSOC, 0); 123 if (IS_ERR_OR_NULL(cs_fwnode)) 124 return 0; 125 126 /* allocate memory */ 127 tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS, 128 NR_V8ETM_INOUT_SIGS); 129 if (!tc) 130 goto create_v8_etm_out; 131 132 /* build connection data */ 133 tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */ 134 tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */ 135 136 /* 137 * The EXTOUT type signals from the ETM are connected to a set of input 138 * triggers on the CTI, the EXTIN being connected to output triggers. 139 */ 140 for (i = 0; i < NR_V8ETM_INOUT_SIGS; i++) { 141 tc->con_in->sig_types[i] = ETM_EXTOUT; 142 tc->con_out->sig_types[i] = ETM_EXTIN; 143 } 144 145 /* 146 * We look to see if the ETM coresight device associated with this 147 * handle has been registered with the system - i.e. probed before 148 * this CTI. If so csdev will be non NULL and we can use the device 149 * name and pass the csdev to the connection entry function where 150 * the association will be recorded. 151 * If not, then simply record the name in the connection data, the 152 * probing of the ETM will call into the CTI driver API to update the 153 * association then. 154 */ 155 assoc_name = cti_plat_get_csdev_or_node_name(cs_fwnode, &csdev); 156 ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name); 157 158 create_v8_etm_out: 159 fwnode_handle_put(cs_fwnode); 160 return ret; 161 } 162 163 /* 164 * Create an architecturally defined v8 connection 165 * must have a cpu, can have an ETM. 166 */ 167 static int cti_plat_create_v8_connections(struct device *dev, 168 struct cti_drvdata *drvdata) 169 { 170 struct cti_device *cti_dev = &drvdata->ctidev; 171 struct cti_trig_con *tc = NULL; 172 int cpuid = 0; 173 char cpu_name_str[16]; 174 int ret = -ENOMEM; 175 176 /* Must have a cpu node */ 177 cpuid = cti_plat_get_cpu_at_node(dev_fwnode(dev)); 178 if (cpuid < 0) { 179 dev_warn(dev, 180 "ARM v8 architectural CTI connection: missing cpu\n"); 181 return -EINVAL; 182 } 183 cti_dev->cpu = cpuid; 184 185 /* Allocate the v8 cpu connection memory */ 186 tc = cti_allocate_trig_con(dev, NR_V8PE_IN_SIGS, NR_V8PE_OUT_SIGS); 187 if (!tc) 188 goto of_create_v8_out; 189 190 /* Set the v8 PE CTI connection data */ 191 tc->con_in->used_mask = 0x3; /* sigs <0 1> */ 192 tc->con_in->sig_types[0] = PE_DBGTRIGGER; 193 tc->con_in->sig_types[1] = PE_PMUIRQ; 194 tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */ 195 tc->con_out->sig_types[0] = PE_EDBGREQ; 196 tc->con_out->sig_types[1] = PE_DBGRESTART; 197 tc->con_out->sig_types[2] = PE_CTIIRQ; 198 scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid); 199 200 ret = cti_add_connection_entry(dev, drvdata, tc, NULL, cpu_name_str); 201 if (ret) 202 goto of_create_v8_out; 203 204 /* Create the v8 ETM associated connection */ 205 ret = cti_plat_create_v8_etm_connection(dev, drvdata); 206 if (ret) 207 goto of_create_v8_out; 208 209 /* filter pe_edbgreq - PE trigout sig <0> */ 210 drvdata->config.trig_out_filter |= 0x1; 211 212 of_create_v8_out: 213 return ret; 214 } 215 216 static int cti_plat_check_v8_arch_compatible(struct device *dev) 217 { 218 struct fwnode_handle *fwnode = dev_fwnode(dev); 219 220 if (is_of_node(fwnode)) 221 return of_device_is_compatible(to_of_node(fwnode), 222 CTI_DT_V8ARCH_COMPAT); 223 return 0; 224 } 225 226 static int cti_plat_count_sig_elements(const struct fwnode_handle *fwnode, 227 const char *name) 228 { 229 int nr_elem = fwnode_property_count_u32(fwnode, name); 230 231 return (nr_elem < 0 ? 0 : nr_elem); 232 } 233 234 static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp, 235 const struct fwnode_handle *fwnode, 236 const char *grp_name) 237 { 238 int idx, err = 0; 239 u32 *values; 240 241 if (!tgrp->nr_sigs) 242 return 0; 243 244 values = kcalloc(tgrp->nr_sigs, sizeof(u32), GFP_KERNEL); 245 if (!values) 246 return -ENOMEM; 247 248 err = fwnode_property_read_u32_array(fwnode, grp_name, 249 values, tgrp->nr_sigs); 250 251 if (!err) { 252 /* set the signal usage mask */ 253 for (idx = 0; idx < tgrp->nr_sigs; idx++) 254 tgrp->used_mask |= BIT(values[idx]); 255 } 256 257 kfree(values); 258 return err; 259 } 260 261 static int cti_plat_read_trig_types(struct cti_trig_grp *tgrp, 262 const struct fwnode_handle *fwnode, 263 const char *type_name) 264 { 265 int items, err = 0, nr_sigs; 266 u32 *values = NULL, i; 267 268 /* allocate an array according to number of signals in connection */ 269 nr_sigs = tgrp->nr_sigs; 270 if (!nr_sigs) 271 return 0; 272 273 /* see if any types have been included in the device description */ 274 items = cti_plat_count_sig_elements(fwnode, type_name); 275 if (items > nr_sigs) 276 return -EINVAL; 277 278 /* need an array to store the values iff there are any */ 279 if (items) { 280 values = kcalloc(items, sizeof(u32), GFP_KERNEL); 281 if (!values) 282 return -ENOMEM; 283 284 err = fwnode_property_read_u32_array(fwnode, type_name, 285 values, items); 286 if (err) 287 goto read_trig_types_out; 288 } 289 290 /* 291 * Match type id to signal index, 1st type to 1st index etc. 292 * If fewer types than signals default remainder to GEN_IO. 293 */ 294 for (i = 0; i < nr_sigs; i++) { 295 if (i < items) { 296 tgrp->sig_types[i] = 297 values[i] < CTI_TRIG_MAX ? values[i] : GEN_IO; 298 } else { 299 tgrp->sig_types[i] = GEN_IO; 300 } 301 } 302 303 read_trig_types_out: 304 kfree(values); 305 return err; 306 } 307 308 static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata, 309 const struct fwnode_handle *fwnode) 310 { 311 struct cti_trig_grp *tg = NULL; 312 int err = 0, nr_filter_sigs; 313 314 nr_filter_sigs = cti_plat_count_sig_elements(fwnode, 315 CTI_DT_FILTER_OUT_SIGS); 316 if (nr_filter_sigs == 0) 317 return 0; 318 319 if (nr_filter_sigs > drvdata->config.nr_trig_max) 320 return -EINVAL; 321 322 tg = kzalloc(sizeof(*tg), GFP_KERNEL); 323 if (!tg) 324 return -ENOMEM; 325 326 err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS); 327 if (!err) 328 drvdata->config.trig_out_filter |= tg->used_mask; 329 330 kfree(tg); 331 return err; 332 } 333 334 static int cti_plat_create_connection(struct device *dev, 335 struct cti_drvdata *drvdata, 336 struct fwnode_handle *fwnode) 337 { 338 struct cti_trig_con *tc = NULL; 339 int cpuid = -1, err = 0; 340 struct fwnode_handle *cs_fwnode = NULL; 341 struct coresight_device *csdev = NULL; 342 const char *assoc_name = "unknown"; 343 char cpu_name_str[16]; 344 int nr_sigs_in, nr_sigs_out; 345 346 /* look to see how many in and out signals we have */ 347 nr_sigs_in = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGIN_SIGS); 348 nr_sigs_out = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGOUT_SIGS); 349 350 if ((nr_sigs_in > drvdata->config.nr_trig_max) || 351 (nr_sigs_out > drvdata->config.nr_trig_max)) 352 return -EINVAL; 353 354 tc = cti_allocate_trig_con(dev, nr_sigs_in, nr_sigs_out); 355 if (!tc) 356 return -ENOMEM; 357 358 /* look for the signals properties. */ 359 err = cti_plat_read_trig_group(tc->con_in, fwnode, 360 CTI_DT_TRIGIN_SIGS); 361 if (err) 362 goto create_con_err; 363 364 err = cti_plat_read_trig_types(tc->con_in, fwnode, 365 CTI_DT_TRIGIN_TYPES); 366 if (err) 367 goto create_con_err; 368 369 err = cti_plat_read_trig_group(tc->con_out, fwnode, 370 CTI_DT_TRIGOUT_SIGS); 371 if (err) 372 goto create_con_err; 373 374 err = cti_plat_read_trig_types(tc->con_out, fwnode, 375 CTI_DT_TRIGOUT_TYPES); 376 if (err) 377 goto create_con_err; 378 379 err = cti_plat_process_filter_sigs(drvdata, fwnode); 380 if (err) 381 goto create_con_err; 382 383 /* read the connection name if set - may be overridden by later */ 384 fwnode_property_read_string(fwnode, CTI_DT_CONN_NAME, &assoc_name); 385 386 /* associated cpu ? */ 387 cpuid = cti_plat_get_cpu_at_node(fwnode); 388 if (cpuid >= 0) { 389 drvdata->ctidev.cpu = cpuid; 390 scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid); 391 assoc_name = cpu_name_str; 392 } else { 393 /* associated device ? */ 394 cs_fwnode = fwnode_find_reference(fwnode, 395 CTI_DT_CSDEV_ASSOC, 0); 396 if (!IS_ERR_OR_NULL(cs_fwnode)) { 397 assoc_name = cti_plat_get_csdev_or_node_name(cs_fwnode, 398 &csdev); 399 fwnode_handle_put(cs_fwnode); 400 } 401 } 402 /* set up a connection */ 403 err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name); 404 405 create_con_err: 406 return err; 407 } 408 409 static int cti_plat_create_impdef_connections(struct device *dev, 410 struct cti_drvdata *drvdata) 411 { 412 int rc = 0; 413 struct fwnode_handle *fwnode = dev_fwnode(dev); 414 struct fwnode_handle *child = NULL; 415 416 if (IS_ERR_OR_NULL(fwnode)) 417 return -EINVAL; 418 419 fwnode_for_each_child_node(fwnode, child) { 420 if (cti_plat_node_name_eq(child, CTI_DT_CONNS)) 421 rc = cti_plat_create_connection(dev, drvdata, 422 child); 423 if (rc != 0) 424 break; 425 } 426 fwnode_handle_put(child); 427 428 return rc; 429 } 430 431 /* get the hardware configuration & connection data. */ 432 int cti_plat_get_hw_data(struct device *dev, 433 struct cti_drvdata *drvdata) 434 { 435 int rc = 0; 436 struct cti_device *cti_dev = &drvdata->ctidev; 437 438 /* get any CTM ID - defaults to 0 */ 439 device_property_read_u32(dev, CTI_DT_CTM_ID, &cti_dev->ctm_id); 440 441 /* check for a v8 architectural CTI device */ 442 if (cti_plat_check_v8_arch_compatible(dev)) 443 rc = cti_plat_create_v8_connections(dev, drvdata); 444 else 445 rc = cti_plat_create_impdef_connections(dev, drvdata); 446 if (rc) 447 return rc; 448 449 /* if no connections, just add a single default based on max IN-OUT */ 450 if (cti_dev->nr_trig_con == 0) 451 rc = cti_add_default_connection(dev, drvdata); 452 return rc; 453 } 454 455 struct coresight_platform_data * 456 coresight_cti_get_platform_data(struct device *dev) 457 { 458 int ret = -ENOENT; 459 struct coresight_platform_data *pdata = NULL; 460 struct fwnode_handle *fwnode = dev_fwnode(dev); 461 struct cti_drvdata *drvdata = dev_get_drvdata(dev); 462 463 if (IS_ERR_OR_NULL(fwnode)) 464 goto error; 465 466 /* 467 * Alloc platform data but leave it zero init. CTI does not use the 468 * same connection infrastructuree as trace path components but an 469 * empty struct enables us to use the standard coresight component 470 * registration code. 471 */ 472 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 473 if (!pdata) { 474 ret = -ENOMEM; 475 goto error; 476 } 477 478 /* get some CTI specifics */ 479 ret = cti_plat_get_hw_data(dev, drvdata); 480 481 if (!ret) 482 return pdata; 483 error: 484 return ERR_PTR(ret); 485 } 486