diff mbox series

[v4,1/5] interconnect: qcom: sdm660: Commonize RPM-QoS

Message ID 20210901121518.152481-2-y.oudjana@protonmail.com (mailing list archive)
State Superseded
Headers show
Series interconnect: qcom: Add MSM8996 interconnect driver | expand

Commit Message

Yassine Oudjana Sept. 1, 2021, 12:15 p.m. UTC
SoCs such as MSM8996 also control bus QoS in a similar fashion to SDM660,
with some paths being controlled by RPM and others directly by the AP.
Move relevant functions and defines to a new object so that they can be used
in multiple drivers.

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
---
Changes since v3:
 - Commonize probe function.
 - Don't rename qcom_icc_set in icc-rpmh since it's no longer needed.
Changes since v1:
 - Split first patch into 2 patches, one for renaming qcom_icc_set in icc-rpmh, and another
   one for the actual commonization.
 - Revert unnecessary move of include line in sdm660.c

 drivers/interconnect/qcom/Kconfig       |   5 +-
 drivers/interconnect/qcom/Makefile      |   2 +
 drivers/interconnect/qcom/icc-rpm-qos.c | 358 +++++++++++++++++
 drivers/interconnect/qcom/icc-rpm-qos.h | 135 +++++++
 drivers/interconnect/qcom/sdm660.c      | 487 ++----------------------
 5 files changed, 522 insertions(+), 465 deletions(-)
 create mode 100644 drivers/interconnect/qcom/icc-rpm-qos.c
 create mode 100644 drivers/interconnect/qcom/icc-rpm-qos.h

Comments

AngeloGioacchino Del Regno Sept. 1, 2021, 6:48 p.m. UTC | #1
Il 01/09/21 14:15, Yassine Oudjana ha scritto:
> SoCs such as MSM8996 also control bus QoS in a similar fashion to SDM660,
> with some paths being controlled by RPM and others directly by the AP.
> Move relevant functions and defines to a new object so that they can be used
> in multiple drivers.
> 
> Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>

Hey guys!

I'm waiting for the interconnect RPM-QoS commonization to be merged as I have fresh
interconnect drivers for MSM8998 and MSM8976, ready to send, that are also using
the very same QoS mechanism as SDM660.

Yassine, please check Shawn's recent patches for SDM660 interconnect, which are
fixing some bits for the QoS implementation and adding some required clocks to the
SDM660 interconnect driver.

Adding Shawn to the Ccs as to make him aware of this patch;
also adding Marijn and Konrad from SoMainline as probably interested parties.

Cheers!
- Angelo
Dmitry Baryshkov Sept. 1, 2021, 10:01 p.m. UTC | #2
On 01/09/2021 21:48, AngeloGioacchino Del Regno wrote:
> Il 01/09/21 14:15, Yassine Oudjana ha scritto:
>> SoCs such as MSM8996 also control bus QoS in a similar fashion to SDM660,
>> with some paths being controlled by RPM and others directly by the AP.
>> Move relevant functions and defines to a new object so that they can 
>> be used
>> in multiple drivers.
>>
>> Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
> 
> Hey guys!
> 
> I'm waiting for the interconnect RPM-QoS commonization to be merged as I 
> have fresh
> interconnect drivers for MSM8998 and MSM8976, ready to send, that are 
> also using
> the very same QoS mechanism as SDM660.

We were also looking onto this. I'd propose to merge sdm660 code into 
main icc-rpm.c instead of splitting it into separate file. We have 
enabled QoS for apq8096 (msm8916) and msm8939. See 
https://lore.kernel.org/linux-arm-msm/20210818015732.1717810-1-dmitry.baryshkov@linaro.org/ 
for the reference. I'm waiting for Shawn to publish v2 of his fix, then 
I can post v2 of my patchset.

> 
> Yassine, please check Shawn's recent patches for SDM660 interconnect, 
> which are
> fixing some bits for the QoS implementation and adding some required 
> clocks to the
> SDM660 interconnect driver.
> 
> Adding Shawn to the Ccs as to make him aware of this patch;
> also adding Marijn and Konrad from SoMainline as probably interested 
> parties.
> 
> Cheers!
> - Angelo
AngeloGioacchino Del Regno Sept. 1, 2021, 10:19 p.m. UTC | #3
Il 02/09/21 00:01, Dmitry Baryshkov ha scritto:
> On 01/09/2021 21:48, AngeloGioacchino Del Regno wrote:
>> Il 01/09/21 14:15, Yassine Oudjana ha scritto:
>>> SoCs such as MSM8996 also control bus QoS in a similar fashion to SDM660,
>>> with some paths being controlled by RPM and others directly by the AP.
>>> Move relevant functions and defines to a new object so that they can be used
>>> in multiple drivers.
>>>
>>> Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
>>
>> Hey guys!
>>
>> I'm waiting for the interconnect RPM-QoS commonization to be merged as I have fresh
>> interconnect drivers for MSM8998 and MSM8976, ready to send, that are also using
>> the very same QoS mechanism as SDM660.
> 
> We were also looking onto this. I'd propose to merge sdm660 code into main 
> icc-rpm.c instead of splitting it into separate file. We have enabled QoS for 
> apq8096 (msm8916) and msm8939. See 
> https://lore.kernel.org/linux-arm-msm/20210818015732.1717810-1-dmitry.baryshkov@linaro.org/ 
> for the reference. I'm waiting for Shawn to publish v2 of his fix, then I can post 
> v2 of my patchset.
> 

Merging it into icc-rpm would actually make sense, since the QoS mechanism won't
ever be used by the RPM-Hardened icc... so yeah, on that I agree.

