Introduction of TPDM DSB subunit DSB subunit is responsible for creating a dataset element, and is also optionally responsible for packing it to fit multiple elements on a single ATB transfer if possible in the configuration. The TPDM Core Datapath requests timestamps be stored by the TPDA and then delivering ATB sized data (depending on ATB width and element size, this could be smaller or larger than a dataset element) to the ATB Mast FSM.
The DSB subunit must be configured prior to enablement. This series adds support for TPDM to configure the configure DSB subunit.
Once this series patches are applied properly, the new tpdm nodes for should be observed at the tpdm path /sys/bus/coresight/devices/tpdm* which supports DSB subunit. e.g. /sys/devices/platform/soc@0/69d0000.tpdm/tpdm0#ls -l | grep dsb -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_edge_ctrl -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_edge_ctrl_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_mode -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_ts -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_type -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_val -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_patt_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_patt_val -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_ts -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_type
We can use the commands are similar to the below to configure the TPDMs which support DSB subunit. Enable coresight sink first. echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tpdm0/reset echo 0x3 0x3 0x1 > /sys/bus/coresight/devices/tpdm0/dsb_edge_ctrl_mask echo 0x6d 0x6d 0 > /sys/bus/coresight/devices/tpdm0/dsb_edge_ctrl echo 1 > /sys/bus/coresight/devices/tpdm0/dsb_patt_ts echo 1 > /sys/bus/coresight/devices/tpdm0/dsb_patt_type echo 0 > /sys/bus/coresight/devices/tpdm0/dsb_trig_ts echo 0 0xFFFFFFFF > /sys/bus/coresight/devices/tpdm0/dsb_patt_mask echo 0 0xFFFFFFFF > /sys/bus/coresight/devices/tpdm0/dsb_trig_patt_val
This series applies to coresight/next https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git?h=next
This patch series depends on patch series "[v12,0/9] Coresight: Add support for TPDM and TPDA" https://patchwork.kernel.org/project/linux-arm-kernel/cover/20221114144027.1...
Tao Zhang (9): dt-bindings: arm: Add support for DSB element coresight-tpda: Add DSB dataset support coresight-tpdm: Initialize DSB subunit configuration coresight-tpdm: Add reset node to TPDM node coresight-tpdm: Add nodes to set trigger timestamp and type coresight-tpdm: Add node to set dsb programming mode coresight-tpdm: Add nodes for dsb element creation coresight-tpdm: Add nodes to configure pattern match output coresight-tpdm: Add nodes for timestamp request
.../bindings/arm/qcom,coresight-tpda.yaml | 9 + drivers/hwtracing/coresight/coresight-tpda.c | 62 ++ drivers/hwtracing/coresight/coresight-tpda.h | 4 + drivers/hwtracing/coresight/coresight-tpdm.c | 630 ++++++++++++++++++++- drivers/hwtracing/coresight/coresight-tpdm.h | 65 +++ 5 files changed, 765 insertions(+), 5 deletions(-)
Add property "qcom,dsb-elem-size" to support DSB(Discrete Single Bit) element for TPDA. Specifies the DSB element size supported by each monitor connected to the aggregator on each port. Should be specified in pairs (port, dsb element size).
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml index c46ddea..e3b58b5 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml @@ -58,6 +58,13 @@ properties: minItems: 1 maxItems: 2
+ qcom,dsb-elem-size: + description: | + Specifies the DSB element size supported by each monitor + connected to the aggregator on each port. Should be specified + in pairs (port, dsb element size). + $ref: /schemas/types.yaml#/definitions/uint32-matrix + clocks: maxItems: 1
@@ -100,6 +107,8 @@ examples: compatible = "qcom,coresight-tpda", "arm,primecell"; reg = <0x6004000 0x1000>;
+ qcom,dsb-elem-size = <0 32>; + clocks = <&aoss_qmp>; clock-names = "apb_pclk";
On 21/11/2022 08:21, Tao Zhang wrote:
Add property "qcom,dsb-elem-size" to support DSB(Discrete Single Bit) element for TPDA. Specifies the DSB element size supported by each monitor connected to the aggregator on each port. Should be specified in pairs (port, dsb element size).
Signed-off-by: Tao Zhang quic_taozha@quicinc.com
Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml index c46ddea..e3b58b5 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml @@ -58,6 +58,13 @@ properties: minItems: 1 maxItems: 2
- qcom,dsb-elem-size:
minor nit: Couldn't this be qcom,dsb-element-size ? Its not too long from what we have and is more meaningful.
Otherwise,
Acked-by: Suzuki K Poulose suzuki.poulose@arm.com
- description: |
Specifies the DSB element size supported by each monitor
connected to the aggregator on each port. Should be specified
in pairs (port, dsb element size).
- $ref: /schemas/types.yaml#/definitions/uint32-matrix
- clocks: maxItems: 1
@@ -100,6 +107,8 @@ examples: compatible = "qcom,coresight-tpda", "arm,primecell"; reg = <0x6004000 0x1000>;
qcom,dsb-elem-size = <0 32>;
clocks = <&aoss_qmp>; clock-names = "apb_pclk";
Read the DSB element size from the device tree. Set the register bit that controls the DSB element size of the corresponding port.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpda.c | 62 ++++++++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpda.h | 4 ++ 2 files changed, 66 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 7e4c287..8c6ea8a 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -37,6 +37,15 @@ static void tpda_enable_port(struct tpda_drvdata *drvdata, int port) u32 val;
val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port)); + /* + * Configure aggregator port n DSB data set element size + * Set the bit to 0 if the size is 32 + * Set the bit to 1 if the size is 64 + */ + if (drvdata->dsb_esize[port] == 32) + val &= ~TPDA_Pn_CR_DSBSIZE; + else if (drvdata->dsb_esize[port] == 64) + val |= TPDA_Pn_CR_DSBSIZE; /* Enable the port */ val |= TPDA_Pn_CR_ENA; writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port)); @@ -105,6 +114,55 @@ static const struct coresight_ops tpda_cs_ops = { .link_ops = &tpda_link_ops, };
+static int tpda_parse_dsb(struct tpda_drvdata *drvdata) +{ + int len, port, i; + const __be32 *prop; + struct device_node *node = drvdata->dev->of_node; + + /* Read the size of DSB element */ + prop = of_get_property(node, "qcom,dsb-elem-size", &len); + if (prop) { + len /= sizeof(__be32); + /* + * The read set of data is port and size, so the number of data + * is a multiple of two. And the number of data will not exceed + * two times that of the TPDA inpurts number. + */ + if (len < 2 || len >= (2 * TPDA_MAX_INPORTS) || len % 2 != 0) { + dev_err(drvdata->dev, + "Dataset DSB width entries are wrong\n"); + return -EINVAL; + } + + for (i = 0; i < len; i += 2) { + port = be32_to_cpu(prop[i]); + if (port >= TPDA_MAX_INPORTS) { + dev_err(drvdata->dev, + "Wrong port specified for DSB\n"); + return -EINVAL; + } + /* Set DSB element size for corresponding port to dsb_esize*/ + drvdata->dsb_esize[port] = be32_to_cpu(prop[i + 1]); + } + } + + return 0; +} + +static int tpda_parse_of_data(struct tpda_drvdata *drvdata) +{ + int ret; + + ret = tpda_parse_dsb(drvdata); + if (ret) { + dev_err(drvdata->dev, "Fail to get DSB data set element size\n"); + return -EINVAL; + } + + return 0; +} + static int tpda_init_default_data(struct tpda_drvdata *drvdata) { int atid; @@ -151,6 +209,10 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
spin_lock_init(&drvdata->spinlock);
+ ret = tpda_parse_of_data(drvdata); + if (ret) + return ret; + ret = tpda_init_default_data(drvdata); if (ret) return ret; diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h index 4beb332..af3cc8f 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.h +++ b/drivers/hwtracing/coresight/coresight-tpda.h @@ -10,6 +10,8 @@ #define TPDA_Pn_CR(n) (0x004 + (n * 4)) /* Aggregator port enable bit */ #define TPDA_Pn_CR_ENA BIT(0) +/* Aggregator port DSB data set element size bit */ +#define TPDA_Pn_CR_DSBSIZE BIT(8)
#define TPDA_MAX_INPORTS 32
@@ -23,6 +25,7 @@ * @csdev: component vitals needed by the framework. * @spinlock: lock for the drvdata value. * @enable: enable status of the component. + * @dsb_esize: DSB element size */ struct tpda_drvdata { void __iomem *base; @@ -30,6 +33,7 @@ struct tpda_drvdata { struct coresight_device *csdev; spinlock_t spinlock; u8 atid; + u32 dsb_esize[TPDA_MAX_INPORTS]; };
#endif /* _CORESIGHT_CORESIGHT_TPDA_H */
DSB subunit need to be configured in enablement and disablement. A struct that specifics associated to dsb dataset is needed. It saves the configuration and parameters of the dsb datasets. This change is to add this struct and initialize the configuration of DSB subunit.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 57 ++++++++++++++++++++++++++-- drivers/hwtracing/coresight/coresight-tpdm.h | 17 +++++++++ 2 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 88df3e6..60de21d 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -24,13 +24,35 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) { u32 val;
+ val = readl_relaxed(drvdata->base + TPDM_DSB_TIER); + /* Set trigger timestamp */ + if (drvdata->dsb->trig_ts) + val |= TPDM_DSB_XTRIG_TSENAB; + else + val &= ~TPDM_DSB_XTRIG_TSENAB; + writel_relaxed(val, drvdata->base + TPDM_DSB_TIER); + + val = readl_relaxed(drvdata->base + TPDM_DSB_CR); + /* Set trigger type */ + if (drvdata->dsb->trig_type) + val |= TPDM_DSB_TRIG_TYPE; + else + val &= ~TPDM_DSB_TRIG_TYPE; + writel_relaxed(val, drvdata->base + TPDM_DSB_CR); + /* Set the enable bit of DSB control register to 1 */ val = readl_relaxed(drvdata->base + TPDM_DSB_CR); val |= TPDM_DSB_CR_ENA; writel_relaxed(val, drvdata->base + TPDM_DSB_CR); }
-/* TPDM enable operations */ +/* TPDM enable operations + * The TPDM or Monitor serves as data collection component for various + * dataset types. It covers Basic Counts(BC), Tenure Counts(TC), + * Continuous Multi-Bit(CMB), Multi-lane CMB(MCMB) and Discrete Single + * Bit(DSB). This function will initialize the configuration according + * to the dataset type supported by the TPDM. + */ static void __tpdm_enable(struct tpdm_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -110,15 +132,33 @@ static const struct coresight_ops tpdm_cs_ops = { .source_ops = &tpdm_source_ops, };
-static void tpdm_init_default_data(struct tpdm_drvdata *drvdata) +static void tpdm_datasets_setup(struct tpdm_drvdata *drvdata) { u32 pidr;
- CS_UNLOCK(drvdata->base); /* Get the datasets present on the TPDM. */ pidr = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR0); drvdata->datasets |= pidr & GENMASK(TPDM_DATASETS - 1, 0); - CS_LOCK(drvdata->base); +} + +static int tpdm_datasets_alloc(struct tpdm_drvdata *drvdata) +{ + if (drvdata->datasets & TPDM_PIDR0_DS_DSB) { + drvdata->dsb = devm_kzalloc(drvdata->dev, sizeof(*drvdata->dsb), + GFP_KERNEL); + if (!drvdata->dsb) + return -ENOMEM; + } + + return 0; +} + +static void tpdm_init_default_data(struct tpdm_drvdata *drvdata) +{ + if (drvdata->datasets & TPDM_PIDR0_DS_DSB) { + drvdata->dsb->trig_ts = true; + drvdata->dsb->trig_type = false; + } }
/* @@ -181,6 +221,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) struct coresight_platform_data *pdata; struct tpdm_drvdata *drvdata; struct coresight_desc desc = { 0 }; + int ret;
pdata = coresight_get_platform_data(dev); if (IS_ERR(pdata)) @@ -200,6 +241,8 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->base = base;
+ tpdm_datasets_setup(drvdata); + /* Set up coresight component description */ desc.name = coresight_alloc_device_name(&tpdm_devs, dev); if (!desc.name) @@ -216,7 +259,13 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) return PTR_ERR(drvdata->csdev);
spin_lock_init(&drvdata->spinlock); + ret = tpdm_datasets_alloc(drvdata); + if (ret) { + coresight_unregister(drvdata->csdev); + return ret; + } tpdm_init_default_data(drvdata); + /* Decrease pm refcount when probe is done.*/ pm_runtime_put(&adev->dev);
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index d808fa1..dd4a013 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -11,8 +11,14 @@
/* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) +#define TPDM_DSB_TIER (0x784) + /* Enable bit for DSB subunit */ #define TPDM_DSB_CR_ENA BIT(0) +/* Enable bit for DSB subunit trigger timestamp */ +#define TPDM_DSB_XTRIG_TSENAB BIT(1) +/* Enable bit for DSB subunit trigger type */ +#define TPDM_DSB_TRIG_TYPE BIT(12)
/* TPDM integration test registers */ #define TPDM_ITATBCNTRL (0xEF0) @@ -41,6 +47,16 @@ #define TPDM_PIDR0_DS_DSB BIT(1)
/** + * struct dsb_dataset - specifics associated to dsb dataset + * @trig_ts: Enable/Disable trigger timestamp. + * @trig_type: Enable/Disable trigger type. + */ +struct dsb_dataset { + bool trig_ts; + bool trig_type; +}; + +/** * struct tpdm_drvdata - specifics associated to an TPDM component * @base: memory mapped base address for this component. * @dev: The device entity associated to this component. @@ -57,6 +73,7 @@ struct tpdm_drvdata { spinlock_t spinlock; bool enable; unsigned long datasets; + struct dsb_dataset *dsb; };
#endif /* _CORESIGHT_CORESIGHT_TPDM_H */
TPDM device need a node to reset the configurations and status of it. So as to avoid the previous configurations affecting the current use, the configurations need to be reset first. And in some scenarios, it may be necessary to reset the TPDM configurations to complete the verification of certain function. This change provides a node to reset the configurations and disable the TPDM if it has been enabled.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 60de21d..5d5f442 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -161,6 +161,37 @@ static void tpdm_init_default_data(struct tpdm_drvdata *drvdata) } }
+static ssize_t reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + int ret = 0; + unsigned long val; + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + ret = kstrtoul(buf, 0, &val); + if (ret || (val != 1)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + /* Reset all datasets to ZERO */ + if (drvdata->dsb != NULL) + memset(drvdata->dsb, 0, sizeof(struct dsb_dataset)); + + /* Init the default data */ + tpdm_init_default_data(drvdata); + + spin_unlock(&drvdata->spinlock); + + /* Disable tpdm if enabled */ + if (drvdata->enable) + coresight_disable(drvdata->csdev); + + return size; +} +static DEVICE_ATTR_WO(reset); + /* * value 1: 64 bits test data * value 2: 32 bits test data @@ -201,6 +232,7 @@ static ssize_t integration_test_store(struct device *dev, static DEVICE_ATTR_WO(integration_test);
static struct attribute *tpdm_attrs[] = { + &dev_attr_reset.attr, &dev_attr_integration_test.attr, NULL, };
The nodes are needed to set or show the trigger timestamp and trigger type. This change is to add these nodes to achieve these function.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 97 ++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 5d5f442..35b328e 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -20,6 +20,22 @@
DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm");
+static umode_t tpdm_dsb_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (drvdata) { + if (drvdata->datasets & TPDM_PIDR0_DS_DSB) + return attr->mode; + else + return 0; + } + + return 0; +} + static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) { u32 val; @@ -241,8 +257,89 @@ static struct attribute_group tpdm_attr_grp = { .attrs = tpdm_attrs, };
+static ssize_t dsb_trig_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->dsb->trig_type); +} + +/* + * value 0: set trigger type as enablement + * value 1: set trigger type as disablement + */ +static ssize_t dsb_trig_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if ((kstrtoul(buf, 0, &val)) || val < 0 || val > 1) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + if (val) + drvdata->dsb->trig_type = true; + else + drvdata->dsb->trig_type = false; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_type); + +static ssize_t dsb_trig_ts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->dsb->trig_ts); +} + +/* + * value 0: set trigger timestamp as enablement + * value 1: set trigger timestamp as disablement + */ +static ssize_t dsb_trig_ts_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if ((kstrtoul(buf, 0, &val)) || val < 0 || val > 1) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + if (val) + drvdata->dsb->trig_ts = true; + else + drvdata->dsb->trig_ts = false; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_ts); +static struct attribute *tpdm_dsb_attrs[] = { + &dev_attr_dsb_trig_ts.attr, + &dev_attr_dsb_trig_type.attr, + NULL, +}; + +static struct attribute_group tpdm_dsb_attr_grp = { + .attrs = tpdm_dsb_attrs, + .is_visible = tpdm_dsb_is_visible, +}; + static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_attr_grp, + &tpdm_dsb_attr_grp, NULL, };
Add node to set and show programming mode for TPDM DSB subunit. Once the DSB programming mode is set, it will be written to the register DSB_CR. Bit[10:9] of the DSB_CR register is used to set the DSB test mode.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 45 +++++++++++++++++++++++++++- drivers/hwtracing/coresight/coresight-tpdm.h | 12 ++++++++ 2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 35b328e..8872e3a 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -4,6 +4,7 @@ */
#include <linux/amba/bus.h> +#include <linux/bitfield.h> #include <linux/bitmap.h> #include <linux/coresight.h> #include <linux/coresight-pmu.h> @@ -38,7 +39,7 @@ static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) { - u32 val; + u32 val, mode;
val = readl_relaxed(drvdata->base + TPDM_DSB_TIER); /* Set trigger timestamp */ @@ -58,6 +59,19 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
/* Set the enable bit of DSB control register to 1 */ val = readl_relaxed(drvdata->base + TPDM_DSB_CR); + /* Set the cycle accurate mode */ + mode = TPDM_DSB_MODE_CYCACC(drvdata->dsb->mode); + val &= ~TPDM_DSB_TEST_MODE; + val |= FIELD_PREP(TPDM_DSB_TEST_MODE, mode); + /* Set the byte lane for high-performance mode */ + mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode); + val &= ~TPDM_DSB_HPSEL; + val |= FIELD_PREP(TPDM_DSB_HPSEL, mode); + /* Set the performance mode */ + if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF) + val |= TPDM_DSB_MODE; + else + val &= ~TPDM_DSB_MODE; val |= TPDM_DSB_CR_ENA; writel_relaxed(val, drvdata->base + TPDM_DSB_CR); } @@ -257,6 +271,34 @@ static struct attribute_group tpdm_attr_grp = { .attrs = tpdm_attrs, };
+static ssize_t dsb_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%lx\n", + (unsigned long)drvdata->dsb->mode); +} + +static ssize_t dsb_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if ((kstrtoul(buf, 0, &val)) || val < 0) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + drvdata->dsb->mode = val & TPDM_MODE_ALL; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_mode); + static ssize_t dsb_trig_type_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -327,6 +369,7 @@ static ssize_t dsb_trig_ts_store(struct device *dev, } static DEVICE_ATTR_RW(dsb_trig_ts); static struct attribute *tpdm_dsb_attrs[] = { + &dev_attr_dsb_mode.attr, &dev_attr_dsb_trig_ts.attr, &dev_attr_dsb_trig_type.attr, NULL, diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index dd4a013..de1492c 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -19,6 +19,16 @@ #define TPDM_DSB_XTRIG_TSENAB BIT(1) /* Enable bit for DSB subunit trigger type */ #define TPDM_DSB_TRIG_TYPE BIT(12) +/* Enable bit for DSB subunit perfmance mode */ +#define TPDM_DSB_MODE BIT(1) + +/* DSB programming modes */ +#define TPDM_DSB_MODE_CYCACC(val) (val & GENMASK(2, 0)) +#define TPDM_DSB_MODE_PERF BIT(3) +#define TPDM_DSB_MODE_HPBYTESEL(val) (val & GENMASK(8, 4)) +#define TPDM_MODE_ALL (0xFFFFFFF) +#define TPDM_DSB_TEST_MODE GENMASK(11, 9) +#define TPDM_DSB_HPSEL GENMASK(6, 2)
/* TPDM integration test registers */ #define TPDM_ITATBCNTRL (0xEF0) @@ -48,10 +58,12 @@
/** * struct dsb_dataset - specifics associated to dsb dataset + * @mode: DSB programming mode * @trig_ts: Enable/Disable trigger timestamp. * @trig_type: Enable/Disable trigger type. */ struct dsb_dataset { + u32 mode; bool trig_ts; bool trig_type; };
Add the nodes to set value for DSB edge control and DSB edge control mask. Each DSB subunit TPDM has maximum of n(n<16) EDCR resgisters to configure edge control. DSB edge detection control 00: Rising edge detection 01: Falling edge detection 10: Rising and falling edge detection (toggle detection) And each DSB subunit TPDM has maximum of m(m<8) ECDMR registers to configure mask. Eight 32 bit registers providing DSB interface edge detection mask control.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 142 ++++++++++++++++++++++++++- drivers/hwtracing/coresight/coresight-tpdm.h | 14 +++ 2 files changed, 155 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 8872e3a..b0cc161 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -39,7 +39,14 @@ static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) { - u32 val, mode; + u32 val, mode, i; + + for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) + writel_relaxed(drvdata->dsb->edge_ctrl[i], + drvdata->base + TPDM_DSB_EDCR(i)); + for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++) + writel_relaxed(drvdata->dsb->edge_ctrl_mask[i], + drvdata->base + TPDM_DSB_EDCMR(i));
val = readl_relaxed(drvdata->base + TPDM_DSB_TIER); /* Set trigger timestamp */ @@ -299,6 +306,137 @@ static ssize_t dsb_mode_store(struct device *dev, } static DEVICE_ATTR_RW(dsb_mode);
+static ssize_t dsb_edge_ctrl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i; + + spin_lock(&drvdata->spinlock); + for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) { + size += sysfs_emit_at(buf, size, + "Index:0x%x Val:0x%x\n", i, + drvdata->dsb->edge_ctrl[i]); + } + spin_unlock(&drvdata->spinlock); + return size; +} + +/* + * value 1: Start EDCR register number + * value 2: End EDCR register number + * value 3: The value need to be written + * The EDCR registers can include up to 16 32-bit registers, and each + * one can be configured to control up to 16 edge detections(2 bits + * control one edge detection). So a total 256 edge detections can be + * configured. So the starting number(value 1) and ending number(value 2) + * cannot be greater than 256, and value 1 should be less than value 2. + * The following values are the rage of value 3. + * 0 - Rising edge detection + * 1 - Falling edge detection + * 2 - Rising and falling edge detection (toggle detection) + */ +static ssize_t dsb_edge_ctrl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long start, end, edge_ctrl; + uint32_t val; + int i, index, bit, reg; + + if (sscanf(buf, "%lx %lx %lx", &start, &end, &edge_ctrl) != 3) + return -EINVAL; + if ((start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES) || + edge_ctrl > 0x2) + return -EPERM; + + spin_lock(&drvdata->spinlock); + for (i = start; i <= end; i++) { + /* + * The 32-bit register has 32 bits(NUM_OF_BITS). + * Each one register can be configured to control 16 + * (NUM_OF_BITS / 2) edge detectioins. + */ + reg = i / (NUM_OF_BITS / 2); + index = i % (NUM_OF_BITS / 2); + bit = index * 2; + + val = drvdata->dsb->edge_ctrl[reg]; + val &= ~GENMASK((bit + 1), bit); + val |= (edge_ctrl << bit); + drvdata->dsb->edge_ctrl[reg] = val; + } + spin_unlock(&drvdata->spinlock); + + return size; +} +static DEVICE_ATTR_RW(dsb_edge_ctrl); + +static ssize_t dsb_edge_ctrl_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i; + + spin_lock(&drvdata->spinlock); + for (i = 0; i < TPDM_DSB_MAX_EDCR / 2; i++) { + size += sysfs_emit_at(buf, size, + "Index:0x%x Val:0x%x\n", i, + drvdata->dsb->edge_ctrl_mask[i]); + } + spin_unlock(&drvdata->spinlock); + return size; +} + +/* + * value 1: Start EDCMR register number + * value 2: End EDCMR register number + * value 3: The value need to be written + */ +static ssize_t dsb_edge_ctrl_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long start, end, val; + u32 set; + int i, index, reg; + + if (sscanf(buf, "%lx %lx %lx", &start, &end, &val) != 3) + return -EINVAL; + if ((start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES) + || (val < 0) || (val > 1)) + return -EPERM; + + spin_lock(&drvdata->spinlock); + for (i = start; i <= end; i++) { + /* + * The 32-bit register has 32 bits(NUM_OF_BITS). + * Each one register can be configured to control 32 + * (NUM_OF_BITS) edge detectioin masks. + */ + reg = i / NUM_OF_BITS; + index = (i % NUM_OF_BITS); + + set = drvdata->dsb->edge_ctrl_mask[reg]; + if (val) + set |= BIT(index); + else + set &= ~BIT(index); + drvdata->dsb->edge_ctrl_mask[reg] = set; + } + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_edge_ctrl_mask); + static ssize_t dsb_trig_type_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -370,6 +508,8 @@ static ssize_t dsb_trig_ts_store(struct device *dev, static DEVICE_ATTR_RW(dsb_trig_ts); static struct attribute *tpdm_dsb_attrs[] = { &dev_attr_dsb_mode.attr, + &dev_attr_dsb_edge_ctrl.attr, + &dev_attr_dsb_edge_ctrl_mask.attr, &dev_attr_dsb_trig_ts.attr, &dev_attr_dsb_trig_type.attr, NULL, diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index de1492c..bd9d006 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -12,6 +12,8 @@ /* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) #define TPDM_DSB_TIER (0x784) +#define TPDM_DSB_EDCR(n) (0x808 + (n * 4)) +#define TPDM_DSB_EDCMR(n) (0x848 + (n * 4))
/* Enable bit for DSB subunit */ #define TPDM_DSB_CR_ENA BIT(0) @@ -30,6 +32,8 @@ #define TPDM_DSB_TEST_MODE GENMASK(11, 9) #define TPDM_DSB_HPSEL GENMASK(6, 2)
+#define NUM_OF_BITS 32 + /* TPDM integration test registers */ #define TPDM_ITATBCNTRL (0xEF0) #define TPDM_ITCNTRL (0xF00) @@ -56,14 +60,24 @@ #define TPDM_PIDR0_DS_IMPDEF BIT(0) #define TPDM_PIDR0_DS_DSB BIT(1)
+#define TPDM_DSB_MAX_LINES 256 +/* MAX number of EDCR registers */ +#define TPDM_DSB_MAX_EDCR 16 +/* MAX number of EDCMR registers */ +#define TPDM_DSB_MAX_EDCMR 8 + /** * struct dsb_dataset - specifics associated to dsb dataset * @mode: DSB programming mode + * @edge_ctrl: Save value for edge control + * @edge_ctrl_mask: Save value for edge control mask * @trig_ts: Enable/Disable trigger timestamp. * @trig_type: Enable/Disable trigger type. */ struct dsb_dataset { u32 mode; + u32 edge_ctrl[TPDM_DSB_MAX_EDCR]; + u32 edge_ctrl_mask[TPDM_DSB_MAX_EDCMR]; bool trig_ts; bool trig_type; };
Add nodes to configure trigger pattern and trigger pattern mask. Each DSB subunit TPDM has maximum of n(n<7) XPR registers to configure trigger pattern match output. Eight 32 bit registers providing DSB interface trigger output pattern match comparison. And each DSB subunit TPDM has maximum of m(m<7) XPMR registers to configure trigger pattern mask match output. Eight 32 bit registers providing DSB interface trigger output pattern match mask.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 85 ++++++++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpdm.h | 8 +++ 2 files changed, 93 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index b0cc161..2a0b8ed 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -48,6 +48,13 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) writel_relaxed(drvdata->dsb->edge_ctrl_mask[i], drvdata->base + TPDM_DSB_EDCMR(i));
+ for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + writel_relaxed(drvdata->dsb->trig_patt_val[i], + drvdata->base + TPDM_DSB_XPR(i)); + writel_relaxed(drvdata->dsb->trig_patt_mask[i], + drvdata->base + TPDM_DSB_XPMR(i)); + } + val = readl_relaxed(drvdata->base + TPDM_DSB_TIER); /* Set trigger timestamp */ if (drvdata->dsb->trig_ts) @@ -437,6 +444,82 @@ static ssize_t dsb_edge_ctrl_mask_store(struct device *dev, } static DEVICE_ATTR_RW(dsb_edge_ctrl_mask);
+static ssize_t dsb_trig_patt_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + spin_lock(&drvdata->spinlock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += sysfs_emit_at(buf, size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->trig_patt_val[i]); + } + spin_unlock(&drvdata->spinlock); + return size; +} + +static ssize_t dsb_trig_patt_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + spin_lock(&drvdata->spinlock); + drvdata->dsb->trig_patt_val[index] = val; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_patt_val); + +static ssize_t dsb_trig_patt_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + spin_lock(&drvdata->spinlock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += sysfs_emit_at(buf, size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->trig_patt_mask[i]); + } + spin_unlock(&drvdata->spinlock); + return size; +} + +static ssize_t dsb_trig_patt_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + spin_lock(&drvdata->spinlock); + drvdata->dsb->trig_patt_mask[index] = val; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_patt_mask); + static ssize_t dsb_trig_type_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -510,6 +593,8 @@ static struct attribute *tpdm_dsb_attrs[] = { &dev_attr_dsb_mode.attr, &dev_attr_dsb_edge_ctrl.attr, &dev_attr_dsb_edge_ctrl_mask.attr, + &dev_attr_dsb_trig_patt_val.attr, + &dev_attr_dsb_trig_patt_mask.attr, &dev_attr_dsb_trig_ts.attr, &dev_attr_dsb_trig_type.attr, NULL, diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index bd9d006..386a0e5 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -12,6 +12,8 @@ /* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) #define TPDM_DSB_TIER (0x784) +#define TPDM_DSB_XPR(n) (0x7C8 + (n * 4)) +#define TPDM_DSB_XPMR(n) (0x7E8 + (n * 4)) #define TPDM_DSB_EDCR(n) (0x808 + (n * 4)) #define TPDM_DSB_EDCMR(n) (0x848 + (n * 4))
@@ -65,12 +67,16 @@ #define TPDM_DSB_MAX_EDCR 16 /* MAX number of EDCMR registers */ #define TPDM_DSB_MAX_EDCMR 8 +/* MAX number of DSB pattern */ +#define TPDM_DSB_MAX_PATT 8
/** * struct dsb_dataset - specifics associated to dsb dataset * @mode: DSB programming mode * @edge_ctrl: Save value for edge control * @edge_ctrl_mask: Save value for edge control mask + * @trig_patt_val: Save value for trigger pattern + * @trig_patt_mask: Save value for trigger pattern mask * @trig_ts: Enable/Disable trigger timestamp. * @trig_type: Enable/Disable trigger type. */ @@ -78,6 +84,8 @@ struct dsb_dataset { u32 mode; u32 edge_ctrl[TPDM_DSB_MAX_EDCR]; u32 edge_ctrl_mask[TPDM_DSB_MAX_EDCMR]; + u32 trig_patt_val[TPDM_DSB_MAX_PATT]; + u32 trig_patt_mask[TPDM_DSB_MAX_PATT]; bool trig_ts; bool trig_type; };
Add nodes to configure the timestamp request based on input pattern match. Each TPDM that support DSB subunit has maximum of n(n<7) TPR registers to configure value for timestamp request based on input pattern match. Eight 32 bit registers providing DSB interface timestamp request pattern match comparison. And each TPDM that support DSB subunit has maximum of m(m<7) TPMR registers to configure pattern mask for timestamp request. Eight 32 bit registers providing DSB interface timestamp request pattern match mask generation. Add nodes to enable/disable pattern timestamp and set pattern timestamp type.
Signed-off-by: Tao Zhang quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 174 +++++++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpdm.h | 14 +++ 2 files changed, 188 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 2a0b8ed..1cc9eb0 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -49,6 +49,13 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) drvdata->base + TPDM_DSB_EDCMR(i));
for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + writel_relaxed(drvdata->dsb->patt_val[i], + drvdata->base + TPDM_DSB_TPR(i)); + writel_relaxed(drvdata->dsb->patt_mask[i], + drvdata->base + TPDM_DSB_TPMR(i)); + } + + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { writel_relaxed(drvdata->dsb->trig_patt_val[i], drvdata->base + TPDM_DSB_XPR(i)); writel_relaxed(drvdata->dsb->trig_patt_mask[i], @@ -56,6 +63,16 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) }
val = readl_relaxed(drvdata->base + TPDM_DSB_TIER); + /* Set pattern timestamp type and enablement */ + if (drvdata->dsb->patt_ts) { + val |= TPDM_DSB_PATT_TSENAB; + if (drvdata->dsb->patt_type) + val |= TPDM_DSB_PATT_TYPE; + else + val &= ~TPDM_DSB_PATT_TYPE; + } else { + val &= ~TPDM_DSB_PATT_TSENAB; + } /* Set trigger timestamp */ if (drvdata->dsb->trig_ts) val |= TPDM_DSB_XTRIG_TSENAB; @@ -444,6 +461,159 @@ static ssize_t dsb_edge_ctrl_mask_store(struct device *dev, } static DEVICE_ATTR_RW(dsb_edge_ctrl_mask);
+static ssize_t dsb_patt_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + spin_lock(&drvdata->spinlock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += sysfs_emit_at(buf, size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->patt_val[i]); + } + spin_unlock(&drvdata->spinlock); + return size; +} + +/* + * value 1: Index of TPR register + * value 2: Value need to be written + */ +static ssize_t dsb_patt_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + spin_lock(&drvdata->spinlock); + drvdata->dsb->patt_val[index] = val; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_val); + +static ssize_t dsb_patt_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + spin_lock(&drvdata->spinlock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += sysfs_emit_at(buf, size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->patt_mask[i]); + } + spin_unlock(&drvdata->spinlock); + return size; +} + +/* + * value 1: Index of TPMR register + * value 2: Value need to be written + */ +static ssize_t dsb_patt_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + spin_lock(&drvdata->spinlock); + drvdata->dsb->patt_mask[index] = val; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_mask); + +static ssize_t dsb_patt_ts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->dsb->patt_ts); +} + +/* + * value 1: Enable/Disable DSB pattern timestamp + */ +static ssize_t dsb_patt_ts_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(drvdata->datasets & TPDM_PIDR0_DS_DSB)) + return -EPERM; + + spin_lock(&drvdata->spinlock); + if (val) + drvdata->dsb->patt_ts = true; + else + drvdata->dsb->patt_ts = false; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_ts); + +static ssize_t dsb_patt_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + + return sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->dsb->patt_type); +} + +/* + * value 1: Set DSB pattern type + */ +static ssize_t dsb_patt_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + if (val) + drvdata->dsb->patt_type = true; + else + drvdata->dsb->patt_type = false; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_type); + static ssize_t dsb_trig_patt_val_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -593,6 +763,10 @@ static struct attribute *tpdm_dsb_attrs[] = { &dev_attr_dsb_mode.attr, &dev_attr_dsb_edge_ctrl.attr, &dev_attr_dsb_edge_ctrl_mask.attr, + &dev_attr_dsb_patt_val.attr, + &dev_attr_dsb_patt_mask.attr, + &dev_attr_dsb_patt_ts.attr, + &dev_attr_dsb_patt_type.attr, &dev_attr_dsb_trig_patt_val.attr, &dev_attr_dsb_trig_patt_mask.attr, &dev_attr_dsb_trig_ts.attr, diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index 386a0e5..fa550f3 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -12,6 +12,8 @@ /* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) #define TPDM_DSB_TIER (0x784) +#define TPDM_DSB_TPR(n) (0x788 + (n * 4)) +#define TPDM_DSB_TPMR(n) (0x7A8 + (n * 4)) #define TPDM_DSB_XPR(n) (0x7C8 + (n * 4)) #define TPDM_DSB_XPMR(n) (0x7E8 + (n * 4)) #define TPDM_DSB_EDCR(n) (0x808 + (n * 4)) @@ -19,8 +21,12 @@
/* Enable bit for DSB subunit */ #define TPDM_DSB_CR_ENA BIT(0) +/* Enable bit for DSB subunit pattern timestamp */ +#define TPDM_DSB_PATT_TSENAB BIT(0) /* Enable bit for DSB subunit trigger timestamp */ #define TPDM_DSB_XTRIG_TSENAB BIT(1) +/* Bit for DSB subunit pattern type */ +#define TPDM_DSB_PATT_TYPE BIT(2) /* Enable bit for DSB subunit trigger type */ #define TPDM_DSB_TRIG_TYPE BIT(12) /* Enable bit for DSB subunit perfmance mode */ @@ -75,6 +81,10 @@ * @mode: DSB programming mode * @edge_ctrl: Save value for edge control * @edge_ctrl_mask: Save value for edge control mask + * @patt_val: Save value for pattern + * @patt_mask: Save value for pattern mask + * @patt_ts: Enable/Disable pattern timestamp + * @patt_type: Set pattern type * @trig_patt_val: Save value for trigger pattern * @trig_patt_mask: Save value for trigger pattern mask * @trig_ts: Enable/Disable trigger timestamp. @@ -84,6 +94,10 @@ struct dsb_dataset { u32 mode; u32 edge_ctrl[TPDM_DSB_MAX_EDCR]; u32 edge_ctrl_mask[TPDM_DSB_MAX_EDCMR]; + u32 patt_val[TPDM_DSB_MAX_PATT]; + u32 patt_mask[TPDM_DSB_MAX_PATT]; + bool patt_ts; + bool patt_type; u32 trig_patt_val[TPDM_DSB_MAX_PATT]; u32 trig_patt_mask[TPDM_DSB_MAX_PATT]; bool trig_ts;
On 21/11/2022 08:21, Tao Zhang wrote:
Introduction of TPDM DSB subunit DSB subunit is responsible for creating a dataset element, and is also optionally responsible for packing it to fit multiple elements on a single ATB transfer if possible in the configuration. The TPDM Core Datapath requests timestamps be stored by the TPDA and then delivering ATB sized data (depending on ATB width and element size, this could be smaller or larger than a dataset element) to the ATB Mast FSM.
The DSB subunit must be configured prior to enablement. This series adds support for TPDM to configure the configure DSB subunit.
Once this series patches are applied properly, the new tpdm nodes for should be observed at the tpdm path /sys/bus/coresight/devices/tpdm* which supports DSB subunit. e.g. /sys/devices/platform/soc@0/69d0000.tpdm/tpdm0#ls -l | grep dsb -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_edge_ctrl -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_edge_ctrl_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_mode -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_ts -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_type -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_val -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_patt_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_patt_val -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_ts -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_type
We can use the commands are similar to the below to configure the TPDMs which support DSB subunit. Enable coresight sink first. echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tpdm0/reset echo 0x3 0x3 0x1 > /sys/bus/coresight/devices/tpdm0/dsb_edge_ctrl_mask echo 0x6d 0x6d 0 > /sys/bus/coresight/devices/tpdm0/dsb_edge_ctrl echo 1 > /sys/bus/coresight/devices/tpdm0/dsb_patt_ts echo 1 > /sys/bus/coresight/devices/tpdm0/dsb_patt_type echo 0 > /sys/bus/coresight/devices/tpdm0/dsb_trig_ts echo 0 0xFFFFFFFF > /sys/bus/coresight/devices/tpdm0/dsb_patt_mask echo 0 0xFFFFFFFF > /sys/bus/coresight/devices/tpdm0/dsb_trig_patt_val
This series applies to coresight/next https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git?h=next
Does it ?
This patch series depends on patch series "[v12,0/9] Coresight: Add support for TPDM and TPDA" https://patchwork.kernel.org/project/linux-arm-kernel/cover/20221114144027.1...
And the CoreSight Dynamice Trace ID series too.
Change log please
Suzuki
On 21/11/2022 10:21, Suzuki Kuruppassery Poulose wrote:
On 21/11/2022 08:21, Tao Zhang wrote:
Introduction of TPDM DSB subunit DSB subunit is responsible for creating a dataset element, and is also optionally responsible for packing it to fit multiple elements on a single ATB transfer if possible in the configuration. The TPDM Core Datapath requests timestamps be stored by the TPDA and then delivering ATB sized data (depending on ATB width and element size, this could be smaller or larger than a dataset element) to the ATB Mast FSM.
The DSB subunit must be configured prior to enablement. This series adds support for TPDM to configure the configure DSB subunit.
Once this series patches are applied properly, the new tpdm nodes for should be observed at the tpdm path /sys/bus/coresight/devices/tpdm* which supports DSB subunit. e.g. /sys/devices/platform/soc@0/69d0000.tpdm/tpdm0#ls -l | grep dsb -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_edge_ctrl -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_edge_ctrl_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_mode -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_ts -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_type -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_patt_val -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_patt_mask -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_patt_val -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_ts -rw-r--r-- 1 root root 4096 Jan 1 00:01 dsb_trig_type
We can use the commands are similar to the below to configure the TPDMs which support DSB subunit. Enable coresight sink first. echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tpdm0/reset echo 0x3 0x3 0x1 > /sys/bus/coresight/devices/tpdm0/dsb_edge_ctrl_mask echo 0x6d 0x6d 0 > /sys/bus/coresight/devices/tpdm0/dsb_edge_ctrl echo 1 > /sys/bus/coresight/devices/tpdm0/dsb_patt_ts echo 1 > /sys/bus/coresight/devices/tpdm0/dsb_patt_type echo 0 > /sys/bus/coresight/devices/tpdm0/dsb_trig_ts echo 0 0xFFFFFFFF > /sys/bus/coresight/devices/tpdm0/dsb_patt_mask echo 0 0xFFFFFFFF > /sys/bus/coresight/devices/tpdm0/dsb_trig_patt_val
This series applies to coresight/next https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git?h=next
Does it ?
This patch series depends on patch series "[v12,0/9] Coresight: Add support for TPDM and TPDA" https://patchwork.kernel.org/project/linux-arm-kernel/cover/20221114144027.1...
And the CoreSight Dynamice Trace ID series too.
Change log please
Also, more importantly, as requested previousl please host a tree with all the dependencies applied including this series. It is hard to review looking all the way back to a dependent series back and forth. Or we could shelve this until the dependencies are merged/queued.
Suzuki