diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c
index 3c501e027bc0..fdfda1975188 100644
--- a/drivers/hwtracing/coresight/coresight-config.c
+++ b/drivers/hwtracing/coresight/coresight-config.c
@@ -23,6 +23,10 @@ static void cscfg_set_reg(struct cscfg_regval_csdev *reg_csdev)
 	u32 *p_val32 = (u32 *)reg_csdev->driver_regval;
 	u32 tmp32 = reg_csdev->reg_desc.val32;
 
+	/* resource mapped registers may have custom handling in the device */
+	if (!reg_csdev->driver_regval)
+		return;
+
 	if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT) {
 		*((u64 *)reg_csdev->driver_regval) = reg_csdev->reg_desc.val64;
 		return;
@@ -43,6 +47,8 @@ static void cscfg_save_reg(struct cscfg_regval_csdev *reg_csdev)
 {
 	if (!(reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_SAVE))
 		return;
+	if (!reg_csdev->driver_regval)
+		return;
 	if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT)
 		reg_csdev->reg_desc.val64 = *(u64 *)(reg_csdev->driver_regval);
 	else
@@ -73,15 +79,20 @@ static void cscfg_init_reg_param(struct cscfg_feature_csdev *feat_csdev,
 /* set values into the driver locations referenced in cscfg_reg_csdev */
 static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat_csdev)
 {
-	int i;
+	int i, err = 0;
 
 	spin_lock(feat_csdev->drv_spinlock);
 	for (i = 0; i < feat_csdev->nr_regs; i++)
 		cscfg_set_reg(&feat_csdev->regs_csdev[i]);
 	spin_unlock(feat_csdev->drv_spinlock);
+
+	if (feat_csdev->feat_ops->set_on_enable)
+		err = feat_csdev->feat_ops->set_on_enable(feat_csdev);
+
 	dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
-		feat_csdev->feat_desc->name, "set on enable");
-	return 0;
+		feat_csdev->feat_desc->name,
+		err ? "error on enable" : "set on enable");
+	return err;
 }
 
 /* copy back values from the driver locations referenced in cscfg_reg_csdev */
@@ -89,6 +100,9 @@ static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat_csdev)
 {
 	int i;
 
+	if (feat_csdev->feat_ops->clear_on_disable)
+		feat_csdev->feat_ops->clear_on_disable(feat_csdev);
+
 	spin_lock(feat_csdev->drv_spinlock);
 	for (i = 0; i < feat_csdev->nr_regs; i++)
 		cscfg_save_reg(&feat_csdev->regs_csdev[i]);
@@ -217,6 +231,37 @@ static int cscfg_update_curr_params(struct cscfg_config_csdev *config_csdev)
 	return 0;
 }
 
