diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm
index aa357f463d03..403c45fcdcfe 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm
@@ -212,3 +212,9 @@ Description:	(RW) Read or write the status of timestamp upon all interface.
 		Only value 0 and 1  can be written to this node. Set this node to 1 to requeset
 		timestamp to all trace packet.
 
+What:           /sys/bus/coresight/devices/<tpdm-name>/cmb_msr
+Date:           March 2023
+KernelVersion   6.3
+Contact:        Jinlong Mao <quic_jinlmao@quicinc.com>
+Description:    (RW) Read or write the value of CMB msr.
+
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 88bb740cddd6..91b9ec80bf23 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -72,6 +72,14 @@ static int tpdm_init_datasets(struct tpdm_drvdata *drvdata)
 			if (!drvdata->cmb)
 				return -ENOMEM;
 		}
+
+		/* Get cmb msr number*/
+		of_property_read_u32(drvdata->dev->of_node, "qcom,cmb-msr-num",
+				&drvdata->cmb->msr_num);
+		drvdata->cmb->msr = devm_kzalloc(drvdata->dev,
+					(drvdata->cmb->msr_num * sizeof(u32)), GFP_KERNEL);
+		if (!drvdata->cmb->msr)
+			return -ENOMEM;
 	}
 
 	return 0;
@@ -206,6 +214,12 @@ static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata)
 		val = val & ~TPDM_CMB_TIER_TS_ALL;
 	writel_relaxed(val, drvdata->base + TPDM_CMB_TIER);
 
+	/* Configure MSR registers */
+	if (drvdata->cmb->msr_num != 0)
+		for (i = 0; i < drvdata->cmb->msr_num; i++)
+			writel_relaxed(drvdata->cmb->msr[i],
+				drvdata->base + TPDM_CMB_MSR(i));
+
 	val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
 	/*
 	 * Set to 0 for continuous CMB collection mode,
@@ -1159,6 +1173,50 @@ static ssize_t cmb_trig_ts_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(cmb_trig_ts);
 
+static ssize_t cmb_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 size = 0;
+
+	if (drvdata->cmb->msr_num == 0)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	for (i = 0; i < drvdata->cmb->msr_num; i++) {
+		size += sysfs_emit_at(buf, size,
+				  "%u 0x%x\n", i, drvdata->cmb->msr[i]);
+	}
+	spin_unlock(&drvdata->spinlock);
+
+	return size;
+}
+
+static ssize_t cmb_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->cmb->msr_num == 0)
+		return -EINVAL;
+
+	nval = sscanf(buf, "%u %x", &num, &val);
+	if ((nval != 2) || (num >= (drvdata->cmb->msr_num - 1)))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->cmb->msr[num] = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(cmb_msr);
+
 static struct attribute *tpdm_dsb_attrs[] = {
 	&dev_attr_dsb_mode.attr,
 	&dev_attr_dsb_edge_ctrl.attr,
@@ -1184,6 +1242,7 @@ static struct attribute *tpdm_cmb_attrs[] = {
 	&dev_attr_cmb_patt_ts.attr,
 	&dev_attr_cmb_ts_all.attr,
 	&dev_attr_cmb_trig_ts.attr,
+	&dev_attr_cmb_msr.attr,
 	NULL,
 };
 
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h
index 88ade2f2ef6c..d783fc94252b 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.h
+++ b/drivers/hwtracing/coresight/coresight-tpdm.h
@@ -22,6 +22,8 @@
 #define TPDM_CMB_XPR(n)		(0xA18 + (n * 4))
 /*CMB subunit trigger pattern mask registers*/
 #define TPDM_CMB_XPMR(n)	(0xA20 + (n * 4))
+/* CMB MSR register */
+#define TPDM_CMB_MSR(n)		(0xA80 + (n * 4))
 
 /* Enable bit for CMB subunit */
 #define TPDM_CMB_CR_ENA		BIT(0)
@@ -145,6 +147,8 @@ struct dsb_dataset {
  * @patt_mask:        Save value for pattern mask
  * @trig_patt_val:    Save value for trigger pattern
  * @trig_patt_mask:   Save value for trigger pattern mask
+ * @msr_num:	      The number of msr register
+ * @msr:	      Save value for msr registers
  * @patt_ts:	      Indicates if pattern match for timestamp is enabled.
  * @trig_ts:	      Indicates if CTI trigger for timestamp is enabled.
  * @ts_all:	      Indicates if timestamp is enabled for all packets.
@@ -155,6 +159,8 @@ struct cmb_dataset {
 	u32				patt_mask[TPDM_CMB_MAX_PATT];
 	u32				trig_patt_val[TPDM_CMB_MAX_PATT];
 	u32				trig_patt_mask[TPDM_CMB_MAX_PATT];
+	u32				msr_num;
+	u32				*msr;
 	bool				patt_ts;
 	bool				trig_ts;
 	bool				ts_all;
