aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinaro CI <ci_notify@linaro.org>2018-07-14 18:35:30 +0000
committerLinaro CI <ci_notify@linaro.org>2018-07-14 18:35:30 +0000
commitb9b9e0dc4e05530481a6a67bd685e5c1bb120f75 (patch)
tree29ac56310ce10e376b629330c75bc7e6ad4c44ec
parent871a91287c3ded982d515798417cf26c165d80c3 (diff)
parentde8f1c301ba14451cc92c298af60fab470b6f935 (diff)
Merge remote-tracking branch 'bus-scaling/bus-scaling' into integration-linux-qcomlt
# Conflicts: # arch/arm64/boot/dts/qcom/msm8916.dtsi # arch/arm64/boot/dts/qcom/msm8996.dtsi
-rw-r--r--Documentation/devicetree/bindings/interconnect/interconnect.txt60
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt39
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt95
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom-sdm845.txt22
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom-smd.txt32
-rw-r--r--Documentation/interconnect/interconnect.rst96
-rw-r--r--MAINTAINERS10
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi41
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996.dtsi107
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845.dtsi5
-rw-r--r--arch/arm64/configs/defconfig4
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/interconnect/Kconfig15
-rw-r--r--drivers/interconnect/Makefile3
-rw-r--r--drivers/interconnect/core.c743
-rw-r--r--drivers/interconnect/qcom/Kconfig40
-rw-r--r--drivers/interconnect/qcom/Makefile6
-rw-r--r--drivers/interconnect/qcom/msm8916.c508
-rw-r--r--drivers/interconnect/qcom/msm8996.c658
-rw-r--r--drivers/interconnect/qcom/qcom-icc-ids.h142
-rw-r--r--drivers/interconnect/qcom/sdm845.c870
-rw-r--r--drivers/interconnect/qcom/smd-rpm.c91
-rw-r--r--drivers/interconnect/qcom/smd-rpm.h16
-rw-r--r--include/dt-bindings/interconnect/qcom.h440
-rw-r--r--include/linux/interconnect-provider.h130
-rw-r--r--include/linux/interconnect.h49
27 files changed, 4225 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/interconnect/interconnect.txt b/Documentation/devicetree/bindings/interconnect/interconnect.txt
new file mode 100644
index 000000000000..5cb7d3c8d44d
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/interconnect.txt
@@ -0,0 +1,60 @@
+Interconnect Provider Device Tree Bindings
+=========================================
+
+The purpose of this document is to define a common set of generic interconnect
+providers/consumers properties.
+
+
+= interconnect providers =
+
+The interconnect provider binding is intended to represent the interconnect
+controllers in the system. Each provider registers a set of interconnect
+nodes, which expose the interconnect related capabilities of the interconnect
+to consumer drivers. These capabilities can be throughput, latency, priority
+etc. The consumer drivers set constraints on interconnect path (or endpoints)
+depending on the use case. Interconnect providers can also be interconnect
+consumers, such as in the case where two network-on-chip fabrics interface
+directly
+
+Required properties:
+- compatible : contains the interconnect provider compatible string
+- #interconnect-cells : number of cells in a interconnect specifier needed to
+ encode the interconnect node id
+
+Example:
+
+ snoc: snoc@580000 {
+ compatible = "qcom,msm8916-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x14000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ };
+
+
+= interconnect consumers =
+
+The interconnect consumers are device nodes which dynamically express their
+bandwidth requirements along interconnect paths they are connected to. There
+can be multiple interconnect providers on a SoC and the consumer may consume
+multiple paths from different providers depending on use case and the
+components it has to interact with.
+
+Required properties:
+interconnects : Pairs of phandles and interconnect provider specifier to denote
+ the edge source and destination ports of the interconnect path.
+
+Optional properties:
+interconnect-names : List of interconnect path name strings sorted in the same
+ order as the interconnects property. Consumers drivers will use
+ interconnect-names to match interconnect paths with interconnect
+ specifiers.
+
+Example:
+
+ sdhci@7864000 {
+ ...
+ interconnects = <&pnoc MASTER_SDCC_1 &bimc SLAVE_EBI_CH0>;
+ interconnect-names = "ddr";
+ };
diff --git a/Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt b/Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt
new file mode 100644
index 000000000000..f309eaed3d19
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt
@@ -0,0 +1,39 @@
+Qualcomm MSM8916 Network-On-Chip interconnect driver binding
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,msm8916-bimc"
+ "qcom,msm8916-pnoc"
+ "qcom,msm8916-snoc"
+- #interconnect-cells : should contain 1
+- reg : shall contain base register location and length
+
+Optional properties :
+clocks : list of phandles and specifiers to all interconnect bus clocks
+clock-names : clock names should include both "bus_clk" and "bus_a_clk"
+
+Examples:
+
+ snoc: snoc@580000 {
+ compatible = "qcom,msm8916-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x14000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>, <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ };
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8916-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>, <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ };
+ pnoc: pnoc@500000 {
+ compatible = "qcom,msm8916-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x11000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ };
+
diff --git a/Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt b/Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt
new file mode 100644
index 000000000000..26bbc564cd60
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt
@@ -0,0 +1,95 @@
+Qualcomm MSM8996 Network-On-Chip interconnect driver binding
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,msm8996-a0noc"
+ "qcom,msm8996-a1noc"
+ "qcom,msm8996-a2noc"
+ "qcom,msm8996-bimc"
+ "qcom,msm8996-cnoc"
+ "qcom,msm8996-mmnoc"
+ "qcom,msm8996-snoc"
+ "qcom,msm8996-pnoc"
+- #interconnect-cells : should contain 1
+- reg : shall contain base register location and length
+
+Optional properties :
+clocks : list of phandles and specifiers to all interconnect bus clocks
+clock-names : clock names should include both "bus_clk" and "bus_a_clk"
+
+Examples:
+
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8996-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+ <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ };
+
+ cnoc: cnoc@500000 {
+ compatible = "qcom,msm8996-cnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x80>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
+ <&rpmcc RPM_SMD_CNOC_A_CLK>;
+ };
+
+ snoc: snoc@520000 {
+ compatible = "qcom,msm8996-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x520000 0xa100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ };
+
+ a0noc: a0noc@540000 {
+ compatible = "qcom,msm8996-a0noc";
+ #interconnect-cells = <1>;
+ reg = <0x540000 0x5100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&gcc GCC_AGGRE0_SNOC_AXI_CLK>,
+ <&gcc GCC_AGGRE0_SNOC_AXI_CLK>;
+ power-domains = <&gcc AGGRE0_NOC_GDSC>;
+ };
+
+ a1noc: a1noc@560000 {
+ compatible = "qcom,msm8996-a1noc";
+ #interconnect-cells = <1>;
+ reg = <0x560000 0x3100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>;
+ };
+
+ a2noc: a2noc@580000 {
+ compatible = "qcom,msm8996-a2noc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x8100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>;
+ };
+
+ mmnoc: mmnoc@5a0000 {
+ compatible = "qcom,msm8996-mmnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5a0000 0xb080>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_MMAXI_CLK>,
+ <&rpmcc RPM_SMD_MMAXI_A_CLK>;
+ power-domains = <&mmcc MMAGIC_BIMC_GDSC>;
+ };
+
+ pnoc: pnoc@5c0000 {
+ compatible = "qcom,msm8996-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5c0000 0x2480>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ };
diff --git a/Documentation/devicetree/bindings/interconnect/qcom-sdm845.txt b/Documentation/devicetree/bindings/interconnect/qcom-sdm845.txt
new file mode 100644
index 000000000000..6248523527a0
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom-sdm845.txt
@@ -0,0 +1,22 @@
+Qualcomm SDM845 Network-On-Chip interconnect driver binding
+----------------------------------------------------
+
+SDM845 interconnect providers support system bandwidth requirements through
+RPMh hardware accelerators known as Bus Clock Manager(BCM). The provider is able
+to communicate with the BCM through the Resource State Coordinator(RSC)
+associated with each execution environment. Provider nodes must reside within
+an RPMh device node pertaining to their RSC and each provider maps to
+a single RPMh resource.
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,sdm845-rsc-hlos"
+
+Examples:
+
+apps_rsc: rsc {
+ qnoc: qnoc-rsc-hlos {
+ compatible = "qcom,sdm845-rsc-hlos";
+ };
+};
+
diff --git a/Documentation/devicetree/bindings/interconnect/qcom-smd.txt b/Documentation/devicetree/bindings/interconnect/qcom-smd.txt
new file mode 100644
index 000000000000..88a5aeb50935
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom-smd.txt
@@ -0,0 +1,32 @@
+Qualcomm SMD-RPM interconnect driver binding
+------------------------------------------------
+The RPM (Resource Power Manager) is a dedicated hardware engine
+for managing the shared SoC resources in order to keep the lowest
+power profile. It communicates with other hardware subsystems via
+the shared memory driver (SMD) back-end and accepts requests for
+various resources.
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,interconnect-smd-rpm"
+
+Example:
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <0 168 1>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+
+ rpm_requests {
+ compatible = "qcom,rpm-msm8916";
+ qcom,smd-channels = "rpm_requests";
+
+ interconnect-smd-rpm {
+ compatible = "qcom,interconnect-smd-rpm";
+ };
+
+ };
+ };
+ };
diff --git a/Documentation/interconnect/interconnect.rst b/Documentation/interconnect/interconnect.rst
new file mode 100644
index 000000000000..e628881ee218
--- /dev/null
+++ b/Documentation/interconnect/interconnect.rst
@@ -0,0 +1,96 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+GENERIC SYSTEM INTERCONNECT SUBSYSTEM
+=====================================
+
+Introduction
+------------
+
+This framework is designed to provide a standard kernel interface to control
+the settings of the interconnects on a SoC. These settings can be throughput,
+latency and priority between multiple interconnected devices or functional
+blocks. This can be controlled dynamically in order to save power or provide
+maximum performance.
+
+The interconnect bus is a hardware with configurable parameters, which can be
+set on a data path according to the requests received from various drivers.
+An example of interconnect buses are the interconnects between various
+components or functional blocks in chipsets. There can be multiple interconnects
+on a SoC that can be multi-tiered.
+
+Below is a simplified diagram of a real-world SoC interconnect bus topology.
+
+::
+
+ +----------------+ +----------------+
+ | HW Accelerator |--->| M NoC |<---------------+
+ +----------------+ +----------------+ |
+ | | +------------+
+ +-----+ +-------------+ V +------+ | |
+ | DDR | | +--------+ | PCIe | | |
+ +-----+ | | Slaves | +------+ | |
+ ^ ^ | +--------+ | | C NoC |
+ | | V V | |
+ +------------------+ +------------------------+ | | +-----+
+ | |-->| |-->| |-->| CPU |
+ | |-->| |<--| | +-----+
+ | Mem NoC | | S NoC | +------------+
+ | |<--| |---------+ |
+ | |<--| |<------+ | | +--------+
+ +------------------+ +------------------------+ | | +-->| Slaves |
+ ^ ^ ^ ^ ^ | | +--------+
+ | | | | | | V
+ +------+ | +-----+ +-----+ +---------+ +----------------+ +--------+
+ | CPUs | | | GPU | | DSP | | Masters |-->| P NoC |-->| Slaves |
+ +------+ | +-----+ +-----+ +---------+ +----------------+ +--------+
+ |
+ +-------+
+ | Modem |
+ +-------+
+
+Terminology
+-----------
+
+Interconnect provider is the software definition of the interconnect hardware.
+The interconnect providers on the above diagram are M NoC, S NoC, C NoC, P NoC
+and Mem NoC.
+
+Interconnect node is the software definition of the interconnect hardware
+port. Each interconnect provider consists of multiple interconnect nodes,
+which are connected to other SoC components including other interconnect
+providers. The point on the diagram where the CPUs connect to the memory is
+called an interconnect node, which belongs to the Mem NoC interconnect provider.
+
+Interconnect endpoints are the first or the last element of the path. Every
+endpoint is a node, but not every node is an endpoint.
+
+Interconnect path is everything between two endpoints including all the nodes
+that have to be traversed to reach from a source to destination node. It may
+include multiple master-slave pairs across several interconnect providers.
+
+Interconnect consumers are the entities which make use of the data paths exposed
+by the providers. The consumers send requests to providers requesting various
+throughput, latency and priority. Usually the consumers are device drivers, that
+send request based on their needs. An example for a consumer is a video decoder
+that supports various formats and image sizes.
+
+Interconnect providers
+----------------------
+
+Interconnect provider is an entity that implements methods to initialize and
+configure a interconnect bus hardware. The interconnect provider drivers should
+be registered with the interconnect provider core.
+
+The interconnect framework provider API functions are documented in
+.. kernel-doc:: include/linux/interconnect-provider.h
+
+Interconnect consumers
+----------------------
+
+Interconnect consumers are the clients which use the interconnect APIs to
+get paths between endpoints and set their bandwidth/latency/QoS requirements
+for these interconnect paths.
+
+The interconnect framework consumer API functions are documented in
+.. kernel-doc:: include/linux/interconnect.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 96e98e206b0d..72477747699a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7419,6 +7419,16 @@ L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-intel-mid.c
+INTERCONNECT API
+M: Georgi Djakov <georgi.djakov@linaro.org>
+S: Maintained
+F: Documentation/interconnect/
+F: Documentation/devicetree/bindings/interconnect/
+F: drivers/interconnect/
+F: include/linux/dt-bindings/interconnect/
+F: include/linux/interconnect-provider.h
+F: include/linux/interconnect.h
+
INVENSENSE MPU-3050 GYROSCOPE DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-iio@vger.kernel.org
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 207b3a1889fe..37b677f8f0a1 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/interconnect/qcom.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8916.h>
#include <dt-bindings/reset/qcom,gcc-msm8916.h>
@@ -1415,6 +1416,42 @@
qcom,vdd-apc-step-down-limit = <1>;
qcom,cpr-cpus = <&CPU0 &CPU1 &CPU2 &CPU3>;
};
+
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8916-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+ <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ base-offset = <0>;
+ qos-offset = <0>;
+ status = "okay";
+ };
+
+ pnoc: pnoc@500000 {
+ compatible = "qcom,msm8916-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x11000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ base-offset = <0x7000>;
+ qos-offset = <0x1000>;
+ status = "okay";
+ };
+
+ snoc: snoc@580000 {
+ compatible = "qcom,msm8916-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x14000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ base-offset = <0x7000>;
+ qos-offset = <0x1000>;
+ status = "okay";
+ };
};
smd {
@@ -1434,6 +1471,10 @@
#clock-cells = <1>;
};
+ interconnect-smd-rpm {
+ compatible = "qcom,interconnect-smd-rpm";
+ };
+
smd_rpm_regulators: pm8916-regulators {
compatible = "qcom,rpm-pm8916-regulators";
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 071063547677..60dd4170ef1a 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/interconnect/qcom.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8996.h>
#include <dt-bindings/clock/qcom,mmcc-msm8996.h>
@@ -570,6 +571,10 @@
#clock-cells = <1>;
};
+ interconnect-smd-rpm {
+ compatible = "qcom,interconnect-smd-rpm";
+ };
+
pm8994-regulators {
compatible = "qcom,rpm-pm8994-regulators";
@@ -1739,6 +1744,108 @@
qcom,remote-pid = <1>;
};
};
+
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8996-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ type = <2>;
+ base-offset = <0x8000>;
+ qos-offset = <0x4000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+ <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ status = "okay";
+ };
+
+ cnoc: cnoc@500000 {
+ compatible = "qcom,msm8996-cnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x80>;
+ type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
+ <&rpmcc RPM_SMD_CNOC_A_CLK>;
+ status = "okay";
+ };
+
+ snoc: snoc@520000 {
+ compatible = "qcom,msm8996-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x520000 0xa100>;
+ type = <1>;
+ base-offset = <0x4000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ status = "okay";
+ };
+
+ a0noc: a0noc@540000 {
+ compatible = "qcom,msm8996-a0noc";
+ #interconnect-cells = <1>;
+ reg = <0x540000 0x5100>;
+ type = <1>;
+ qcom,base-offset = <0x3000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&gcc GCC_AGGRE0_SNOC_AXI_CLK>,
+ <&gcc GCC_AGGRE0_SNOC_AXI_CLK>;
+ power-domains = <&gcc AGGRE0_NOC_GDSC>;
+ status = "okay";
+ };
+
+ a1noc: a1noc@560000 {
+ compatible = "qcom,msm8996-a1noc";
+ #interconnect-cells = <1>;
+ reg = <0x560000 0x3100>;
+ type = <1>;
+ base-offset = <0x2000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>;
+ status = "okay";
+ };
+
+ a2noc: a2noc@580000 {
+ compatible = "qcom,msm8996-a2noc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x8100>;
+ base-offset = <0x3000>;
+ qos-offset = <0x1000>;
+ type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>;
+ status = "okay";
+ };
+
+ mmnoc: mmnoc@5a0000 {
+ compatible = "qcom,msm8996-mmnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5a0000 0xb080>;
+ type = <1>;
+ base-offset = <0x4000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_MMAXI_CLK>,
+ <&rpmcc RPM_SMD_MMAXI_A_CLK>;
+ power-domains = <&mmcc MMAGIC_BIMC_GDSC>;
+ status = "okay";
+ };
+
+ pnoc: pnoc@5c0000 {
+ compatible = "qcom,msm8996-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5c0000 0x2480>;
+ type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ status = "okay";
+ };
};
sound: sound {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 1097c7ef31b9..adc42dda9ece 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1628,6 +1628,11 @@
reg = <0x17d10000 0x1000>;
status = "disabled";
};
+
+ qnoc: qnoc-rsc-hlos{
+ compatible = "qcom,sdm845-rsc-hlos";
+ status = "okay";
+ };
};
apps_rsc: rsc@179c0000 {
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 457ed78523ad..9aeb36ab651e 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -669,6 +669,10 @@ CONFIG_UNIPHIER_EFUSE=y
CONFIG_MESON_EFUSE=m
CONFIG_TEE=y
CONFIG_OPTEE=y
+CONFIG_INTERCONNECT=y
+CONFIG_INTERCONNECT_QCOM=y
+CONFIG_INTERCONNECT_QCOM_MSM8916=y
+CONFIG_INTERCONNECT_QCOM_MSM8996=y
CONFIG_ARM_SCPI_PROTOCOL=y
CONFIG_RASPBERRYPI_FIRMWARE=y
CONFIG_EFI_CAPSULE_LOADER=y
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 95b9ccc08165..3ed6ede9d021 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -217,4 +217,6 @@ source "drivers/siox/Kconfig"
source "drivers/slimbus/Kconfig"
+source "drivers/interconnect/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 24cd47014657..0cca95740d9b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -185,3 +185,4 @@ obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_MULTIPLEXER) += mux/
obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
obj-$(CONFIG_SIOX) += siox/
+obj-$(CONFIG_INTERCONNECT) += interconnect/
diff --git a/drivers/interconnect/Kconfig b/drivers/interconnect/Kconfig
new file mode 100644
index 000000000000..07a8276fa35a
--- /dev/null
+++ b/drivers/interconnect/Kconfig
@@ -0,0 +1,15 @@
+menuconfig INTERCONNECT
+ tristate "On-Chip Interconnect management support"
+ help
+ Support for management of the on-chip interconnects.
+
+ This framework is designed to provide a generic interface for
+ managing the interconnects in a SoC.
+
+ If unsure, say no.
+
+if INTERCONNECT
+
+source "drivers/interconnect/qcom/Kconfig"
+
+endif
diff --git a/drivers/interconnect/Makefile b/drivers/interconnect/Makefile
new file mode 100644
index 000000000000..7944cbca0527
--- /dev/null
+++ b/drivers/interconnect/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_INTERCONNECT) += core.o
+obj-$(CONFIG_INTERCONNECT_QCOM) += qcom/
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
new file mode 100644
index 000000000000..4997679c39c0
--- /dev/null
+++ b/drivers/interconnect/core.c
@@ -0,0 +1,743 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework core driver
+ *
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/overflow.h>
+#include <linux/uaccess.h>
+
+static DEFINE_IDR(icc_idr);
+static LIST_HEAD(icc_provider_list);
+static DEFINE_MUTEX(icc_lock);
+static struct dentry *icc_debugfs_dir;
+
+/**
+ * struct icc_req - constraints that are attached to each node
+ *
+ * @req_node: entry in list of requests for the particular @node
+ * @node: the interconnect node to which this constraint applies
+ * @dev: reference to the device that sets the constraints
+ * @avg_bw: an integer describing the average bandwidth in kbps
+ * @peak_bw: an integer describing the peak bandwidth in kbps
+ */
+struct icc_req {
+ struct hlist_node req_node;
+ struct icc_node *node;
+ struct device *dev;
+ u32 avg_bw;
+ u32 peak_bw;
+};
+
+/**
+ * struct icc_path - interconnect path structure
+ * @num_nodes: number of hops (nodes)
+ * @reqs: array of the requests applicable to this path of nodes
+ */
+struct icc_path {
+ u8 tag;
+ size_t num_nodes;
+ struct icc_req reqs[];
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static void icc_summary_show_one(struct seq_file *s, struct icc_node *n)
+{
+ if (!n)
+ return;
+
+ seq_printf(s, "%-30s %12d %12d\n",
+ n->name, n->avg_bw, n->peak_bw);
+}
+
+static int icc_summary_show(struct seq_file *s, void *data)
+{
+ struct icc_provider *provider;
+
+ seq_puts(s, " node avg peak\n");
+ seq_puts(s, "--------------------------------------------------------\n");
+
+ mutex_lock(&icc_lock);
+
+ list_for_each_entry(provider, &icc_provider_list, provider_list) {
+ struct icc_node *n;
+
+ list_for_each_entry(n, &provider->nodes, node_list) {
+ struct icc_req *r;
+
+ icc_summary_show_one(s, n);
+ hlist_for_each_entry(r, &n->req_list, req_node) {
+ if (!r->dev)
+ continue;
+
+ seq_printf(s, " %-26s %12d %12d\n",
+ dev_name(r->dev), r->avg_bw,
+ r->peak_bw);
+ }
+ }
+ }
+
+ mutex_unlock(&icc_lock);
+
+ return 0;
+}
+
+static int icc_summary_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, icc_summary_show, inode->i_private);
+}
+
+static const struct file_operations icc_summary_fops = {
+ .open = icc_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init icc_debugfs_init(void)
+{
+ struct dentry *file;
+
+ icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
+ if (!icc_debugfs_dir) {
+ pr_err("interconnect: error creating debugfs directory\n");
+ return -ENODEV;
+ }
+
+ file = debugfs_create_file("interconnect_summary", 0444,
+ icc_debugfs_dir, NULL, &icc_summary_fops);
+ if (!file)
+ return -ENODEV;
+
+ return 0;
+}
+late_initcall(icc_debugfs_init);
+#endif
+
+static struct icc_node *node_find(const int id)
+{
+ return idr_find(&icc_idr, id);
+}
+
+static struct icc_path *path_init(struct device *dev, struct icc_node *dst,
+ ssize_t num_nodes)
+{
+ struct icc_node *node = dst;
+ struct icc_path *path;
+ size_t i;
+
+ path = kzalloc(struct_size(path, reqs, num_nodes), GFP_KERNEL);
+ if (!path)
+ return ERR_PTR(-ENOMEM);
+
+ path->num_nodes = num_nodes;
+
+ for (i = 0; i < num_nodes; i++) {
+ node->provider->users++;
+ hlist_add_head(&path->reqs[i].req_node, &node->req_list);
+ path->reqs[i].node = node;
+ path->reqs[i].dev = dev;
+ /* reference to previous node was saved during path traversal */
+ node = node->reverse;
+ }
+
+ return path;
+}
+
+static struct icc_path *path_find(struct device *dev, struct icc_node *src,
+ struct icc_node *dst)
+{
+ struct icc_path *path = ERR_PTR(-EPROBE_DEFER);
+ struct icc_node *n, *node = NULL;
+ struct icc_provider *provider;
+ struct list_head traverse_list;
+ struct list_head edge_list;
+ struct list_head visited_list;
+ size_t i, depth = 1;
+ bool found = false;
+
+ INIT_LIST_HEAD(&traverse_list);
+ INIT_LIST_HEAD(&edge_list);
+ INIT_LIST_HEAD(&visited_list);
+
+ list_add_tail(&src->search_list, &traverse_list);
+ src->reverse = NULL;
+
+ do {
+ list_for_each_entry_safe(node, n, &traverse_list, search_list) {
+ if (node == dst) {
+ found = true;
+ list_add(&node->search_list, &visited_list);
+ break;
+ }
+ for (i = 0; i < node->num_links; i++) {
+ struct icc_node *tmp = node->links[i];
+
+ if (!tmp) {
+ path = ERR_PTR(-ENOENT);
+ goto out;
+ }
+
+ if (tmp->is_traversed)
+ continue;
+
+ tmp->is_traversed = true;
+ tmp->reverse = node;
+ list_add(&tmp->search_list, &edge_list);
+ }
+ }
+ if (found)
+ break;
+
+ list_splice_init(&traverse_list, &visited_list);
+ list_splice_init(&edge_list, &traverse_list);
+
+ /* count the hops including the source */
+ depth++;
+
+ } while (!list_empty(&traverse_list));
+
+out:
+ /* reset the traversed state */
+ list_for_each_entry(provider, &icc_provider_list, provider_list)
+ list_for_each_entry(n, &provider->nodes, node_list)
+ n->is_traversed = false;
+
+ if (found)
+ path = path_init(dev, dst, depth);
+
+ return path;
+}
+
+/*
+ * We want the path to honor all bandwidth requests, so the average
+ * bandwidth requirements from each consumer are aggregated at each node
+ * and provider level. By default the average bandwidth is the sum of all
+ * averages and the peak will be the highest of all peak bandwidth requests.
+ */
+
+static int aggregate_requests(struct icc_node *node, u8 tag)
+{
+ struct icc_provider *p = node->provider;
+ struct icc_req *r;
+
+ node->avg_bw = 0;
+ node->peak_bw = 0;
+
+ hlist_for_each_entry(r, &node->req_list, req_node)
+ p->aggregate(node, tag, r->avg_bw, r->peak_bw,
+ &node->avg_bw, &node->peak_bw);
+
+ return 0;
+}
+
+static void aggregate_provider(struct icc_provider *p, u8 tag)
+{
+ struct icc_node *n;
+
+ p->avg_bw = 0;
+ p->peak_bw = 0;
+
+ list_for_each_entry(n, &p->nodes, node_list)
+ p->aggregate(n, tag, n->avg_bw, n->peak_bw,
+ &p->avg_bw, &p->peak_bw);
+}
+
+static int apply_constraints(struct icc_path *path)
+{
+ struct icc_node *next, *prev = NULL;
+ int ret;
+ int i;
+
+ for (i = 0; i < path->num_nodes; i++, prev = next) {
+ struct icc_provider *p;
+
+ next = path->reqs[i].node;
+ /*
+ * Both endpoints should be valid master-slave pairs of the
+ * same interconnect provider that will be configured.
+ */
+ if (!prev || next->provider != prev->provider)
+ continue;
+
+ p = next->provider;
+
+ aggregate_provider(p, path->tag);
+
+ /* set the constraints */
+ ret = p->set(prev, next, p->avg_bw, p->peak_bw);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+struct icc_path *of_icc_get(struct device *dev, const char *name)
+{
+ struct device_node *np = NULL;
+ struct of_phandle_args src_args, dst_args;
+ u32 src_id, dst_id;
+ int idx = 0;
+ int ret;
+
+ if (!dev || !dev->of_node)
+ return ERR_PTR(-ENODEV);
+
+ np = dev->of_node;
+
+ /*
+ * When the consumer DT node do not have "interconnects" property
+ * return a NULL path to skip setting constraints.
+ */
+ if (!of_find_property(np, "interconnects", NULL))
+ return NULL;
+
+ /*
+ * We use a combination of phandle and specifier for endpoint. For now
+ * lets support only global ids and extend this is the future if needed
+ * without breaking DT compatibility.
+ */
+ if (name) {
+ idx = of_property_match_string(np, "interconnect-names", name);
+ if (idx < 0)
+ return ERR_PTR(idx);
+ }
+
+ ret = of_parse_phandle_with_args(np, "interconnects",
+ "#interconnect-cells", idx * 2,
+ &src_args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ of_node_put(src_args.np);
+
+ if (!src_args.args_count || src_args.args_count > 1)
+ return ERR_PTR(-EINVAL);
+
+ src_id = src_args.args[0];
+
+ ret = of_parse_phandle_with_args(np, "interconnects",
+ "#interconnect-cells", idx * 2 + 1,
+ &dst_args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ of_node_put(dst_args.np);
+
+ if (!dst_args.args_count || dst_args.args_count > 1)
+ return ERR_PTR(-EINVAL);
+
+ dst_id = dst_args.args[0];
+
+ return icc_get(dev, src_id, dst_id);
+}
+EXPORT_SYMBOL_GPL(of_icc_get);
+
+/**
+ * icc_set_tag() - set tag on a path
+ * @path: the path we want to tag
+ * @tag: the tag value
+ *
+ * This function allows consumers to append a tag to the path, so that a
+ * different aggregation could be done based on this tag.
+ */
+void icc_set_tag(struct icc_path *path, u8 tag)
+{
+ if (!path)
+ return;
+
+ path->tag = tag;
+}
+EXPORT_SYMBOL_GPL(icc_set_tag);
+
+/**
+ * icc_set() - set constraints on an interconnect path between two endpoints
+ * @path: reference to the path returned by icc_get()
+ * @avg_bw: average bandwidth in kbps
+ * @peak_bw: peak bandwidth in kbps
+ *
+ * This function is used by an interconnect consumer to express its own needs
+ * in terms of bandwidth for a previously requested path between two endpoints.
+ * The requests are aggregated and each node is updated accordingly. The entire
+ * path is locked by a mutex to ensure that the set() is completed.
+ * The @path can be NULL when the "interconnects" DT properties is missing,
+ * which will mean that no constraints will be set.
+ *
+ * Returns 0 on success, or an appropriate error code otherwise.
+ */
+int icc_set(struct icc_path *path, u32 avg_bw, u32 peak_bw)
+{
+ struct icc_node *node;
+ struct icc_provider *p;
+ size_t i;
+ int ret;
+
+ if (!path)
+ return 0;
+
+ mutex_lock(&icc_lock);
+
+ for (i = 0; i < path->num_nodes; i++) {
+ node = path->reqs[i].node;
+ p = node->provider;
+
+ /* update the consumer request for this path */
+ path->reqs[i].avg_bw = avg_bw;
+ path->reqs[i].peak_bw = peak_bw;
+
+ /* aggregate requests for this node */
+ aggregate_requests(node, path->tag);
+ }
+
+ ret = apply_constraints(path);
+ if (ret)
+ pr_err("interconnect: error applying constraints (%d)", ret);
+
+ mutex_unlock(&icc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icc_set);
+
+/**
+ * icc_get() - return a handle for path between two endpoints
+ * @dev: the device requesting the path
+ * @src_id: source device port id
+ * @dst_id: destination device port id
+ *
+ * This function will search for a path between two endpoints and return an
+ * icc_path handle on success. Use icc_put() to release
+ * constraints when the they are not needed anymore.
+ *
+ * Return: icc_path pointer on success, or ERR_PTR() on error
+ */
+struct icc_path *icc_get(struct device *dev, const int src_id, const int dst_id)
+{
+ struct icc_node *src, *dst;
+ struct icc_path *path = ERR_PTR(-EPROBE_DEFER);
+
+ mutex_lock(&icc_lock);
+
+ src = node_find(src_id);
+ if (!src)
+ goto out;
+
+ dst = node_find(dst_id);
+ if (!dst)
+ goto out;
+
+ path = path_find(dev, src, dst);
+ if (IS_ERR(path))
+ dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
+
+out:
+ mutex_unlock(&icc_lock);
+ return path;
+}
+EXPORT_SYMBOL_GPL(icc_get);
+
+/**
+ * icc_put() - release the reference to the icc_path
+ * @path: interconnect path
+ *
+ * Use this function to release the constraints on a path when the path is
+ * no longer needed. The constraints will be re-aggregated.
+ */
+void icc_put(struct icc_path *path)
+{
+ struct icc_node *node;
+ size_t i;
+ int ret;
+
+ if (!path || WARN_ON(IS_ERR(path)))
+ return;
+
+ ret = icc_set(path, 0, 0);
+ if (ret)
+ pr_err("%s: error (%d)\n", __func__, ret);
+
+ mutex_lock(&icc_lock);
+ for (i = 0; i < path->num_nodes; i++) {
+ node = path->reqs[i].node;
+ hlist_del(&path->reqs[i].req_node);
+ if (!WARN_ON(!node->provider->users))
+ node->provider->users--;
+ }
+ mutex_unlock(&icc_lock);
+
+ kfree(path);
+}
+EXPORT_SYMBOL_GPL(icc_put);
+
+static struct icc_node *icc_node_create_nolock(int id)
+{
+ struct icc_node *node;
+
+ /* check if node already exists */
+ node = node_find(id);
+ if (node)
+ goto out;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ node = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL);
+ if (WARN(id < 0, "couldn't get idr")) {
+ kfree(node);
+ node = ERR_PTR(id);
+ goto out;
+ }
+
+ node->id = id;
+
+out:
+ return node;
+}
+
+/**
+ * icc_node_create() - create a node
+ * @id: node id
+ *
+ * Return: icc_node pointer on success, or ERR_PTR() on error
+ */
+struct icc_node *icc_node_create(int id)
+{
+ struct icc_node *node;
+
+ mutex_lock(&icc_lock);
+
+ node = icc_node_create_nolock(id);
+
+ mutex_unlock(&icc_lock);
+
+ return node;
+}
+EXPORT_SYMBOL_GPL(icc_node_create);
+
+/**
+ * icc_node_destroy() - destroy a node
+ * @id: node id
+ *
+ */
+void icc_node_destroy(int id)
+{
+ struct icc_node *node;
+
+ mutex_lock(&icc_lock);
+
+ node = node_find(id);
+ if (node) {
+ idr_remove(&icc_idr, node->id);
+ WARN_ON(!hlist_empty(&node->req_list));
+ }
+
+ mutex_unlock(&icc_lock);
+
+ kfree(node);
+}
+EXPORT_SYMBOL_GPL(icc_node_destroy);
+
+/**
+ * icc_link_create() - create a link between two nodes
+ * @src_id: source node id
+ * @dst_id: destination node id
+ *
+ * Create a link between two nodes. The nodes might belong to different
+ * interconnect providers and the @dst_id node might not exist (if the
+ * provider driver has not probed yet). So just create the @dst_id node
+ * and when the actual provider driver is probed, the rest of the node
+ * data is filled.
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_link_create(struct icc_node *node, const int dst_id)
+{
+ struct icc_node *dst;
+ struct icc_node **new;
+ int ret = 0;
+
+ if (!node->provider)
+ return -EINVAL;
+
+ mutex_lock(&icc_lock);
+
+ dst = node_find(dst_id);
+ if (!dst) {
+ dst = icc_node_create_nolock(dst_id);
+
+ if (IS_ERR(dst)) {
+ ret = PTR_ERR(dst);
+ goto out;
+ }
+ }
+
+ new = krealloc(node->links,
+ (node->num_links + 1) * sizeof(*node->links),
+ GFP_KERNEL);
+ if (!new) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ node->links = new;
+ node->links[node->num_links++] = dst;
+
+out:
+ mutex_unlock(&icc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icc_link_create);
+
+/**
+ * icc_link_destroy() - destroy a link between two nodes
+ * @src: pointer to source node
+ * @dst: pointer to destination node
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_link_destroy(struct icc_node *src, struct icc_node *dst)
+{
+ struct icc_node **new;
+ size_t slot;
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(src))
+ return -EINVAL;
+
+ if (IS_ERR_OR_NULL(dst))
+ return -EINVAL;
+
+ mutex_lock(&icc_lock);
+
+ for (slot = 0; slot < src->num_links; slot++)
+ if (src->links[slot] == dst)
+ break;
+
+ if (WARN_ON(slot == src->num_links)) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ src->links[slot] = src->links[src->num_links - 1];
+ src->num_links--;
+
+ new = krealloc(src->links,
+ (src->num_links) * sizeof(*src->links),
+ GFP_KERNEL);
+ if (new)
+ src->links = new;
+
+out:
+ mutex_unlock(&icc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icc_link_destroy);
+
+/**
+ * icc_node_add() - add interconnect node to interconnect provider
+ * @node: pointer to the interconnect node
+ * @provider: pointer to the interconnect provider
+ *
+ */
+void icc_node_add(struct icc_node *node, struct icc_provider *provider)
+{
+ mutex_lock(&icc_lock);
+
+ node->provider = provider;
+ list_add(&node->node_list, &provider->nodes);
+
+ mutex_unlock(&icc_lock);
+}
+EXPORT_SYMBOL_GPL(icc_node_add);
+
+/**
+ * icc_node_del() - delete interconnect node from interconnect provider
+ * @node: pointer to the interconnect node
+ *
+ */
+void icc_node_del(struct icc_node *node)
+{
+ mutex_lock(&icc_lock);
+
+ list_del(&node->node_list);
+
+ mutex_unlock(&icc_lock);
+}
+EXPORT_SYMBOL_GPL(icc_node_del);
+
+/**
+ * icc_provider_add() - add a new interconnect provider
+ * @icc_provider: the interconnect provider that will be added into topology
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_provider_add(struct icc_provider *provider)
+{
+ if (WARN_ON(!provider->set))
+ return -EINVAL;
+
+ mutex_lock(&icc_lock);
+
+ INIT_LIST_HEAD(&provider->nodes);
+ list_add(&provider->provider_list, &icc_provider_list);
+
+ mutex_unlock(&icc_lock);
+
+ dev_dbg(provider->dev, "interconnect provider added to topology\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(icc_provider_add);
+
+/**
+ * icc_provider_del() - delete previously added interconnect provider
+ * @icc_provider: the interconnect provider that will be removed from topology
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_provider_del(struct icc_provider *provider)
+{
+ mutex_lock(&icc_lock);
+ if (provider->users) {
+ pr_warn("interconnect provider still has %d users\n",
+ provider->users);
+ mutex_unlock(&icc_lock);
+ return -EBUSY;
+ }
+
+ if (!list_empty(&provider->nodes)) {
+ pr_warn("interconnect provider still has nodes\n");
+ mutex_unlock(&icc_lock);
+ return -EBUSY;
+ }
+
+ list_del(&provider->provider_list);
+ mutex_unlock(&icc_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(icc_provider_del);
+
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org");
+MODULE_DESCRIPTION("Interconnect Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
new file mode 100644
index 000000000000..5ad88346270b
--- /dev/null
+++ b/drivers/interconnect/qcom/Kconfig
@@ -0,0 +1,40 @@
+config INTERCONNECT_QCOM
+ bool "Qualcomm Network-on-Chip interconnect drivers"
+ depends on INTERCONNECT
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ Support for Qualcomm's Network-on-Chip interconnect hardware.
+
+config INTERCONNECT_QCOM_SMD_RPM
+ tristate "Qualcomm SMD RPM interconnect driver"
+ depends on INTERCONNECT_QCOM
+ depends on QCOM_SMD_RPM
+ help
+ This is a driver for communicating interconnect related configuration
+ details with a remote processor (RPM) on Qualcomm platforms.
+
+config INTERCONNECT_QCOM_MSM8916
+ tristate "Qualcomm MSM8916 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ depends on QCOM_SMD_RPM
+ select INTERCONNECT_QCOM_SMD_RPM
+ help
+ This is a driver for the Qualcomm Network-on-Chip on msm8916-based
+ platforms.
+
+config INTERCONNECT_QCOM_MSM8996
+ tristate "Qualcomm MSM8996 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ depends on QCOM_SMD_RPM
+ select INTERCONNECT_QCOM_SMD_RPM
+ help
+ This is a driver for the Qualcomm Network-on-Chip on msm8996-based
+ platforms.
+
+config INTERCONNECT_QCOM_SDM845
+ tristate "Qualcomm SDM845 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ depends on (QCOM_RPMH && QCOM_COMMAND_DB && OF) || COMPILE_TEST
+ help
+ This is a driver for the Qualcomm Network-on-Chip on sdm845-based
+ platforms.
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
new file mode 100644
index 000000000000..d7ead97b4835
--- /dev/null
+++ b/drivers/interconnect/qcom/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += smd-rpm.o
+
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += msm8916.o
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += msm8996.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += sdm845.o
diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c
new file mode 100644
index 000000000000..4bf734adbc92
--- /dev/null
+++ b/drivers/interconnect/qcom/msm8916.c
@@ -0,0 +1,508 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Linaro Ltd
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <dt-bindings/interconnect/qcom.h>
+#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/slab.h>
+
+#include "smd-rpm.h"
+
+#define RPM_BUS_MASTER_REQ 0x73616d62
+#define RPM_BUS_SLAVE_REQ 0x766c7362
+
+#define to_qcom_provider(_provider) \
+ container_of(_provider, struct qcom_icc_provider, provider)
+
+enum qcom_qos_mode {
+ QCOM_QOS_MODE_BYPASS = 0,
+ QCOM_QOS_MODE_FIXED,
+ QCOM_QOS_MODE_MAX,
+};
+
+struct qcom_icc_provider {
+ struct icc_provider provider;
+ void __iomem *base;
+ struct clk *bus_clk;
+ struct clk *bus_a_clk;
+};
+
+#define MSM8916_MAX_LINKS 8
+
+/**
+ * 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
+ * @port: the offset index into the masters QoS register space
+ * @buswidth: width of the interconnect between a node and the bus (bytes)
+ * @ap_owned: the AP CPU does the writing to QoS registers
+ * @qos_mode: QoS mode for ap_owned resources
+ * @mas_rpm_id: RPM id for devices that are bus masters
+ * @slv_rpm_id: RPM id for devices that are bus slaves
+ * @rate: current bus clock rate in Hz
+ */
+struct qcom_icc_node {
+ unsigned char *name;
+ u16 id;
+ u16 links[MSM8916_MAX_LINKS];
+ u16 num_links;
+ u16 port;
+ u16 buswidth;
+ bool ap_owned;
+ enum qcom_qos_mode qos_mode;
+ int mas_rpm_id;
+ int slv_rpm_id;
+ u64 rate;
+};
+
+struct qcom_icc_desc {
+ struct qcom_icc_node **nodes;
+ size_t num_nodes;
+};
+
+#define DEFINE_QNODE(_name, _id, _port, _buswidth, _ap_owned, \
+ _mas_rpm_id, _slv_rpm_id, _qos_mode, \
+ _numlinks, ...) \
+ static struct qcom_icc_node _name = { \
+ .name = #_name, \
+ .id = _id, \
+ .port = _port, \
+ .buswidth = _buswidth, \
+ .ap_owned = _ap_owned, \
+ .mas_rpm_id = _mas_rpm_id, \
+ .slv_rpm_id = _slv_rpm_id, \
+ .qos_mode = _qos_mode, \
+ .num_links = _numlinks, \
+ .links = { __VA_ARGS__ }, \
+ }
+
+DEFINE_QNODE(mas_video, MASTER_VIDEO_P0, 8, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_0, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_jpeg, MASTER_JPEG, 6, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_0, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_vfe, MASTER_VFE, 9, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_1, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_mdp, MASTER_MDP_PORT0, 7, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_0, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_qdss_bam, MASTER_QDSS_BAM, 11, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_QDSS_INT);
+DEFINE_QNODE(mas_snoc_cfg, MASTER_SNOC_CFG, 0, 16, 0, 20, -1, QCOM_QOS_MODE_BYPASS, 1, SNOC_QDSS_INT);
+DEFINE_QNODE(mas_qdss_etr, MASTER_QDSS_ETR, 10, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_QDSS_INT);
+DEFINE_QNODE(mm_int_0, SNOC_MM_INT_0, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_MM_INT_BIMC);
+DEFINE_QNODE(mm_int_1, SNOC_MM_INT_1, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_MM_INT_BIMC);
+DEFINE_QNODE(mm_int_2, SNOC_MM_INT_2, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_INT_0);
+DEFINE_QNODE(mm_int_bimc, SNOC_MM_INT_BIMC, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_1_MAS);
+DEFINE_QNODE(snoc_int_0, SNOC_INT_0, 0, 8, 0, 99, 130, QCOM_QOS_MODE_FIXED, 3, SLAVE_QDSS_STM, SLAVE_SYSTEM_IMEM, MNOC_BIMC_MAS);
+DEFINE_QNODE(snoc_int_1, SNOC_INT_1, 0, 8, 0, 100, 131, QCOM_QOS_MODE_FIXED, 3, SYSTEM_SLAVE_FAB_APPS, SLAVE_CATS_128, SLAVE_OCMEM_64);
+DEFINE_QNODE(snoc_int_bimc, SNOC_INT_BIMC, 0, 8, 0, 101, 132, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_0_MAS);
+DEFINE_QNODE(snoc_bimc_0_mas, SNOC_BIMC_0_MAS, 0, 8, 0, 3, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_0_SLV);
+DEFINE_QNODE(snoc_bimc_1_mas, SNOC_BIMC_1_MAS, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_1_SLV);
+DEFINE_QNODE(qdss_int, SNOC_QDSS_INT, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 2, SNOC_INT_0, SNOC_INT_BIMC);
+DEFINE_QNODE(bimc_snoc_slv, BIMC_SNOC_SLV, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 2, SNOC_INT_0, SNOC_INT_1);
+DEFINE_QNODE(snoc_pnoc_mas, MNOC_BIMC_MAS, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(pnoc_snoc_slv, PNOC_SNOC_SLV, 0, 8, 0, -1, 45, QCOM_QOS_MODE_FIXED, 3, SNOC_INT_0, SNOC_INT_BIMC, SNOC_INT_1);
+DEFINE_QNODE(slv_srvc_snoc, SLAVE_SERVICE_SNOC, 0, 8, 0, -1, 29, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_qdss_stm, SLAVE_QDSS_STM, 0, 4, 0, -1, 30, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_imem, SLAVE_SYSTEM_IMEM, 0, 8, 0, -1, 26, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_apss, SYSTEM_SLAVE_FAB_APPS, 0, 4, 0, -1, 20, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_cats_0, SLAVE_CATS_128, 0, 16, 0, -1, 106, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_cats_1, SLAVE_OCMEM_64, 0, 8, 0, -1, 107, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(mas_apss, MASTER_AMPSS_M0, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_tcu0, MASTER_TCU_0, 5, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_tcu1, MASTER_TCU_1, 6, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_gfx, MASTER_GRAPHICS_3D, 2, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(bimc_snoc_mas, BIMC_SNOC_MAS, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, BIMC_SNOC_SLV);
+DEFINE_QNODE(snoc_bimc_0_slv, SNOC_BIMC_0_SLV, 0, 8, 0, -1, 24, QCOM_QOS_MODE_FIXED, 1, SLAVE_EBI_CH0);
+DEFINE_QNODE(snoc_bimc_1_slv, SNOC_BIMC_1_SLV, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SLAVE_EBI_CH0);
+DEFINE_QNODE(slv_ebi_ch0, SLAVE_EBI_CH0, 0, 8, 0, -1, 0, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_apps_l2, SLAVE_AMPSS_L2, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(snoc_pnoc_slv, MNOC_BIMC_SLV, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_0);
+DEFINE_QNODE(pnoc_int_0, PNOC_INT_0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 8, PNOC_SNOC_MAS, PNOC_SLV_0, PNOC_SLV_1, PNOC_SLV_2, PNOC_SLV_3, PNOC_SLV_4, PNOC_SLV_8, PNOC_SLV_9);
+DEFINE_QNODE(pnoc_int_1, PNOC_INT_1, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_SNOC_MAS);
+DEFINE_QNODE(pnoc_m_0, PNOC_M_0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_0);
+DEFINE_QNODE(pnoc_m_1, PNOC_M_1, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_SNOC_MAS);
+DEFINE_QNODE(pnoc_s_0, PNOC_SLV_0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_CLK_CTL, SLAVE_TLMM, SLAVE_MSM_TCSR, SLAVE_SECURITY, SLAVE_MSS);
+DEFINE_QNODE(pnoc_s_1, PNOC_SLV_1, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_IMEM_CFG, SLAVE_CRYPTO_0_CFG, SLAVE_RPM_MSG_RAM, SLAVE_MSM_PDM, SLAVE_PRNG);
+DEFINE_QNODE(pnoc_s_2, PNOC_SLV_2, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_SPDM, SLAVE_BOOT_ROM, SLAVE_BIMC_CFG, SLAVE_PNOC_CFG, SLAVE_PMIC_ARB);
+DEFINE_QNODE(pnoc_s_3, PNOC_SLV_3, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_MPM, SLAVE_IPS_CFG, SLAVE_RBCPR_CFG, SLAVE_QDSS_CFG, SLAVE_DEHR_CFG);
+DEFINE_QNODE(pnoc_s_4, PNOC_SLV_4, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_VENUS_CFG, SLAVE_CAMERA_CFG, SLAVE_DISPLAY_CFG);
+DEFINE_QNODE(pnoc_s_8, PNOC_SLV_8, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_USB_HS, SLAVE_SDCC_1, SLAVE_BLSP_1);
+DEFINE_QNODE(pnoc_s_9, PNOC_SLV_9, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_SDCC_4, SLAVE_LPASS, SLAVE_GRAPHICS_3D_CFG);
+DEFINE_QNODE(slv_imem_cfg, SLAVE_IMEM_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_crypto_0_cfg, SLAVE_CRYPTO_0_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_msg_ram, SLAVE_RPM_MSG_RAM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_pdm, SLAVE_MSM_PDM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_prng, SLAVE_PRNG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_clk_ctl, SLAVE_CLK_CTL, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_mss, SLAVE_MSS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_tlmm, SLAVE_TLMM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_tcsr, SLAVE_MSM_TCSR, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_security, SLAVE_SECURITY, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_spdm, SLAVE_SPDM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_pnoc_cfg, SLAVE_PNOC_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_pmic_arb, SLAVE_PMIC_ARB, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_bimc_cfg, SLAVE_BIMC_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_boot_rom, SLAVE_BOOT_ROM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_mpm, SLAVE_MPM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_qdss_cfg, SLAVE_QDSS_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_rbcpr_cfg, SLAVE_RBCPR_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_snoc_cfg, SLAVE_IPS_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_dehr_cfg, SLAVE_DEHR_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_venus_cfg, SLAVE_VENUS_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_display_cfg, SLAVE_DISPLAY_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_camera_cfg, SLAVE_CAMERA_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_usb_hs, SLAVE_USB_HS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_sdcc_1, SLAVE_SDCC_1, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_blsp_1, SLAVE_BLSP_1, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_sdcc_2, SLAVE_SDCC_4, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_gfx_cfg, SLAVE_GRAPHICS_3D_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_audio, SLAVE_LPASS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(mas_blsp_1, MASTER_BLSP_1, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_1);
+DEFINE_QNODE(mas_spdm, MASTER_SPDM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_0);
+DEFINE_QNODE(mas_dehr, MASTER_DEHR, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_0);
+DEFINE_QNODE(mas_audio, MASTER_LPASS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_0);
+DEFINE_QNODE(mas_usb_hs, MASTER_USB_HS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_1);
+DEFINE_QNODE(mas_pnoc_crypto_0, MASTER_CRYPTO_CORE0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_1);
+DEFINE_QNODE(mas_pnoc_sdcc_1, MASTER_SDCC_1, 7, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_1);
+DEFINE_QNODE(mas_pnoc_sdcc_2, MASTER_SDCC_2, 8, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_1);
+DEFINE_QNODE(pnoc_snoc_mas, PNOC_SNOC_MAS, 0, 8, 0, 29, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_SNOC_SLV);
+
+static struct qcom_icc_node *msm8916_snoc_nodes[] = {
+ &mas_video,
+ &mas_jpeg,
+ &mas_vfe,
+ &mas_mdp,
+ &mas_qdss_bam,
+ &mas_snoc_cfg,
+ &mas_qdss_etr,
+ &mm_int_0,
+ &mm_int_1,
+ &mm_int_2,
+ &mm_int_bimc,
+ &snoc_int_0,
+ &snoc_int_1,
+ &snoc_int_bimc,
+ &snoc_bimc_0_mas,
+ &snoc_bimc_1_mas,
+ &qdss_int,
+ &bimc_snoc_slv,
+ &snoc_pnoc_mas,
+ &pnoc_snoc_slv,
+ &slv_srvc_snoc,
+ &slv_qdss_stm,
+ &slv_imem,
+ &slv_apss,
+ &slv_cats_0,
+ &slv_cats_1,
+};
+
+static struct qcom_icc_desc msm8916_snoc = {
+ .nodes = msm8916_snoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_snoc_nodes),
+};
+
+static struct qcom_icc_node *msm8916_bimc_nodes[] = {
+ &mas_apss,
+ &mas_tcu0,
+ &mas_tcu1,
+ &mas_gfx,
+ &bimc_snoc_mas,
+ &snoc_bimc_0_slv,
+ &snoc_bimc_1_slv,
+ &slv_ebi_ch0,
+ &slv_apps_l2,
+};
+
+static struct qcom_icc_desc msm8916_bimc = {
+ .nodes = msm8916_bimc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_bimc_nodes),
+};
+
+static struct qcom_icc_node *msm8916_pnoc_nodes[] = {
+ &snoc_pnoc_slv,
+ &pnoc_int_0,
+ &pnoc_int_1,
+ &pnoc_m_0,
+ &pnoc_m_1,
+ &pnoc_s_0,
+ &pnoc_s_1,
+ &pnoc_s_2,
+ &pnoc_s_3,
+ &pnoc_s_4,
+ &pnoc_s_8,
+ &pnoc_s_9,
+ &slv_imem_cfg,
+ &slv_crypto_0_cfg,
+ &slv_msg_ram,
+ &slv_pdm,
+ &slv_prng,
+ &slv_clk_ctl,
+ &slv_mss,
+ &slv_tlmm,
+ &slv_tcsr,
+ &slv_security,
+ &slv_spdm,
+ &slv_pnoc_cfg,
+ &slv_pmic_arb,
+ &slv_bimc_cfg,
+ &slv_boot_rom,
+ &slv_mpm,
+ &slv_qdss_cfg,
+ &slv_rbcpr_cfg,
+ &slv_snoc_cfg,
+ &slv_dehr_cfg,
+ &slv_venus_cfg,
+ &slv_display_cfg,
+ &slv_camera_cfg,
+ &slv_usb_hs,
+ &slv_sdcc_1,
+ &slv_blsp_1,
+ &slv_sdcc_2,
+ &slv_gfx_cfg,
+ &slv_audio,
+ &mas_blsp_1,
+ &mas_spdm,
+ &mas_dehr,
+ &mas_audio,
+ &mas_usb_hs,
+ &mas_pnoc_crypto_0,
+ &mas_pnoc_sdcc_1,
+ &mas_pnoc_sdcc_2,
+ &pnoc_snoc_mas,
+};
+
+static struct qcom_icc_desc msm8916_pnoc = {
+ .nodes = msm8916_pnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_pnoc_nodes),
+};
+
+static int qcom_icc_aggregate(struct icc_node *node, u8 tag, u32 avg_bw,
+ u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
+{
+ *agg_avg += avg_bw;
+ *agg_peak = max(*agg_peak, peak_bw);
+
+ return 0;
+}
+
+static int qcom_icc_set(struct icc_node *src, struct icc_node *dst,
+ u32 avg, u32 peak)
+{
+ struct qcom_icc_provider *qp;
+ struct qcom_icc_node *qn;
+ struct icc_node *node;
+ struct icc_provider *provider;
+ u64 avg_bw = icc_units_to_bps(avg);
+ u64 peak_bw = icc_units_to_bps(peak);
+ int ret = 0;
+ u64 rate;
+
+ if (!src)
+ node = dst;
+ else
+ node = src;
+
+ qn = node->data;
+ provider = node->provider;
+ qp = to_qcom_provider(provider);
+
+ /* set bandwidth */
+ if (qn->ap_owned) {
+ /* TODO: set QoS */
+ } else {
+ /* send message to the RPM processor */
+ if (qn->mas_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_MASTER_REQ,
+ qn->mas_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send mas error %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (qn->slv_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_SLAVE_REQ,
+ qn->slv_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send slv error %d\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ rate = max(avg_bw, peak_bw);
+
+ do_div(rate, qn->buswidth);
+
+ if (qn->rate != rate) {
+ ret = clk_set_rate(qp->bus_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ ret = clk_set_rate(qp->bus_a_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ qn->rate = rate;
+ }
+
+ return ret;
+}
+
+static int qnoc_probe(struct platform_device *pdev)
+{
+ const struct qcom_icc_desc *desc;
+ struct qcom_icc_node **qnodes;
+ struct icc_node *node;
+ struct qcom_icc_provider *qp;
+ struct resource *res;
+ struct icc_provider *provider;
+ size_t num_nodes, i;
+ int ret;
+
+ /* wait for RPM */
+ if (!qcom_icc_rpm_smd_available())
+ return -EPROBE_DEFER;
+
+ desc = of_device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ qnodes = desc->nodes;
+ num_nodes = desc->num_nodes;
+
+ qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ qp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(qp->base))
+ return PTR_ERR(qp->base);
+
+ qp->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(qp->bus_clk))
+ return PTR_ERR(qp->bus_clk);
+
+ ret = clk_prepare_enable(qp->bus_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_clk: %d\n", ret);
+ return ret;
+ }
+
+ qp->bus_a_clk = devm_clk_get(&pdev->dev, "bus_a_clk");
+ if (IS_ERR(qp->bus_a_clk))
+ return PTR_ERR(qp->bus_a_clk);
+
+ ret = clk_prepare_enable(qp->bus_a_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_a_clk: %d\n", ret);
+ clk_disable_unprepare(qp->bus_clk);
+ return ret;
+ }
+
+ provider = &qp->provider;
+ provider->dev = &pdev->dev;
+ provider->set = &qcom_icc_set;
+ provider->aggregate = &qcom_icc_aggregate;
+ INIT_LIST_HEAD(&provider->nodes);
+ provider->data = qp;
+
+ ret = icc_provider_add(provider);
+ if (ret) {
+ dev_err(&pdev->dev, "error adding interconnect provider\n");
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ return ret;
+ }
+
+ for (i = 0; i < num_nodes; i++) {
+ int ret;
+ 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);
+
+ dev_dbg(&pdev->dev, "registered node %s\n", node->name);
+
+ /* populate links */
+ for (j = 0; j < qnodes[i]->num_links; j++)
+ if (qnodes[i]->links[j])
+ icc_link_create(node, qnodes[i]->links[j]);
+ }
+
+ platform_set_drvdata(pdev, provider);
+
+ return ret;
+err:
+ list_for_each_entry(node, &provider->nodes, node_list) {
+ icc_node_del(node);
+ icc_node_destroy(node->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ icc_provider_del(provider);
+
+ return ret;
+}
+
+static int qnoc_remove(struct platform_device *pdev)
+{
+ struct icc_provider *provider = platform_get_drvdata(pdev);
+ struct qcom_icc_provider *qp = to_qcom_provider(provider);
+ struct icc_node *n;
+
+ list_for_each_entry(n, &provider->nodes, node_list) {
+ icc_node_del(n);
+ icc_node_destroy(n->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+
+
+ return icc_provider_del(provider);
+}
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,msm8916-pnoc", .data = &msm8916_pnoc },
+ { .compatible = "qcom,msm8916-snoc", .data = &msm8916_snoc },
+ { .compatible = "qcom,msm8916-bimc", .data = &msm8916_bimc },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qnoc_probe,
+ .remove = qnoc_remove,
+ .driver = {
+ .name = "qnoc-msm8916",
+ .of_match_table = qnoc_of_match,
+ },
+};
+module_platform_driver(qnoc_driver);
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm msm8916 NoC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c
new file mode 100644
index 000000000000..39d08f7e0d7a
--- /dev/null
+++ b/drivers/interconnect/qcom/msm8996.c
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Linaro Ltd
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <dt-bindings/interconnect/qcom.h>
+#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/slab.h>
+
+#include "smd-rpm.h"
+
+#define RPM_MASTER_FIELD_BW 0x00007762
+#define RPM_BUS_MASTER_REQ 0x73616d62
+#define RPM_BUS_SLAVE_REQ 0x766c7362
+
+#define to_qcom_provider(_provider) \
+ container_of(_provider, struct qcom_icc_provider, provider)
+
+enum qcom_qos_mode {
+ QCOM_QOS_MODE_BYPASS = 0,
+ QCOM_QOS_MODE_FIXED,
+ QCOM_QOS_MODE_MAX,
+};
+
+struct qcom_icc_provider {
+ struct icc_provider provider;
+ void __iomem *base;
+ struct clk *bus_clk;
+ struct clk *bus_a_clk;
+};
+
+#define MSM8996_MAX_LINKS 38
+
+/**
+ * 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
+ * @port: the offset index into the masters QoS register space
+ * @agg_ports: the number of aggregation ports on the bus
+ * @buswidth: width of the interconnect between a node and the bus (bytes)
+ * @ap_owned: the AP CPU does the writing to QoS registers
+ * @qos_mode: QoS mode for ap_owned resources
+ * @mas_rpm_id: RPM id for devices that are bus masters
+ * @slv_rpm_id: RPM id for devices that are bus slaves
+ * @rate: current bus clock rate in Hz
+ */
+struct qcom_icc_node {
+ unsigned char *name;
+ u16 id;
+ u16 links[MSM8996_MAX_LINKS];
+ u16 num_links;
+ u16 port;
+ u16 agg_ports;
+ u16 buswidth;
+ bool ap_owned;
+ enum qcom_qos_mode qos_mode;
+ int mas_rpm_id;
+ int slv_rpm_id;
+ u64 rate;
+};
+
+struct qcom_icc_desc {
+ struct qcom_icc_node **nodes;
+ size_t num_nodes;
+};
+
+#define DEFINE_QNODE(_name, _id, _port, _agg_ports, _buswidth, \
+ _qos_mode, _ap_owned, _mas_rpm_id, _slv_rpm_id, \
+ _numlinks, ...) \
+ static struct qcom_icc_node _name = { \
+ .name = #_name, \
+ .id = _id, \
+ .port = _port, \
+ .agg_ports = _agg_ports, \
+ .buswidth = _buswidth, \
+ .qos_mode = _qos_mode, \
+ .ap_owned = _ap_owned, \
+ .mas_rpm_id = _mas_rpm_id, \
+ .slv_rpm_id = _slv_rpm_id, \
+ .num_links = _numlinks, \
+ .links = { __VA_ARGS__ }, \
+ }
+
+DEFINE_QNODE(mas_pcie_0, MASTER_PCIE, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 65, -1, 1, A0NOC_SNOC_SLV);
+DEFINE_QNODE(mas_pcie_1, MASTER_PCIE_1, 1, 1, 8, QCOM_QOS_MODE_FIXED, 1, 66, -1, 1, A0NOC_SNOC_SLV);
+DEFINE_QNODE(mas_pcie_2, MASTER_PCIE_2, 2, 1, 8, QCOM_QOS_MODE_FIXED, 1, 119, -1, 1, A0NOC_SNOC_SLV);
+DEFINE_QNODE(mas_cnoc_a1noc, CNOC_A1NOC_MAS, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 116, -1, 1, A1NOC_SNOC_SLV);
+DEFINE_QNODE(mas_crypto_c0, MASTER_CRYPTO_CORE0, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 23, -1, 1, A1NOC_SNOC_SLV);
+DEFINE_QNODE(mas_pnoc_a1noc, PNOC_A1NOC_MAS, 1, 1, 8, QCOM_QOS_MODE_FIXED, 0, 117, -1, 1, A1NOC_SNOC_SLV);
+DEFINE_QNODE(mas_usb3, MASTER_USB3, 3, 1, 8, QCOM_QOS_MODE_FIXED, 1, 32, -1, 1, A2NOC_SNOC_SLV);
+DEFINE_QNODE(mas_ipa, MASTER_IPA, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 59, -1, 1, A2NOC_SNOC_SLV);
+DEFINE_QNODE(mas_ufs, MASTER_UFS, 2, 1, 8, QCOM_QOS_MODE_FIXED, 1, 68, -1, 1, A2NOC_SNOC_SLV);
+DEFINE_QNODE(mas_apps_proc, MASTER_AMPSS_M0, 0, 2, 8, QCOM_QOS_MODE_FIXED, 1, 0, -1, 3, BIMC_SNOC_1_SLV, SLAVE_EBI_CH0, BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_oxili, MASTER_GRAPHICS_3D, 1, 2, 8, QCOM_QOS_MODE_BYPASS, 1, 6, -1, 4, BIMC_SNOC_1_SLV, SLAVE_HMSS_L3, SLAVE_EBI_CH0, BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_mnoc_bimc, MNOC_BIMC_MAS, 2, 2, 8, QCOM_QOS_MODE_BYPASS, 1, 2, -1, 4, BIMC_SNOC_1_SLV, SLAVE_HMSS_L3, SLAVE_EBI_CH0, BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_snoc_bimc, SNOC_BIMC_MAS, 0, 2, 8, QCOM_QOS_MODE_BYPASS, 0, 3, -1, 2, SLAVE_HMSS_L3, SLAVE_EBI_CH0);
+DEFINE_QNODE(mas_snoc_cnoc, SNOC_CNOC_MAS, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 52, -1, 37, SLAVE_CLK_CTL, SLAVE_RBCPR_CX, SLAVE_A2NOC_SMMU_CFG, SLAVE_A0NOC_MPU_CFG, SLAVE_MESSAGE_RAM, SLAVE_CNOC_MNOC_MMSS_CFG, SLAVE_PCIE_0_CFG, SLAVE_TLMM, SLAVE_MPM, SLAVE_A0NOC_SMMU_CFG, SLAVE_EBI1_PHY_CFG, SLAVE_BIMC_CFG, SLAVE_PIMEM_CFG, SLAVE_RBCPR_MX, SLAVE_PRNG, SLAVE_PCIE20_AHB2PHY, SLAVE_A2NOC_MPU_CFG, SLAVE_QDSS_CFG, SLAVE_A2NOC_CFG, SLAVE_A0NOC_CFG, SLAVE_UFS_CFG, SLAVE_CRYPTO_0_CFG, SLAVE_PCIE_1_CFG, SLAVE_SNOC_CFG, SLAVE_SNOC_MPU_CFG, SLAVE_A1NOC_MPU_CFG, SLAVE_A1NOC_SMMU_CFG, SLAVE_PCIE_2_CFG, SLAVE_CNOC_MNOC_CFG, SLAVE_QDSS_RBCPR_APU_CFG, SLAVE_PMIC_ARB, SLAVE_IMEM_CFG, SLAVE_A1NOC_CFG, SLAVE_SSC_CFG, SLAVE_TCSR, SLAVE_LPASS_SMMU_CFG, SLAVE_DCC_CFG);
+DEFINE_QNODE(mas_qdss_dap, MASTER_QDSS_DAP, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 1, 49, -1, 38, SLAVE_QDSS_RBCPR_APU_CFG, SLAVE_RBCPR_CX, SLAVE_A2NOC_SMMU_CFG, SLAVE_A0NOC_MPU_CFG, SLAVE_MESSAGE_RAM, SLAVE_PCIE_0_CFG, SLAVE_TLMM, SLAVE_MPM, SLAVE_A0NOC_SMMU_CFG, SLAVE_EBI1_PHY_CFG, SLAVE_BIMC_CFG, SLAVE_PIMEM_CFG, SLAVE_RBCPR_MX, SLAVE_CLK_CTL, SLAVE_PRNG, SLAVE_PCIE20_AHB2PHY, SLAVE_A2NOC_MPU_CFG, SLAVE_QDSS_CFG, SLAVE_A2NOC_CFG, SLAVE_A0NOC_CFG, SLAVE_UFS_CFG, SLAVE_CRYPTO_0_CFG, CNOC_SNOC_SLV, SLAVE_PCIE_1_CFG, SLAVE_SNOC_CFG, SLAVE_SNOC_MPU_CFG, SLAVE_A1NOC_MPU_CFG, SLAVE_A1NOC_SMMU_CFG, SLAVE_PCIE_2_CFG, SLAVE_CNOC_MNOC_CFG, SLAVE_CNOC_MNOC_MMSS_CFG, SLAVE_PMIC_ARB, SLAVE_IMEM_CFG, SLAVE_A1NOC_CFG, SLAVE_SSC_CFG, SLAVE_TCSR, SLAVE_LPASS_SMMU_CFG, SLAVE_DCC_CFG);
+DEFINE_QNODE(mas_cnoc_mnoc_mmss_cfg, MASTER_CNOC_MNOC_MMSS_CFG, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 1, 4, -1, 21, SLAVE_MMAGIC_CFG, SLAVE_DSA_MPU_CFG, SLAVE_MMSS_CLK_CFG, SLAVE_CAMERA_THROTTLE_CFG, SLAVE_VENUS_CFG, SLAVE_SMMU_VFE_CFG, SLAVE_MISC_CFG, SLAVE_SMMU_CPP_CFG, SLAVE_GRAPHICS_3D_CFG, SLAVE_DISPLAY_THROTTLE_CFG, SLAVE_VENUS_THROTTLE_CFG, SLAVE_CAMERA_CFG, SLAVE_DISPLAY_CFG, SLAVE_CPR_CFG, SLAVE_SMMU_ROTATOR_CFG, SLAVE_DSA_CFG, SLAVE_SMMU_VENUS_CFG, SLAVE_VMEM_CFG, SLAVE_SMMU_JPEG_CFG, SLAVE_SMMU_MDP_CFG, SLAVE_MNOC_MPU_CFG);
+DEFINE_QNODE(mas_cnoc_mnoc_cfg, MASTER_CNOC_MNOC_CFG, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 1, 5, -1, 1, SLAVE_SERVICE_MNOC);
+DEFINE_QNODE(mas_cpp, MASTER_CPP, 5, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 115, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_jpeg, MASTER_JPEG, 7, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 7, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_mdp_p0, MASTER_MDP_PORT0, 1, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 8, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_mdp_p1, MASTER_MDP_PORT1, 2, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 61, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_rotator, MASTER_ROTATOR, 0, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 120, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_venus, MASTER_VIDEO_P0, 3, 2, 32, QCOM_QOS_MODE_BYPASS, 1, 9, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_vfe, MASTER_VFE, 6, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 11, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_snoc_vmem, MASTER_SNOC_VMEM, 0, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 114, -1, 1, SLAVE_VMEM_CFG);
+DEFINE_QNODE(mas_venus_vmem, MASTER_VIDEO_P0_OCMEM, 0, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 121, -1, 1, SLAVE_VMEM_CFG);
+DEFINE_QNODE(mas_snoc_pnoc, SNOC_PNOC_MAS, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 44, -1, 9, SLAVE_BLSP_1, SLAVE_BLSP_2, SLAVE_USB_HS, SLAVE_SDCC_1, SLAVE_SDCC_2, SLAVE_SDCC_4, SLAVE_TSIF, SLAVE_PDM, SLAVE_AHB2PHY);
+DEFINE_QNODE(mas_sdcc_1, MASTER_SDCC_1, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 33, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_sdcc_2, MASTER_SDCC_2, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 35, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_sdcc_4, MASTER_SDCC_4, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 36, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_usb_hs, MASTER_USB_HS, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 42, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_blsp_1, MASTER_BLSP_1, 0, 1, 4, QCOM_QOS_MODE_BYPASS, 0, 41, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_blsp_2, MASTER_BLSP_2, 0, 1, 4, QCOM_QOS_MODE_BYPASS, 0, 39, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_tsif, MASTER_TSIF, 0, 1, 4, QCOM_QOS_MODE_BYPASS, 0, 37, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_hmss, MASTER_HMSS, 4, 1, 8, QCOM_QOS_MODE_FIXED, 1, 118, -1, 3, SLAVE_PIMEM, SLAVE_OCIMEM, SNOC_BIMC_SLV);
+DEFINE_QNODE(mas_qdss_bam, MASTER_QDSS_BAM, 2, 1, 16, QCOM_QOS_MODE_FIXED, 1, 19, -1, 5, SLAVE_PIMEM, SLAVE_USB3, SLAVE_OCIMEM, SNOC_BIMC_SLV, SNOC_PNOC_SLV);
+DEFINE_QNODE(mas_snoc_cfg, MASTER_SNOC_CFG, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 20, -1, 1, SLAVE_SERVICE_SNOC);
+DEFINE_QNODE(mas_bimc_snoc_0, BIMC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 21, -1, 9, SLAVE_SNOC_VMEM, SLAVE_USB3, SLAVE_PIMEM, SLAVE_LPASS, SLAVE_APPSS, SNOC_CNOC_SLV, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_QDSS_STM);
+DEFINE_QNODE(mas_bimc_snoc_1, BIMC_SNOC_1_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 109, -1, 3, SLAVE_PCIE_2, SLAVE_PCIE_1, SLAVE_PCIE_0);
+DEFINE_QNODE(mas_a0noc_snoc, A0NOC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 110, -1, 5, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_APPSS, SNOC_BIMC_SLV, SLAVE_PIMEM);
+DEFINE_QNODE(mas_a1noc_snoc, A1NOC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, 111, -1, 13, SLAVE_SNOC_VMEM, SLAVE_USB3, SLAVE_PCIE_0, SLAVE_PIMEM, SLAVE_PCIE_2, SLAVE_LPASS, SLAVE_PCIE_1, SLAVE_APPSS, SNOC_BIMC_SLV, SNOC_CNOC_SLV, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_QDSS_STM);
+DEFINE_QNODE(mas_a2noc_snoc, A2NOC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, 112, -1, 12, SLAVE_SNOC_VMEM, SLAVE_USB3, SLAVE_PCIE_1, SLAVE_PIMEM, SLAVE_PCIE_2, SLAVE_QDSS_STM, SLAVE_LPASS, SNOC_BIMC_SLV, SNOC_CNOC_SLV, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_PCIE_0);
+DEFINE_QNODE(mas_qdss_etr, MASTER_QDSS_ETR, 3, 1, 16, QCOM_QOS_MODE_FIXED, 1, 31, -1, 5, SLAVE_PIMEM, SLAVE_USB3, SLAVE_OCIMEM, SNOC_BIMC_SLV, SNOC_PNOC_SLV);
+DEFINE_QNODE(slv_a0noc_snoc, A0NOC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 141, 1, A0NOC_SNOC_MAS);
+DEFINE_QNODE(slv_a1noc_snoc, A1NOC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 142, 1, A1NOC_SNOC_MAS);
+DEFINE_QNODE(slv_a2noc_snoc, A2NOC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 143, 1, A2NOC_SNOC_MAS);
+DEFINE_QNODE(slv_ebi, SLAVE_EBI_CH0, 0, 2, 8, QCOM_QOS_MODE_FIXED, 0, -1, 0, 0, 0);
+DEFINE_QNODE(slv_hmss_l3, SLAVE_HMSS_L3, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 160, 0, 0);
+DEFINE_QNODE(slv_bimc_snoc_0, BIMC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 2, 1, BIMC_SNOC_MAS);
+DEFINE_QNODE(slv_bimc_snoc_1, BIMC_SNOC_1_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 138, 1, BIMC_SNOC_1_MAS);
+DEFINE_QNODE(slv_cnoc_a1noc, CNOC_SNOC_SLV, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 75, 1, CNOC_A1NOC_MAS);
+DEFINE_QNODE(slv_clk_ctl, SLAVE_CLK_CTL, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 47, 0, 0);
+DEFINE_QNODE(slv_tcsr, SLAVE_TCSR, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 50, 0, 0);
+DEFINE_QNODE(slv_tlmm, SLAVE_TLMM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 51, 0, 0);
+DEFINE_QNODE(slv_crypto0_cfg, SLAVE_CRYPTO_0_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 52, 0, 0);
+DEFINE_QNODE(slv_mpm, SLAVE_MPM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 62, 0, 0);
+DEFINE_QNODE(slv_pimem_cfg, SLAVE_PIMEM_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 167, 0, 0);
+DEFINE_QNODE(slv_imem_cfg, SLAVE_IMEM_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 54, 0, 0);
+DEFINE_QNODE(slv_message_ram, SLAVE_MESSAGE_RAM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 55, 0, 0);
+DEFINE_QNODE(slv_bimc_cfg, SLAVE_BIMC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 56, 0, 0);
+DEFINE_QNODE(slv_pmic_arb, SLAVE_PMIC_ARB, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 59, 0, 0);
+DEFINE_QNODE(slv_prng, SLAVE_PRNG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 44, 0, 0);
+DEFINE_QNODE(slv_dcc_cfg, SLAVE_DCC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 155, 0, 0);
+DEFINE_QNODE(slv_rbcpr_mx, SLAVE_RBCPR_MX, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 170, 0, 0);
+DEFINE_QNODE(slv_qdss_cfg, SLAVE_QDSS_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 63, 0, 0);
+DEFINE_QNODE(slv_rbcpr_cx, SLAVE_RBCPR_CX, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 169, 0, 0);
+DEFINE_QNODE(slv_cpr_apu_cfg, SLAVE_QDSS_RBCPR_APU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 168, 0, 0);
+DEFINE_QNODE(slv_cnoc_mnoc_cfg, SLAVE_CNOC_MNOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 66, 1, MASTER_CNOC_MNOC_CFG);
+DEFINE_QNODE(slv_snoc_cfg, SLAVE_SNOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 70, 0, 0);
+DEFINE_QNODE(slv_snoc_mpu_cfg, SLAVE_SNOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 67, 0, 0);
+DEFINE_QNODE(slv_ebi1_phy_cfg, SLAVE_EBI1_PHY_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 73, 0, 0);
+DEFINE_QNODE(slv_a0noc_cfg, SLAVE_A0NOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 144, 0, 0);
+DEFINE_QNODE(slv_pcie_1_cfg, SLAVE_PCIE_1_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 89, 0, 0);
+DEFINE_QNODE(slv_pcie_2_cfg, SLAVE_PCIE_2_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 165, 0, 0);
+DEFINE_QNODE(slv_pcie_0_cfg, SLAVE_PCIE_0_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 88, 0, 0);
+DEFINE_QNODE(slv_pcie20_ahb2phy, SLAVE_PCIE20_AHB2PHY, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 163, 0, 0);
+DEFINE_QNODE(slv_a0noc_mpu_cfg, SLAVE_A0NOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 145, 0, 0);
+DEFINE_QNODE(slv_ufs_cfg, SLAVE_UFS_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 92, 0, 0);
+DEFINE_QNODE(slv_a1noc_cfg, SLAVE_A1NOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 147, 0, 0);
+DEFINE_QNODE(slv_a1noc_mpu_cfg, SLAVE_A1NOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 148, 0, 0);
+DEFINE_QNODE(slv_a2noc_cfg, SLAVE_A2NOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 150, 0, 0);
+DEFINE_QNODE(slv_a2noc_mpu_cfg, SLAVE_A2NOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 151, 0, 0);
+DEFINE_QNODE(slv_ssc_cfg, SLAVE_SSC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 177, 0, 0);
+DEFINE_QNODE(slv_a0noc_smmu_cfg, SLAVE_A0NOC_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 146, 0, 0);
+DEFINE_QNODE(slv_a1noc_smmu_cfg, SLAVE_A1NOC_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 149, 0, 0);
+DEFINE_QNODE(slv_a2noc_smmu_cfg, SLAVE_A2NOC_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 152, 0, 0);
+DEFINE_QNODE(slv_lpass_smmu_cfg, SLAVE_LPASS_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 161, 0, 0);
+DEFINE_QNODE(slv_cnoc_mnoc_mmss_cfg, SLAVE_CNOC_MNOC_MMSS_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 58, 1, MASTER_CNOC_MNOC_MMSS_CFG);
+DEFINE_QNODE(slv_mmagic_cfg, SLAVE_MMAGIC_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 162, 0, 0);
+DEFINE_QNODE(slv_cpr_cfg, SLAVE_CPR_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 6, 0, 0);
+DEFINE_QNODE(slv_misc_cfg, SLAVE_MISC_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 8, 0, 0);
+DEFINE_QNODE(slv_venus_throttle_cfg, SLAVE_VENUS_THROTTLE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 178, 0, 0);
+DEFINE_QNODE(slv_venus_cfg, SLAVE_VENUS_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 10, 0, 0);
+DEFINE_QNODE(slv_vmem_cfg, SLAVE_VMEM_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 180, 0, 0);
+DEFINE_QNODE(slv_dsa_cfg, SLAVE_DSA_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 157, 0, 0);
+DEFINE_QNODE(slv_mnoc_clocks_cfg, SLAVE_MMSS_CLK_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 12, 0, 0);
+DEFINE_QNODE(slv_dsa_mpu_cfg, SLAVE_DSA_MPU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 158, 0, 0);
+DEFINE_QNODE(slv_mnoc_mpu_cfg, SLAVE_MNOC_MPU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 14, 0, 0);
+DEFINE_QNODE(slv_display_cfg, SLAVE_DISPLAY_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 4, 0, 0);
+DEFINE_QNODE(slv_display_throttle_cfg, SLAVE_DISPLAY_THROTTLE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 156, 0, 0);
+DEFINE_QNODE(slv_camera_cfg, SLAVE_CAMERA_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 3, 0, 0);
+DEFINE_QNODE(slv_camera_throttle_cfg, SLAVE_CAMERA_THROTTLE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 154, 0, 0);
+DEFINE_QNODE(slv_oxili_cfg, SLAVE_GRAPHICS_3D_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 11, 0, 0);
+DEFINE_QNODE(slv_smmu_mdp_cfg, SLAVE_SMMU_MDP_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 173, 0, 0);
+DEFINE_QNODE(slv_smmu_rot_cfg, SLAVE_SMMU_ROTATOR_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 174, 0, 0);
+DEFINE_QNODE(slv_smmu_venus_cfg, SLAVE_SMMU_VENUS_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 175, 0, 0);
+DEFINE_QNODE(slv_smmu_cpp_cfg, SLAVE_SMMU_CPP_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 171, 0, 0);
+DEFINE_QNODE(slv_smmu_jpeg_cfg, SLAVE_SMMU_JPEG_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 172, 0, 0);
+DEFINE_QNODE(slv_smmu_vfe_cfg, SLAVE_SMMU_VFE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 176, 0, 0);
+DEFINE_QNODE(slv_mnoc_bimc, MNOC_BIMC_SLV, 0, 2, 32, QCOM_QOS_MODE_FIXED, 1, -1, 16, 1, MNOC_BIMC_MAS);
+DEFINE_QNODE(slv_vmem, SLAVE_VMEM, 0, 1, 32, QCOM_QOS_MODE_FIXED, 1, -1, 179, 0, 0);
+DEFINE_QNODE(slv_srvc_mnoc, SLAVE_SERVICE_MNOC, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 17, 0, 0);
+DEFINE_QNODE(slv_pnoc_a1noc, PNOC_A1NOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 139, 1, PNOC_A1NOC_MAS);
+DEFINE_QNODE(slv_usb_hs, SLAVE_USB_HS, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 40, 0, 0);
+DEFINE_QNODE(slv_sdcc_2, SLAVE_SDCC_2, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 33, 0, 0);
+DEFINE_QNODE(slv_sdcc_4, SLAVE_SDCC_4, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 34, 0, 0);
+DEFINE_QNODE(slv_tsif, SLAVE_TSIF, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 35, 0, 0);
+DEFINE_QNODE(slv_blsp_2, SLAVE_BLSP_2, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 37, 0, 0);
+DEFINE_QNODE(slv_sdcc_1, SLAVE_SDCC_1, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 31, 0, 0);
+DEFINE_QNODE(slv_blsp_1, SLAVE_BLSP_1, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 39, 0, 0);
+DEFINE_QNODE(slv_pdm, SLAVE_PDM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 41, 0, 0);
+DEFINE_QNODE(slv_ahb2phy, SLAVE_AHB2PHY, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 153, 0, 0);
+DEFINE_QNODE(slv_hmss, SLAVE_APPSS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 20, 0, 0);
+DEFINE_QNODE(slv_lpass, SLAVE_LPASS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 21, 0, 0);
+DEFINE_QNODE(slv_usb3, SLAVE_USB3, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 22, 0, 0);
+DEFINE_QNODE(slv_snoc_bimc, SNOC_BIMC_SLV, 0, 2, 32, QCOM_QOS_MODE_FIXED, 0, -1, 24, 1, SNOC_BIMC_MAS);
+DEFINE_QNODE(slv_snoc_cnoc, SNOC_CNOC_SLV, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 25, 1, SNOC_CNOC_MAS);
+DEFINE_QNODE(slv_imem, SLAVE_OCIMEM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 26, 0, 0);
+DEFINE_QNODE(slv_pimem, SLAVE_PIMEM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 166, 0, 0);
+DEFINE_QNODE(slv_snoc_vmem, SLAVE_SNOC_VMEM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 140, 1, MASTER_SNOC_VMEM);
+DEFINE_QNODE(slv_snoc_pnoc, SNOC_PNOC_SLV, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 28, 1, SNOC_PNOC_MAS);
+DEFINE_QNODE(slv_qdss_stm, SLAVE_QDSS_STM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 30, 0, 0);
+DEFINE_QNODE(slv_pcie_0, SLAVE_PCIE_0, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 84, 0, 0);
+DEFINE_QNODE(slv_pcie_1, SLAVE_PCIE_1, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 85, 0, 0);
+DEFINE_QNODE(slv_pcie_2, SLAVE_PCIE_2, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 164, 0, 0);
+DEFINE_QNODE(slv_srvc_snoc, SLAVE_SERVICE_SNOC, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 29, 0, 0);
+
+static struct qcom_icc_node *msm8996_snoc_nodes[] = {
+ &mas_hmss,
+ &mas_qdss_bam,
+ &mas_snoc_cfg,
+ &mas_bimc_snoc_0,
+ &mas_bimc_snoc_1,
+ &mas_a0noc_snoc,
+ &mas_a1noc_snoc,
+ &mas_a2noc_snoc,
+ &mas_qdss_etr,
+ &slv_a0noc_snoc,
+ &slv_a1noc_snoc,
+ &slv_a2noc_snoc,
+ &slv_hmss,
+ &slv_lpass,
+ &slv_usb3,
+ &slv_snoc_bimc,
+ &slv_snoc_cnoc,
+ &slv_imem,
+ &slv_pimem,
+ &slv_snoc_vmem,
+ &slv_snoc_pnoc,
+ &slv_qdss_stm,
+ &slv_pcie_0,
+ &slv_pcie_1,
+ &slv_pcie_2,
+ &slv_srvc_snoc,
+};
+
+static struct qcom_icc_desc msm8996_snoc = {
+ .nodes = msm8996_snoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_snoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_bimc_nodes[] = {
+ &mas_apps_proc,
+ &mas_oxili,
+ &mas_mnoc_bimc,
+ &mas_snoc_bimc,
+ &slv_ebi,
+ &slv_hmss_l3,
+ &slv_bimc_snoc_0,
+ &slv_bimc_snoc_1,
+};
+
+static struct qcom_icc_desc msm8996_bimc = {
+ .nodes = msm8996_bimc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_bimc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_pnoc_nodes[] = {
+ &mas_snoc_pnoc,
+ &mas_sdcc_1,
+ &mas_sdcc_2,
+ &mas_sdcc_4,
+ &mas_usb_hs,
+ &mas_blsp_1,
+ &mas_blsp_2,
+ &mas_tsif,
+ &slv_pnoc_a1noc,
+ &slv_usb_hs,
+ &slv_sdcc_2,
+ &slv_sdcc_4,
+ &slv_tsif,
+ &slv_blsp_2,
+ &slv_sdcc_1,
+ &slv_blsp_1,
+ &slv_pdm,
+ &slv_ahb2phy,
+};
+
+static struct qcom_icc_desc msm8996_pnoc = {
+ .nodes = msm8996_pnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_pnoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_cnoc_nodes[] = {
+ &mas_snoc_cnoc,
+ &mas_qdss_dap,
+ &slv_cnoc_a1noc,
+ &slv_clk_ctl,
+ &slv_tcsr,
+ &slv_tlmm,
+ &slv_crypto0_cfg,
+ &slv_mpm,
+ &slv_pimem_cfg,
+ &slv_imem_cfg,
+ &slv_message_ram,
+ &slv_bimc_cfg,
+ &slv_pmic_arb,
+ &slv_prng,
+ &slv_dcc_cfg,
+ &slv_rbcpr_mx,
+ &slv_qdss_cfg,
+ &slv_rbcpr_cx,
+ &slv_cpr_apu_cfg,
+ &slv_cnoc_mnoc_cfg,
+ &slv_snoc_cfg,
+ &slv_snoc_mpu_cfg,
+ &slv_ebi1_phy_cfg,
+ &slv_a0noc_cfg,
+ &slv_pcie_1_cfg,
+ &slv_pcie_2_cfg,
+ &slv_pcie_0_cfg,
+ &slv_pcie20_ahb2phy,
+ &slv_a0noc_mpu_cfg,
+ &slv_ufs_cfg,
+ &slv_a1noc_cfg,
+ &slv_a1noc_mpu_cfg,
+ &slv_a2noc_cfg,
+ &slv_a2noc_mpu_cfg,
+ &slv_ssc_cfg,
+ &slv_a0noc_smmu_cfg,
+ &slv_a1noc_smmu_cfg,
+ &slv_a2noc_smmu_cfg,
+ &slv_lpass_smmu_cfg,
+ &slv_cnoc_mnoc_mmss_cfg,
+};
+
+static struct qcom_icc_desc msm8996_cnoc = {
+ .nodes = msm8996_cnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_cnoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_mnoc_nodes[] = {
+ &mas_cnoc_mnoc_mmss_cfg,
+ &mas_cnoc_mnoc_cfg,
+ &mas_cpp,
+ &mas_jpeg,
+ &mas_mdp_p0,
+ &mas_mdp_p1,
+ &mas_rotator,
+ &mas_venus,
+ &mas_vfe,
+ &mas_snoc_vmem,
+ &mas_venus_vmem,
+ &slv_mmagic_cfg,
+ &slv_cpr_cfg,
+ &slv_misc_cfg,
+ &slv_venus_throttle_cfg,
+ &slv_venus_cfg,
+ &slv_vmem_cfg,
+ &slv_dsa_cfg,
+ &slv_mnoc_clocks_cfg,
+ &slv_dsa_mpu_cfg,
+ &slv_mnoc_mpu_cfg,
+ &slv_display_cfg,
+ &slv_display_throttle_cfg,
+ &slv_camera_cfg,
+ &slv_camera_throttle_cfg,
+ &slv_oxili_cfg,
+ &slv_smmu_mdp_cfg,
+ &slv_smmu_rot_cfg,
+ &slv_smmu_venus_cfg,
+ &slv_smmu_cpp_cfg,
+ &slv_smmu_jpeg_cfg,
+ &slv_smmu_vfe_cfg,
+ &slv_mnoc_bimc,
+ &slv_vmem,
+ &slv_srvc_mnoc,
+};
+
+static struct qcom_icc_desc msm8996_mnoc = {
+ .nodes = msm8996_mnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_mnoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_a0noc_nodes[] = {
+ &mas_pcie_0,
+ &mas_pcie_1,
+ &mas_pcie_2,
+};
+
+static struct qcom_icc_desc msm8996_a0noc = {
+ .nodes = msm8996_a0noc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_a0noc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_a1noc_nodes[] = {
+ &mas_cnoc_a1noc,
+ &mas_crypto_c0,
+ &mas_pnoc_a1noc,
+};
+
+static struct qcom_icc_desc msm8996_a1noc = {
+ .nodes = msm8996_a1noc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_a1noc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_a2noc_nodes[] = {
+ &mas_usb3,
+ &mas_ipa,
+ &mas_ufs,
+};
+
+static struct qcom_icc_desc msm8996_a2noc = {
+ .nodes = msm8996_a2noc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_a2noc_nodes),
+};
+
+static int qcom_icc_aggregate(struct icc_node *node, u8 tag, u32 avg_bw,
+ u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
+{
+ *agg_avg += avg_bw;
+ *agg_peak = max(*agg_peak, peak_bw);
+
+ return 0;
+}
+
+static int qcom_icc_set(struct icc_node *src, struct icc_node *dst,
+ u32 avg, u32 peak)
+{
+ struct qcom_icc_provider *qp;
+ struct qcom_icc_node *qn;
+ struct icc_node *node;
+ struct icc_provider *provider;
+ u64 avg_bw = icc_units_to_bps(avg);
+ u64 peak_bw = icc_units_to_bps(peak);
+ int ret = 0;
+ u64 rate;
+
+ if (!src)
+ node = dst;
+ else
+ node = src;
+
+ qn = node->data;
+ provider = node->provider;
+ qp = to_qcom_provider(provider);
+
+ /* set bandwidth */
+ if (qn->ap_owned) {
+ /* TODO: set QoS */
+ } else {
+ /* send message to the RPM processor */
+
+ if (qn->mas_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_MASTER_REQ,
+ qn->mas_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send mas error %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (qn->slv_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_SLAVE_REQ,
+ qn->slv_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send slv error %d\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ rate = max(avg_bw, peak_bw);
+
+ do_div(rate, qn->buswidth);
+
+ if (qn->rate != rate) {
+ ret = clk_set_rate(qp->bus_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ ret = clk_set_rate(qp->bus_a_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ qn->rate = rate;
+ }
+
+ return ret;
+}
+
+static int qnoc_probe(struct platform_device *pdev)
+{
+ const struct qcom_icc_desc *desc;
+ struct qcom_icc_node **qnodes;
+ struct icc_node *node;
+ struct qcom_icc_provider *qp;
+ struct resource *res;
+ struct icc_provider *provider;
+ size_t num_nodes, i;
+ int ret;
+
+ /* wait for RPM */
+ if (!qcom_icc_rpm_smd_available())
+ return -EPROBE_DEFER;
+
+ desc = of_device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ qnodes = desc->nodes;
+ num_nodes = desc->num_nodes;
+
+ qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ qp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(qp->base))
+ return PTR_ERR(qp->base);
+
+ qp->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(qp->bus_clk))
+ return PTR_ERR(qp->bus_clk);
+
+ ret = clk_prepare_enable(qp->bus_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_clk: %d\n", ret);
+ return ret;
+ }
+
+ qp->bus_a_clk = devm_clk_get(&pdev->dev, "bus_a_clk");
+ if (IS_ERR(qp->bus_a_clk))
+ return PTR_ERR(qp->bus_a_clk);
+
+ ret = clk_prepare_enable(qp->bus_a_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_a_clk: %d\n", ret);
+ clk_disable_unprepare(qp->bus_clk);
+ return ret;
+ }
+
+ provider = &qp->provider;
+ provider->dev = &pdev->dev;
+ provider->set = &qcom_icc_set;
+ provider->aggregate = &qcom_icc_aggregate;
+ INIT_LIST_HEAD(&provider->nodes);
+ provider->data = qp;
+
+ ret = icc_provider_add(provider);
+ if (ret) {
+ dev_err(&pdev->dev, "error adding interconnect provider\n");
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ return ret;
+ }
+
+ for (i = 0; i < num_nodes; i++) {
+ int ret;
+ 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);
+
+ dev_dbg(&pdev->dev, "registered node %s\n", node->name);
+
+ /* populate links */
+ for (j = 0; j < qnodes[i]->num_links; j++)
+ if (qnodes[i]->links[j])
+ icc_link_create(node, qnodes[i]->links[j]);
+ }
+
+ platform_set_drvdata(pdev, provider);
+
+ return ret;
+err:
+ list_for_each_entry(node, &provider->nodes, node_list) {
+ icc_node_del(node);
+ icc_node_destroy(node->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ icc_provider_del(provider);
+
+ return ret;
+}
+
+static int qnoc_remove(struct platform_device *pdev)
+{
+ struct icc_provider *provider = platform_get_drvdata(pdev);
+ struct qcom_icc_provider *qp = to_qcom_provider(provider);
+ struct icc_node *n;
+
+ list_for_each_entry(n, &provider->nodes, node_list) {
+ icc_node_del(n);
+ icc_node_destroy(n->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+
+ return icc_provider_del(provider);
+}
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,msm8996-bimc", .data = &msm8996_bimc },
+ { .compatible = "qcom,msm8996-cnoc", .data = &msm8996_cnoc },
+ { .compatible = "qcom,msm8996-snoc", .data = &msm8996_snoc },
+ { .compatible = "qcom,msm8996-a0noc", .data = &msm8996_a0noc },
+ { .compatible = "qcom,msm8996-a1noc", .data = &msm8996_a1noc },
+ { .compatible = "qcom,msm8996-a2noc", .data = &msm8996_a2noc },
+ { .compatible = "qcom,msm8996-mmnoc", .data = &msm8996_mnoc },
+ { .compatible = "qcom,msm8996-pnoc", .data = &msm8996_pnoc },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qnoc_probe,
+ .remove = qnoc_remove,
+ .driver = {
+ .name = "qnoc-msm8996",
+ .of_match_table = qnoc_of_match,
+ },
+};
+module_platform_driver(qnoc_driver);
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm msm8996 NoC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/qcom-icc-ids.h b/drivers/interconnect/qcom/qcom-icc-ids.h
new file mode 100644
index 000000000000..5bd0db23cf4f
--- /dev/null
+++ b/drivers/interconnect/qcom/qcom-icc-ids.h
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ */
+
+#ifndef _QCOM_ICC_IDS_H
+#define _QCOM_ICC_IDS_H
+
+#define MASTER_APPSS_PROC 0
+#define MASTER_TCU_0 1
+#define MASTER_IPA_CORE 2
+#define MASTER_LLCC 3
+#define MASTER_GNOC_CFG 4
+#define MASTER_A1NOC_CFG 5
+#define MASTER_A2NOC_CFG 6
+#define MASTER_CNOC_DC_NOC 7
+#define MASTER_MEM_NOC_CFG 8
+#define MASTER_CNOC_MNOC_CFG 9
+#define MASTER_QDSS_BAM 10
+#define MASTER_BLSP_1 11
+#define MASTER_BLSP_2 12
+#define MASTER_SNOC_CFG 13
+#define MASTER_SPDM 14
+#define MASTER_TIC 15
+#define MASTER_TSIF 16
+#define MASTER_A1NOC_SNOC 17
+#define MASTER_A2NOC_SNOC 18
+#define MASTER_GNOC_MEM_NOC 19
+#define MASTER_CNOC_A2NOC 20
+#define MASTER_GNOC_SNOC 21
+#define MASTER_MEM_NOC_SNOC 22
+#define MASTER_MNOC_HF_MEM_NOC 23
+#define MASTER_MNOC_SF_MEM_NOC 24
+#define MASTER_ANOC_PCIE_SNOC 25
+#define MASTER_SNOC_CNOC 26
+#define MASTER_SNOC_GC_MEM_NOC 27
+#define MASTER_SNOC_SF_MEM_NOC 28
+#define MASTER_CAMNOC_HF0 29
+#define MASTER_CAMNOC_HF0_UNCOMP 30
+#define MASTER_CAMNOC_HF1 31
+#define MASTER_CAMNOC_HF1_UNCOMP 32
+#define MASTER_CAMNOC_SF 33
+#define MASTER_CAMNOC_SF_UNCOMP 34
+#define MASTER_CRYPTO 35
+#define MASTER_GFX3D 36
+#define MASTER_IPA 37
+#define MASTER_MDP0 38
+#define MASTER_MDP1 39
+#define MASTER_PIMEM 40
+#define MASTER_ROTATOR 41
+#define MASTER_VIDEO_P0 42
+#define MASTER_VIDEO_P1 43
+#define MASTER_VIDEO_PROC 44
+#define MASTER_GIC 45
+#define MASTER_PCIE_1 46
+#define MASTER_PCIE_0 47
+#define MASTER_QDSS_DAP 48
+#define MASTER_QDSS_ETR 49
+#define MASTER_SDCC_2 50
+#define MASTER_SDCC_4 51
+#define MASTER_UFS_CARD 52
+#define MASTER_UFS_MEM 53
+#define MASTER_USB3_0 54
+#define MASTER_USB3_1 55
+#define SLAVE_EBI1 512
+#define SLAVE_IPA_CORE 513
+#define SLAVE_A1NOC_CFG 514
+#define SLAVE_A2NOC_CFG 515
+#define SLAVE_AOP 516
+#define SLAVE_AOSS 517
+#define SLAVE_APPSS 518
+#define SLAVE_CAMERA_CFG 519
+#define SLAVE_CLK_CTL 520
+#define SLAVE_CDSP_CFG 521
+#define SLAVE_RBCPR_CX_CFG 522
+#define SLAVE_CRYPTO_0_CFG 523
+#define SLAVE_DCC_CFG 524
+#define SLAVE_CNOC_DDRSS 525
+#define SLAVE_DISPLAY_CFG 526
+#define SLAVE_GLM 527
+#define SLAVE_GFX3D_CFG 528
+#define SLAVE_IMEM_CFG 529
+#define SLAVE_IPA_CFG 530
+#define SLAVE_LLCC_CFG 531
+#define SLAVE_MSS_PROC_MS_MPU_CFG 532
+#define SLAVE_MEM_NOC_CFG 533
+#define SLAVE_CNOC_MNOC_CFG 534
+#define SLAVE_PCIE_0_CFG 535
+#define SLAVE_PCIE_1_CFG 536
+#define SLAVE_PDM 537
+#define SLAVE_SOUTH_PHY_CFG 538
+#define SLAVE_PIMEM_CFG 539
+#define SLAVE_PRNG 540
+#define SLAVE_QDSS_CFG 541
+#define SLAVE_BLSP_2 542
+#define SLAVE_BLSP_1 543
+#define SLAVE_SDCC_2 544
+#define SLAVE_SDCC_4 545
+#define SLAVE_SNOC_CFG 546
+#define SLAVE_SPDM_WRAPPER 547
+#define SLAVE_SPSS_CFG 548
+#define SLAVE_TCSR 549
+#define SLAVE_TLMM_NORTH 550
+#define SLAVE_TLMM_SOUTH 551
+#define SLAVE_TSIF 552
+#define SLAVE_UFS_CARD_CFG 553
+#define SLAVE_UFS_MEM_CFG 554
+#define SLAVE_USB3_0 555
+#define SLAVE_USB3_1 556
+#define SLAVE_VENUS_CFG 557
+#define SLAVE_VSENSE_CTRL_CFG 558
+#define SLAVE_MNOC_SF_MEM_NOC 559
+#define SLAVE_A1NOC_SNOC 560
+#define SLAVE_A2NOC_SNOC 561
+#define SLAVE_MEM_NOC_GNOC 562
+#define SLAVE_CAMNOC_UNCOMP 563
+#define SLAVE_SNOC_CNOC 564
+#define SLAVE_CNOC_A2NOC 565
+#define SLAVE_GNOC_SNOC 566
+#define SLAVE_GNOC_MEM_NOC 567
+#define SLAVE_LLCC 568
+#define SLAVE_MNOC_HF_MEM_NOC 569
+#define SLAVE_SNOC_MEM_NOC_GC 570
+#define SLAVE_SNOC_MEM_NOC_SF 571
+#define SLAVE_MEM_NOC_SNOC 572
+#define SLAVE_ANOC_PCIE_A1NOC_SNOC 573
+#define SLAVE_ANOC_PCIE_SNOC 574
+#define SLAVE_IMEM 575
+#define SLAVE_PCIE_0 576
+#define SLAVE_PCIE_1 577
+#define SLAVE_PIMEM 578
+#define SLAVE_SERVICE_A1NOC 579
+#define SLAVE_SERVICE_A2NOC 580
+#define SLAVE_SERVICE_CNOC 581
+#define SLAVE_SERVICE_GNOC 582
+#define SLAVE_SERVICE_MEM_NOC 583
+#define SLAVE_SERVICE_MNOC 584
+#define SLAVE_SERVICE_SNOC 585
+#define SLAVE_QDSS_STM 586
+#define SLAVE_TCU 587
+#endif
diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c
new file mode 100644
index 000000000000..093c998e0651
--- /dev/null
+++ b/drivers/interconnect/qcom/sdm845.c
@@ -0,0 +1,870 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+
+#include <soc/qcom/cmd-db.h>
+#include <soc/qcom/rpmh.h>
+#include <soc/qcom/tcs.h>
+
+#include "qcom-icc-ids.h"
+
+#define BCM_TCS_CMD_COMMIT_SHFT 30
+#define BCM_TCS_CMD_COMMIT_MASK 0x40000000
+#define BCM_TCS_CMD_VALID_SHFT 29
+#define BCM_TCS_CMD_VALID_MASK 0x200010000
+#define BCM_TCS_CMD_VOTE_X_SHFT 14
+#define BCM_TCS_CMD_VOTE_MASK 0x3fff
+#define BCM_TCS_CMD_VOTE_Y_SHFT 0
+#define BCM_TCS_CMD_VOTE_Y_MASK 0xfffc000
+
+#define BCM_TCS_CMD(commit, valid, vote_x, vote_y) \
+ ((commit << BCM_TCS_CMD_COMMIT_SHFT) |\
+ (valid << BCM_TCS_CMD_VALID_SHFT) |\
+ ((vote_x & BCM_TCS_CMD_VOTE_MASK) << BCM_TCS_CMD_VOTE_X_SHFT) |\
+ ((vote_y & BCM_TCS_CMD_VOTE_MASK) << BCM_TCS_CMD_VOTE_Y_SHFT))
+
+#define to_qcom_provider(_provider) \
+ container_of(_provider, struct qcom_icc_provider, provider)
+
+#define DEFINE_QNODE(_name, _id, _channels, _buswidth, \
+ _numlinks, ...) \
+ static struct qcom_icc_node _name = { \
+ .id = _id, \
+ .name = #_name, \
+ .channels = _channels, \
+ .buswidth = _buswidth, \
+ .num_links = _numlinks, \
+ .links = { __VA_ARGS__ }, \
+ }
+
+#define DEFINE_QBCM(_name, _bcmname, _numnodes, ...) \
+ static struct qcom_icc_bcm _name = { \
+ .num_nodes = _numnodes, \
+ .name = _bcmname, \
+ .nodes = { __VA_ARGS__ }, \
+ }
+
+struct qcom_icc_provider {
+ struct icc_provider provider;
+ void __iomem *base;
+ struct rpmh_client *rpmh_client;
+ struct qcom_icc_bcm **bcms;
+ size_t num_bcms;
+};
+
+/**
+ * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM)
+ * @unit: bcm threshold values are in magnitudes of this
+ * @width: prototype width
+ * @vcd: virtual clock domain that this bcm belongs to
+ */
+
+struct bcm_db {
+ u32 unit;
+ u16 width;
+ u8 vcd;
+ u8 reserved;
+};
+
+#define SDM845_MAX_LINKS 43
+#define SDM845_MAX_BCMS 30
+#define SDM845_MAX_BCM_PER_NODE 2
+#define SDM845_MAX_VCD 10
+#define SDM845_MAX_CTX 2
+#define SDM845_EE_STATE 2
+#define EE_STATE_WAKE 0
+#define EE_STATE_SLEEP 1
+#define AO_CTX 0
+#define DUAL_CTX 1
+
+/**
+ * struct qcom_icc_node - Qualcomm specific interconnect nodes
+ * @name: the node name used in debugfs
+ * @links: an array of nodes where we can go next while traversing
+ * @id: a unique node identifier
+ * @num_links: the total number of @links
+ * @channels: num of channels at this node
+ * @buswidth: width of the interconnect between a node and the bus
+ * @sum_avg: current sum aggregate value of all avg bw requests
+ * @max_peak: current max aggregate value of all peak bw requests
+ * @bcms: list of bcms associated with this logical node
+ * @num_bcm: num of @bcms
+ */
+struct qcom_icc_node {
+ const char *name;
+ u16 links[SDM845_MAX_LINKS];
+ u16 id;
+ u16 num_links;
+ u16 channels;
+ u16 buswidth;
+ u64 sum_avg[SDM845_MAX_CTX];
+ u64 max_peak[SDM845_MAX_CTX];
+ struct qcom_icc_bcm *bcms[SDM845_MAX_BCM_PER_NODE];
+ size_t num_bcms;
+};
+
+/**
+ * struct qcom_icc_bcm - Qualcomm specific hardware accelerator nodes
+ * known as Bus Clock Manager(BCM)
+ * @name: the bcm node name used to fetch BCM data from command db
+ * @type: latency or bandwidth bcm
+ * @addr: address offsets used when voting to RPMH
+ * @vote_x: aggregated threshold values, represents sum_bw when @type is bw bcm
+ * @vote_y: aggregated threshold values, represents peak_bw when @type is bw bcm
+ * @dirty: flag used to indicate whether or bcm needs to be committed
+ * @aux_data: auxiliary data used when calculating threshold values and
+ * communicating with RPMh
+ * @list: used to link to other bcms when compiling lists for commit
+ * @num_nodes: total number of @num_nodes
+ * @nodes: list of qcom_icc_nodes that this BCM encapsulates
+ */
+
+struct qcom_icc_bcm {
+ const char *name;
+ u32 type;
+ u32 addr;
+ u64 vote_x[SDM845_EE_STATE];
+ u64 vote_y[SDM845_EE_STATE];
+ bool dirty;
+ struct bcm_db aux_data;
+ struct list_head list;
+ size_t num_nodes;
+ struct qcom_icc_node *nodes[];
+};
+
+struct qcom_icc_fabric {
+ struct qcom_icc_node **nodes;
+ size_t num_nodes;
+ u32 base_offset;
+ u32 qos_offset;
+};
+
+struct qcom_icc_desc {
+ struct qcom_icc_node **nodes;
+ size_t num_nodes;
+ struct qcom_icc_bcm **bcms;
+ size_t num_bcms;
+};
+
+DEFINE_QNODE(qhm_a1noc_cfg, MASTER_A1NOC_CFG, 1, 4, 1, SLAVE_SERVICE_A1NOC);
+DEFINE_QNODE(qhm_qup1, MASTER_BLSP_1, 1, 4, 1, SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(qhm_tsif, MASTER_TSIF, 1, 4, 1, SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_sdc2, MASTER_SDCC_2, 1, 8, 1, SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_sdc4, MASTER_SDCC_4, 1, 8, 1, SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_ufs_card, MASTER_UFS_CARD, 1, 8, 1, SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_ufs_mem, MASTER_UFS_MEM, 1, 8, 1, SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_pcie_0, MASTER_PCIE_0, 1, 8, 1, SLAVE_ANOC_PCIE_A1NOC_SNOC);
+DEFINE_QNODE(qhm_a2noc_cfg, MASTER_A2NOC_CFG, 1, 4, 1, SLAVE_SERVICE_A2NOC);
+DEFINE_QNODE(qhm_qdss_bam, MASTER_QDSS_BAM, 1, 4, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qhm_qup2, MASTER_BLSP_2, 1, 4, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qnm_cnoc, MASTER_CNOC_A2NOC, 1, 8, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qxm_crypto, MASTER_CRYPTO, 1, 8, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qxm_ipa, MASTER_IPA, 1, 8, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(xm_pcie3_1, MASTER_PCIE_1, 1, 8, 1, SLAVE_ANOC_PCIE_SNOC);
+DEFINE_QNODE(xm_qdss_etr, MASTER_QDSS_ETR, 1, 8, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(xm_usb3_0, MASTER_USB3_0, 1, 8, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(xm_usb3_1, MASTER_USB3_1, 1, 8, 1, SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qxm_camnoc_hf0_uncomp, MASTER_CAMNOC_HF0_UNCOMP, 1, 32, 1, SLAVE_CAMNOC_UNCOMP);
+DEFINE_QNODE(qxm_camnoc_hf1_uncomp, MASTER_CAMNOC_HF1_UNCOMP, 1, 32, 1, SLAVE_CAMNOC_UNCOMP);
+DEFINE_QNODE(qxm_camnoc_sf_uncomp, MASTER_CAMNOC_SF_UNCOMP, 1, 32, 1, SLAVE_CAMNOC_UNCOMP);
+DEFINE_QNODE(qhm_spdm, MASTER_SPDM, 1, 4, 1, SLAVE_CNOC_A2NOC);
+DEFINE_QNODE(qhm_tic, MASTER_TIC, 1, 4, 43, SLAVE_A1NOC_CFG, SLAVE_A2NOC_CFG, SLAVE_AOP, SLAVE_AOSS, SLAVE_CAMERA_CFG, SLAVE_CLK_CTL, SLAVE_CDSP_CFG, SLAVE_RBCPR_CX_CFG, SLAVE_CRYPTO_0_CFG, SLAVE_DCC_CFG, SLAVE_CNOC_DDRSS, SLAVE_DISPLAY_CFG, SLAVE_GLM, SLAVE_GFX3D_CFG, SLAVE_IMEM_CFG, SLAVE_IPA_CFG, SLAVE_CNOC_MNOC_CFG, SLAVE_PCIE_0_CFG, SLAVE_PCIE_1_CFG, SLAVE_PDM, SLAVE_SOUTH_PHY_CFG, SLAVE_PIMEM_CFG, SLAVE_PRNG, SLAVE_QDSS_CFG, SLAVE_BLSP_2, SLAVE_BLSP_1, SLAVE_SDCC_2, SLAVE_SDCC_4, SLAVE_SNOC_CFG, SLAVE_SPDM_WRAPPER, SLAVE_SPSS_CFG, SLAVE_TCSR, SLAVE_TLMM_NORTH, SLAVE_TLMM_SOUTH, SLAVE_TSIF, SLAVE_UFS_CARD_CFG, SLAVE_UFS_MEM_CFG, SLAVE_USB3_0, SLAVE_USB3_1, SLAVE_VENUS_CFG, SLAVE_VSENSE_CTRL_CFG, SLAVE_CNOC_A2NOC, SLAVE_SERVICE_CNOC);
+DEFINE_QNODE(qnm_snoc, MASTER_SNOC_CNOC, 1, 8, 42, SLAVE_A1NOC_CFG, SLAVE_A2NOC_CFG, SLAVE_AOP, SLAVE_AOSS, SLAVE_CAMERA_CFG, SLAVE_CLK_CTL, SLAVE_CDSP_CFG, SLAVE_RBCPR_CX_CFG, SLAVE_CRYPTO_0_CFG, SLAVE_DCC_CFG, SLAVE_CNOC_DDRSS, SLAVE_DISPLAY_CFG, SLAVE_GLM, SLAVE_GFX3D_CFG, SLAVE_IMEM_CFG, SLAVE_IPA_CFG, SLAVE_CNOC_MNOC_CFG, SLAVE_PCIE_0_CFG, SLAVE_PCIE_1_CFG, SLAVE_PDM, SLAVE_SOUTH_PHY_CFG, SLAVE_PIMEM_CFG, SLAVE_PRNG, SLAVE_QDSS_CFG, SLAVE_BLSP_2, SLAVE_BLSP_1, SLAVE_SDCC_2, SLAVE_SDCC_4, SLAVE_SNOC_CFG, SLAVE_SPDM_WRAPPER, SLAVE_SPSS_CFG, SLAVE_TCSR, SLAVE_TLMM_NORTH, SLAVE_TLMM_SOUTH, SLAVE_TSIF, SLAVE_UFS_CARD_CFG, SLAVE_UFS_MEM_CFG, SLAVE_USB3_0, SLAVE_USB3_1, SLAVE_VENUS_CFG, SLAVE_VSENSE_CTRL_CFG, SLAVE_SERVICE_CNOC);
+DEFINE_QNODE(xm_qdss_dap, MASTER_QDSS_DAP, 1, 8, 43, SLAVE_A1NOC_CFG, SLAVE_A2NOC_CFG, SLAVE_AOP, SLAVE_AOSS, SLAVE_CAMERA_CFG, SLAVE_CLK_CTL, SLAVE_CDSP_CFG, SLAVE_RBCPR_CX_CFG, SLAVE_CRYPTO_0_CFG, SLAVE_DCC_CFG, SLAVE_CNOC_DDRSS, SLAVE_DISPLAY_CFG, SLAVE_GLM, SLAVE_GFX3D_CFG, SLAVE_IMEM_CFG, SLAVE_IPA_CFG, SLAVE_CNOC_MNOC_CFG, SLAVE_PCIE_0_CFG, SLAVE_PCIE_1_CFG, SLAVE_PDM, SLAVE_SOUTH_PHY_CFG, SLAVE_PIMEM_CFG, SLAVE_PRNG, SLAVE_QDSS_CFG, SLAVE_BLSP_2, SLAVE_BLSP_1, SLAVE_SDCC_2, SLAVE_SDCC_4, SLAVE_SNOC_CFG, SLAVE_SPDM_WRAPPER, SLAVE_SPSS_CFG, SLAVE_TCSR, SLAVE_TLMM_NORTH, SLAVE_TLMM_SOUTH, SLAVE_TSIF, SLAVE_UFS_CARD_CFG, SLAVE_UFS_MEM_CFG, SLAVE_USB3_0, SLAVE_USB3_1, SLAVE_VENUS_CFG, SLAVE_VSENSE_CTRL_CFG, SLAVE_CNOC_A2NOC, SLAVE_SERVICE_CNOC);
+DEFINE_QNODE(qhm_cnoc, MASTER_CNOC_DC_NOC, 1, 4, 2, SLAVE_LLCC_CFG, SLAVE_MEM_NOC_CFG);
+DEFINE_QNODE(acm_l3, MASTER_APPSS_PROC, 1, 16, 3, SLAVE_GNOC_SNOC, SLAVE_GNOC_MEM_NOC, SLAVE_SERVICE_GNOC);
+DEFINE_QNODE(pm_gnoc_cfg, MASTER_GNOC_CFG, 1, 4, 1, SLAVE_SERVICE_GNOC);
+DEFINE_QNODE(ipa_core_master, MASTER_IPA_CORE, 1, 8, 1, SLAVE_IPA_CORE);
+DEFINE_QNODE(llcc_mc, MASTER_LLCC, 4, 4, 1, SLAVE_EBI1);
+DEFINE_QNODE(acm_tcu, MASTER_TCU_0, 1, 8, 3, SLAVE_MEM_NOC_GNOC, SLAVE_LLCC, SLAVE_MEM_NOC_SNOC);
+DEFINE_QNODE(qhm_memnoc_cfg, MASTER_MEM_NOC_CFG, 1, 4, 2, SLAVE_MSS_PROC_MS_MPU_CFG, SLAVE_SERVICE_MEM_NOC);
+DEFINE_QNODE(qnm_apps, MASTER_GNOC_MEM_NOC, 2, 32, 1, SLAVE_LLCC);
+DEFINE_QNODE(qnm_mnoc_hf, MASTER_MNOC_HF_MEM_NOC, 2, 32, 2, SLAVE_MEM_NOC_GNOC, SLAVE_LLCC);
+DEFINE_QNODE(qnm_mnoc_sf, MASTER_MNOC_SF_MEM_NOC, 1, 32, 3, SLAVE_MEM_NOC_GNOC, SLAVE_LLCC, SLAVE_MEM_NOC_SNOC);
+DEFINE_QNODE(qnm_snoc_gc, MASTER_SNOC_GC_MEM_NOC, 1, 8, 1, SLAVE_LLCC);
+DEFINE_QNODE(qnm_snoc_sf, MASTER_SNOC_SF_MEM_NOC, 1, 16, 2, SLAVE_MEM_NOC_GNOC, SLAVE_LLCC);
+DEFINE_QNODE(qxm_gpu, MASTER_GFX3D, 2, 32, 3, SLAVE_MEM_NOC_GNOC, SLAVE_LLCC, SLAVE_MEM_NOC_SNOC);
+DEFINE_QNODE(qhm_mnoc_cfg, MASTER_CNOC_MNOC_CFG, 1, 4, 1, SLAVE_SERVICE_MNOC);
+DEFINE_QNODE(qxm_camnoc_hf0, MASTER_CAMNOC_HF0, 1, 32, 1, SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_camnoc_hf1, MASTER_CAMNOC_HF1, 1, 32, 1, SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_camnoc_sf, MASTER_CAMNOC_SF, 1, 32, 1, SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_mdp0, MASTER_MDP0, 1, 32, 1, SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_mdp1, MASTER_MDP1, 1, 32, 1, SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_rot, MASTER_ROTATOR, 1, 32, 1, SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_venus0, MASTER_VIDEO_P0, 1, 32, 1, SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_venus1, MASTER_VIDEO_P1, 1, 32, 1, SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_venus_arm9, MASTER_VIDEO_PROC, 1, 8, 1, SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qhm_snoc_cfg, MASTER_SNOC_CFG, 1, 4, 1, SLAVE_SERVICE_SNOC);
+DEFINE_QNODE(qnm_aggre1_noc, MASTER_A1NOC_SNOC, 1, 16, 6, SLAVE_APPSS, SLAVE_SNOC_CNOC, SLAVE_SNOC_MEM_NOC_SF, SLAVE_IMEM, SLAVE_PIMEM, SLAVE_QDSS_STM);
+DEFINE_QNODE(qnm_aggre2_noc, MASTER_A2NOC_SNOC, 1, 16, 9, SLAVE_APPSS, SLAVE_SNOC_CNOC, SLAVE_SNOC_MEM_NOC_SF, SLAVE_IMEM, SLAVE_PCIE_0, SLAVE_PCIE_1, SLAVE_PIMEM, SLAVE_QDSS_STM, SLAVE_TCU);
+DEFINE_QNODE(qnm_gladiator_sodv, MASTER_GNOC_SNOC, 1, 8, 8, SLAVE_APPSS, SLAVE_SNOC_CNOC, SLAVE_IMEM, SLAVE_PCIE_0, SLAVE_PCIE_1, SLAVE_PIMEM, SLAVE_QDSS_STM, SLAVE_TCU);
+DEFINE_QNODE(qnm_memnoc, MASTER_MEM_NOC_SNOC, 1, 8, 5, SLAVE_APPSS, SLAVE_SNOC_CNOC, SLAVE_IMEM, SLAVE_PIMEM, SLAVE_QDSS_STM);
+DEFINE_QNODE(qnm_pcie_anoc, MASTER_ANOC_PCIE_SNOC, 1, 16, 5, SLAVE_APPSS, SLAVE_SNOC_CNOC, SLAVE_SNOC_MEM_NOC_SF, SLAVE_IMEM, SLAVE_QDSS_STM);
+DEFINE_QNODE(qxm_pimem, MASTER_PIMEM, 1, 8, 2, SLAVE_SNOC_MEM_NOC_GC, SLAVE_IMEM);
+DEFINE_QNODE(xm_gic, MASTER_GIC, 1, 8, 2, SLAVE_SNOC_MEM_NOC_GC, SLAVE_IMEM);
+DEFINE_QNODE(qns_a1noc_snoc, SLAVE_A1NOC_SNOC, 1, 16, 1, MASTER_A1NOC_SNOC);
+DEFINE_QNODE(srvc_aggre1_noc, SLAVE_SERVICE_A1NOC, 1, 4, 0);
+DEFINE_QNODE(qns_pcie_a1noc_snoc, SLAVE_ANOC_PCIE_A1NOC_SNOC, 1, 16, 1, MASTER_ANOC_PCIE_SNOC);
+DEFINE_QNODE(qns_a2noc_snoc, SLAVE_A2NOC_SNOC, 1, 16, 1, MASTER_A2NOC_SNOC);
+DEFINE_QNODE(qns_pcie_snoc, SLAVE_ANOC_PCIE_SNOC, 1, 16, 1, MASTER_ANOC_PCIE_SNOC);
+DEFINE_QNODE(srvc_aggre2_noc, SLAVE_SERVICE_A2NOC, 1, 4, 0);
+DEFINE_QNODE(qns_camnoc_uncomp, SLAVE_CAMNOC_UNCOMP, 1, 32, 0);
+DEFINE_QNODE(qhs_a1_noc_cfg, SLAVE_A1NOC_CFG, 1, 4, 1, MASTER_A1NOC_CFG);
+DEFINE_QNODE(qhs_a2_noc_cfg, SLAVE_A2NOC_CFG, 1, 4, 1, MASTER_A2NOC_CFG);
+DEFINE_QNODE(qhs_aop, SLAVE_AOP, 1, 4, 0);
+DEFINE_QNODE(qhs_aoss, SLAVE_AOSS, 1, 4, 0);
+DEFINE_QNODE(qhs_camera_cfg, SLAVE_CAMERA_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_clk_ctl, SLAVE_CLK_CTL, 1, 4, 0);
+DEFINE_QNODE(qhs_compute_dsp_cfg, SLAVE_CDSP_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_cpr_cx, SLAVE_RBCPR_CX_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_crypto0_cfg, SLAVE_CRYPTO_0_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_dcc_cfg, SLAVE_DCC_CFG, 1, 4, 1, MASTER_CNOC_DC_NOC);
+DEFINE_QNODE(qhs_ddrss_cfg, SLAVE_CNOC_DDRSS, 1, 4, 0);
+DEFINE_QNODE(qhs_display_cfg, SLAVE_DISPLAY_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_glm, SLAVE_GLM, 1, 4, 0);
+DEFINE_QNODE(qhs_gpuss_cfg, SLAVE_GFX3D_CFG, 1, 8, 0);
+DEFINE_QNODE(qhs_imem_cfg, SLAVE_IMEM_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_ipa, SLAVE_IPA_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_mnoc_cfg, SLAVE_CNOC_MNOC_CFG, 1, 4, 1, MASTER_CNOC_MNOC_CFG);
+DEFINE_QNODE(qhs_pcie0_cfg, SLAVE_PCIE_0_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_pcie_gen3_cfg, SLAVE_PCIE_1_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_pdm, SLAVE_PDM, 1, 4, 0);
+DEFINE_QNODE(qhs_phy_refgen_south, SLAVE_SOUTH_PHY_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_pimem_cfg, SLAVE_PIMEM_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_prng, SLAVE_PRNG, 1, 4, 0);
+DEFINE_QNODE(qhs_qdss_cfg, SLAVE_QDSS_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_qupv3_north, SLAVE_BLSP_2, 1, 4, 0);
+DEFINE_QNODE(qhs_qupv3_south, SLAVE_BLSP_1, 1, 4, 0);
+DEFINE_QNODE(qhs_sdc2, SLAVE_SDCC_2, 1, 4, 0);
+DEFINE_QNODE(qhs_sdc4, SLAVE_SDCC_4, 1, 4, 0);
+DEFINE_QNODE(qhs_snoc_cfg, SLAVE_SNOC_CFG, 1, 4, 1, MASTER_SNOC_CFG);
+DEFINE_QNODE(qhs_spdm, SLAVE_SPDM_WRAPPER, 1, 4, 0);
+DEFINE_QNODE(qhs_spss_cfg, SLAVE_SPSS_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_tcsr, SLAVE_TCSR, 1, 4, 0);
+DEFINE_QNODE(qhs_tlmm_north, SLAVE_TLMM_NORTH, 1, 4, 0);
+DEFINE_QNODE(qhs_tlmm_south, SLAVE_TLMM_SOUTH, 1, 4, 0);
+DEFINE_QNODE(qhs_tsif, SLAVE_TSIF, 1, 4, 0);
+DEFINE_QNODE(qhs_ufs_card_cfg, SLAVE_UFS_CARD_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_ufs_mem_cfg, SLAVE_UFS_MEM_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_usb3_0, SLAVE_USB3_0, 1, 4, 0);
+DEFINE_QNODE(qhs_usb3_1, SLAVE_USB3_1, 1, 4, 0);
+DEFINE_QNODE(qhs_venus_cfg, SLAVE_VENUS_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_vsense_ctrl_cfg, SLAVE_VSENSE_CTRL_CFG, 1, 4, 0);
+DEFINE_QNODE(qns_cnoc_a2noc, SLAVE_CNOC_A2NOC, 1, 8, 1, MASTER_CNOC_A2NOC);
+DEFINE_QNODE(srvc_cnoc, SLAVE_SERVICE_CNOC, 1, 4, 0);
+DEFINE_QNODE(qhs_llcc, SLAVE_LLCC_CFG, 1, 4, 0);
+DEFINE_QNODE(qhs_memnoc, SLAVE_MEM_NOC_CFG, 1, 4, 1, MASTER_MEM_NOC_CFG);
+DEFINE_QNODE(qns_gladiator_sodv, SLAVE_GNOC_SNOC, 1, 8, 1, MASTER_GNOC_SNOC);
+DEFINE_QNODE(qns_gnoc_memnoc, SLAVE_GNOC_MEM_NOC, 2, 32, 1, MASTER_GNOC_MEM_NOC);
+DEFINE_QNODE(srvc_gnoc, SLAVE_SERVICE_GNOC, 1, 4, 0);
+DEFINE_QNODE(ipa_core_slave, SLAVE_IPA_CORE, 1, 8, 0);
+DEFINE_QNODE(ebi, SLAVE_EBI1, 4, 4, 0);
+DEFINE_QNODE(qhs_mdsp_ms_mpu_cfg, SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4, 0);
+DEFINE_QNODE(qns_apps_io, SLAVE_MEM_NOC_GNOC, 1, 32, 0);
+DEFINE_QNODE(qns_llcc, SLAVE_LLCC, 4, 16, 1, MASTER_LLCC);
+DEFINE_QNODE(qns_memnoc_snoc, SLAVE_MEM_NOC_SNOC, 1, 8, 1, MASTER_MEM_NOC_SNOC);
+DEFINE_QNODE(srvc_memnoc, SLAVE_SERVICE_MEM_NOC, 1, 4, 0);
+DEFINE_QNODE(qns2_mem_noc, SLAVE_MNOC_SF_MEM_NOC, 1, 32, 1, MASTER_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qns_mem_noc_hf, SLAVE_MNOC_HF_MEM_NOC, 2, 32, 1, MASTER_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(srvc_mnoc, SLAVE_SERVICE_MNOC, 1, 4, 0);
+DEFINE_QNODE(qhs_apss, SLAVE_APPSS, 1, 8, 0);
+DEFINE_QNODE(qns_cnoc, SLAVE_SNOC_CNOC, 1, 8, 1, MASTER_SNOC_CNOC);
+DEFINE_QNODE(qns_memnoc_gc, SLAVE_SNOC_MEM_NOC_GC, 1, 8, 1, MASTER_SNOC_GC_MEM_NOC);
+DEFINE_QNODE(qns_memnoc_sf, SLAVE_SNOC_MEM_NOC_SF, 1, 16, 1, MASTER_SNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxs_imem, SLAVE_IMEM, 1, 8, 0);
+DEFINE_QNODE(qxs_pcie, SLAVE_PCIE_0, 1, 8, 0);
+DEFINE_QNODE(qxs_pcie_gen3, SLAVE_PCIE_1, 1, 8, 0);
+DEFINE_QNODE(qxs_pimem, SLAVE_PIMEM, 1, 8, 0);
+DEFINE_QNODE(srvc_snoc, SLAVE_SERVICE_SNOC, 1, 4, 0);
+DEFINE_QNODE(xs_qdss_stm, SLAVE_QDSS_STM, 1, 4, 0);
+DEFINE_QNODE(xs_sys_tcu_cfg, SLAVE_TCU, 1, 8, 0);
+
+DEFINE_QBCM(bcm_acv, "ACV", 1, &ebi);
+DEFINE_QBCM(bcm_mc0, "MC0", 1, &ebi);
+DEFINE_QBCM(bcm_sh0, "SH0", 1, &qns_llcc);
+DEFINE_QBCM(bcm_mm0, "MM0", 1, &qns_mem_noc_hf);
+DEFINE_QBCM(bcm_sh1, "SH1", 1, &qns_apps_io);
+DEFINE_QBCM(bcm_mm1, "MM1", 7, &qxm_camnoc_hf0_uncomp, &qxm_camnoc_hf1_uncomp, &qxm_camnoc_sf_uncomp, &qxm_camnoc_hf0, &qxm_camnoc_hf1, &qxm_mdp0, &qxm_mdp1);
+DEFINE_QBCM(bcm_sh2, "SH2", 1, &qns_memnoc_snoc);
+DEFINE_QBCM(bcm_mm2, "MM2", 1, &qns2_mem_noc);
+DEFINE_QBCM(bcm_sh3, "SH3", 1, &acm_tcu);
+DEFINE_QBCM(bcm_mm3, "MM3", 5, &qxm_camnoc_sf, &qxm_rot, &qxm_venus0, &qxm_venus1, &qxm_venus_arm9);
+DEFINE_QBCM(bcm_sh5, "SH5", 1, &qnm_apps);
+DEFINE_QBCM(bcm_sn0, "SN0", 1, &qns_memnoc_sf);
+DEFINE_QBCM(bcm_ce0, "CE0", 1, &qxm_crypto);
+DEFINE_QBCM(bcm_ip0, "IP0", 1, &ipa_core_slave);
+DEFINE_QBCM(bcm_cn0, "CN0", 47, &qhm_spdm, &qhm_tic, &qnm_snoc, &xm_qdss_dap, &qhs_a1_noc_cfg, &qhs_a2_noc_cfg, &qhs_aop, &qhs_aoss, &qhs_camera_cfg, &qhs_clk_ctl, &qhs_compute_dsp_cfg, &qhs_cpr_cx, &qhs_crypto0_cfg, &qhs_dcc_cfg, &qhs_ddrss_cfg, &qhs_display_cfg, &qhs_glm, &qhs_gpuss_cfg, &qhs_imem_cfg, &qhs_ipa, &qhs_mnoc_cfg, &qhs_pcie0_cfg, &qhs_pcie_gen3_cfg, &qhs_pdm, &qhs_phy_refgen_south, &qhs_pimem_cfg, &qhs_prng, &qhs_qdss_cfg, &qhs_qupv3_north, &qhs_qupv3_south, &qhs_sdc2, &qhs_sdc4, &qhs_snoc_cfg, &qhs_spdm, &qhs_spss_cfg, &qhs_tcsr, &qhs_tlmm_north, &qhs_tlmm_south, &qhs_tsif, &qhs_ufs_card_cfg, &qhs_ufs_mem_cfg, &qhs_usb3_0, &qhs_usb3_1, &qhs_venus_cfg, &qhs_vsense_ctrl_cfg, &qns_cnoc_a2noc, &srvc_cnoc);
+DEFINE_QBCM(bcm_qup0, "QUP0", 2, &qhm_qup1, &qhm_qup2);
+DEFINE_QBCM(bcm_sn1, "SN1", 1, &qxs_imem);
+DEFINE_QBCM(bcm_sn2, "SN2", 1, &qns_memnoc_gc);
+DEFINE_QBCM(bcm_sn3, "SN3", 1, &qns_cnoc);
+DEFINE_QBCM(bcm_sn4, "SN4", 1, &qxm_pimem);
+DEFINE_QBCM(bcm_sn5, "SN5", 1, &xs_qdss_stm);
+DEFINE_QBCM(bcm_sn6, "SN6", 3, &qhs_apss, &srvc_snoc, &xs_sys_tcu_cfg);
+DEFINE_QBCM(bcm_sn7, "SN7", 1, &qxs_pcie);
+DEFINE_QBCM(bcm_sn8, "SN8", 1, &qxs_pcie_gen3);
+DEFINE_QBCM(bcm_sn9, "SN9", 2, &srvc_aggre1_noc, &qnm_aggre1_noc);
+DEFINE_QBCM(bcm_sn11, "SN11", 2, &srvc_aggre2_noc, &qnm_aggre2_noc);
+DEFINE_QBCM(bcm_sn12, "SN12", 2, &qnm_gladiator_sodv, &xm_gic);
+DEFINE_QBCM(bcm_sn14, "SN14", 1, &qnm_pcie_anoc);
+DEFINE_QBCM(bcm_sn15, "SN15", 1, &qnm_memnoc);
+
+static struct qcom_icc_node *rsc_hlos_nodes[] = {
+ &acm_l3,
+ &acm_tcu,
+ &ipa_core_master,
+ &llcc_mc,
+ &pm_gnoc_cfg,
+ &qhm_a1noc_cfg,
+ &qhm_a2noc_cfg,
+ &qhm_cnoc,
+ &qhm_memnoc_cfg,
+ &qhm_mnoc_cfg,
+ &qhm_qdss_bam,
+ &qhm_qup1,
+ &qhm_qup2,
+ &qhm_snoc_cfg,
+ &qhm_spdm,
+ &qhm_tic,
+ &qhm_tsif,
+ &qnm_aggre1_noc,
+ &qnm_aggre2_noc,
+ &qnm_apps,
+ &qnm_cnoc,
+ &qnm_gladiator_sodv,
+ &qnm_memnoc,
+ &qnm_mnoc_hf,
+ &qnm_mnoc_sf,
+ &qnm_pcie_anoc,
+ &qnm_snoc,
+ &qnm_snoc_gc,
+ &qnm_snoc_sf,
+ &qxm_camnoc_hf0,
+ &qxm_camnoc_hf0_uncomp,
+ &qxm_camnoc_hf1,
+ &qxm_camnoc_hf1_uncomp,
+ &qxm_camnoc_sf,
+ &qxm_camnoc_sf_uncomp,
+ &qxm_crypto,
+ &qxm_gpu,
+ &qxm_ipa,
+ &qxm_mdp0,
+ &qxm_mdp1,
+ &qxm_pimem,
+ &qxm_rot,
+ &qxm_venus0,
+ &qxm_venus1,
+ &qxm_venus_arm9,
+ &xm_gic,
+ &xm_pcie3_1,
+ &xm_pcie_0,
+ &xm_qdss_dap,
+ &xm_qdss_etr,
+ &xm_sdc2,
+ &xm_sdc4,
+ &xm_ufs_card,
+ &xm_ufs_mem,
+ &xm_usb3_0,
+ &xm_usb3_1,
+ &ebi,
+ &ipa_core_slave,
+ &qhs_a1_noc_cfg,
+ &qhs_a2_noc_cfg,
+ &qhs_aop,
+ &qhs_aoss,
+ &qhs_apss,
+ &qhs_camera_cfg,
+ &qhs_clk_ctl,
+ &qhs_compute_dsp_cfg,
+ &qhs_cpr_cx,
+ &qhs_crypto0_cfg,
+ &qhs_dcc_cfg,
+ &qhs_ddrss_cfg,
+ &qhs_display_cfg,
+ &qhs_glm,
+ &qhs_gpuss_cfg,
+ &qhs_imem_cfg,
+ &qhs_ipa,
+ &qhs_llcc,
+ &qhs_mdsp_ms_mpu_cfg,
+ &qhs_memnoc,
+ &qhs_mnoc_cfg,
+ &qhs_pcie0_cfg,
+ &qhs_pcie_gen3_cfg,
+ &qhs_pdm,
+ &qhs_phy_refgen_south,
+ &qhs_pimem_cfg,
+ &qhs_prng,
+ &qhs_qdss_cfg,
+ &qhs_qupv3_north,
+ &qhs_qupv3_south,
+ &qhs_sdc2,
+ &qhs_sdc4,
+ &qhs_snoc_cfg,
+ &qhs_spdm,
+ &qhs_spss_cfg,
+ &qhs_tcsr,
+ &qhs_tlmm_north,
+ &qhs_tlmm_south,
+ &qhs_tsif,
+ &qhs_ufs_card_cfg,
+ &qhs_ufs_mem_cfg,
+ &qhs_usb3_0,
+ &qhs_usb3_1,
+ &qhs_venus_cfg,
+ &qhs_vsense_ctrl_cfg,
+ &qns2_mem_noc,
+ &qns_a1noc_snoc,
+ &qns_a2noc_snoc,
+ &qns_apps_io,
+ &qns_camnoc_uncomp,
+ &qns_cnoc,
+ &qns_cnoc_a2noc,
+ &qns_gladiator_sodv,
+ &qns_gnoc_memnoc,
+ &qns_llcc,
+ &qns_mem_noc_hf,
+ &qns_memnoc_gc,
+ &qns_memnoc_sf,
+ &qns_memnoc_snoc,
+ &qns_pcie_a1noc_snoc,
+ &qns_pcie_snoc,
+ &qxs_imem,
+ &qxs_pcie,
+ &qxs_pcie_gen3,
+ &qxs_pimem,
+ &srvc_aggre1_noc,
+ &srvc_aggre2_noc,
+ &srvc_cnoc,
+ &srvc_gnoc,
+ &srvc_memnoc,
+ &srvc_mnoc,
+ &srvc_snoc,
+ &xs_qdss_stm,
+ &xs_sys_tcu_cfg,
+};
+
+static struct qcom_icc_bcm *rsc_hlos_bcms[] = {
+ &bcm_acv,
+ &bcm_mc0,
+ &bcm_sh0,
+ &bcm_mm0,
+ &bcm_sh1,
+ &bcm_mm1,
+ &bcm_sh2,
+ &bcm_mm2,
+ &bcm_sh3,
+ &bcm_mm3,
+ &bcm_sh5,
+ &bcm_sn0,
+ &bcm_ce0,
+ &bcm_ip0,
+ &bcm_cn0,
+ &bcm_qup0,
+ &bcm_sn1,
+ &bcm_sn2,
+ &bcm_sn3,
+ &bcm_sn4,
+ &bcm_sn5,
+ &bcm_sn6,
+ &bcm_sn7,
+ &bcm_sn8,
+ &bcm_sn9,
+ &bcm_sn11,
+ &bcm_sn12,
+ &bcm_sn14,
+ &bcm_sn15,
+};
+
+static struct qcom_icc_desc sdm845_rsc_hlos = {
+ .nodes = rsc_hlos_nodes,
+ .num_nodes = ARRAY_SIZE(rsc_hlos_nodes),
+ .bcms = rsc_hlos_bcms,
+ .num_bcms = ARRAY_SIZE(rsc_hlos_bcms),
+};
+
+static int qcom_icc_init(struct icc_node *node)
+{
+ /* TODO: init qos and priority */
+
+ return 0;
+}
+
+static int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
+{
+ struct qcom_icc_node *qn;
+ int ret, i;
+
+ bcm->addr = cmd_db_read_addr(bcm->name);
+ if (!bcm->addr) {
+ dev_err(dev, "%s could not find RPMh address\n",
+ bcm->name);
+ return -EINVAL;
+ }
+
+ if (!cmd_db_read_aux_data_len(bcm->name)) {
+ dev_err(dev, "%s command db missing aux data\n",
+ bcm->name);
+ return -EINVAL;
+ }
+
+ ret = cmd_db_read_aux_data(bcm->name, (u8 *)&bcm->aux_data,
+ sizeof(struct bcm_db));
+ if (ret < 0) {
+ dev_err(dev, "%s command db read error (%d)\n",
+ bcm->name, ret);
+ return ret;
+ }
+
+ for (i = 0; i < bcm->num_nodes; i++) {
+ qn = bcm->nodes[i];
+ qn->bcms[qn->num_bcms] = bcm;
+ qn->num_bcms++;
+ }
+
+ return 0;
+}
+
+static int qcom_tcs_cmd_gen(struct tcs_cmd *cmd, u64 vote_x,
+ u64 vote_y, u32 addr, bool commit)
+{
+ int ret = 0;
+ bool valid = true;
+
+ if (!cmd)
+ return ret;
+
+ if (vote_x == 0 && vote_y == 0)
+ valid = false;
+
+ if (vote_x > BCM_TCS_CMD_VOTE_MASK)
+ vote_x = BCM_TCS_CMD_VOTE_MASK;
+
+ if (vote_y > BCM_TCS_CMD_VOTE_MASK)
+ vote_y = BCM_TCS_CMD_VOTE_MASK;
+
+ cmd->addr = addr;
+ cmd->data = BCM_TCS_CMD(commit, valid, vote_x, vote_y);
+
+ /* Set the wait for completion flag on commands that have the commit
+ * set, in order to indicate to the RSC to not release the TCS slot
+ * until hardware has acknowledged that this transaction has completed
+ */
+ if (commit)
+ cmd->wait = true;
+
+ return ret;
+}
+
+static void qcom_tcs_list_gen(struct list_head *bcm_list, int ee_state,
+ struct tcs_cmd *tcs_list, int *n)
+{
+ struct qcom_icc_bcm *bcm;
+ bool commit;
+ size_t idx = 0, batch = 0, cur_vcd_size = 0;
+
+ memset(n, 0, sizeof(int) * SDM845_MAX_VCD);
+
+ list_for_each_entry(bcm, bcm_list, list) {
+ commit = false;
+ cur_vcd_size++;
+ if ((bcm->aux_data.vcd !=
+ list_next_entry(bcm, list)->aux_data.vcd) ||
+ list_is_last(&bcm->list, bcm_list)) {
+ commit = true;
+ cur_vcd_size = 0;
+ }
+ qcom_tcs_cmd_gen(&tcs_list[idx], bcm->vote_x[ee_state],
+ bcm->vote_y[ee_state], bcm->addr, commit);
+ idx++;
+ n[batch]++;
+ if (n[batch] >= MAX_RPMH_PAYLOAD) {
+ if (!commit) {
+ n[batch] -= cur_vcd_size;
+ n[batch+1] = cur_vcd_size;
+ }
+ batch++;
+ }
+ }
+}
+
+static void qcom_icc_bcm_aggregate(struct qcom_icc_bcm *bcm)
+{
+ size_t i, ctx_idx;
+ u64 agg_avg[SDM845_MAX_CTX] = {0};
+ u64 agg_peak[SDM845_MAX_CTX] = {0};
+
+ for (ctx_idx = 0; ctx_idx < SDM845_MAX_CTX; ctx_idx++) {
+ for (i = 0; i < bcm->num_nodes; i++) {
+ agg_avg[ctx_idx] = max(agg_avg[ctx_idx],
+ bcm->nodes[i]->sum_avg[ctx_idx] * bcm->aux_data.width /
+ (bcm->nodes[i]->buswidth * bcm->nodes[i]->channels));
+ agg_peak[ctx_idx] = max(agg_peak[ctx_idx],
+ bcm->nodes[i]->max_peak[ctx_idx] * bcm->aux_data.width /
+ bcm->nodes[i]->buswidth);
+ }
+ }
+
+ bcm->vote_x[EE_STATE_WAKE] = (u64)((agg_avg[AO_CTX] +
+ agg_avg[DUAL_CTX]) *
+ 1000ULL / bcm->aux_data.unit);
+ bcm->vote_y[EE_STATE_WAKE] = (u64)(max(agg_peak[AO_CTX],
+ agg_peak[DUAL_CTX]) *
+ 1000ULL / bcm->aux_data.unit);
+ bcm->vote_x[EE_STATE_SLEEP] = (u64)(agg_avg[DUAL_CTX] *
+ 1000ULL / bcm->aux_data.unit);
+ bcm->vote_y[EE_STATE_SLEEP] = (u64)(agg_peak[DUAL_CTX] *
+ 1000ULL / bcm->aux_data.unit);
+ bcm->dirty = false;
+}
+
+static int qcom_icc_aggregate(struct icc_node *node, u8 tag, u32 avg_bw,
+ u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
+{
+ size_t i;
+ struct qcom_icc_node *qn;
+ u32 ctx_idx = 0;
+
+ qn = node->data;
+ ctx_idx = (!!tag) ? AO_CTX : DUAL_CTX;
+
+ *agg_avg += avg_bw;
+ *agg_peak = max_t(u64, agg_peak, peak_bw);
+
+ qn->sum_avg[ctx_idx] = *agg_avg;
+ qn->max_peak[ctx_idx] = *agg_peak;
+
+ for (i = 0; i < qn->num_bcms; i++)
+ qn->bcms[i]->dirty = true;
+
+ return 0;
+}
+
+static int qcom_icc_set(struct icc_node *src, struct icc_node *dst,
+ u32 avg, u32 peak)
+{
+ struct qcom_icc_provider *qp;
+ struct qcom_icc_node *qn;
+ struct icc_node *node;
+ struct icc_provider *provider;
+ struct tcs_cmd cmds[SDM845_MAX_BCMS];
+ struct list_head commit_list;
+ int commit_idx[SDM845_MAX_VCD];
+ int ret = 0, i;
+
+ if (!src)
+ node = dst;
+ else
+ node = src;
+
+ qn = node->data;
+ provider = node->provider;
+ qp = to_qcom_provider(node->provider);
+
+ INIT_LIST_HEAD(&commit_list);
+
+ for (i = 0; i < qp->num_bcms; i++) {
+ if (qp->bcms[i]->dirty) {
+ qcom_icc_bcm_aggregate(qn->bcms[i]);
+ list_add_tail(&qp->bcms[i]->list, &commit_list);
+ }
+ }
+
+ /* Construct the command list based on a pre ordered list of BCMs
+ * based on VCD
+ */
+ qcom_tcs_list_gen(&commit_list, EE_STATE_WAKE, cmds, commit_idx);
+
+ if (!commit_idx[0])
+ return ret;
+
+ ret = rpmh_invalidate(qp->rpmh_client);
+ if (ret) {
+ pr_err("Error invalidating RPMH client (%d)\n", ret);
+ return ret;
+ }
+
+ ret = rpmh_write_batch(qp->rpmh_client, RPMH_ACTIVE_ONLY_STATE,
+ cmds, commit_idx);
+ if (ret) {
+ pr_err("Error sending AMC RPMH requests (%d)\n", ret);
+ return ret;
+ }
+
+ INIT_LIST_HEAD(&commit_list);
+
+ for (i = 0; i < qp->num_bcms; i++) {
+
+ /* Only generate WAKE and SLEEP commands if a resource's
+ * requirements change as the execution environment transitions
+ * between different power states.
+ */
+ if (qp->bcms[i]->vote_x[EE_STATE_WAKE] !=
+ qp->bcms[i]->vote_x[EE_STATE_SLEEP] ||
+ qp->bcms[i]->vote_y[EE_STATE_WAKE] !=
+ qp->bcms[i]->vote_y[EE_STATE_SLEEP]) {
+ list_add_tail(&qp->bcms[i]->list, &commit_list);
+ }
+ }
+
+ qcom_tcs_list_gen(&commit_list, EE_STATE_WAKE, cmds, commit_idx);
+
+ ret = rpmh_write_batch(qp->rpmh_client, RPMH_WAKE_ONLY_STATE,
+ cmds, commit_idx);
+ if (ret) {
+ pr_err("Error sending WAKE RPMH requests (%d)\n", ret);
+ return ret;
+ }
+
+ qcom_tcs_list_gen(&commit_list, EE_STATE_SLEEP, cmds, commit_idx);
+
+ ret = rpmh_write_batch(qp->rpmh_client, RPMH_SLEEP_STATE,
+ cmds, commit_idx);
+ if (ret) {
+ pr_err("Error sending SLEEP RPMH requests (%d)\n", ret);
+ return ret;
+ }
+
+
+ return ret;
+}
+
+static int cmp_vcd(const void *_l, const void *_r)
+{
+ const struct qcom_icc_bcm **l = (const struct qcom_icc_bcm **)_l;
+ const struct qcom_icc_bcm **r = (const struct qcom_icc_bcm **)_r;
+
+ if (l[0]->aux_data.vcd < r[0]->aux_data.vcd)
+ return -1;
+ else if (l[0]->aux_data.vcd == r[0]->aux_data.vcd)
+ return 0;
+ else
+ return 1;
+}
+
+static int qnoc_probe(struct platform_device *pdev)
+{
+ const struct qcom_icc_desc *desc;
+ struct qcom_icc_node **qnodes;
+ struct qcom_icc_provider *qp;
+ struct icc_provider *provider;
+ size_t num_nodes, i;
+ int ret;
+
+ desc = of_device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ qnodes = desc->nodes;
+ num_nodes = desc->num_nodes;
+
+ qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return -ENOMEM;
+
+ provider = &qp->provider;
+ provider->dev = &pdev->dev;
+ provider->set = &qcom_icc_set;
+ provider->aggregate = &qcom_icc_aggregate;
+ INIT_LIST_HEAD(&provider->nodes);
+ provider->data = qp;
+
+ qp->rpmh_client = rpmh_get_client(pdev);
+ qp->bcms = desc->bcms;
+ qp->num_bcms = desc->num_bcms;
+
+ ret = icc_provider_add(provider);
+ if (ret) {
+ dev_err(&pdev->dev, "error adding interconnect provider\n");
+ return ret;
+ }
+
+ for (i = 0; i < num_nodes; i++) {
+ struct icc_node *node;
+ int ret;
+ 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);
+
+ dev_dbg(&pdev->dev, "registered node %p %s %d\n", node,
+ qnodes[i]->name, node->id);
+
+ ret = qcom_icc_init(node);
+ if (ret)
+ dev_err(&pdev->dev, "%s init error (%d)\n", node->name,
+ ret);
+
+ /* populate links */
+ for (j = 0; j < qnodes[i]->num_links; j++)
+ if (qnodes[i]->links[j])
+ icc_link_create(node, qnodes[i]->links[j]);
+ }
+
+ for (i = 0; i < qp->num_bcms; i++)
+ qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
+
+ /* Pre sort the BCMs based on VCD for ease of generating a command list
+ * that groups the BCMs with the same VCD together. VCDs are numbered
+ * with lowest being the most expensive time wise, ensuring that
+ * those commands are being sent the earliest in the queue.
+ */
+ sort(qp->bcms, qp->num_bcms, sizeof(*qp->bcms), cmp_vcd, NULL);
+
+ platform_set_drvdata(pdev, provider);
+ dev_info(&pdev->dev, "Registered SDM845 ICC\n");
+
+ return ret;
+err:
+ icc_provider_del(provider);
+ return ret;
+}
+
+static int qnoc_remove(struct platform_device *pdev)
+{
+ struct icc_provider *provider = platform_get_drvdata(pdev);
+
+ icc_provider_del(provider);
+
+ return 0;
+}
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,sdm845-rsc-hlos", .data = &sdm845_rsc_hlos },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qnoc_probe,
+ .remove = qnoc_remove,
+ .driver = {
+ .name = "qnoc-sdm845",
+ .of_match_table = qnoc_of_match,
+ },
+};
+module_platform_driver(qnoc_driver);
+
+MODULE_AUTHOR("David Dai <daidavid1@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm sdm845 NoC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/smd-rpm.c b/drivers/interconnect/qcom/smd-rpm.c
new file mode 100644
index 000000000000..48b7a2a6eb84
--- /dev/null
+++ b/drivers/interconnect/qcom/smd-rpm.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RPM over SMD communication wrapper for interconnects
+ *
+ * Copyright (C) 2018 Linaro Ltd
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/smd-rpm.h>
+#include "smd-rpm.h"
+
+#define RPM_KEY_BW 0x00007762
+
+static struct qcom_icc_rpm {
+ struct qcom_smd_rpm *rpm;
+} icc_rpm_smd;
+
+struct icc_rpm_smd_req {
+ __le32 key;
+ __le32 nbytes;
+ __le32 value;
+};
+
+bool qcom_icc_rpm_smd_available(void)
+{
+ if (!icc_rpm_smd.rpm)
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_available);
+
+int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val)
+{
+ struct icc_rpm_smd_req req = {
+ .key = cpu_to_le32(RPM_KEY_BW),
+ .nbytes = cpu_to_le32(sizeof(u32)),
+ .value = cpu_to_le32(val),
+ };
+
+ return qcom_rpm_smd_write(icc_rpm_smd.rpm, ctx, rsc_type, id, &req,
+ sizeof(req));
+}
+EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_send);
+
+static int qcom_icc_rpm_smd_probe(struct platform_device *pdev)
+{
+ icc_rpm_smd.rpm = dev_get_drvdata(pdev->dev.parent);
+ if (!icc_rpm_smd.rpm) {
+ dev_err(&pdev->dev, "unable to retrieve handle to RPM\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id qcom_icc_rpm_smd_dt_match[] = {
+ { .compatible = "qcom,interconnect-smd-rpm", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, qcom_icc_rpm_smd_dt_match);
+
+static struct platform_driver qcom_interconnect_rpm_smd_driver = {
+ .driver = {
+ .name = "qcom-interconnect-smd-rpm",
+ .of_match_table = qcom_icc_rpm_smd_dt_match,
+ },
+ .probe = qcom_icc_rpm_smd_probe,
+};
+
+static int __init rpm_smd_interconnect_init(void)
+{
+ return platform_driver_register(&qcom_interconnect_rpm_smd_driver);
+}
+subsys_initcall(rpm_smd_interconnect_init);
+
+static void __exit rpm_smd_interconnect_exit(void)
+{
+ platform_driver_unregister(&qcom_interconnect_rpm_smd_driver);
+}
+module_exit(rpm_smd_interconnect_exit)
+
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm SMD RPM interconnect driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/smd-rpm.h b/drivers/interconnect/qcom/smd-rpm.h
new file mode 100644
index 000000000000..3b1c347475ff
--- /dev/null
+++ b/drivers/interconnect/qcom/smd-rpm.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_SMD_RPM_H
+#define __DRIVERS_INTERCONNECT_QCOM_SMD_RPM_H
+
+
+#include <linux/soc/qcom/smd-rpm.h>
+
+bool qcom_icc_rpm_smd_available(void);
+int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val);
+
+#endif
diff --git a/include/dt-bindings/interconnect/qcom.h b/include/dt-bindings/interconnect/qcom.h
new file mode 100644
index 000000000000..fe23aff7b619
--- /dev/null
+++ b/include/dt-bindings/interconnect/qcom.h
@@ -0,0 +1,440 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Qualcomm interconnect IDs
+ *
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef __QCOM_INTERCONNECT_IDS_H
+#define __QCOM_INTERCONNECT_IDS_H
+
+#define FAB_BIMC 0
+#define FAB_SYS_NOC 1024
+#define FAB_MMSS_NOC 2048
+#define FAB_OCMEM_NOC 3072
+#define FAB_PERIPH_NOC 4096
+#define FAB_CONFIG_NOC 5120
+#define FAB_OCMEM_VNOC 6144
+#define FAB_MMSS_AHB 2049
+#define FAB_A0_NOC 6145
+#define FAB_A1_NOC 6146
+#define FAB_A2_NOC 6147
+#define FAB_GNOC 6148
+#define FAB_CR_VIRT 6149
+
+#define MASTER_AMPSS_M0 1
+#define MASTER_AMPSS_M1 2
+#define APPSS_MASTER_FAB_MMSS 3
+#define APPSS_MASTER_FAB_SYSTEM 4
+#define SYSTEM_MASTER_FAB_APPSS 5
+#define MASTER_SPS 6
+#define MASTER_ADM_PORT0 7
+#define MASTER_ADM_PORT1 8
+#define SYSTEM_MASTER_ADM1_PORT0 9
+#define MASTER_ADM1_PORT1 10
+#define MASTER_LPASS_PROC 11
+#define MASTER_MSS_PROCI 12
+#define MASTER_MSS_PROCD 13
+#define MASTER_MSS_MDM_PORT0 14
+#define MASTER_LPASS 15
+#define SYSTEM_MASTER_CPSS_FPB 16
+#define SYSTEM_MASTER_SYSTEM_FPB 17
+#define SYSTEM_MASTER_MMSS_FPB 18
+#define MASTER_ADM1_CI 19
+#define MASTER_ADM0_CI 20
+#define MASTER_MSS_MDM_PORT1 21
+#define MASTER_MDP_PORT0 22
+#define MASTER_MDP_PORT1 23
+#define MMSS_MASTER_ADM1_PORT0 24
+#define MASTER_ROTATOR 25
+#define MASTER_GRAPHICS_3D 26
+#define MASTER_JPEG_DEC 27
+#define MASTER_GRAPHICS_2D_CORE0 28
+#define MASTER_VFE 29
+#define MASTER_VPE 30
+#define MASTER_JPEG_ENC 31
+#define MASTER_GRAPHICS_2D_CORE1 32
+#define MMSS_MASTER_APPS_FAB 33
+#define MASTER_HD_CODEC_PORT0 34
+#define MASTER_HD_CODEC_PORT1 35
+#define MASTER_SPDM 36
+#define MASTER_RPM 37
+#define MASTER_MSS 38
+#define MASTER_RIVA 39
+#define MASTER_SNOC_VMEM 40
+#define MASTER_MSS_SW_PROC 41
+#define MASTER_MSS_FW_PROC 42
+#define MASTER_HMSS 43
+#define MASTER_GSS_NAV 44
+#define MASTER_PCIE 45
+#define MASTER_SATA 46
+#define MASTER_CRYPTO 47
+#define MASTER_VIDEO_CAP 48
+#define MASTER_GRAPHICS_3D_PORT1 49
+#define MASTER_VIDEO_ENC 50
+#define MASTER_VIDEO_DEC 51
+#define MASTER_LPASS_AHB 52
+#define MASTER_QDSS_BAM 53
+#define MASTER_SNOC_CFG 54
+#define MASTER_CRYPTO_CORE0 55
+#define MASTER_CRYPTO_CORE1 56
+#define MASTER_MSS_NAV 57
+#define MASTER_OCMEM_DMA 58
+#define MASTER_WCSS 59
+#define MASTER_QDSS_ETR 60
+#define MASTER_USB3 61
+#define MASTER_JPEG 62
+#define MASTER_VIDEO_P0 63
+#define MASTER_VIDEO_P1 64
+#define MASTER_MSS_PROC 65
+#define MASTER_JPEG_OCMEM 66
+#define MASTER_MDP_OCMEM 67
+#define MASTER_VIDEO_P0_OCMEM 68
+#define MASTER_VIDEO_P1_OCMEM 69
+#define MASTER_VFE_OCMEM 70
+#define MASTER_CNOC_ONOC_CFG 71
+#define MASTER_RPM_INST 72
+#define MASTER_RPM_DATA 73
+#define MASTER_RPM_SYS 74
+#define MASTER_DEHR 75
+#define MASTER_QDSS_DAP 76
+#define MASTER_TIC 77
+#define MASTER_SDCC_1 78
+#define MASTER_SDCC_3 79
+#define MASTER_SDCC_4 80
+#define MASTER_SDCC_2 81
+#define MASTER_TSIF 82
+#define MASTER_BAM_DMA 83
+#define MASTER_BLSP_2 84
+#define MASTER_USB_HSIC 85
+#define MASTER_BLSP_1 86
+#define MASTER_USB_HS 87
+#define MASTER_PNOC_CFG 88
+#define MASTER_V_OCMEM_GFX3D 89
+#define MASTER_IPA 90
+#define MASTER_QPIC 91
+#define MASTER_MDPE 92
+#define MASTER_USB_HS2 93
+#define MASTER_VPU 94
+#define MASTER_UFS 95
+#define MASTER_BCAST 96
+#define MASTER_CRYPTO_CORE2 97
+#define MASTER_EMAC 98
+#define MASTER_VPU_1 99
+#define MASTER_PCIE_1 100
+#define MASTER_USB3_1 101
+#define MASTER_CNOC_MNOC_MMSS_CFG 102
+#define MASTER_CNOC_MNOC_CFG 103
+#define MASTER_TCU_0 104
+#define MASTER_TCU_1 105
+#define MASTER_CPP 106
+#define MASTER_AUDIO 107
+#define MASTER_PCIE_2 108
+#define MASTER_VFE1 109
+#define MASTER_XM_USB_HS1 110
+#define MASTER_PCNOC_BIMC_1 111
+#define MASTER_BIMC_PCNOC 112
+#define MASTER_XI_USB_HSIC 113
+#define MASTER_SGMII 114
+#define SPMI_FETCHER 115
+#define MASTER_GNOC_BIMC 116
+#define MASTER_CRVIRT_A2NOC 117
+#define MASTER_CNOC_A2NOC 118
+#define MASTER_WLAN 119
+#define MASTER_MSS_CE 120
+#define MASTER_MASTER_LAST 121
+
+#define SNOC_MM_INT_0 10000
+#define SNOC_MM_INT_1 10001
+#define SNOC_MM_INT_2 10002
+#define SNOC_MM_INT_BIMC 10003
+#define SNOC_INT_0 10004
+#define SNOC_INT_1 10005
+#define SNOC_INT_BIMC 10006
+#define SNOC_BIMC_0_MAS 10007
+#define SNOC_BIMC_1_MAS 10008
+#define SNOC_QDSS_INT 10009
+#define PNOC_SNOC_MAS 10010
+#define PNOC_SNOC_SLV 10011
+#define PNOC_INT_0 10012
+#define PNOC_INT_1 10013
+#define PNOC_M_0 10014
+#define PNOC_M_1 10015
+#define BIMC_SNOC_MAS 10016
+#define BIMC_SNOC_SLV 10017
+#define PNOC_SLV_0 10018
+#define PNOC_SLV_1 10019
+#define PNOC_SLV_2 10020
+#define PNOC_SLV_3 10021
+#define PNOC_SLV_4 10022
+#define PNOC_SLV_8 10023
+#define PNOC_SLV_9 10024
+#define SNOC_BIMC_0_SLV 10025
+#define SNOC_BIMC_1_SLV 10026
+#define MNOC_BIMC_MAS 10027
+#define MNOC_BIMC_SLV 10028
+#define BIMC_MNOC_MAS 10029
+#define BIMC_MNOC_SLV 10030
+#define SNOC_BIMC_MAS 10031
+#define SNOC_BIMC_SLV 10032
+#define CNOC_SNOC_MAS 10033
+#define CNOC_SNOC_SLV 10034
+#define SNOC_CNOC_MAS 10035
+#define SNOC_CNOC_SLV 10036
+#define OVNOC_SNOC_MAS 10037
+#define OVNOC_SNOC_SLV 10038
+#define SNOC_OVNOC_MAS 10039
+#define SNOC_OVNOC_SLV 10040
+#define SNOC_PNOC_MAS 10041
+#define SNOC_PNOC_SLV 10042
+#define BIMC_INT_APPS_EBI 10043
+#define BIMC_INT_APPS_SNOC 10044
+#define SNOC_BIMC_2_MAS 10045
+#define SNOC_BIMC_2_SLV 10046
+#define PNOC_SLV_5 10047
+#define PNOC_SLV_7 10048
+#define PNOC_INT_2 10049
+#define PNOC_INT_3 10050
+#define PNOC_INT_4 10051
+#define PNOC_INT_5 10052
+#define PNOC_INT_6 10053
+#define PNOC_INT_7 10054
+#define BIMC_SNOC_1_MAS 10055
+#define BIMC_SNOC_1_SLV 10056
+#define PNOC_A1NOC_MAS 10057
+#define PNOC_A1NOC_SLV 10058
+#define CNOC_A1NOC_MAS 10059
+#define A0NOC_SNOC_MAS 10060
+#define A0NOC_SNOC_SLV 10061
+#define A1NOC_SNOC_SLV 10062
+#define A1NOC_SNOC_MAS 10063
+#define A2NOC_SNOC_MAS 10064
+#define A2NOC_SNOC_SLV 10065
+#define SNOC_INT_2 10066
+#define A0NOC_QDSS_INT 10067
+
+#define SLAVE_EBI_CH0 512
+#define SLAVE_EBI_CH1 513
+#define SLAVE_AMPSS_L2 514
+#define APPSS_SLAVE_FAB_MMSS 515
+#define APPSS_SLAVE_FAB_SYSTEM 516
+#define SYSTEM_SLAVE_FAB_APPS 517
+#define SLAVE_SPS 518
+#define SLAVE_SYSTEM_IMEM 519
+#define SLAVE_AMPSS 520
+#define SLAVE_MSS 521
+#define SLAVE_LPASS 522
+#define SYSTEM_SLAVE_CPSS_FPB 523
+#define SYSTEM_SLAVE_SYSTEM_FPB 524
+#define SYSTEM_SLAVE_MMSS_FPB 525
+#define SLAVE_CORESIGHT 526
+#define SLAVE_RIVA 527
+#define SLAVE_SMI 528
+#define MMSS_SLAVE_FAB_APPS 529
+#define MMSS_SLAVE_FAB_APPS_1 530
+#define SLAVE_MM_IMEM 531
+#define SLAVE_CRYPTO 532
+#define SLAVE_SPDM 533
+#define SLAVE_RPM 534
+#define SLAVE_RPM_MSG_RAM 535
+#define SLAVE_MPM 536
+#define SLAVE_PMIC1_SSBI1_A 537
+#define SLAVE_PMIC1_SSBI1_B 538
+#define SLAVE_PMIC1_SSBI1_C 539
+#define SLAVE_PMIC2_SSBI2_A 540
+#define SLAVE_PMIC2_SSBI2_B 541
+#define SLAVE_GSBI1_UART 542
+#define SLAVE_GSBI2_UART 543
+#define SLAVE_GSBI3_UART 544
+#define SLAVE_GSBI4_UART 545
+#define SLAVE_GSBI5_UART 546
+#define SLAVE_GSBI6_UART 547
+#define SLAVE_GSBI7_UART 548
+#define SLAVE_GSBI8_UART 549
+#define SLAVE_GSBI9_UART 550
+#define SLAVE_GSBI10_UART 551
+#define SLAVE_GSBI11_UART 552
+#define SLAVE_GSBI12_UART 553
+#define SLAVE_GSBI1_QUP 554
+#define SLAVE_GSBI2_QUP 555
+#define SLAVE_GSBI3_QUP 556
+#define SLAVE_GSBI4_QUP 557
+#define SLAVE_GSBI5_QUP 558
+#define SLAVE_GSBI6_QUP 559
+#define SLAVE_GSBI7_QUP 560
+#define SLAVE_GSBI8_QUP 561
+#define SLAVE_GSBI9_QUP 562
+#define SLAVE_GSBI10_QUP 563
+#define SLAVE_GSBI11_QUP 564
+#define SLAVE_GSBI12_QUP 565
+#define SLAVE_EBI2_NAND 566
+#define SLAVE_EBI2_CS0 567
+#define SLAVE_EBI2_CS1 568
+#define SLAVE_EBI2_CS2 569
+#define SLAVE_EBI2_CS3 570
+#define SLAVE_EBI2_CS4 571
+#define SLAVE_EBI2_CS5 572
+#define SLAVE_USB_FS1 573
+#define SLAVE_USB_FS2 574
+#define SLAVE_TSIF 575
+#define SLAVE_MSM_TSSC 576
+#define SLAVE_MSM_PDM 577
+#define SLAVE_MSM_DIMEM 578
+#define SLAVE_MSM_TCSR 579
+#define SLAVE_MSM_PRNG 580
+#define SLAVE_GSS 581
+#define SLAVE_SATA 582
+#define SLAVE_USB3 583
+#define SLAVE_WCSS 584
+#define SLAVE_OCIMEM 585
+#define SLAVE_SNOC_OCMEM 586
+#define SLAVE_SERVICE_SNOC 587
+#define SLAVE_QDSS_STM 588
+#define SLAVE_CAMERA_CFG 589
+#define SLAVE_DISPLAY_CFG 590
+#define SLAVE_OCMEM_CFG 591
+#define SLAVE_CPR_CFG 592
+#define SLAVE_CPR_XPU_CFG 593
+#define SLAVE_MISC_CFG 594
+#define SLAVE_MISC_XPU_CFG 595
+#define SLAVE_VENUS_CFG 596
+#define SLAVE_MISC_VENUS_CFG 597
+#define SLAVE_GRAPHICS_3D_CFG 598
+#define SLAVE_MMSS_CLK_CFG 599
+#define SLAVE_MMSS_CLK_XPU_CFG 600
+#define SLAVE_MNOC_MPU_CFG 601
+#define SLAVE_ONOC_MPU_CFG 602
+#define SLAVE_SERVICE_MNOC 603
+#define SLAVE_OCMEM 604
+#define SLAVE_SERVICE_ONOC 605
+#define SLAVE_SDCC_1 606
+#define SLAVE_SDCC_3 607
+#define SLAVE_SDCC_2 608
+#define SLAVE_SDCC_4 609
+#define SLAVE_BAM_DMA 610
+#define SLAVE_BLSP_2 611
+#define SLAVE_USB_HSIC 612
+#define SLAVE_BLSP_1 613
+#define SLAVE_USB_HS 614
+#define SLAVE_PDM 615
+#define SLAVE_PERIPH_APU_CFG 616
+#define SLAVE_PNOC_MPU_CFG 617
+#define SLAVE_PRNG 618
+#define SLAVE_SERVICE_PNOC 619
+#define SLAVE_CLK_CTL 620
+#define SLAVE_CNOC_MSS 621
+#define SLAVE_SECURITY 622
+#define SLAVE_TCSR 623
+#define SLAVE_TLMM 624
+#define SLAVE_CRYPTO_0_CFG 625
+#define SLAVE_CRYPTO_1_CFG 626
+#define SLAVE_IMEM_CFG 627
+#define SLAVE_MESSAGE_RAM 628
+#define SLAVE_BIMC_CFG 629
+#define SLAVE_BOOT_ROM 630
+#define SLAVE_CNOC_MNOC_MMSS_CFG 631
+#define SLAVE_PMIC_ARB 632
+#define SLAVE_SPDM_WRAPPER 633
+#define SLAVE_DEHR_CFG 634
+#define SLAVE_QDSS_CFG 635
+#define SLAVE_RBCPR_CFG 636
+#define SLAVE_RBCPR_QDSS_APU_CFG 637
+#define SLAVE_SNOC_MPU_CFG 638
+#define SLAVE_CNOC_ONOC_CFG 639
+#define SLAVE_CNOC_MNOC_CFG 640
+#define SLAVE_PNOC_CFG 641
+#define SLAVE_SNOC_CFG 642
+#define SLAVE_EBI1_DLL_CFG 643
+#define SLAVE_PHY_APU_CFG 644
+#define SLAVE_EBI1_PHY_CFG 645
+#define SLAVE_SERVICE_CNOC 646
+#define SLAVE_IPS_CFG 647
+#define SLAVE_QPIC 648
+#define SLAVE_DSI_CFG 649
+#define SLAVE_UFS_CFG 650
+#define SLAVE_RBCPR_CX_CFG 651
+#define SLAVE_RBCPR_MX_CFG 652
+#define SLAVE_PCIE_CFG 653
+#define SLAVE_USB_PHYS_CFG 654
+#define SLAVE_VIDEO_CAP_CFG 655
+#define SLAVE_AVSYNC_CFG 656
+#define SLAVE_CRYPTO_2_CFG 657
+#define SLAVE_VPU_CFG 658
+#define SLAVE_BCAST_CFG 659
+#define SLAVE_KLM_CFG 660
+#define SLAVE_GENI_IR_CFG 661
+#define SLAVE_OCMEM_GFX 662
+#define SLAVE_CATS_128 663
+#define SLAVE_OCMEM_64 664
+#define SLAVE_PCIE_0 665
+#define SLAVE_PCIE_1 666
+#define SLAVE_PCIE_0_CFG 667
+#define SLAVE_PCIE_1_CFG 668
+#define SLAVE_SRVC_MNOC 669
+#define SLAVE_USB_HS2 670
+#define SLAVE_AUDIO 671
+#define SLAVE_TCU 672
+#define SLAVE_APPSS 673
+#define SLAVE_PCIE_PARF 674
+#define SLAVE_USB3_PHY_CFG 675
+#define SLAVE_IPA_CFG 676
+#define SLAVE_A0NOC_SNOC 677
+#define SLAVE_A1NOC_SNOC 678
+#define SLAVE_A2NOC_SNOC 679
+#define SLAVE_HMSS_L3 680
+#define SLAVE_PIMEM_CFG 681
+#define SLAVE_DCC_CFG 682
+#define SLAVE_QDSS_RBCPR_APU_CFG 683
+#define SLAVE_PCIE_2_CFG 684
+#define SLAVE_PCIE20_AHB2PHY 685
+#define SLAVE_A0NOC_CFG 686
+#define SLAVE_A1NOC_CFG 687
+#define SLAVE_A2NOC_CFG 688
+#define SLAVE_A1NOC_MPU_CFG 689
+#define SLAVE_A2NOC_MPU_CFG 690
+#define SLAVE_A0NOC_SMMU_CFG 691
+#define SLAVE_A1NOC_SMMU_CFG 692
+#define SLAVE_A2NOC_SMMU_CFG 693
+#define SLAVE_LPASS_SMMU_CFG 694
+#define SLAVE_MMAGIC_CFG 695
+#define SLAVE_VENUS_THROTTLE_CFG 696
+#define SLAVE_SSC_CFG 697
+#define SLAVE_DSA_CFG 698
+#define SLAVE_DSA_MPU_CFG 699
+#define SLAVE_DISPLAY_THROTTLE_CFG 700
+#define SLAVE_SMMU_CPP_CFG 701
+#define SLAVE_SMMU_JPEG_CFG 702
+#define SLAVE_SMMU_MDP_CFG 703
+#define SLAVE_SMMU_ROTATOR_CFG 704
+#define SLAVE_SMMU_VENUS_CFG 705
+#define SLAVE_SMMU_VFE_CFG 706
+#define SLAVE_A0NOC_MPU_CFG 707
+#define SLAVE_VMEM_CFG 708
+#define SLAVE_CAMERA_THROTTLE_CFG 709
+#define SLAVE_VMEM 710
+#define SLAVE_AHB2PHY 711
+#define SLAVE_PIMEM 712
+#define SLAVE_SNOC_VMEM 713
+#define SLAVE_PCIE_2 714
+#define SLAVE_RBCPR_MX 715
+#define SLAVE_RBCPR_CX 716
+#define SLAVE_BIMC_PCNOC 717
+#define SLAVE_PCNOC_BIMC_1 718
+#define SLAVE_SGMII 719
+#define SLAVE_SPMI_FETCHER 720
+#define PNOC_SLV_6 721
+#define SLAVE_MMSS_SMMU_CFG 722
+#define SLAVE_WLAN 723
+#define SLAVE_CRVIRT_A2NOC 724
+#define SLAVE_CNOC_A2NOC 725
+#define SLAVE_GLM 726
+#define SLAVE_GNOC_BIMC 727
+#define SLAVE_GNOC_SNOC 728
+#define SLAVE_QM_CFG 729
+#define SLAVE_TLMM_EAST 730
+#define SLAVE_TLMM_NORTH 731
+#define SLAVE_TLMM_WEST 732
+#define SLAVE_SKL 733
+
+#endif
diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h
new file mode 100644
index 000000000000..1774fa6ade1f
--- /dev/null
+++ b/include/linux/interconnect-provider.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef _LINUX_INTERCONNECT_PROVIDER_H
+#define _LINUX_INTERCONNECT_PROVIDER_H
+
+#include <linux/interconnect.h>
+
+#define icc_units_to_bps(bw) ((bw) * 1000ULL)
+
+struct icc_node;
+
+/**
+ * struct icc_provider - interconnect provider (controller) entity that might
+ * provide multiple interconnect controls
+ *
+ * @provider_list: list of the registered interconnect providers
+ * @nodes: internal list of the interconnect provider nodes
+ * @set: pointer to device specific set operation function
+ * @aggregate: pointer to device specific aggregate operation function
+ * @dev: the device this interconnect provider belongs to
+ * @users: count of active users
+ * @avg_bw: aggregated value of average bandwidth requests from all nodes
+ * @peak_bw: aggregated value of peak bandwidth requests from all nodes
+ * @data: pointer to private data
+ */
+struct icc_provider {
+ struct list_head provider_list;
+ struct list_head nodes;
+ int (*set)(struct icc_node *src, struct icc_node *dst,
+ u32 avg_bw, u32 peak_bw);
+ int (*aggregate)(struct icc_node *node, u8 tag, u32 avg_bw,
+ u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
+ struct device *dev;
+ int users;
+ u32 avg_bw;
+ u32 peak_bw;
+ void *data;
+};
+
+/**
+ * struct icc_node - entity that is part of the interconnect topology
+ *
+ * @id: platform specific node id
+ * @name: node name used in debugfs
+ * @links: a list of targets pointing to where we can go next when traversing
+ * @num_links: number of links to other interconnect nodes
+ * @provider: points to the interconnect provider of this node
+ * @node_list: the list entry in the parent provider's "nodes" list
+ * @search_list: list used when walking the nodes graph
+ * @reverse: pointer to previous node when walking the nodes graph
+ * @is_traversed: flag that is used when walking the nodes graph
+ * @req_list: a list of QoS constraint requests associated with this node
+ * @avg_bw: aggregated value of average bandwidth requests from all consumers
+ * @peak_bw: aggregated value of peak bandwidth requests from all consumers
+ * @data: pointer to private data
+ */
+struct icc_node {
+ int id;
+ const char *name;
+ struct icc_node **links;
+ size_t num_links;
+
+ struct icc_provider *provider;
+ struct list_head node_list;
+ struct list_head search_list;
+ struct icc_node *reverse;
+ bool is_traversed;
+ struct hlist_head req_list;
+ u32 avg_bw;
+ u32 peak_bw;
+ void *data;
+};
+
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+
+struct icc_node *icc_node_create(int id);
+void icc_node_destroy(int id);
+int icc_link_create(struct icc_node *node, const int dst_id);
+int icc_link_destroy(struct icc_node *src, struct icc_node *dst);
+void icc_node_add(struct icc_node *node, struct icc_provider *provider);
+void icc_node_del(struct icc_node *node);
+int icc_provider_add(struct icc_provider *provider);
+int icc_provider_del(struct icc_provider *provider);
+
+#else
+
+static inline struct icc_node *icc_node_create(int id)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+void icc_node_destroy(int id)
+{
+}
+
+static inline int icc_link_create(struct icc_node *node, const int dst_id)
+{
+ return -ENOTSUPP;
+}
+
+int icc_link_destroy(struct icc_node *src, struct icc_node *dst)
+{
+ return -ENOTSUPP;
+}
+
+void icc_node_add(struct icc_node *node, struct icc_provider *provider)
+{
+}
+
+void icc_node_del(struct icc_node *node)
+{
+}
+
+static inline int icc_provider_add(struct icc_provider *provider)
+{
+ return -ENOTSUPP;
+}
+
+static inline int icc_provider_del(struct icc_provider *provider)
+{
+ return -ENOTSUPP;
+}
+
+#endif /* CONFIG_INTERCONNECT */
+
+#endif /* _LINUX_INTERCONNECT_PROVIDER_H */
diff --git a/include/linux/interconnect.h b/include/linux/interconnect.h
new file mode 100644
index 000000000000..ae6744da9bc2
--- /dev/null
+++ b/include/linux/interconnect.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef _LINUX_INTERCONNECT_H
+#define _LINUX_INTERCONNECT_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+struct icc_path;
+struct device;
+
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+
+struct icc_path *icc_get(struct device *dev, const int src_id,
+ const int dst_id);
+struct icc_path *of_icc_get(struct device *dev, const char *name);
+void icc_put(struct icc_path *path);
+int icc_set(struct icc_path *path, u32 avg_bw, u32 peak_bw);
+
+#else
+
+static inline struct icc_path *icc_get(struct device *dev, const int src_id,
+ const int dst_id)
+{
+ return NULL;
+}
+
+static inline struct icc_path *of_icc_get(struct device *dev,
+ const char *name)
+{
+ return NULL;
+}
+
+static inline void icc_put(struct icc_path *path)
+{
+}
+
+static inline int icc_set(struct icc_path *path, u32 avg_bw, u32 peak_bw)
+{
+ return 0;
+}
+
+#endif /* CONFIG_INTERCONNECT */
+
+#endif /* _LINUX_INTERCONNECT_H */