+static void cscfg_clear_res_config(struct cscfg_config_csdev *config_csdev)
+{
+	int i;
+	struct cscfg_feature_csdev *feat_csdev;
+
+	for (i = 0; i < config_csdev->nr_feat; i++) {
+		feat_csdev = config_csdev->feats_csdev[i];
+		if (feat_csdev->feat_ops->clear_feat_res)
+			feat_csdev->feat_ops->clear_feat_res(feat_csdev);
+	}
+}
+
+#define FEAT_ALLOC_RES_FMT "coresight-syscfg: Insufficient resource to enable feature %s\n"
+static int cscfg_alloc_res_config(struct cscfg_config_csdev *config_csdev)
+{
+	int err = 0, i;
+	struct cscfg_feature_csdev *feat_csdev;
+
+	for (i = 0; i < config_csdev->nr_feat; i++) {
+		feat_csdev = config_csdev->feats_csdev[i];
+		if (feat_csdev->feat_ops->alloc_feat_res)
+			err = feat_csdev->feat_ops->alloc_feat_res(feat_csdev);
+		if (err) {
+			pr_warn(FEAT_ALLOC_RES_FMT, feat_csdev->feat_desc->name);
+			cscfg_clear_res_config(config_csdev);
+			break;
+		}
+	}
+	return err;
+}
+
 /*
  * Configuration values will be programmed into the driver locations if enabling, or read
  * from relevant locations on disable.
@@ -227,19 +272,29 @@ static int cscfg_prog_config(struct cscfg_config_csdev *config_csdev, bool enabl
 	struct cscfg_feature_csdev *feat_csdev;
 	struct coresight_device *csdev;
 
+	/* check we have resources to enable this */
+	if (enable) {
+		err = cscfg_alloc_res_config(config_csdev);
+		if (err)
+			return err;
+	} else
+		cscfg_clear_res_config(config_csdev);
+
 	for (i = 0; i < config_csdev->nr_feat; i++) {
 		feat_csdev = config_csdev->feats_csdev[i];
 		csdev = feat_csdev->csdev;
 		dev_dbg(&csdev->dev, "cfg %s;  %s feature:%s", config_csdev->config_desc->name,
 			enable ? "enable" : "disable", feat_csdev->feat_desc->name);
 
-		if (enable)
+		if (enable) {
 			err = cscfg_set_on_enable(feat_csdev);
-		else
+			if (err) {
+				/* failed to enable - release any resources */
+				cscfg_clear_res_config(config_csdev);
+				break;
+			}
+		} else
 			cscfg_save_on_disable(feat_csdev);
-
-		if (err)
-			break;
 	}
 	return err;
 }
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h
index 9bd44b940add..0e46832df993 100644
--- a/drivers/hwtracing/coresight/coresight-config.h
+++ b/drivers/hwtracing/coresight/coresight-config.h
@@ -199,6 +199,8 @@ struct cscfg_parameter_csdev {
  * @params_csdev:	current parameter values on this device
  * @nr_regs:		number of registers to be programmed.
  * @regs_csdev:		Programming details for the registers
+ * @res_used:		Device specific context for resources used on enable.
+ * @feat_ops:		Feature operations to support alloc/release of resources.
  */
 struct cscfg_feature_csdev {
 	const struct cscfg_feature_desc *feat_desc;
@@ -209,6 +211,8 @@ struct cscfg_feature_csdev {
 	struct cscfg_parameter_csdev *params_csdev;
 	int nr_regs;
 	struct cscfg_regval_csdev *regs_csdev;
+	void *res_used;
+	struct cscfg_csdev_feat_ops *feat_ops;
 };
 
 /**
@@ -238,14 +242,44 @@ struct cscfg_config_csdev {
  * Coresight device operations.
  *
  * Registered coresight devices provide these operations to manage feature
- * instances compatible with the device hardware and drivers
+ * instances compatible with the device hardware and drivers.
+ *
+ * The @check_feat_res function can be used at load time to see if the device has
+ * sufficient resources to support the feature. This takes into account all resources
+ * on the device. e.g. if the feature requires three counters, and the device has a
+ * total of two implemented counters, this will return a -ENODEV error.
+ *
+ * The @alloc_feat_res function checks if there are sufficient unallocated resources
+ * left to enable the feature. This allows for multiple features being loaded that
+ * may compete for resources and also selects and allocates resources at enable time.
+ * e.g. if a feature requires two comparators, and there is only one left unallocated,
+ * then this will return a -ENOSPC error.
  *
  * @load_feat:	Pass a feature descriptor into the device and create the
  *		loaded feature instance (struct cscfg_feature_csdev).
+ * @check_feat_res: Check that the coresight device has sufficient resources to
+ *		    load the feature. Optional function. Return -ENODEV if this device
+ *                  does not have enough resources. Called before @load_feat for feature
+ *		    to ensure all feature can be installed on device.
+ * @alloc_feat_res: Allocate release feature resources when enabling a feature on the device
+ *		  . Optional function. Returns -ENOSPC if the device has not enough available
+ *		    resources to enable the feature. Called before registers programmed.
+ * @clear_feat_res: Release allocated resources. Must be implemented if @alloc_feat_res is
+ *		    implemented.
+ * @set_on_enable : Optional programming specific to device. Called immediately after
+ *		    generic register programming operation.
+ * @clear_on_disable: Optional programming specific to device. Called before generic register
+ *		      save operation.
  */
 struct cscfg_csdev_feat_ops {
 	int (*load_feat)(struct coresight_device *csdev,
 			 struct cscfg_feature_csdev *feat_csdev);
+	int (*check_feat_res)(struct coresight_device *csdev,
+			      struct cscfg_feature_desc *feat_desc);
+	int (*alloc_feat_res)(struct cscfg_feature_csdev *feat_csdev);
+	void (*clear_feat_res)(struct cscfg_feature_csdev *feat_csdev);
+	int (*set_on_enable)(struct cscfg_feature_csdev *feat_csdev);
+	void (*clear_on_disable)(struct cscfg_feature_csdev *feat_csdev);
 };
 
 /* coresight config helper functions*/
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
index ab74e33b892b..984459c8f168 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg.c
@@ -121,7 +121,8 @@ static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)
  * memory allocated using the csdev->dev object using devm managed allocator.
  */
 static struct cscfg_feature_csdev *
-cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)
+cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc,
+		       struct cscfg_csdev_feat_ops *ops)
 {
 	struct cscfg_feature_csdev *feat_csdev = NULL;
 	struct device *dev = csdev->dev.parent;
@@ -165,9 +166,16 @@ cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc
 	if (!feat_csdev->regs_csdev)
 		return NULL;
 
+	/* copy the static register info */
+	for (i = 0; i < feat_desc->nr_regs; i++) {
+		memcpy(&feat_csdev->regs_csdev[i].reg_desc,
+		       &feat_desc->regs_desc[i], sizeof(struct cscfg_regval_desc));
+	}
+
 	/* load the feature default values */
 	feat_csdev->feat_desc = feat_desc;
 	feat_csdev->csdev = csdev;
+	feat_csdev->feat_ops = ops;
 
 	return feat_csdev;
 }