Whenever you guys send the new patchsets, if you can please make sure to Cc me
and/or the other SoMainline guys, we will make sure to review and test the sets
as soon as possible, as a way to speed up the merge process, if that helps!

Thank you,
- Angelo

>>
>> Yassine, please check Shawn's recent patches for SDM660 interconnect, which are
>> fixing some bits for the QoS implementation and adding some required clocks to the
>> SDM660 interconnect driver.
>>
>> Adding Shawn to the Ccs as to make him aware of this patch;
>> also adding Marijn and Konrad from SoMainline as probably interested parties.
>>
>> Cheers!
>> - Angelo
> 
>
Yassine Oudjana Sept. 2, 2021, 9:42 a.m. UTC | #4
On Thu, Sep 2 2021 at 02:01:59 +0400, Dmitry Baryshkov 
<dmitry.baryshkov@linaro.org> wrote:
> On 01/09/2021 21:48, AngeloGioacchino Del Regno wrote:
>>  Il 01/09/21 14:15, Yassine Oudjana ha scritto:
>>>  SoCs such as MSM8996 also control bus QoS in a similar fashion to 
>>> SDM660,
>>>  with some paths being controlled by RPM and others directly by the 
>>> AP.
>>>  Move relevant functions and defines to a new object so that they 
>>> can
>>>  be used
>>>  in multiple drivers.
>>> 
>>>  Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
>> 
>>  Hey guys!
>> 
>>  I'm waiting for the interconnect RPM-QoS commonization to be merged 
>> as I
>>  have fresh
>>  interconnect drivers for MSM8998 and MSM8976, ready to send, that 
>> are
>>  also using
>>  the very same QoS mechanism as SDM660.
> 
> We were also looking onto this. I'd propose to merge sdm660 code into
> main icc-rpm.c instead of splitting it into separate file. We have
> enabled QoS for apq8096 (msm8916) and msm8939. See
> https://lore.kernel.org/linux-arm-msm/20210818015732.1717810-1-dmitry.baryshkov@linaro.org/
> for the reference. I'm waiting for Shawn to publish v2 of his fix, 
> then
> I can post v2 of my patchset.

I'll wait for your v2 to post v5 of this series then.
Please add me to Cc when you send it.

> 
>> 
>>  Yassine, please check Shawn's recent patches for SDM660 
>> interconnect,
>>  which are
>>  fixing some bits for the QoS implementation and adding some required
>>  clocks to the
>>  SDM660 interconnect driver.
>> 
>>  Adding Shawn to the Ccs as to make him aware of this patch;
>>  also adding Marijn and Konrad from SoMainline as probably interested
>>  parties.
>> 
>>  Cheers!
>>  - Angelo
> 
> 
> --
> With best wishes
> Dmitry

Thanks,
Yassine
diff mbox series

Patch

diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index daf1e25f6042..9e4303350afb 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -96,7 +96,7 @@  config INTERCONNECT_QCOM_SDM660
 	tristate "Qualcomm SDM660 interconnect driver"
 	depends on INTERCONNECT_QCOM
 	depends on QCOM_SMD_RPM
-	select INTERCONNECT_QCOM_SMD_RPM
+	select INTERCONNECT_QCOM_SMD_RPM_QOS
 	help
 	  This is a driver for the Qualcomm Network-on-Chip on sdm660-based
 	  platforms.
@@ -148,3 +148,6 @@  config INTERCONNECT_QCOM_SM8350
 
 config INTERCONNECT_QCOM_SMD_RPM
 	tristate
+
+config INTERCONNECT_QCOM_SMD_RPM_QOS
+	tristate
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index 69300b1d48ef..03a5a1e9c45e 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -17,6 +17,7 @@  qnoc-sm8150-objs			:= sm8150.o
 qnoc-sm8250-objs			:= sm8250.o
 qnoc-sm8350-objs			:= sm8350.o
 icc-smd-rpm-objs			:= smd-rpm.o icc-rpm.o
+icc-smd-rpm-qos-objs			:= smd-rpm.o icc-rpm-qos.o
 
 obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
