diff mbox series

[07/10] Coresight: Enable DSB subunit for TPDM

Message ID 1634801936-15080-8-git-send-email-quic_taozha@quicinc.com (mailing list archive)
State New, archived
Headers show
Series [01/10] coresight: add support to enable more coresight paths | expand

Commit Message

Tao Zhang Oct. 21, 2021, 7:38 a.m. UTC
Enable Discrete Single Bit(DSB) subunit for TPDM. The DSB dataset
elements flow out ATB while the BC/TC dataset elements are sent
only on ATB flush requests from the TPDA.
The DSB data set subunit is responsible for collection of DSB data
sets. The width of the DSB subunit interface must be between 8 and
256 bits. A monitor may support either a 32 or 64 bit DSB data set
element size (e.g. via a hardware parameter).

Signed-off-by: Tao Zhang <quic_taozha@quicinc.com>
---
 drivers/hwtracing/coresight/coresight-tpdm.c | 680 +++++++++++++++++++
 1 file changed, 680 insertions(+)
diff mbox series

Patch

diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 635382be5de6..5f07363e4650 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -309,6 +309,17 @@  static void __tpdm_config_tc_msr(struct tpdm_drvdata *drvdata)
 		tpdm_writel(drvdata, drvdata->tc->msr[i], TPDM_TC_MSR(i));
 }
 
+static void __tpdm_config_dsb_msr(struct tpdm_drvdata *drvdata)
+{
+	int i;
+
+	if (!drvdata->msr_support)
+		return;
+
+	for (i = 0; i < TPDM_DSB_MAX_MSR; i++)
+		tpdm_writel(drvdata, drvdata->dsb->msr[i], TPDM_DSB_MSR(i));
+}
+
 static void __tpdm_enable_bc(struct tpdm_drvdata *drvdata)
 {
 	int i;
@@ -434,6 +445,86 @@  static void __tpdm_enable_tc(struct tpdm_drvdata *drvdata)
 	tpdm_writel(drvdata, val, TPDM_TC_CR);
 }
 
+static void __tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
+{
+	uint32_t val, mode, i;
+
+	for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
+		tpdm_writel(drvdata, drvdata->dsb->edge_ctrl[i],
+			    TPDM_DSB_EDCR(i));
+	for (i = 0; i < TPDM_DSB_MAX_EDCR / 2; i++)
+		tpdm_writel(drvdata, drvdata->dsb->edge_ctrl_mask[i],
+			    TPDM_DSB_EDCMR(i));
+
+	for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
+		tpdm_writel(drvdata, drvdata->dsb->patt_val[i],
+			    TPDM_DSB_TPR(i));
+		tpdm_writel(drvdata, drvdata->dsb->patt_mask[i],
+			    TPDM_DSB_TPMR(i));
+	}
+
+	for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
+		tpdm_writel(drvdata, drvdata->dsb->trig_patt_val[i],
+			    TPDM_DSB_XPR(i));
+		tpdm_writel(drvdata, drvdata->dsb->trig_patt_mask[i],
+			    TPDM_DSB_XPMR(i));
+	}
+
+	for (i = 0; i < TPDM_DSB_MAX_SELECT; i++)
+		tpdm_writel(drvdata, drvdata->dsb->select_val[i],
+			    TPDM_DSB_CA_SELECT(i));
+
+	val = tpdm_readl(drvdata, TPDM_DSB_TIER);
+	if (drvdata->dsb->patt_ts) {
+		val = val | BIT(0);
+		if (drvdata->dsb->patt_type)
+			val = val | BIT(2);
+		else
+			val = val & ~BIT(2);
+	} else {
+		val = val & ~BIT(0);
+	}
+	if (drvdata->dsb->trig_ts)
+		val = val | BIT(1);
+	else
+		val = val & ~BIT(1);
+	tpdm_writel(drvdata, val, TPDM_DSB_TIER);
+
+	if (!drvdata->msr_fix_req)
+		__tpdm_config_dsb_msr(drvdata);
+
+	val = tpdm_readl(drvdata, TPDM_DSB_CR);
+	/* Set the cycle accurate mode */
+	mode = TPDM_DSB_MODE_CYCACC(drvdata->dsb->mode);
+	val = val & ~(0x7 << 9);
+	val = val | (mode << 9);
+	/* Set the byte lane for high-performance mode */
+	mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode);
+	val = val & ~(0x1F << 2);
+	val = val | (mode << 2);
+	/* Set the performance mode */
+	if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF)
+		val = val | BIT(1);
+	else
+		val = val & ~BIT(1);
+
+	/* Set trigger type */
+	if (drvdata->dsb->trig_type)
+		val = val | BIT(12);
+	else
+		val = val & ~BIT(12);
+
+	tpdm_writel(drvdata, val, TPDM_DSB_CR);
+
+	val = tpdm_readl(drvdata, TPDM_DSB_CR);
+	/* Set the enable bit */
+	val = val | BIT(0);
+	tpdm_writel(drvdata, val, TPDM_DSB_CR);
+
+	if (drvdata->msr_fix_req)
+		__tpdm_config_dsb_msr(drvdata);
+}
+
 static void __tpdm_enable(struct tpdm_drvdata *drvdata)
 {
 	TPDM_UNLOCK(drvdata);
@@ -450,6 +541,9 @@  static void __tpdm_enable(struct tpdm_drvdata *drvdata)
 	if (test_bit(TPDM_DS_TC, drvdata->enable_ds))
 		__tpdm_enable_tc(drvdata);
 
+	if (test_bit(TPDM_DS_DSB, drvdata->enable_ds))
+		__tpdm_enable_dsb(drvdata);
+
 	TPDM_LOCK(drvdata);
 }
 
