The v8 architecture defines the relationship between a PE, its optional ETM and a CTI. Unlike non-architectural CTIs which are implementation defined, this has a fixed set of connections which can therefore be represented as a simple tag in the device tree.
This patch defines the tags needed to create an entry for this PE/ETM/CTI relationship, and provides functionality to implement the connection model in the CTI driver.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/coresight-cti.c | 10 +- drivers/hwtracing/coresight/coresight-cti.h | 5 + .../hwtracing/coresight/of_coresight-cti.c | 179 +++++++++++++++++- 3 files changed, 188 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 06b1f84795a4..32d9bf0bf0b9 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -192,11 +192,11 @@ static void cti_set_default_config(struct cti_config *config) * Add a connection entry to the list of connections for this * CTI device. */ -static int cti_add_connection_entry(struct cti_drvdata *drvdata, - struct cti_trig_grp *in_info, - struct cti_trig_grp *out_info, - struct coresight_device *csdev, - const char *assoc_dev_name) +int cti_add_connection_entry(struct cti_drvdata *drvdata, + struct cti_trig_grp *in_info, + struct cti_trig_grp *out_info, + struct coresight_device *csdev, + const char *assoc_dev_name) { struct cti_trig_con *tc; struct cti_device *cti_dev = &drvdata->ctidev; diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index a5bf59155f62..df40ca2d9548 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -234,6 +234,11 @@ enum cti_chan_set_op { extern const struct attribute_group *coresight_cti_groups[];
int cti_add_default_connection(struct cti_drvdata *drvdata); +int cti_add_connection_entry(struct cti_drvdata *drvdata, + struct cti_trig_grp *in_info, + struct cti_trig_grp *out_info, + struct coresight_device *csdev, + const char *assoc_dev_name); int cti_enable(struct coresight_device *csdev, void *__unused); int cti_disable(struct coresight_device *csdev, void *__unused); void cti_write_all_hw_regs(struct cti_drvdata *drvdata); diff --git a/drivers/hwtracing/coresight/of_coresight-cti.c b/drivers/hwtracing/coresight/of_coresight-cti.c index 379ca1113deb..ee9a5906dc37 100644 --- a/drivers/hwtracing/coresight/of_coresight-cti.c +++ b/drivers/hwtracing/coresight/of_coresight-cti.c @@ -18,6 +18,16 @@
#include "coresight-cti.h"
+/* Number of CTI signals in the v8 architecturally defined connection */ +#define NR_V8PE_IN_SIGS 2 +#define NR_V8PE_OUT_SIGS 3 +#define NR_V8ETM_INOUT_SIGS 4 + +/* CTI device tree connection property keywords */ +#define CTI_DT_V8ARCH "arm,cti-v8-arch" +#define CTI_DT_CSDEV_ASSOC "arm,cs-dev-assoc" +#define CTI_DT_CTM_ID "arm,cti-ctm-id" + #ifdef CONFIG_OF
/* @@ -40,6 +50,166 @@ static int of_cti_get_cpu(const struct device_node *node) return (cpu < 0) ? -1 : cpu; }
+/* match function to pass to find_device */ +static int of_dev_node_match(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/* + * Find a registered coresight device from the device_node. + * The node info is associated with the AMBA parent, so we + * search this first to find a name, and use the name to find + * the device on the coresight bus as they are always named the same. + */ +static struct coresight_device * +of_cti_get_assoc_cs_dev_by_node(struct device_node *node) +{ + struct device *dev, *adev; + struct coresight_device *csdev = NULL; + const char *amba_dev_name = NULL; + + if (!node) + return NULL; + + adev = bus_find_device(&amba_bustype, NULL, node, of_dev_node_match); + if (adev) { + amba_dev_name = dev_name(adev); + dev = bus_find_device_by_name(&coresight_bustype, NULL, + amba_dev_name); + if (dev) { + csdev = to_coresight_device(dev); + put_device(dev); + } + put_device(adev); + } + return csdev; +} + +/* + * Create an architecturally defined v8 connection + * must have a cpu, can have an ETM. + */ +static int of_cti_create_v8_connections(struct cti_drvdata *drvdata, + struct device_node *np) +{ + struct cti_device *cti_dev = &drvdata->ctidev; + struct cti_trig_grp *in = 0, *out = 0, *etm_in = 0, *etm_out = 0; + int cpuid = 0, i; + struct device_node *cs_np; + struct coresight_device *csdev = NULL; + char cpu_name_str[16]; + const char *assoc_name = NULL; + int *sig_in_types = 0, *sig_out_types = 0; + int *etm_sig_in_types = 0, *etm_sig_out_types = 0; + + /* Must have a cpu node */ + cpuid = of_cti_get_cpu(np); + if (cpuid < 0) { + dev_warn(drvdata->dev, "CTI v8 DT binding no cpu\n"); + return -EINVAL; + } + cti_dev->cpu = cpuid; + + /* Can have an etm node */ + cs_np = of_parse_phandle(np, CTI_DT_CSDEV_ASSOC, 0); + + /* Allocate the v8 cpu memory */ + in = kzalloc(sizeof(struct cti_trig_grp), GFP_KERNEL); + if (!in) + goto of_create_v8_mem_err; + + out = kzalloc(sizeof(struct cti_trig_grp), GFP_KERNEL); + if (!out) + goto of_create_v8_mem_err; + + sig_in_types = kzalloc(sizeof(int) * NR_V8PE_IN_SIGS, GFP_KERNEL); + if (!sig_in_types) + goto of_create_v8_mem_err; + + sig_out_types = kzalloc(sizeof(int) * NR_V8PE_OUT_SIGS, GFP_KERNEL); + if (!sig_out_types) + goto of_create_v8_mem_err; + + /* Allocate the ETM connection memory if required */ + if (cs_np) { + etm_in = kzalloc(sizeof(struct cti_trig_grp), GFP_KERNEL); + if (!etm_in) + goto of_create_v8_mem_err; + + etm_out = kzalloc(sizeof(struct cti_trig_grp), GFP_KERNEL); + if (!etm_out) + goto of_create_v8_mem_err; + + etm_sig_in_types = + kzalloc(sizeof(int) * NR_V8ETM_INOUT_SIGS, GFP_KERNEL); + if (!etm_sig_in_types) + goto of_create_v8_mem_err; + + etm_sig_out_types = + kzalloc(sizeof(int) * NR_V8ETM_INOUT_SIGS, GFP_KERNEL); + if (!etm_sig_out_types) + goto of_create_v8_mem_err; + } + + /* Create the v8 PE CTI connection */ + in->nr_sigs = NR_V8PE_IN_SIGS; + in->used_mask = 0x3; /* sigs <0 1> */ + in->sig_types = sig_in_types; + sig_in_types[0] = CTITRIG_PE_DBGTRIGGER; + sig_in_types[1] = CTITRIG_PE_PMUIRQ; + out->nr_sigs = NR_V8PE_OUT_SIGS; + out->used_mask = 0x7; /* sigs <0 1 2 > */ + out->sig_types = sig_out_types; + sig_out_types[0] = CTITRIG_PE_EDBGREQ; + sig_out_types[1] = CTITRIG_PE_DBGRESTART; + sig_out_types[2] = CTITRIG_PE_CTIIRQ; + scnprintf(cpu_name_str, 16, "cpu%d", cpuid); + + cti_add_connection_entry(drvdata, in, out, NULL, cpu_name_str); + + /* filter pe_edbgreq */ + drvdata->config.trig_out_filter = 0x1; + + /* Create the v8 ETM associated connection */ + if (cs_np) { + etm_in->nr_sigs = NR_V8ETM_INOUT_SIGS; + etm_in->used_mask = 0xF0; + etm_in->sig_types = etm_sig_in_types; + etm_out->nr_sigs = NR_V8ETM_INOUT_SIGS; + etm_out->used_mask = 0xF0; + etm_out->sig_types = etm_sig_out_types; + + for (i = 0; i < NR_V8ETM_INOUT_SIGS; i++) { + etm_sig_in_types[i] = CTITRIG_ETM_EXTOUT; + etm_sig_out_types[i] = CTITRIG_ETM_EXTIN; + } + + csdev = of_cti_get_assoc_cs_dev_by_node(cs_np); + if (csdev) + assoc_name = dev_name(&csdev->dev); + else + assoc_name = cs_np->full_name; + cti_add_connection_entry(drvdata, etm_in, etm_out, + csdev, assoc_name); + of_node_put(cs_np); + } + return 0; + +of_create_v8_mem_err: + kfree(in); + kfree(out); + kfree(sig_in_types); + kfree(sig_out_types); + if (cs_np) { + kfree(etm_in); + kfree(etm_out); + kfree(etm_sig_in_types); + kfree(etm_sig_out_types); + } + return -ENOMEM; +} + /* get the hardware configuration & connection data. */ int of_cti_get_hw_data(struct device *dev, struct device_node *np, @@ -48,8 +218,15 @@ int of_cti_get_hw_data(struct device *dev, int rc = 0; struct cti_device *cti_dev = &drvdata->ctidev;
+ /* get any CTM ID - defaults to 0 */ + of_property_read_u32(np, CTI_DT_CTM_ID, &cti_dev->ctm_id); + + /* check for a v8 architectural CTI device */ + if (of_property_read_bool(np, CTI_DT_V8ARCH)) + rc = of_cti_create_v8_connections(drvdata, np); + /* if no connections, just add a single default based on max IN-OUT */ - if (cti_dev->nr_trig_con == 0) + if (!rc && (cti_dev->nr_trig_con == 0)) rc = cti_add_default_connection(drvdata); return rc; }