@@ -35,3 +36,4 @@  obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM_QOS) += icc-smd-rpm-qos.o
diff --git a/drivers/interconnect/qcom/icc-rpm-qos.c b/drivers/interconnect/qcom/icc-rpm-qos.c
new file mode 100644
index 000000000000..3f0b16caa812
--- /dev/null
+++ b/drivers/interconnect/qcom/icc-rpm-qos.c
@@ -0,0 +1,358 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020, AngeloGioacchino Del Regno <kholk11@gmail.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "smd-rpm.h"
+#include "icc-rpm-qos.h"
+
+static int qcom_icc_bimc_set_qos_health(struct regmap *rmap,
+					struct qcom_icc_qos *qos,
+					int regnum)
+{
+	u32 val;
+	u32 mask;
+
+	val = qos->prio_level;
+	mask = M_BKE_HEALTH_CFG_PRIOLVL_MASK;
+
+	val |= qos->areq_prio << M_BKE_HEALTH_CFG_AREQPRIO_SHIFT;
+	mask |= M_BKE_HEALTH_CFG_AREQPRIO_MASK;
+
+	/* LIMITCMDS is not present on M_BKE_HEALTH_3 */
+	if (regnum != 3) {
+		val |= qos->limit_commands << M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT;
+		mask |= M_BKE_HEALTH_CFG_LIMITCMDS_MASK;
+	}
+
+	return regmap_update_bits(rmap,
+				  M_BKE_HEALTH_CFG_ADDR(regnum, qos->qos_port),
+				  mask, val);
+}
+
+static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw,
+				 bool bypass_mode)
+{
+	struct qcom_icc_provider *qp;
+	struct qcom_icc_node *qn;
+	struct icc_provider *provider;
+	u32 mode = NOC_QOS_MODE_BYPASS;
+	u32 val = 0;
+	int i, rc = 0;
+
+	qn = src->data;
+	provider = src->provider;
+	qp = to_qcom_provider(provider);
+
+	if (qn->qos.qos_mode != -1)
+		mode = qn->qos.qos_mode;
+
+	/* QoS Priority: The QoS Health parameters are getting considered
+	 * only if we are NOT in Bypass Mode.
+	 */
+	if (mode != NOC_QOS_MODE_BYPASS) {
+		for (i = 3; i >= 0; i--) {
+			rc = qcom_icc_bimc_set_qos_health(qp->regmap,
+							  &qn->qos, i);
+			if (rc)
+				return rc;
+		}
+
+		/* Set BKE_EN to 1 when Fixed, Regulator or Limiter Mode */
+		val = 1;
+	}
+
+	return regmap_update_bits(qp->regmap, M_BKE_EN_ADDR(qn->qos.qos_port),
+				  M_BKE_EN_EN_BMASK, val);
+}
+
+static int qcom_icc_noc_set_qos_priority(struct regmap *rmap,
+					 struct qcom_icc_qos *qos)
+{
+	u32 val;
+	int rc;
+
+	/* Must be updated one at a time, P1 first, P0 last */
+	val = qos->areq_prio << NOC_QOS_PRIORITY_P1_SHIFT;
+	rc = regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
+				NOC_QOS_PRIORITY_MASK, val);
+	if (rc)
+		return rc;
+
+	val = qos->prio_level << NOC_QOS_PRIORITY_P0_SHIFT;
+	return regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
+				  NOC_QOS_PRIORITY_MASK, val);
+}
+
+static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw)
+{
+	struct qcom_icc_provider *qp;
+	struct qcom_icc_node *qn;
+	struct icc_provider *provider;
+	u32 mode = NOC_QOS_MODE_BYPASS;
+	int rc = 0;
+
+	qn = src->data;
+	provider = src->provider;
+	qp = to_qcom_provider(provider);
+
+	if (qn->qos.qos_port < 0) {
+		dev_dbg(src->provider->dev,
+			"NoC QoS: Skipping %s: vote aggregated on parent.\n",
+			qn->name);
+		return 0;
+	}
+
+	if (qn->qos.qos_mode != -1)
+		mode = qn->qos.qos_mode;
+
+	if (mode == NOC_QOS_MODE_FIXED) {
+		dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n",
+			qn->name);
+		rc = qcom_icc_noc_set_qos_priority(qp->regmap, &qn->qos);
+		if (rc)
+			return rc;
+	} else if (mode == NOC_QOS_MODE_BYPASS) {
+		dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n",
+			qn->name);
+	}
+
+	return regmap_update_bits(qp->regmap,
+				  NOC_QOS_MODEn_ADDR(qn->qos.qos_port),
+				  NOC_QOS_MODEn_MASK, mode);
+}
+
+static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw)
+{
+	struct qcom_icc_provider *qp = to_qcom_provider(node->provider);
+	struct qcom_icc_node *qn = node->data;
+
+	dev_dbg(node->provider->dev, "Setting QoS for %s\n", qn->name);
+
+	if (qp->is_bimc_node)
+		return qcom_icc_set_bimc_qos(node, sum_bw,
+				(qn->qos.qos_mode == NOC_QOS_MODE_BYPASS));
+
+	return qcom_icc_set_noc_qos(node, sum_bw);
+}
+
+static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw)
+{
+	int ret = 0;
+
+	if (mas_rpm_id != -1) {
+		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+					    RPM_BUS_MASTER_REQ,
+					    mas_rpm_id,
+					    sum_bw);
+		if (ret) {
+			pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
+			       mas_rpm_id, ret);
+			return ret;
+		}
+	}
+
+	if (slv_rpm_id != -1) {
+		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+					    RPM_BUS_SLAVE_REQ,
+					    slv_rpm_id,
+					    sum_bw);
+		if (ret) {
+			pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
+			       slv_rpm_id, ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int qcom_icc_rpm_qos_set(struct icc_node *src, struct icc_node *dst)
+{
+	struct qcom_icc_provider *qp;
+	struct qcom_icc_node *qn;
+	struct icc_provider *provider;
+	struct icc_node *n;
+	u64 sum_bw;
+	u64 max_peak_bw;
+	u64 rate;
+	u32 agg_avg = 0;
+	u32 agg_peak = 0;
+	int ret, i;
+
+	qn = src->data;
+	provider = src->provider;
+	qp = to_qcom_provider(provider);
+
+	list_for_each_entry(n, &provider->nodes, node_list)
+		provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
+				    &agg_avg, &agg_peak);
+
+	sum_bw = icc_units_to_bps(agg_avg);
+	max_peak_bw = icc_units_to_bps(agg_peak);
+
+	if (!qn->qos.ap_owned) {
+		/* send bandwidth request message to the RPM processor */
+		ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw);
+		if (ret)
+			return ret;
+	} else if (qn->qos.qos_mode != -1) {
+		/* set bandwidth directly from the AP */
+		ret = qcom_icc_qos_set(src, sum_bw);
+		if (ret)
+			return ret;
+	}
+
+	rate = max(sum_bw, max_peak_bw);
+
+	do_div(rate, qn->buswidth);
+
+	if (qn->rate == rate)
+		return 0;
+
+	for (i = 0; i < qp->num_clks; i++) {
+		ret = clk_set_rate(qp->bus_clks[i].clk, rate);
+		if (ret) {
+			pr_err("%s clk_set_rate error: %d\n",
+			       qp->bus_clks[i].id, ret);
+			return ret;
+		}
+	}
+
+	qn->rate = rate;
+
+	return 0;
+}
+
+int qcom_icc_rpm_qos_probe(struct platform_device *pdev, size_t cd_size, int cd_num,
+	       const struct clk_bulk_data *cd, bool is_bimc)
+{
+	struct device *dev = &pdev->dev;
+	const struct qcom_icc_desc *desc;
+	struct icc_onecell_data *data;
+	struct icc_provider *provider;
+	struct qcom_icc_node **qnodes;
+	struct qcom_icc_provider *qp;
+	struct icc_node *node;
+	struct resource *res;
+	size_t num_nodes, i;
+	int ret;
+
+	/* wait for the RPM proxy */
+	if (!qcom_icc_rpm_smd_available())
+		return -EPROBE_DEFER;
+
+	desc = of_device_get_match_data(dev);
+	if (!desc)
+		return -EINVAL;
+
+	qnodes = desc->nodes;
+	num_nodes = desc->num_nodes;
+
+	qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
+	if (!qp)
+		return -ENOMEM;
+
+	data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	qp->bus_clks = devm_kmemdup(dev, cd, cd_size, GFP_KERNEL);
+	if (!qp->bus_clks)
+		return -ENOMEM;
+
+	qp->num_clks = cd_num;
+
+	qp->is_bimc_node = is_bimc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	qp->mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(qp->mmio)) {
+		dev_err(dev, "Cannot ioremap interconnect bus resource\n");
+		return PTR_ERR(qp->mmio);
+	}
+
+	qp->regmap = devm_regmap_init_mmio(dev, qp->mmio, desc->regmap_cfg);
+	if (IS_ERR(qp->regmap)) {
+		dev_err(dev, "Cannot regmap interconnect bus resource\n");
+		return PTR_ERR(qp->regmap);
+	}
+
+	ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
+	if (ret)
+		return ret;
+
+	provider = &qp->provider;
+	INIT_LIST_HEAD(&provider->nodes);
+	provider->dev = dev;
+	provider->set = qcom_icc_rpm_qos_set;
+	provider->aggregate = icc_std_aggregate;
+	provider->xlate = of_icc_xlate_onecell;
+	provider->data = data;
+
+	ret = icc_provider_add(provider);
+	if (ret) {
+		dev_err(dev, "error adding interconnect provider: %d\n", ret);
+		clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+		return ret;
+	}
+
+	for (i = 0; i < num_nodes; i++) {
+		size_t j;
+
+		node = icc_node_create(qnodes[i]->id);
+		if (IS_ERR(node)) {
+			ret = PTR_ERR(node);
+			goto err;
+		}
+
+		node->name = qnodes[i]->name;
+		node->data = qnodes[i];
+		icc_node_add(node, provider);
+
+		for (j = 0; j < qnodes[i]->num_links; j++)
+			icc_link_create(node, qnodes[i]->links[j]);
+
+		data->nodes[i] = node;
+	}
+	data->num_nodes = num_nodes;
+	platform_set_drvdata(pdev, qp);
+
+	return 0;
+err:
+	icc_nodes_remove(provider);
+	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+	icc_provider_del(provider);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_icc_rpm_qos_probe);
+
+int qcom_icc_rpm_qos_remove(struct platform_device *pdev)
+{
+	struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
+
+	icc_nodes_remove(&qp->provider);
+	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+	return icc_provider_del(&qp->provider);
+}
+EXPORT_SYMBOL_GPL(qcom_icc_rpm_qos_remove);
diff --git a/drivers/interconnect/qcom/icc-rpm-qos.h b/drivers/interconnect/qcom/icc-rpm-qos.h
new file mode 100644
index 000000000000..a20d3ccc7df0
--- /dev/null
+++ b/drivers/interconnect/qcom/icc-rpm-qos.h
@@ -0,0 +1,135 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020, AngeloGioacchino Del Regno <kholk11@gmail.com>
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_QOS_H__
+#define __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_QOS_H__
+
+#define RPM_BUS_MASTER_REQ	0x73616d62
+#define RPM_BUS_SLAVE_REQ	0x766c7362
+
+/* BIMC QoS */
+#define M_BKE_REG_BASE(n)		(0x300 + (0x4000 * n))
+#define M_BKE_EN_ADDR(n)		(M_BKE_REG_BASE(n))
+#define M_BKE_HEALTH_CFG_ADDR(i, n)	(M_BKE_REG_BASE(n) + 0x40 + (0x4 * i))
+
+#define M_BKE_HEALTH_CFG_LIMITCMDS_MASK	0x80000000
+#define M_BKE_HEALTH_CFG_AREQPRIO_MASK	0x300
+#define M_BKE_HEALTH_CFG_PRIOLVL_MASK	0x3
+#define M_BKE_HEALTH_CFG_AREQPRIO_SHIFT	0x8
+#define M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT 0x1f
+
+#define M_BKE_EN_EN_BMASK		0x1
+
+/* Valid for both NoC and BIMC */
+#define NOC_QOS_MODE_FIXED		0x0
+#define NOC_QOS_MODE_LIMITER		0x1
+#define NOC_QOS_MODE_BYPASS		0x2
+
+/* NoC QoS */
+#define NOC_PERM_MODE_FIXED		1
+#define NOC_PERM_MODE_BYPASS		(1 << NOC_QOS_MODE_BYPASS)
+
+#define NOC_QOS_PRIORITYn_ADDR(n)	(0x8 + (n * 0x1000))
+#define NOC_QOS_PRIORITY_MASK		0xf
+#define NOC_QOS_PRIORITY_P1_SHIFT	0x2
+#define NOC_QOS_PRIORITY_P0_SHIFT	0x3
+
+#define NOC_QOS_MODEn_ADDR(n)		(0xc + (n * 0x1000))
+#define NOC_QOS_MODEn_MASK		0x3
+
+#define to_qcom_provider(_provider) \
+	container_of(_provider, struct qcom_icc_provider, provider)
+
+/**
+ * struct qcom_icc_provider - Qualcomm specific interconnect provider
+ * @provider: generic interconnect provider
+ * @bus_clks: the clk_bulk_data table of bus clocks
+ * @num_clks: the total number of clk_bulk_data entries
+ * @is_bimc_node: indicates whether to use bimc specific setting
+ * @regmap: regmap for QoS registers read/write access
+ * @mmio: NoC base iospace
+ */
+struct qcom_icc_provider {
+	struct icc_provider provider;
+	struct clk_bulk_data *bus_clks;
+	int num_clks;
+	bool is_bimc_node;
+	struct regmap *regmap;
+	void __iomem *mmio;
+};
+
+/**
+ * struct qcom_icc_qos - Qualcomm specific interconnect QoS parameters
+ * @areq_prio: node requests priority
+ * @prio_level: priority level for bus communication
+ * @limit_commands: activate/deactivate limiter mode during runtime
+ * @ap_owned: indicates if the node is owned by the AP or by the RPM
+ * @qos_mode: default qos mode for this node
+ * @qos_port: qos port number for finding qos registers of this node
+ */
+struct qcom_icc_qos {
+	u32 areq_prio;
+	u32 prio_level;
+	bool limit_commands;
+	bool ap_owned;
+	int qos_mode;
+	int qos_port;
+};
+
+/**
+ * struct qcom_icc_node - Qualcomm specific interconnect nodes
+ * @name: the node name used in debugfs
+ * @id: a unique node identifier
+ * @links: an array of nodes where we can go next while traversing
+ * @num_links: the total number of @links
+ * @buswidth: width of the interconnect between a node and the bus (bytes)
+ * @mas_rpm_id: RPM id for devices that are bus masters
+ * @slv_rpm_id: RPM id for devices that are bus slaves
+ * @qos: NoC QoS setting parameters
+ * @rate: current bus clock rate in Hz
+ */
+
+#define MAX_LINKS	38
+
+struct qcom_icc_node {
+	unsigned char *name;
+	u16 id;
+	u16 links[MAX_LINKS];
+	u16 num_links;
+	u16 buswidth;
+	int mas_rpm_id;
+	int slv_rpm_id;
+	struct qcom_icc_qos qos;
+	u64 rate;
+};
+
+struct qcom_icc_desc {
+	struct qcom_icc_node **nodes;
+	size_t num_nodes;
+	const struct regmap_config *regmap_cfg;
+};
+
+#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id,	\
+		     _ap_owned, _qos_mode, _qos_prio, _qos_port, ...)	\
+		static struct qcom_icc_node _name = {			\
+		.name = #_name,						\
+		.id = _id,						\
+		.buswidth = _buswidth,					\
+		.mas_rpm_id = _mas_rpm_id,				\
+		.slv_rpm_id = _slv_rpm_id,				\
+		.qos.ap_owned = _ap_owned,				\
+		.qos.qos_mode = _qos_mode,				\
+		.qos.areq_prio = _qos_prio,				\
+		.qos.prio_level = _qos_prio,				\
+		.qos.qos_port = _qos_port,				\
+		.num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })),	\
+		.links = { __VA_ARGS__ },				\
+	}
+
+int qcom_icc_rpm_qos_probe(struct platform_device *pdev, size_t cd_size, int cd_num,
+	       const struct clk_bulk_data *cd, bool is_bimc);
+int qcom_icc_rpm_qos_remove(struct platform_device *pdev);
+
+#endif
diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c
index 632dbdd21915..2fd587e32d04 100644
--- a/drivers/interconnect/qcom/sdm660.c
+++ b/drivers/interconnect/qcom/sdm660.c
@@ -4,7 +4,6 @@ 
  * Copyright (C) 2020, AngeloGioacchino Del Regno <kholk11@gmail.com>
  */
 