@@ -492,6 +586,15 @@  static void __tpdm_disable_tc(struct tpdm_drvdata *drvdata)
 	tpdm_writel(drvdata, config, TPDM_TC_CR);
 }
 
+static void __tpdm_disable_dsb(struct tpdm_drvdata *drvdata)
+{
+	uint32_t config;
+
+	config = tpdm_readl(drvdata, TPDM_DSB_CR);
+	config = config & ~BIT(0);
+	tpdm_writel(drvdata, config, TPDM_DSB_CR);
+}
+
 static void __tpdm_disable(struct tpdm_drvdata *drvdata)
 {
 	TPDM_UNLOCK(drvdata);
@@ -502,6 +605,9 @@  static void __tpdm_disable(struct tpdm_drvdata *drvdata)
 	if (test_bit(TPDM_DS_TC, drvdata->enable_ds))
 		__tpdm_disable_tc(drvdata);
 
+	if (test_bit(TPDM_DS_DSB, drvdata->enable_ds))
+		__tpdm_disable_dsb(drvdata);
+
 	if (drvdata->clk_enable)
 		tpdm_writel(drvdata, 0x0, TPDM_CLK_CTRL);
 
@@ -2474,6 +2580,558 @@  static ssize_t tc_msr_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(tc_msr);
 
+static ssize_t dsb_mode_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	return scnprintf(buf, PAGE_SIZE, "%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, 16, &val))
+		return -EINVAL;
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	drvdata->dsb->mode = val & TPDM_MODE_ALL;
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+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;
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) {
+		size += scnprintf(buf + size, PAGE_SIZE - size,
+				  "Index:0x%x Val:0x%x\n", i,
+				  drvdata->dsb->edge_ctrl[i]);
+	}
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+
+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, bit, reg;
+
+	if (sscanf(buf, "%lx %lx %lx", &start, &end, &edge_ctrl) != 3)
+		return -EINVAL;
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets) ||
+	    (start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES) ||
+	    edge_ctrl > 0x2)
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	for (i = start; i <= end; i++) {
+		reg = i / (NUM_OF_BITS / 2);
+		bit = i % (NUM_OF_BITS / 2);
+		bit = bit * 2;
+
+		val = drvdata->dsb->edge_ctrl[reg];
+		val = val & ~GENMASK((bit + 1), bit);
+		val = val | (edge_ctrl << bit);
+		drvdata->dsb->edge_ctrl[reg] = val;
+	}
+	mutex_unlock(&drvdata->lock);
+	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;
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	for (i = 0; i < TPDM_DSB_MAX_EDCR / 2; i++) {
+		size += scnprintf(buf + size, PAGE_SIZE - size,
+				  "Index:0x%x Val:0x%x\n", i,
+				  drvdata->dsb->edge_ctrl_mask[i]);
+	}
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+
+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;
+	uint32_t set;
+	int i, bit, reg;
+
+	if (sscanf(buf, "%lx %lx %lx", &start, &end, &val) != 3)
+		return -EINVAL;
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets) ||
+	    (start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	for (i = start; i <= end; i++) {
+		reg = i / NUM_OF_BITS;
+		bit = (i % NUM_OF_BITS);
+
+		set = drvdata->dsb->edge_ctrl_mask[reg];
+		if (val)
+			set = set | BIT(bit);
+		else
+			set = set & ~BIT(bit);
+		drvdata->dsb->edge_ctrl_mask[reg] = set;
+	}
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+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 (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	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]);
+	}
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+
+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 (!test_bit(TPDM_DS_DSB, drvdata->datasets) ||
+	    index >= TPDM_DSB_MAX_PATT)
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	drvdata->dsb->patt_val[index] = val;
+	mutex_unlock(&drvdata->lock);
+	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 (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	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]);
+	}
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+
+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 (!test_bit(TPDM_DS_DSB, drvdata->datasets) ||
+	    index >= TPDM_DSB_MAX_PATT)
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	drvdata->dsb->patt_mask[index] = val;
+	mutex_unlock(&drvdata->lock);
+	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 (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n",
+			 (unsigned int)drvdata->dsb->patt_ts);
+}
+
+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 (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	if (val)
+		drvdata->dsb->patt_ts = true;
+	else
+		drvdata->dsb->patt_ts = false;
+	mutex_unlock(&drvdata->lock);
+	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 (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n",
+			 (unsigned int)drvdata->dsb->patt_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 (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	if (val)
+		drvdata->dsb->patt_type = true;
+	else
+		drvdata->dsb->patt_type = false;
+	mutex_unlock(&drvdata->lock);
+	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)
+{
+	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	ssize_t size = 0;
+	int i = 0;
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	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->trig_patt_val[i]);
+	}
+	mutex_unlock(&drvdata->lock);
+	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 (!test_bit(TPDM_DS_DSB, drvdata->datasets) ||
+	    index >= TPDM_DSB_MAX_PATT)
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	drvdata->dsb->trig_patt_val[index] = val;
+	mutex_unlock(&drvdata->lock);
+	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;
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	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->trig_patt_mask[i]);
+	}
+	mutex_unlock(&drvdata->lock);
+	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 (!test_bit(TPDM_DS_DSB, drvdata->datasets) ||
+	    index >= TPDM_DSB_MAX_PATT)
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	drvdata->dsb->trig_patt_mask[index] = val;
+	mutex_unlock(&drvdata->lock);
+	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)
+{
+	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n",
+			 (unsigned int)drvdata->dsb->trig_type);
+}
+
+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, 16, &val))
+		return -EINVAL;
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	if (val)
+		drvdata->dsb->trig_type = true;
+	else
+		drvdata->dsb->trig_type = false;
+	mutex_unlock(&drvdata->lock);
+	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);
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n",
+			 (unsigned int)drvdata->dsb->trig_ts);
+}
+
+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, 16, &val))
+		return -EINVAL;
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	if (val)
+		drvdata->dsb->trig_ts = true;
+	else
+		drvdata->dsb->trig_ts = false;
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+static DEVICE_ATTR_RW(dsb_trig_ts);
+
+static ssize_t dsb_select_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;
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	for (i = 0; i < TPDM_DSB_MAX_SELECT; i++) {
+		size += scnprintf(buf + size, PAGE_SIZE - size,
+				  "Index:0x%x Val:0x%x\n", i,
+				  drvdata->dsb->select_val[i]);
+	}
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+
+static ssize_t dsb_select_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 start, end;
+	uint32_t val;
+	int i, bit, reg;
+
+	if (sscanf(buf, "%lx %lx", &start, &end) != 2)
+		return -EINVAL;
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets) ||
+	    (start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES))
+		return -EPERM;
+
+	mutex_lock(&drvdata->lock);
+	for (i = start; i <= end; i++) {
+		reg = i / NUM_OF_BITS;
+		bit = (i % NUM_OF_BITS);
+
+		val = drvdata->dsb->select_val[reg];
+		val = val | BIT(bit);
+		drvdata->dsb->select_val[reg] = val;
+	}
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+static DEVICE_ATTR_RW(dsb_select_val);
+
+static ssize_t dsb_msr_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned int i;
+	ssize_t len = 0;
+
+	if (!drvdata->msr_support)
+		return -EINVAL;
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	for (i = 0; i < TPDM_DSB_MAX_MSR; i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%u 0x%x\n",
+				 i, drvdata->dsb->msr[i]);
+
+	return len;
+}
+
+static ssize_t dsb_msr_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t size)
+{
+	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned int num, val;
+	int nval;
+
+	if (!drvdata->msr_support)
+		return -EINVAL;
+
+	if (!test_bit(TPDM_DS_DSB, drvdata->datasets))
+		return -EPERM;
+
+	nval = sscanf(buf, "%u %x", &num, &val);
+	if (nval != 2)
+		return -EINVAL;
+
+	if (num >= TPDM_DSB_MAX_MSR)
+		return -EINVAL;
+
+	mutex_lock(&drvdata->lock);
+	drvdata->dsb->msr[num] = val;
+	mutex_unlock(&drvdata->lock);
+	return size;
+}
+static DEVICE_ATTR_RW(dsb_msr);
+
 static struct attribute *tpdm_bc_attrs[] = {
 	&dev_attr_bc_capture_mode.attr,
 	&dev_attr_bc_retrieval_mode.attr,
@@ -2522,6 +3180,23 @@  static struct attribute *tpdm_tc_attrs[] = {
 	NULL,
 };
 
+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,
+	&dev_attr_dsb_trig_type.attr,
+	&dev_attr_dsb_select_val.attr,
+	&dev_attr_dsb_msr.attr,
+	NULL,
+};
+
 static struct attribute_group tpdm_bc_attr_grp = {
 	.attrs = tpdm_bc_attrs,
 };
@@ -2530,6 +3205,10 @@  static struct attribute_group tpdm_tc_attr_grp = {
 	.attrs = tpdm_tc_attrs,
 };
 
+static struct attribute_group tpdm_dsb_attr_grp = {
+	.attrs = tpdm_dsb_attrs,
+};
+
 static struct attribute *tpdm_attrs[] = {
 	&dev_attr_available_datasets.attr,
 	&dev_attr_enable_datasets.attr,
@@ -2547,6 +3226,7 @@  static const struct attribute_group *tpdm_attr_grps[] = {
 	&tpdm_attr_grp,
 	&tpdm_bc_attr_grp,
 	&tpdm_tc_attr_grp,
+	&tpdm_dsb_attr_grp,
 	NULL,
 };