[PATCH 9/9] coresight-tpdm: Add nodes for timestamp request

From: Tao Zhang
Date: Thu Sep 08 2022 - 04:46:39 EST


Add nodes to configure the timestamp request based on input
pattern match. Each TPDM that support DSB subunit has n(0-7) TPR
registers to configure value for timestamp request based on input
pattern match, and has m(0-7) TPMR registers to configure pattern
mask for timestamp request.
Add nodes to enable/disable pattern timestamp and set pattern
timestamp type.

Signed-off-by: Tao Zhang <quic_taozha@xxxxxxxxxxx>
---
drivers/hwtracing/coresight/coresight-tpdm.c | 189 +++++++++++++++++++++++++++
drivers/hwtracing/coresight/coresight-tpdm.h | 14 ++
2 files changed, 203 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 648bbe6..4212ff4 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -32,6 +32,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],
@@ -39,6 +46,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;
@@ -411,6 +428,174 @@ 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;
+
+ if (!(drvdata->datasets & TPDM_PIDR0_DS_DSB))
+ return -EPERM;
+
+ spin_lock(&drvdata->spinlock);
+ for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
+ size += scnprintf(buf + size, PAGE_SIZE - 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 (!(drvdata->datasets & TPDM_PIDR0_DS_DSB) ||
+ 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;
+
+ if (!(drvdata->datasets & TPDM_PIDR0_DS_DSB))
+ return -EPERM;
+
+ spin_lock(&drvdata->spinlock);
+ for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
+ size += scnprintf(buf + size, PAGE_SIZE - 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 (!(drvdata->datasets & TPDM_PIDR0_DS_DSB) ||
+ 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);
+
+ if (!(drvdata->datasets & TPDM_PIDR0_DS_DSB))
+ return -EPERM;
+
+ return scnprintf(buf, PAGE_SIZE, "%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);
+
+ if (!(drvdata->datasets & TPDM_PIDR0_DS_DSB))
+ return -EPERM;
+
+ return scnprintf(buf, PAGE_SIZE, "%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;
+ if (!(drvdata->datasets & TPDM_PIDR0_DS_DSB))
+ return -EPERM;
+
+ 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)
@@ -578,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 468f97a..a169ddb 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 */
@@ -70,6 +76,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.
@@ -79,6 +89,10 @@ struct dsb_dataset {
u32 mode;
u32 edge_ctrl[TPDM_DSB_MAX_EDCR];
u32 edge_ctrl_mask[TPDM_DSB_MAX_EDCR / 2];
+ 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;
--
2.7.4