-#include <dt-bindings/interconnect/qcom,sdm660.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/interconnect-provider.h>
@@ -14,42 +13,11 @@ 
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-#include <linux/slab.h>
-
-#include "smd-rpm.h"
-
-#define RPM_BUS_MASTER_REQ	0x73616d62
-#define RPM_BUS_SLAVE_REQ	0x766c7362
-
-/* BIMC QoS */
-#define M_BKE_REG_BASE(n)		(0x300 + (0x4000 * n))
-#define M_BKE_EN_ADDR(n)		(M_BKE_REG_BASE(n))
-#define M_BKE_HEALTH_CFG_ADDR(i, n)	(M_BKE_REG_BASE(n) + 0x40 + (0x4 * i))
-
-#define M_BKE_HEALTH_CFG_LIMITCMDS_MASK	0x80000000
-#define M_BKE_HEALTH_CFG_AREQPRIO_MASK	0x300
-#define M_BKE_HEALTH_CFG_PRIOLVL_MASK	0x3
-#define M_BKE_HEALTH_CFG_AREQPRIO_SHIFT	0x8
-#define M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT 0x1f
 
-#define M_BKE_EN_EN_BMASK		0x1
-
-/* Valid for both NoC and BIMC */
-#define NOC_QOS_MODE_FIXED		0x0
-#define NOC_QOS_MODE_LIMITER		0x1
-#define NOC_QOS_MODE_BYPASS		0x2
-
-/* NoC QoS */
-#define NOC_PERM_MODE_FIXED		1
-#define NOC_PERM_MODE_BYPASS		(1 << NOC_QOS_MODE_BYPASS)
-
-#define NOC_QOS_PRIORITYn_ADDR(n)	(0x8 + (n * 0x1000))
-#define NOC_QOS_PRIORITY_MASK		0xf
-#define NOC_QOS_PRIORITY_P1_SHIFT	0x2
-#define NOC_QOS_PRIORITY_P0_SHIFT	0x3
+#include <dt-bindings/interconnect/qcom,sdm660.h>
 