@@ -180,10 +188,7 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
 	struct cscfg_feature_csdev *feat_csdev;
 	int err;
 
-	if (!ops->load_feat)
-		return -EINVAL;
-
-	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
+	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc, ops);
 	if (!feat_csdev)
 		return -ENOMEM;
 
@@ -201,6 +206,57 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev,
 	return 0;
 }
 
+#define WARN_RES_FMT "coresight-syscfg: Insufficient resources to load feature %s in device %s\n"
+#define PARAM_ERR_FMT "coresight-syscfg: Cannot load feature %s. Invalid parameter index\n"
+
+/*
+ * Check if device supports resource check function, and check for sufficient resources
+ * to load feature onto device. Validate parameter references.
+ *
+ * Load feature if sufficient resources & valid parameter references.
+ */
+static int cscfg_check_feat_res_load(struct coresight_device *csdev,
+				     struct cscfg_feature_desc *feat_desc,
+				     struct cscfg_csdev_feat_ops *ops)
+{
+	int err = 0, i;
+
+	/* if we cannot load - fail early */
+	if (!ops->load_feat)
+		return -EINVAL;
+
+	/* ensure matched resource ops */
+	if ((ops->alloc_feat_res && !ops->clear_feat_res) ||
+	    (!ops->alloc_feat_res && ops->clear_feat_res))
+		return -EINVAL;
+
+	/* ensure that the coresight device can support the feature */
+	if (ops->check_feat_res) {
+		err = ops->check_feat_res(csdev, feat_desc);
+		if (err == -ENODEV) {
+			/* treat as mismatch, warn and continue */
+			pr_warn(WARN_RES_FMT, feat_desc->name,
+				dev_name(&csdev->dev));
+			return 0;
+		}
+	}
+
+	/* check parameter indexes are valid */
+	for (i = 0; i < feat_desc->nr_regs; i++) {
+		if (feat_desc->regs_desc[i].type & CS_CFG_REG_TYPE_VAL_PARAM) {
+			if (feat_desc->regs_desc[i].param_idx >= feat_desc->nr_params) {
+				pr_err(PARAM_ERR_FMT, feat_desc->name);
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* sufficient resources - load if no other error */
+	if (!err)
+		err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
+	return err;
+}
+
 /*
  * Add feature to any matching devices - call with mutex locked.
  * Iterates through devices - any device that matches the feature will be
@@ -213,7 +269,9 @@ static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
 
 	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
 		if (csdev_item->match_flags & feat_desc->match_flags) {
-			err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
+			/* check sufficient resources and load feature */
+			err = cscfg_check_feat_res_load(csdev_item->csdev, feat_desc,
+							&csdev_item->ops);
 			if (err)
 				return err;
 		}
@@ -616,7 +674,7 @@ static int cscfg_add_feats_csdev(struct coresight_device *csdev,
 
 	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
 		if (feat_desc->match_flags & match_flags) {
-			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
+			err = cscfg_check_feat_res_load(csdev, feat_desc, ops);
 			if (err)
 				break;
 		}
