0001
0002
0003
0004
0005 #include <linux/coresight.h>
0006 #include <linux/device.h>
0007 #include <linux/err.h>
0008 #include <linux/of.h>
0009 #include <linux/property.h>
0010 #include <linux/slab.h>
0011
0012 #include <dt-bindings/arm/coresight-cti-dt.h>
0013
0014 #include "coresight-cti.h"
0015 #include "coresight-priv.h"
0016
0017
0018 #define NR_V8PE_IN_SIGS 2
0019 #define NR_V8PE_OUT_SIGS 3
0020 #define NR_V8ETM_INOUT_SIGS 4
0021
0022
0023 #define CTI_DT_CONNS "trig-conns"
0024
0025
0026 #define CTI_DT_V8ARCH_COMPAT "arm,coresight-cti-v8-arch"
0027 #define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc"
0028 #define CTI_DT_TRIGIN_SIGS "arm,trig-in-sigs"
0029 #define CTI_DT_TRIGOUT_SIGS "arm,trig-out-sigs"
0030 #define CTI_DT_TRIGIN_TYPES "arm,trig-in-types"
0031 #define CTI_DT_TRIGOUT_TYPES "arm,trig-out-types"
0032 #define CTI_DT_FILTER_OUT_SIGS "arm,trig-filters"
0033 #define CTI_DT_CONN_NAME "arm,trig-conn-name"
0034 #define CTI_DT_CTM_ID "arm,cti-ctm-id"
0035
0036 #ifdef CONFIG_OF
0037
0038
0039
0040
0041
0042 static int of_cti_get_cpu_at_node(const struct device_node *node)
0043 {
0044 int cpu;
0045 struct device_node *dn;
0046
0047 if (node == NULL)
0048 return -1;
0049
0050 dn = of_parse_phandle(node, "cpu", 0);
0051
0052 if (!dn)
0053 return -1;
0054 cpu = of_cpu_node_to_id(dn);
0055 of_node_put(dn);
0056
0057
0058 return (cpu < 0) ? -1 : cpu;
0059 }
0060
0061 #else
0062 static int of_cti_get_cpu_at_node(const struct device_node *node)
0063 {
0064 return -1;
0065 }
0066
0067 #endif
0068
0069
0070
0071
0072
0073
0074 static int cti_plat_get_cpu_at_node(struct fwnode_handle *fwnode)
0075 {
0076 if (is_of_node(fwnode))
0077 return of_cti_get_cpu_at_node(to_of_node(fwnode));
0078 return -1;
0079 }
0080
0081 const char *cti_plat_get_node_name(struct fwnode_handle *fwnode)
0082 {
0083 if (is_of_node(fwnode))
0084 return of_node_full_name(to_of_node(fwnode));
0085 return "unknown";
0086 }
0087
0088
0089
0090
0091
0092
0093 static const char *
0094 cti_plat_get_csdev_or_node_name(struct fwnode_handle *fwnode,
0095 struct coresight_device **csdev)
0096 {
0097 const char *name = NULL;
0098 *csdev = coresight_find_csdev_by_fwnode(fwnode);
0099 if (*csdev)
0100 name = dev_name(&(*csdev)->dev);
0101 else
0102 name = cti_plat_get_node_name(fwnode);
0103 return name;
0104 }
0105
0106 static bool cti_plat_node_name_eq(struct fwnode_handle *fwnode,
0107 const char *name)
0108 {
0109 if (is_of_node(fwnode))
0110 return of_node_name_eq(to_of_node(fwnode), name);
0111 return false;
0112 }
0113
0114 static int cti_plat_create_v8_etm_connection(struct device *dev,
0115 struct cti_drvdata *drvdata)
0116 {
0117 int ret = -ENOMEM, i;
0118 struct fwnode_handle *root_fwnode, *cs_fwnode;
0119 const char *assoc_name = NULL;
0120 struct coresight_device *csdev;
0121 struct cti_trig_con *tc = NULL;
0122
0123 root_fwnode = dev_fwnode(dev);
0124 if (IS_ERR_OR_NULL(root_fwnode))
0125 return -EINVAL;
0126
0127
0128 cs_fwnode = fwnode_find_reference(root_fwnode, CTI_DT_CSDEV_ASSOC, 0);
0129 if (IS_ERR(cs_fwnode))
0130 return 0;
0131
0132
0133 tc = cti_allocate_trig_con(dev, NR_V8ETM_INOUT_SIGS,
0134 NR_V8ETM_INOUT_SIGS);
0135 if (!tc)
0136 goto create_v8_etm_out;
0137
0138
0139 tc->con_in->used_mask = 0xF0;
0140 tc->con_out->used_mask = 0xF0;
0141
0142
0143
0144
0145
0146 for (i = 0; i < NR_V8ETM_INOUT_SIGS; i++) {
0147 tc->con_in->sig_types[i] = ETM_EXTOUT;
0148 tc->con_out->sig_types[i] = ETM_EXTIN;
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 assoc_name = cti_plat_get_csdev_or_node_name(cs_fwnode, &csdev);
0162 ret = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
0163
0164 create_v8_etm_out:
0165 fwnode_handle_put(cs_fwnode);
0166 return ret;
0167 }
0168
0169
0170
0171
0172
0173 static int cti_plat_create_v8_connections(struct device *dev,
0174 struct cti_drvdata *drvdata)
0175 {
0176 struct cti_device *cti_dev = &drvdata->ctidev;
0177 struct cti_trig_con *tc = NULL;
0178 int cpuid = 0;
0179 char cpu_name_str[16];
0180 int ret = -ENOMEM;
0181
0182
0183 cpuid = cti_plat_get_cpu_at_node(dev_fwnode(dev));
0184 if (cpuid < 0) {
0185 dev_warn(dev,
0186 "ARM v8 architectural CTI connection: missing cpu\n");
0187 return -EINVAL;
0188 }
0189 cti_dev->cpu = cpuid;
0190
0191
0192 tc = cti_allocate_trig_con(dev, NR_V8PE_IN_SIGS, NR_V8PE_OUT_SIGS);
0193 if (!tc)
0194 goto of_create_v8_out;
0195
0196
0197 tc->con_in->used_mask = 0x3;
0198 tc->con_in->sig_types[0] = PE_DBGTRIGGER;
0199 tc->con_in->sig_types[1] = PE_PMUIRQ;
0200 tc->con_out->used_mask = 0x7;
0201 tc->con_out->sig_types[0] = PE_EDBGREQ;
0202 tc->con_out->sig_types[1] = PE_DBGRESTART;
0203 tc->con_out->sig_types[2] = PE_CTIIRQ;
0204 scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid);
0205
0206 ret = cti_add_connection_entry(dev, drvdata, tc, NULL, cpu_name_str);
0207 if (ret)
0208 goto of_create_v8_out;
0209
0210
0211 ret = cti_plat_create_v8_etm_connection(dev, drvdata);
0212 if (ret)
0213 goto of_create_v8_out;
0214
0215
0216 drvdata->config.trig_out_filter |= 0x1;
0217
0218 of_create_v8_out:
0219 return ret;
0220 }
0221
0222 static int cti_plat_check_v8_arch_compatible(struct device *dev)
0223 {
0224 struct fwnode_handle *fwnode = dev_fwnode(dev);
0225
0226 if (is_of_node(fwnode))
0227 return of_device_is_compatible(to_of_node(fwnode),
0228 CTI_DT_V8ARCH_COMPAT);
0229 return 0;
0230 }
0231
0232 static int cti_plat_count_sig_elements(const struct fwnode_handle *fwnode,
0233 const char *name)
0234 {
0235 int nr_elem = fwnode_property_count_u32(fwnode, name);
0236
0237 return (nr_elem < 0 ? 0 : nr_elem);
0238 }
0239
0240 static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
0241 const struct fwnode_handle *fwnode,
0242 const char *grp_name)
0243 {
0244 int idx, err = 0;
0245 u32 *values;
0246
0247 if (!tgrp->nr_sigs)
0248 return 0;
0249
0250 values = kcalloc(tgrp->nr_sigs, sizeof(u32), GFP_KERNEL);
0251 if (!values)
0252 return -ENOMEM;
0253
0254 err = fwnode_property_read_u32_array(fwnode, grp_name,
0255 values, tgrp->nr_sigs);
0256
0257 if (!err) {
0258
0259 for (idx = 0; idx < tgrp->nr_sigs; idx++)
0260 tgrp->used_mask |= BIT(values[idx]);
0261 }
0262
0263 kfree(values);
0264 return err;
0265 }
0266
0267 static int cti_plat_read_trig_types(struct cti_trig_grp *tgrp,
0268 const struct fwnode_handle *fwnode,
0269 const char *type_name)
0270 {
0271 int items, err = 0, nr_sigs;
0272 u32 *values = NULL, i;
0273
0274
0275 nr_sigs = tgrp->nr_sigs;
0276 if (!nr_sigs)
0277 return 0;
0278
0279
0280 items = cti_plat_count_sig_elements(fwnode, type_name);
0281 if (items > nr_sigs)
0282 return -EINVAL;
0283
0284
0285 if (items) {
0286 values = kcalloc(items, sizeof(u32), GFP_KERNEL);
0287 if (!values)
0288 return -ENOMEM;
0289
0290 err = fwnode_property_read_u32_array(fwnode, type_name,
0291 values, items);
0292 if (err)
0293 goto read_trig_types_out;
0294 }
0295
0296
0297
0298
0299
0300 for (i = 0; i < nr_sigs; i++) {
0301 if (i < items) {
0302 tgrp->sig_types[i] =
0303 values[i] < CTI_TRIG_MAX ? values[i] : GEN_IO;
0304 } else {
0305 tgrp->sig_types[i] = GEN_IO;
0306 }
0307 }
0308
0309 read_trig_types_out:
0310 kfree(values);
0311 return err;
0312 }
0313
0314 static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
0315 const struct fwnode_handle *fwnode)
0316 {
0317 struct cti_trig_grp *tg = NULL;
0318 int err = 0, nr_filter_sigs;
0319
0320 nr_filter_sigs = cti_plat_count_sig_elements(fwnode,
0321 CTI_DT_FILTER_OUT_SIGS);
0322 if (nr_filter_sigs == 0)
0323 return 0;
0324
0325 if (nr_filter_sigs > drvdata->config.nr_trig_max)
0326 return -EINVAL;
0327
0328 tg = kzalloc(sizeof(*tg), GFP_KERNEL);
0329 if (!tg)
0330 return -ENOMEM;
0331
0332 err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS);
0333 if (!err)
0334 drvdata->config.trig_out_filter |= tg->used_mask;
0335
0336 kfree(tg);
0337 return err;
0338 }
0339
0340 static int cti_plat_create_connection(struct device *dev,
0341 struct cti_drvdata *drvdata,
0342 struct fwnode_handle *fwnode)
0343 {
0344 struct cti_trig_con *tc = NULL;
0345 int cpuid = -1, err = 0;
0346 struct coresight_device *csdev = NULL;
0347 const char *assoc_name = "unknown";
0348 char cpu_name_str[16];
0349 int nr_sigs_in, nr_sigs_out;
0350
0351
0352 nr_sigs_in = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGIN_SIGS);
0353 nr_sigs_out = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGOUT_SIGS);
0354
0355 if ((nr_sigs_in > drvdata->config.nr_trig_max) ||
0356 (nr_sigs_out > drvdata->config.nr_trig_max))
0357 return -EINVAL;
0358
0359 tc = cti_allocate_trig_con(dev, nr_sigs_in, nr_sigs_out);
0360 if (!tc)
0361 return -ENOMEM;
0362
0363
0364 err = cti_plat_read_trig_group(tc->con_in, fwnode,
0365 CTI_DT_TRIGIN_SIGS);
0366 if (err)
0367 goto create_con_err;
0368
0369 err = cti_plat_read_trig_types(tc->con_in, fwnode,
0370 CTI_DT_TRIGIN_TYPES);
0371 if (err)
0372 goto create_con_err;
0373
0374 err = cti_plat_read_trig_group(tc->con_out, fwnode,
0375 CTI_DT_TRIGOUT_SIGS);
0376 if (err)
0377 goto create_con_err;
0378
0379 err = cti_plat_read_trig_types(tc->con_out, fwnode,
0380 CTI_DT_TRIGOUT_TYPES);
0381 if (err)
0382 goto create_con_err;
0383
0384 err = cti_plat_process_filter_sigs(drvdata, fwnode);
0385 if (err)
0386 goto create_con_err;
0387
0388
0389 fwnode_property_read_string(fwnode, CTI_DT_CONN_NAME, &assoc_name);
0390
0391
0392 cpuid = cti_plat_get_cpu_at_node(fwnode);
0393 if (cpuid >= 0) {
0394 drvdata->ctidev.cpu = cpuid;
0395 scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid);
0396 assoc_name = cpu_name_str;
0397 } else {
0398
0399 struct fwnode_handle *cs_fwnode = fwnode_find_reference(fwnode,
0400 CTI_DT_CSDEV_ASSOC,
0401 0);
0402 if (!IS_ERR(cs_fwnode)) {
0403 assoc_name = cti_plat_get_csdev_or_node_name(cs_fwnode,
0404 &csdev);
0405 fwnode_handle_put(cs_fwnode);
0406 }
0407 }
0408
0409 err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
0410
0411 create_con_err:
0412 return err;
0413 }
0414
0415 static int cti_plat_create_impdef_connections(struct device *dev,
0416 struct cti_drvdata *drvdata)
0417 {
0418 int rc = 0;
0419 struct fwnode_handle *fwnode = dev_fwnode(dev);
0420 struct fwnode_handle *child = NULL;
0421
0422 if (IS_ERR_OR_NULL(fwnode))
0423 return -EINVAL;
0424
0425 fwnode_for_each_child_node(fwnode, child) {
0426 if (cti_plat_node_name_eq(child, CTI_DT_CONNS))
0427 rc = cti_plat_create_connection(dev, drvdata,
0428 child);
0429 if (rc != 0)
0430 break;
0431 }
0432 fwnode_handle_put(child);
0433
0434 return rc;
0435 }
0436
0437
0438 static int cti_plat_get_hw_data(struct device *dev, struct cti_drvdata *drvdata)
0439 {
0440 int rc = 0;
0441 struct cti_device *cti_dev = &drvdata->ctidev;
0442
0443
0444 device_property_read_u32(dev, CTI_DT_CTM_ID, &cti_dev->ctm_id);
0445
0446
0447 if (cti_plat_check_v8_arch_compatible(dev))
0448 rc = cti_plat_create_v8_connections(dev, drvdata);
0449 else
0450 rc = cti_plat_create_impdef_connections(dev, drvdata);
0451 if (rc)
0452 return rc;
0453
0454
0455 if (cti_dev->nr_trig_con == 0)
0456 rc = cti_add_default_connection(dev, drvdata);
0457 return rc;
0458 }
0459
0460 struct coresight_platform_data *
0461 coresight_cti_get_platform_data(struct device *dev)
0462 {
0463 int ret = -ENOENT;
0464 struct coresight_platform_data *pdata = NULL;
0465 struct fwnode_handle *fwnode = dev_fwnode(dev);
0466 struct cti_drvdata *drvdata = dev_get_drvdata(dev);
0467
0468 if (IS_ERR_OR_NULL(fwnode))
0469 goto error;
0470
0471
0472
0473
0474
0475
0476
0477 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
0478 if (!pdata) {
0479 ret = -ENOMEM;
0480 goto error;
0481 }
0482
0483
0484 ret = cti_plat_get_hw_data(dev, drvdata);
0485
0486 if (!ret)
0487 return pdata;
0488 error:
0489 return ERR_PTR(ret);
0490 }