-#define NOC_QOS_MODEn_ADDR(n)		(0xc + (n * 0x1000))
-#define NOC_QOS_MODEn_MASK		0x3
+#include "icc-rpm-qos.h"
+#include "smd-rpm.h"
 
 enum {
 	SDM660_MASTER_IPA = 1,
@@ -159,105 +127,17 @@  enum {
 	SDM660_SNOC,
 };
 
-#define to_qcom_provider(_provider) \
-	container_of(_provider, struct qcom_icc_provider, provider)
-
-static const struct clk_bulk_data bus_clocks[] = {
+const struct clk_bulk_data bus_clocks[] = {
 	{ .id = "bus" },
 	{ .id = "bus_a" },
 };
 
-static const struct clk_bulk_data bus_mm_clocks[] = {
+const struct clk_bulk_data bus_mm_clocks[] = {
 	{ .id = "bus" },
 	{ .id = "bus_a" },
 	{ .id = "iface" },
 };
 
-/**
- * struct qcom_icc_provider - Qualcomm specific interconnect provider
- * @provider: generic interconnect provider
- * @bus_clks: the clk_bulk_data table of bus clocks
- * @num_clks: the total number of clk_bulk_data entries
- * @is_bimc_node: indicates whether to use bimc specific setting
- * @regmap: regmap for QoS registers read/write access
- * @mmio: NoC base iospace
- */
-struct qcom_icc_provider {
-	struct icc_provider provider;
-	struct clk_bulk_data *bus_clks;
-	int num_clks;
-	bool is_bimc_node;
-	struct regmap *regmap;
-	void __iomem *mmio;
-};
-
-#define SDM660_MAX_LINKS	34
-
-/**
- * struct qcom_icc_qos - Qualcomm specific interconnect QoS parameters
- * @areq_prio: node requests priority
- * @prio_level: priority level for bus communication
- * @limit_commands: activate/deactivate limiter mode during runtime
- * @ap_owned: indicates if the node is owned by the AP or by the RPM
- * @qos_mode: default qos mode for this node
- * @qos_port: qos port number for finding qos registers of this node
- */
-struct qcom_icc_qos {
-	u32 areq_prio;
-	u32 prio_level;
-	bool limit_commands;
-	bool ap_owned;
-	int qos_mode;
-	int qos_port;
-};
-
-/**
- * struct qcom_icc_node - Qualcomm specific interconnect nodes
- * @name: the node name used in debugfs
- * @id: a unique node identifier
- * @links: an array of nodes where we can go next while traversing
- * @num_links: the total number of @links
- * @buswidth: width of the interconnect between a node and the bus (bytes)
- * @mas_rpm_id: RPM id for devices that are bus masters
- * @slv_rpm_id: RPM id for devices that are bus slaves
- * @qos: NoC QoS setting parameters
- * @rate: current bus clock rate in Hz
- */
-struct qcom_icc_node {
-	unsigned char *name;
-	u16 id;
-	u16 links[SDM660_MAX_LINKS];
-	u16 num_links;
-	u16 buswidth;
-	int mas_rpm_id;
-	int slv_rpm_id;
-	struct qcom_icc_qos qos;
-	u64 rate;
-};
-
-struct qcom_icc_desc {
-	struct qcom_icc_node **nodes;
-	size_t num_nodes;
-	const struct regmap_config *regmap_cfg;
-};
-
-#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id,	\
-		     _ap_owned, _qos_mode, _qos_prio, _qos_port, ...)	\
-		static struct qcom_icc_node _name = {			\
-		.name = #_name,						\
-		.id = _id,						\
-		.buswidth = _buswidth,					\
-		.mas_rpm_id = _mas_rpm_id,				\
-		.slv_rpm_id = _slv_rpm_id,				\
-		.qos.ap_owned = _ap_owned,				\
-		.qos.qos_mode = _qos_mode,				\
-		.qos.areq_prio = _qos_prio,				\
-		.qos.prio_level = _qos_prio,				\
-		.qos.qos_port = _qos_port,				\
-		.num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })),	\
-		.links = { __VA_ARGS__ },				\
-	}
-
 DEFINE_QNODE(mas_ipa, SDM660_MASTER_IPA, 8, 59, -1, true, NOC_QOS_MODE_FIXED, 1, 3, SDM660_SLAVE_A2NOC_SNOC);
 DEFINE_QNODE(mas_cnoc_a2noc, SDM660_MASTER_CNOC_A2NOC, 8, 146, -1, true, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC);
 DEFINE_QNODE(mas_sdcc_1, SDM660_MASTER_SDCC_1, 8, 33, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC);
@@ -555,348 +435,27 @@  static struct qcom_icc_desc sdm660_snoc = {
 	.regmap_cfg = &sdm660_snoc_regmap_config,
 };
 
-static int qcom_icc_bimc_set_qos_health(struct regmap *rmap,
-					struct qcom_icc_qos *qos,
-					int regnum)
-{
-	u32 val;
-	u32 mask;
-
-	val = qos->prio_level;
-	mask = M_BKE_HEALTH_CFG_PRIOLVL_MASK;
-
-	val |= qos->areq_prio << M_BKE_HEALTH_CFG_AREQPRIO_SHIFT;
-	mask |= M_BKE_HEALTH_CFG_AREQPRIO_MASK;
-
-	/* LIMITCMDS is not present on M_BKE_HEALTH_3 */
-	if (regnum != 3) {
-		val |= qos->limit_commands << M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT;
-		mask |= M_BKE_HEALTH_CFG_LIMITCMDS_MASK;
-	}
-
-	return regmap_update_bits(rmap,
-				  M_BKE_HEALTH_CFG_ADDR(regnum, qos->qos_port),
-				  mask, val);
-}
-
-static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw,
-				 bool bypass_mode)
+static int sdm660_qnoc_probe(struct platform_device *pdev)
 {
-	struct qcom_icc_provider *qp;
-	struct qcom_icc_node *qn;
-	struct icc_provider *provider;
-	u32 mode = NOC_QOS_MODE_BYPASS;
-	u32 val = 0;
-	int i, rc = 0;
-
-	qn = src->data;
-	provider = src->provider;
-	qp = to_qcom_provider(provider);
-
-	if (qn->qos.qos_mode != -1)
-		mode = qn->qos.qos_mode;
-
-	/* QoS Priority: The QoS Health parameters are getting considered
-	 * only if we are NOT in Bypass Mode.
-	 */
-	if (mode != NOC_QOS_MODE_BYPASS) {
-		for (i = 3; i >= 0; i--) {
-			rc = qcom_icc_bimc_set_qos_health(qp->regmap,
-							  &qn->qos, i);
-			if (rc)
-				return rc;
-		}
-
-		/* Set BKE_EN to 1 when Fixed, Regulator or Limiter Mode */
-		val = 1;
-	}
-
-	return regmap_update_bits(qp->regmap, M_BKE_EN_ADDR(qn->qos.qos_port),
-				  M_BKE_EN_EN_BMASK, val);
-}
-
-static int qcom_icc_noc_set_qos_priority(struct regmap *rmap,
-					 struct qcom_icc_qos *qos)
-{
-	u32 val;
-	int rc;
-
-	/* Must be updated one at a time, P1 first, P0 last */
-	val = qos->areq_prio << NOC_QOS_PRIORITY_P1_SHIFT;
-	rc = regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
-				NOC_QOS_PRIORITY_MASK, val);
-	if (rc)
-		return rc;
-
-	val = qos->prio_level << NOC_QOS_PRIORITY_P0_SHIFT;
-	return regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
-				  NOC_QOS_PRIORITY_MASK, val);
-}
-
-static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw)
-{
-	struct qcom_icc_provider *qp;
-	struct qcom_icc_node *qn;
-	struct icc_provider *provider;
-	u32 mode = NOC_QOS_MODE_BYPASS;
-	int rc = 0;
-
-	qn = src->data;
-	provider = src->provider;
-	qp = to_qcom_provider(provider);
-
-	if (qn->qos.qos_port < 0) {
-		dev_dbg(src->provider->dev,
-			"NoC QoS: Skipping %s: vote aggregated on parent.\n",
-			qn->name);
-		return 0;
-	}
-
-	if (qn->qos.qos_mode != -1)
-		mode = qn->qos.qos_mode;
-
-	if (mode == NOC_QOS_MODE_FIXED) {
-		dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n",
-			qn->name);
-		rc = qcom_icc_noc_set_qos_priority(qp->regmap, &qn->qos);
-		if (rc)
-			return rc;
-	} else if (mode == NOC_QOS_MODE_BYPASS) {
-		dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n",
-			qn->name);
-	}
-
-	return regmap_update_bits(qp->regmap,
-				  NOC_QOS_MODEn_ADDR(qn->qos.qos_port),
-				  NOC_QOS_MODEn_MASK, mode);
-}
-
-static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw)
-{
-	struct qcom_icc_provider *qp = to_qcom_provider(node->provider);
-	struct qcom_icc_node *qn = node->data;
-
-	dev_dbg(node->provider->dev, "Setting QoS for %s\n", qn->name);
-
-	if (qp->is_bimc_node)
-		return qcom_icc_set_bimc_qos(node, sum_bw,
-				(qn->qos.qos_mode == NOC_QOS_MODE_BYPASS));
-
-	return qcom_icc_set_noc_qos(node, sum_bw);
-}
-
-static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw)
-{
-	int ret = 0;
-
-	if (mas_rpm_id != -1) {
-		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
-					    RPM_BUS_MASTER_REQ,
-					    mas_rpm_id,
-					    sum_bw);
-		if (ret) {
-			pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
-			       mas_rpm_id, ret);
-			return ret;
-		}
-	}
-
-	if (slv_rpm_id != -1) {
-		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
-					    RPM_BUS_SLAVE_REQ,
-					    slv_rpm_id,
-					    sum_bw);
-		if (ret) {
-			pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
-			       slv_rpm_id, ret);
-			return ret;
-		}
-	}
-
-	return ret;
-}
-
-static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
-{
-	struct qcom_icc_provider *qp;
-	struct qcom_icc_node *qn;
-	struct icc_provider *provider;
-	struct icc_node *n;
-	u64 sum_bw;
-	u64 max_peak_bw;
-	u64 rate;
-	u32 agg_avg = 0;
-	u32 agg_peak = 0;
-	int ret, i;
-
-	qn = src->data;
-	provider = src->provider;
-	qp = to_qcom_provider(provider);
-
-	list_for_each_entry(n, &provider->nodes, node_list)
-		provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
-				    &agg_avg, &agg_peak);
-
-	sum_bw = icc_units_to_bps(agg_avg);
-	max_peak_bw = icc_units_to_bps(agg_peak);
-
-	if (!qn->qos.ap_owned) {
-		/* send bandwidth request message to the RPM processor */
-		ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw);
-		if (ret)
-			return ret;
-	} else if (qn->qos.qos_mode != -1) {
-		/* set bandwidth directly from the AP */
-		ret = qcom_icc_qos_set(src, sum_bw);
-		if (ret)
-			return ret;
-	}
-
-	rate = max(sum_bw, max_peak_bw);
-
-	do_div(rate, qn->buswidth);
-
-	if (qn->rate == rate)
-		return 0;
-
-	for (i = 0; i < qp->num_clks; i++) {
-		ret = clk_set_rate(qp->bus_clks[i].clk, rate);
-		if (ret) {
-			pr_err("%s clk_set_rate error: %d\n",
-			       qp->bus_clks[i].id, ret);
-			return ret;
-		}
-	}
-
-	qn->rate = rate;
-
-	return 0;
-}
-
-static int qnoc_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	const struct qcom_icc_desc *desc;
-	struct icc_onecell_data *data;
-	struct icc_provider *provider;
-	struct qcom_icc_node **qnodes;
-	struct qcom_icc_provider *qp;
-	struct icc_node *node;
-	struct resource *res;
-	size_t num_nodes, i;
-	int ret;
-
-	/* wait for the RPM proxy */
-	if (!qcom_icc_rpm_smd_available())
-		return -EPROBE_DEFER;
-
-	desc = of_device_get_match_data(dev);
-	if (!desc)
-		return -EINVAL;
-
-	qnodes = desc->nodes;
-	num_nodes = desc->num_nodes;
-
-	qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
-	if (!qp)
-		return -ENOMEM;
-
-	data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
-			    GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	if (of_device_is_compatible(dev->of_node, "qcom,sdm660-mnoc")) {
-		qp->bus_clks = devm_kmemdup(dev, bus_mm_clocks,
-					    sizeof(bus_mm_clocks), GFP_KERNEL);
-		qp->num_clks = ARRAY_SIZE(bus_mm_clocks);
+	const struct clk_bulk_data *cd;
+	size_t cd_size;
+	int cd_num;
+	bool is_bimc = false;
+
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,sdm660-mnoc")) {
+		cd = bus_mm_clocks;
+		cd_size = sizeof(bus_mm_clocks);
+		cd_num = ARRAY_SIZE(bus_mm_clocks);
 	} else {
-		if (of_device_is_compatible(dev->of_node, "qcom,sdm660-bimc"))
-			qp->is_bimc_node = true;
-
-		qp->bus_clks = devm_kmemdup(dev, bus_clocks, sizeof(bus_clocks),
-					    GFP_KERNEL);
-		qp->num_clks = ARRAY_SIZE(bus_clocks);
-	}
-	if (!qp->bus_clks)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENODEV;
-
-	qp->mmio = devm_ioremap_resource(dev, res);
-	if (IS_ERR(qp->mmio)) {
-		dev_err(dev, "Cannot ioremap interconnect bus resource\n");
-		return PTR_ERR(qp->mmio);
-	}
-
-	qp->regmap = devm_regmap_init_mmio(dev, qp->mmio, desc->regmap_cfg);
-	if (IS_ERR(qp->regmap)) {
-		dev_err(dev, "Cannot regmap interconnect bus resource\n");
-		return PTR_ERR(qp->regmap);
-	}
+		if (of_device_is_compatible(pdev->dev.of_node, "qcom,sdm660-bimc"))
+			is_bimc = true;
 
-	ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
-	if (ret)
-		return ret;
-
-	ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
-	if (ret)
-		return ret;
-
-	provider = &qp->provider;
-	INIT_LIST_HEAD(&provider->nodes);
-	provider->dev = dev;
-	provider->set = qcom_icc_set;
-	provider->aggregate = icc_std_aggregate;
-	provider->xlate = of_icc_xlate_onecell;
-	provider->data = data;
-
-	ret = icc_provider_add(provider);
-	if (ret) {
-		dev_err(dev, "error adding interconnect provider: %d\n", ret);
-		clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-		return ret;
+		cd = bus_clocks;
+		cd_size = sizeof(bus_clocks);
+		cd_num = ARRAY_SIZE(bus_clocks);
 	}
 
-	for (i = 0; i < num_nodes; i++) {
-		size_t j;
-
-		node = icc_node_create(qnodes[i]->id);
-		if (IS_ERR(node)) {
-			ret = PTR_ERR(node);
-			goto err;
-		}
-
-		node->name = qnodes[i]->name;
-		node->data = qnodes[i];
-		icc_node_add(node, provider);
-
-		for (j = 0; j < qnodes[i]->num_links; j++)
-			icc_link_create(node, qnodes[i]->links[j]);
-
-		data->nodes[i] = node;
-	}
-	data->num_nodes = num_nodes;
-	platform_set_drvdata(pdev, qp);
-
-	return 0;
-err:
-	icc_nodes_remove(provider);
-	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-	icc_provider_del(provider);
-
-	return ret;
-}
-
-static int qnoc_remove(struct platform_device *pdev)
-{
-	struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
-
-	icc_nodes_remove(&qp->provider);
-	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-	return icc_provider_del(&qp->provider);
+	return qcom_icc_rpm_qos_probe(pdev, cd_size, cd_num, cd, is_bimc);
 }
 
 static const struct of_device_id sdm660_noc_of_match[] = {
@@ -911,8 +470,8 @@  static const struct of_device_id sdm660_noc_of_match[] = {
 MODULE_DEVICE_TABLE(of, sdm660_noc_of_match);
 
 static struct platform_driver sdm660_noc_driver = {
-	.probe = qnoc_probe,
-	.remove = qnoc_remove,
+	.probe = sdm660_qnoc_probe,
+	.remove = qcom_icc_rpm_qos_remove,
 	.driver = {
 		.name = "qnoc-sdm660",
 		.of_match_table = sdm660_noc_of_match,