aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinaro CI <ci_notify@linaro.org>2018-09-07 09:29:45 +0000
committerLinaro CI <ci_notify@linaro.org>2018-09-07 09:29:45 +0000
commit7080268255ef13f793e378e9340340e3cf285688 (patch)
tree57b72329a37a4bd42d1e040de6ffeed53699ef05
parent398a5378bd892291ac156200f5e1f75e074983dc (diff)
parentc75eea0a5f080afeec7161c26ab240a04ee63bc0 (diff)
Merge remote-tracking branch 'apq8064-cpufreq/qcomlt-apq8064-cpufreq' into integration-linux-qcomltintegration-linux-qcomlt-20180910-012052-v4.19-rc2-190-g7080268255ef
-rw-r--r--Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt19
-rw-r--r--Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt44
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,hfpll.txt60
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,krait-cc.txt34
-rw-r--r--Documentation/devicetree/bindings/cpufreq/krait-cpufreq.txt363
-rw-r--r--arch/arm/boot/dts/qcom-apq8064.dtsi630
-rw-r--r--arch/arm/common/Kconfig3
-rw-r--r--arch/arm/common/Makefile1
-rw-r--r--arch/arm/common/krait-l2-accessors.c48
-rw-r--r--arch/arm/include/asm/krait-l2-accessors.h9
-rw-r--r--drivers/clk/qcom/Kconfig28
-rw-r--r--drivers/clk/qcom/Makefile5
-rw-r--r--drivers/clk/qcom/clk-hfpll.c244
-rw-r--r--drivers/clk/qcom/clk-hfpll.h44
-rw-r--r--drivers/clk/qcom/clk-krait.c126
-rw-r--r--drivers/clk/qcom/clk-krait.h40
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c82
-rw-r--r--drivers/clk/qcom/gcc-msm8960.c172
-rw-r--r--drivers/clk/qcom/hfpll.c96
-rw-r--r--drivers/clk/qcom/kpss-xcc.c87
-rw-r--r--drivers/clk/qcom/krait-cc.c397
-rw-r--r--drivers/cpufreq/Kconfig.arm10
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c5
-rw-r--r--drivers/cpufreq/qcom-cpufreq.c201
-rw-r--r--include/dt-bindings/clock/qcom,gcc-msm8960.h2
26 files changed, 2743 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
index 1333db9acfee..7f696362a4a1 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
@@ -21,10 +21,29 @@ PROPERTIES
the register region. An optional second element specifies
the base address and size of the alias register region.
+- clocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: reference to the pll parents.
+
+- clock-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "pll8_vote", "pxo".
+
+- clock-output-names:
+ Usage: optional
+ Value type: <string>
+ Definition: Name of the output clock. Typically acpuX_aux where X is a
+ CPU number starting at 0.
+
Example:
clock-controller@2088000 {
compatible = "qcom,kpss-acc-v2";
reg = <0x02088000 0x1000>,
<0x02008000 0x1000>;
+ clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>;
+ clock-names = "pll8_vote", "pxo";
+ clock-output-names = "acpu0_aux";
};
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
new file mode 100644
index 000000000000..e628758950e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
@@ -0,0 +1,44 @@
+Krait Processor Sub-system (KPSS) Global Clock Controller (GCC)
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: should be one of the following. The generic compatible
+ "qcom,kpss-gcc" should also be included.
+ "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc"
+ "qcom,kpss-gcc-apq8064", "qcom,kpss-gcc"
+ "qcom,kpss-gcc-msm8974", "qcom,kpss-gcc"
+ "qcom,kpss-gcc-msm8960", "qcom,kpss-gcc"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: base address and size of the register region
+
+- clocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: reference to the pll parents.
+
+- clock-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "pll8_vote", "pxo".
+
+- clock-output-names:
+ Usage: required
+ Value type: <string>
+ Definition: Name of the output clock. Typically acpu_l2_aux indicating
+ an L2 cache auxiliary clock.
+
+Example:
+
+ l2cc: clock-controller@2011000 {
+ compatible = "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc";
+ reg = <0x2011000 0x1000>;
+ clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>;
+ clock-names = "pll8_vote", "pxo";
+ clock-output-names = "acpu_l2_aux";
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,hfpll.txt b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt
new file mode 100644
index 000000000000..ec02a024424c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt
@@ -0,0 +1,60 @@
+High-Frequency PLL (HFPLL)
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>:
+ shall contain only one of the following. The generic
+ compatible "qcom,hfpll" should be also included.
+
+ "qcom,hfpll-ipq8064", "qcom,hfpll"
+ "qcom,hfpll-apq8064", "qcom,hfpll"
+ "qcom,hfpll-msm8974", "qcom,hfpll"
+ "qcom,hfpll-msm8960", "qcom,hfpll"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: address and size of HPLL registers. An optional second
+ element specifies the address and size of the alias
+ register region.
+
+- clocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: reference to the xo clock.
+
+- clock-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "xo".
+
+- clock-output-names:
+ Usage: required
+ Value type: <string>
+ Definition: Name of the PLL. Typically hfpllX where X is a CPU number
+ starting at 0. Otherwise hfpll_Y where Y is more specific
+ such as "l2".
+
+Example:
+
+1) An HFPLL for the L2 cache.
+
+ clock-controller@f9016000 {
+ compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
+ reg = <0xf9016000 0x30>;
+ clocks = <&xo_board>;
+ clock-names = "xo";
+ clock-output-names = "hfpll_l2";
+ };
+
+2) An HFPLL for CPU0. This HFPLL has the alias register region.
+
+ clock-controller@f908a000 {
+ compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
+ reg = <0xf908a000 0x30>, <0xf900a000 0x30>;
+ clocks = <&xo_board>;
+ clock-names = "xo";
+ clock-output-names = "hfpll0";
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
new file mode 100644
index 000000000000..030ba60dab08
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
@@ -0,0 +1,34 @@
+Krait Clock Controller
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,krait-cc-v1"
+ "qcom,krait-cc-v2"
+
+- #clock-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 1
+
+- clocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: reference to the clock parents of hfpll, secondary muxes.
+
+- clock-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb".
+
+Example:
+
+ kraitcc: clock-controller {
+ compatible = "qcom,krait-cc-v1";
+ clocks = <&hfpll0>, <&hfpll1>, <&acpu0_aux>, <&acpu1_aux>, <qsb>;
+ clock-names = "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb";
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/cpufreq/krait-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/krait-cpufreq.txt
new file mode 100644
index 000000000000..7b083c79a3aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/krait-cpufreq.txt
@@ -0,0 +1,363 @@
+QCOM KRAIT CPUFreq and OPP bindings
+===================================
+
+In Certain QCOM SoCs like ipq8064, apq8064, msm8960, msm8974
+that has KRAIT processors the voltage value of each OPP varies
+based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
+defines the voltage and current value based on the speed/pvs/version
+combination blown in the efuse. The qcom-cpufreq driver reads the efuse
+value from the SoC to provide the OPP framework with required information.
+This is used to determine the voltage and current value for each OPP of
+operating-points-v2 table when it is parsed by the OPP framework.
+
+Required properties:
+--------------------
+In 'cpus' nodes:
+- operating-points-v2: Phandle to the operating-points-v2 table to use.
+
+In 'operating-points-v2' table:
+- compatible: Should be
+ - 'operating-points-v2-krait-cpu' for ipq8064, apq8064, msm8960,
+ msm8974.
+- nvmem-cells: A phandle pointing to a nvmem-cells node representing the
+ efuse registers that has information about the
+ speedbin/pvs/version that is used to select the right
+ voltage/current value pair. Note that the length field of the
+ nvmem-cell is used to differentiate between format 'A' or 'B'
+ efuse settings. len of '4' bytes is for format 'A' and '8'
+ bytes for format 'B'. Please refer the for nvmem-cells
+ bindings Documentation/devicetree/bindings/nvmem/nvmem.txt
+ and also examples below for both the cases.
+Example 1:
+---------
+
+/* For arch/arm/boot/dts/apq8064.dtsi --> format 'A' */
+cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ CPU0: cpu@0 {
+ compatible = "qcom,krait";
+ enable-method = "qcom,kpss-acc-v1";
+ device_type = "cpu";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ qcom,acc = <&acc0>;
+ qcom,saw = <&saw0>;
+ cpu-idle-states = <&CPU_SPC>;
+ operating-points-v2 = <&cpu_opp_table>;
+ };
+};
+
+qfprom: qfprom@700000 {
+ compatible = "qcom,qfprom";
+ reg = <0x00700000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ pvs_efuse: pvs {
+ reg = <0xc0 0x4>;
+ };
+};
+
+cpu_opp_table: opp-table {
+ compatible = "operating-points-v2-krait-cpu";
+ nvmem-cells = <&pvs_efuse>;
+
+ /*
+ * Missing opp-shared property means CPUs switch DVFS states
+ * independently.
+ */
+
+ opp-918000000 {
+ opp-hz = /bits/ 64 <918000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1100000>;
+ opp-microvolt-speed0-pvs1-v0 = <1050000>;
+ opp-microvolt-speed0-pvs3-v0 = <1000000>;
+ opp-microvolt-speed0-pvs4-v0 = <975000>;
+ opp-microvolt-speed1-pvs0-v0 = <1025000>;
+ opp-microvolt-speed1-pvs1-v0 = <1000000>;
+ opp-microvolt-speed1-pvs2-v0 = <950000>;
+ opp-microvolt-speed1-pvs3-v0 = <925000>;
+ opp-microvolt-speed1-pvs4-v0 = <900000>;
+ opp-microvolt-speed1-pvs5-v0 = <900000>;
+ opp-microvolt-speed1-pvs6-v0 = <900000>;
+ opp-microvolt-speed2-pvs0-v0 = <975000>;
+ opp-microvolt-speed2-pvs1-v0 = <950000>;
+ opp-microvolt-speed2-pvs2-v0 = <925000>;
+ opp-microvolt-speed2-pvs3-v0 = <912500>;
+ opp-microvolt-speed2-pvs4-v0 = <900000>;
+ opp-microvolt-speed2-pvs5-v0 = <900000>;
+ opp-microvolt-speed2-pvs6-v0 = <900000>;
+ opp-microvolt-speed14-pvs0-v0 = <1025000>;
+ opp-microvolt-speed14-pvs1-v0 = <1000000>;
+ opp-microvolt-speed14-pvs2-v0 = <950000>;
+ opp-microvolt-speed14-pvs3-v0 = <925000>;
+ opp-microvolt-speed14-pvs4-v0 = <900000>;
+ opp-microvolt-speed14-pvs5-v0 = <900000>;
+ opp-microvolt-speed14-pvs6-v0 = <900000>;
+ };
+
+ opp-810000000 {
+ opp-hz = /bits/ 64 <810000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1075000>;
+ opp-microvolt-speed0-pvs1-v0 = <1025000>;
+ opp-microvolt-speed0-pvs3-v0 = <975000>;
+ opp-microvolt-speed0-pvs3-v0 = <962500>;
+ opp-microvolt-speed1-pvs0-v0 = <1000000>;
+ opp-microvolt-speed1-pvs1-v0 = <975000>;
+ opp-microvolt-speed1-pvs2-v0 = <937500>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <887500>;
+ opp-microvolt-speed1-pvs5-v0 = <887500>;
+ opp-microvolt-speed1-pvs6-v0 = <887500>;
+ opp-microvolt-speed2-pvs0-v0 = <962500>;
+ opp-microvolt-speed2-pvs1-v0 = <937500>;
+ opp-microvolt-speed2-pvs2-v0 = <912500>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <887500>;
+ opp-microvolt-speed2-pvs5-v0 = <887500>;
+ opp-microvolt-speed2-pvs6-v0 = <887500>;
+ opp-microvolt-speed14-pvs0-v0 = <1000000>;
+ opp-microvolt-speed14-pvs1-v0 = <975000>;
+ opp-microvolt-speed14-pvs2-v0 = <937500>;
+ opp-microvolt-speed14-pvs3-v0 = <900000>;
+ opp-microvolt-speed14-pvs4-v0 = <887500>;
+ opp-microvolt-speed14-pvs5-v0 = <887500>;
+ opp-microvolt-speed14-pvs6-v0 = <887500>;
+ };
+
+ opp-702000000 {
+ opp-hz = /bits/ 64 <702000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1025000>;
+ opp-microvolt-speed0-pvs1-v0 = <975000>;
+ opp-microvolt-speed0-pvs3-v0 = <925000>;
+ opp-microvolt-speed0-pvs3-v0 = <925000>;
+ opp-microvolt-speed1-pvs0-v0 = <962500>;
+ opp-microvolt-speed1-pvs1-v0 = <962500>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <950000>;
+ opp-microvolt-speed2-pvs1-v0 = <925000>;
+ opp-microvolt-speed2-pvs2-v0 = <900000>;
+ opp-microvolt-speed2-pvs3-v0 = 900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed14-pvs0-v0 = <962500>;
+ opp-microvolt-speed14-pvs1-v0 = <962500>;
+ opp-microvolt-speed14-pvs2-v0 = <925000>;
+ opp-microvolt-speed14-pvs3-v0 = <900000>;
+ opp-microvolt-speed14-pvs4-v0 = <875000>;
+ opp-microvolt-speed14-pvs5-v0 = <875000>;
+ opp-microvolt-speed14-pvs6-v0 = <875000>;
+ };
+
+ opp-594000000 {
+ opp-hz = /bits/ 64 <594000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1000000>;
+ opp-microvolt-speed0-pvs1-v0 = <950000>;
+ opp-microvolt-speed0-pvs3-v0 = <900000>;
+ opp-microvolt-speed0-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs0-v0 = <950000>;
+ opp-microvolt-speed1-pvs1-v0 = <950000>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <950000>;
+ opp-microvolt-speed2-pvs1-v0 = <925000>;
+ opp-microvolt-speed2-pvs2-v0 = <900000>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed14-pvs0-v0 = <950000>;
+ opp-microvolt-speed14-pvs1-v0 = <950000>;
+ opp-microvolt-speed14-pvs2-v0 = <925000>;
+ opp-microvolt-speed14-pvs3-v0 = <900000>;
+ opp-microvolt-speed14-pvs4-v0 = <875000>;
+ opp-microvolt-speed14-pvs5-v0 = <875000>;
+ opp-microvolt-speed14-pvs6-v0 = <875000>;
+ };
+
+ opp-486000000 {
+ opp-hz = /bits/ 64 <486000000>;
+ opp-microvolt-speed0-pvs0-v0 = <975000>;
+ opp-microvolt-speed0-pvs1-v0 = <925000>;
+ opp-microvolt-speed0-pvs3-v0 = <875000>;
+ opp-microvolt-speed0-pvs3-v0 = <875000>;
+ opp-microvolt-speed1-pvs0-v0 = <950000>;
+ opp-microvolt-speed1-pvs1-v0 = <950000>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <950000>;
+ opp-microvolt-speed2-pvs1-v0 = <925000>;
+ opp-microvolt-speed2-pvs2-v0 = <900000>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed14-pvs0-v0 = <950000>;
+ opp-microvolt-speed14-pvs1-v0 = <950000>;
+ opp-microvolt-speed14-pvs2-v0 = <925000>;
+ opp-microvolt-speed14-pvs3-v0 = <900000>;
+ opp-microvolt-speed14-pvs4-v0 = <875000>;
+ opp-microvolt-speed14-pvs5-v0 = <875000>;
+ opp-microvolt-speed14-pvs6-v0 = <875000>;
+ };
+
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-microvolt-speed0-pvs0-v0 = <950000>;
+ opp-microvolt-speed0-pvs1-v0 = <900000>;
+ opp-microvolt-speed0-pvs3-v0 = <850000>;
+ opp-microvolt-speed0-pvs3-v0 = <850000>;
+ opp-microvolt-speed1-pvs0-v0 = <950000>;
+ opp-microvolt-speed1-pvs1-v0 = <950000>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <950000>;
+ opp-microvolt-speed2-pvs1-v0 = <925000>;
+ opp-microvolt-speed2-pvs2-v0 = <900000>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed14-pvs0-v0 = <950000>;
+ opp-microvolt-speed14-pvs1-v0 = <950000>;
+ opp-microvolt-speed14-pvs2-v0 = <925000>;
+ opp-microvolt-speed14-pvs3-v0 = <900000>;
+ opp-microvolt-speed14-pvs4-v0 = <875000>;
+ opp-microvolt-speed14-pvs5-v0 = <875000>;
+ opp-microvolt-speed14-pvs6-v0 = <875000>;
+ };
+};
+
+EXAMPLE 2:
+---------
+/* For arch/arm/boot/dts/qcom-msm8974.dtsi--> format 'B' */
+
+qfprom: qfprom@700000 {
+ compatible = "qcom,qfprom";
+ reg = <0x00700000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ pvs_efuse: pvs {
+ reg = <0xc0 0x8>;
+ };
+};
+
+cpu_opp_table: opp-table {
+ compatible = "operating-points-v2-krait-cpu";
+ nvmem-cells = <&pvs_efuse>;
+
+ /*
+ * Missing opp-shared property means CPUs switch DVFS states
+ * independently.
+ */
+ opp-960000000 {
+ opp-hz = /bits/ 64 <960000000>;
+ opp-microvolt-speed0-pvs0-v0 = <915000>;
+ opp-microvolt-speed0-pvs1-v0 = <895000>;
+ opp-microvolt-speed0-pvs2-v0 = <875000>;
+ opp-microvolt-speed0-pvs3-v0 = <860000>;
+ opp-microvolt-speed0-pvs4-v0 = <850000>;
+ opp-microvolt-speed0-pvs5-v0 = <840000>;
+ opp-microvolt-speed0-pvs6-v0 = <830000>;
+ opp-microvolt-speed2-pvs0-v0 = <875000>;
+ opp-microvolt-speed2-pvs1-v0 = <860000>;
+ opp-microvolt-speed2-pvs2-v0 = <845000>;
+ opp-microvolt-speed2-pvs3-v0 = <830000>;
+ opp-microvolt-speed2-pvs4-v0 = <820000>;
+ opp-microvolt-speed2-pvs5-v0 = <810000>;
+ opp-microvolt-speed2-pvs6-v0 = <800000>;
+ opp-microvolt-speed1-pvs0-v0 = <840000>;
+ opp-microvolt-speed1-pvs1-v0 = <825000>;
+ opp-microvolt-speed1-pvs2-v0 = <810000>;
+ opp-microvolt-speed1-pvs3-v0 = <795000>;
+ opp-microvolt-speed1-pvs4-v0 = <785000>;
+ opp-microvolt-speed1-pvs5-v0 = <775000>;
+ opp-microvolt-speed1-pvs6-v0 = <765000>;
+
+ opp-microamp-speed0-pvs0-v0 = <252>;
+ opp-microamp-speed0-pvs1-v0 = <252>;
+ opp-microamp-speed0-pvs2-v0 = <252>;
+ opp-microamp-speed0-pvs3-v0 = <252>;
+ opp-microamp-speed0-pvs4-v0 = <252>;
+ opp-microamp-speed0-pvs5-v0 = <252>;
+ opp-microamp-speed0-pvs6-v0 = <252>;
+ opp-microamp-speed2-pvs0-v0 = <245>;
+ opp-microamp-speed2-pvs1-v0 = <245>;
+ opp-microamp-speed2-pvs2-v0 = <245>;
+ opp-microamp-speed2-pvs3-v0 = <245>;
+ opp-microamp-speed2-pvs4-v0 = <245>;
+ opp-microamp-speed2-pvs5-v0 = <245>;
+ opp-microamp-speed2-pvs6-v0 = <245>;
+ opp-microamp-speed1-pvs0-v0 = <242>;
+ opp-microamp-speed1-pvs1-v0 = <242>;
+ opp-microamp-speed1-pvs2-v0 = <242>;
+ opp-microamp-speed1-pvs3-v0 = <242>;
+ opp-microamp-speed1-pvs4-v0 = <242>;
+ opp-microamp-speed1-pvs5-v0 = <242>;
+ opp-microamp-speed1-pvs6-v0 = <242>;
+ };
+
+ opp-883200000 {
+ opp-hz = /bits/ 64 <883200000>;
+ opp-microvolt-speed0-pvs0-v0 = <900000>;
+ opp-microvolt-speed0-pvs1-v0 = <885000>;
+ opp-microvolt-speed0-pvs2-v0 = <865000>;
+ opp-microvolt-speed0-pvs3-v0 = <850000>;
+ opp-microvolt-speed0-pvs4-v0 = <840000>;
+ opp-microvolt-speed0-pvs5-v0 = <830000>;
+ opp-microvolt-speed0-pvs6-v0 = <820000>;
+ opp-microvolt-speed2-pvs0-v0 = <865000>;
+ opp-microvolt-speed2-pvs1-v0 = <850000>;
+ opp-microvolt-speed2-pvs2-v0 = <835000>;
+ opp-microvolt-speed2-pvs3-v0 = <820000>;
+ opp-microvolt-speed2-pvs4-v0 = <810000>;
+ opp-microvolt-speed2-pvs5-v0 = <800000>;
+ opp-microvolt-speed2-pvs6-v0 = <790000>;
+ opp-microvolt-speed1-pvs0-v0 = <830000>;
+ opp-microvolt-speed1-pvs1-v0 = <815000>;
+ opp-microvolt-speed1-pvs2-v0 = <800000>;
+ opp-microvolt-speed1-pvs3-v0 = <785000>;
+ opp-microvolt-speed1-pvs4-v0 = <775000>;
+ opp-microvolt-speed1-pvs5-v0 = <765000>;
+ opp-microvolt-speed1-pvs6-v0 = <755000>;
+
+ opp-microamp-speed0-pvs0-v0 = <229>;
+ opp-microamp-speed0-pvs1-v0 = <229>;
+ opp-microamp-speed0-pvs2-v0 = <229>;
+ opp-microamp-speed0-pvs3-v0 = <229>;
+ opp-microamp-speed0-pvs4-v0 = <229>;
+ opp-microamp-speed0-pvs5-v0 = <229>;
+ opp-microamp-speed0-pvs6-v0 = <229>;
+ opp-microamp-speed2-pvs0-v0 = <223>;
+ opp-microamp-speed2-pvs1-v0 = <223>;
+ opp-microamp-speed2-pvs2-v0 = <223>;
+ opp-microamp-speed2-pvs3-v0 = <223>;
+ opp-microamp-speed2-pvs4-v0 = <223>;
+ opp-microamp-speed2-pvs5-v0 = <223>;
+ opp-microamp-speed2-pvs6-v0 = <223>;
+ opp-microamp-speed1-pvs0-v0 = <221>;
+ opp-microamp-speed1-pvs1-v0 = <221>;
+ opp-microamp-speed1-pvs2-v0 = <221>;
+ opp-microamp-speed1-pvs3-v0 = <221>;
+ opp-microamp-speed1-pvs4-v0 = <221>;
+ opp-microamp-speed1-pvs5-v0 = <221>;
+ opp-microamp-speed1-pvs6-v0 = <221>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index 4a99c9255104..640ebb2b8c6a 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -9,6 +9,8 @@
#include <dt-bindings/soc/qcom,gsbi.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
+
/ {
model = "Qualcomm APQ8064";
compatible = "qcom,apq8064";
@@ -43,6 +45,14 @@
qcom,acc = <&acc0>;
qcom,saw = <&saw0>;
cpu-idle-states = <&CPU_SPC>;
+ clocks = <&kraitcc 0>, <&kraitcc 4>;
+ clock-names = "cpu", "l2";
+ clock-latency = <100000>;
+ cpu-supply = <&saw0_regulator>;
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
+ operating-points-v2 = <&cpu_opp_table>;
};
CPU1: cpu@1 {
@@ -54,6 +64,14 @@
qcom,acc = <&acc1>;
qcom,saw = <&saw1>;
cpu-idle-states = <&CPU_SPC>;
+ clocks = <&kraitcc 1>, <&kraitcc 4>;
+ clock-names = "cpu", "l2";
+ clock-latency = <100000>;
+ cpu-supply = <&saw1_regulator>;
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
+ operating-points-v2 = <&cpu_opp_table>;
};
CPU2: cpu@2 {
@@ -65,6 +83,14 @@
qcom,acc = <&acc2>;
qcom,saw = <&saw2>;
cpu-idle-states = <&CPU_SPC>;
+ clocks = <&kraitcc 2>, <&kraitcc 4>;
+ clock-names = "cpu", "l2";
+ clock-latency = <100000>;
+ cpu-supply = <&saw2_regulator>;
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
+ operating-points-v2 = <&cpu_opp_table>;
};
CPU3: cpu@3 {
@@ -76,6 +102,14 @@
qcom,acc = <&acc3>;
qcom,saw = <&saw3>;
cpu-idle-states = <&CPU_SPC>;
+ clocks = <&kraitcc 3>, <&kraitcc 4>;
+ clock-names = "cpu", "l2";
+ clock-latency = <100000>;
+ cpu-supply = <&saw3_regulator>;
+ cooling-min-level = <0>;
+ cooling-max-level = <7>;
+ #cooling-cells = <2>;
+ operating-points-v2 = <&cpu_opp_table>;
};
L2: l2-cache {
@@ -83,6 +117,10 @@
cache-level = <2>;
};
+ l2-clock {
+ l2-rates = <384000000 972000000 1188000000>;
+ };
+
idle-states {
CPU_SPC: spc {
compatible = "qcom,idle-state-spc",
@@ -114,6 +152,13 @@
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal1 {
@@ -135,6 +180,13 @@
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal2 {
@@ -156,6 +208,13 @@
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert2>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal3 {
@@ -177,6 +236,13 @@
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert3>;
+ cooling-device = <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
};
};
@@ -185,6 +251,11 @@
interrupts = <1 10 0x304>;
};
+ kraitcc: clock-controller {
+ compatible = "qcom,krait-cc-v1";
+ #clock-cells = <1>;
+ };
+
clocks {
cxo_board: cxo_board {
compatible = "fixed-clock";
@@ -333,6 +404,514 @@
<&xoadc 0x00 0x0e>; /* Charger temperature */
};
+ cpu_opp_table: opp-table {
+ compatible = "operating-points-v2-krait-cpu";
+ nvmem-cells = <&pvs_efuse>;
+
+ /*
+ * Missing opp-shared property means CPUs switch DVFS states
+ * independently.
+ */
+
+ opp-391500000 {
+ opp-hz = /bits/ 64 <391500000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <950000>;
+ opp-microvolt-speed0-pvs1-v0 = <900000>;
+ opp-microvolt-speed0-pvs3-v0 = <850000>;
+ opp-microvolt-speed0-pvs4-v0 = <850000>;
+ opp-microvolt-speed1-pvs0-v0 = <950000>;
+ opp-microvolt-speed1-pvs1-v0 = <950000>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <950000>;
+ opp-microvolt-speed2-pvs1-v0 = <950000>;
+ opp-microvolt-speed2-pvs2-v0 = <925000>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed7-pvs0-v0 = <950000>;
+ opp-microvolt-speed7-pvs1-v0 = <925000>;
+ opp-microvolt-speed7-pvs2-v0 = <900000>;
+ opp-microvolt-speed7-pvs3-v0 = <900000>;
+ opp-microvolt-speed7-pvs4-v0 = <875000>;
+ opp-microvolt-speed7-pvs5-v0 = <875000>;
+ opp-microvolt-speed7-pvs6-v0 = <875000>;
+ };
+
+ opp-432000000 {
+ opp-hz = /bits/ 64 <432000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <975000>;
+ opp-microvolt-speed0-pvs1-v0 = <925000>;
+ opp-microvolt-speed0-pvs3-v0 = <875000>;
+ opp-microvolt-speed0-pvs4-v0 = <875000>;
+ };
+
+ opp-486000000 {
+ opp-hz = /bits/ 64 <486000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <975000>;
+ opp-microvolt-speed0-pvs1-v0 = <925000>;
+ opp-microvolt-speed0-pvs3-v0 = <875000>;
+ opp-microvolt-speed0-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs0-v0 = <950000>;
+ opp-microvolt-speed1-pvs1-v0 = <950000>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <950000>;
+ opp-microvolt-speed2-pvs1-v0 = <950000>;
+ opp-microvolt-speed2-pvs2-v0 = <925000>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed7-pvs0-v0 = <950000>;
+ opp-microvolt-speed7-pvs1-v0 = <925000>;
+ opp-microvolt-speed7-pvs2-v0 = <900000>;
+ opp-microvolt-speed7-pvs3-v0 = <900000>;
+ opp-microvolt-speed7-pvs4-v0 = <875000>;
+ opp-microvolt-speed7-pvs5-v0 = <875000>;
+ opp-microvolt-speed7-pvs6-v0 = <875000>;
+ };
+
+ opp-540000000 {
+ opp-hz = /bits/ 64 <540000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1000000>;
+ opp-microvolt-speed0-pvs1-v0 = <950000>;
+ opp-microvolt-speed0-pvs3-v0 = <900000>;
+ opp-microvolt-speed0-pvs4-v0 = <900000>;
+ };
+
+ opp-594000000 {
+ opp-hz = /bits/ 64 <594000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1000000>;
+ opp-microvolt-speed0-pvs1-v0 = <950000>;
+ opp-microvolt-speed0-pvs3-v0 = <900000>;
+ opp-microvolt-speed0-pvs4-v0 = <900000>;
+ opp-microvolt-speed1-pvs0-v0 = <950000>;
+ opp-microvolt-speed1-pvs1-v0 = <950000>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <950000>;
+ opp-microvolt-speed2-pvs1-v0 = <950000>;
+ opp-microvolt-speed2-pvs2-v0 = <925000>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed7-pvs0-v0 = <950000>;
+ opp-microvolt-speed7-pvs1-v0 = <925000>;
+ opp-microvolt-speed7-pvs2-v0 = <900000>;
+ opp-microvolt-speed7-pvs3-v0 = <900000>;
+ opp-microvolt-speed7-pvs4-v0 = <875000>;
+ opp-microvolt-speed7-pvs5-v0 = <875000>;
+ opp-microvolt-speed7-pvs6-v0 = <875000>;
+ };
+
+ opp-648000000 {
+ opp-hz = /bits/ 64 <648000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1025000>;
+ opp-microvolt-speed0-pvs1-v0 = <975000>;
+ opp-microvolt-speed0-pvs3-v0 = <925000>;
+ opp-microvolt-speed0-pvs4-v0 = <925000>;
+ };
+
+ opp-702000000 {
+ opp-hz = /bits/ 64 <702000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1025000>;
+ opp-microvolt-speed0-pvs1-v0 = <975000>;
+ opp-microvolt-speed0-pvs3-v0 = <925000>;
+ opp-microvolt-speed0-pvs4-v0 = <925000>;
+ opp-microvolt-speed1-pvs0-v0 = <962500>;
+ opp-microvolt-speed1-pvs1-v0 = <962500>;
+ opp-microvolt-speed1-pvs2-v0 = <925000>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <875000>;
+ opp-microvolt-speed1-pvs5-v0 = <875000>;
+ opp-microvolt-speed1-pvs6-v0 = <875000>;
+ opp-microvolt-speed2-pvs0-v0 = <962500>;
+ opp-microvolt-speed2-pvs1-v0 = <962500>;
+ opp-microvolt-speed2-pvs2-v0 = <925000>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <875000>;
+ opp-microvolt-speed2-pvs5-v0 = <875000>;
+ opp-microvolt-speed2-pvs6-v0 = <875000>;
+ opp-microvolt-speed7-pvs0-v0 = <950000>;
+ opp-microvolt-speed7-pvs1-v0 = <925000>;
+ opp-microvolt-speed7-pvs2-v0 = <900000>;
+ opp-microvolt-speed7-pvs3-v0 = <900000>;
+ opp-microvolt-speed7-pvs4-v0 = <875000>;
+ opp-microvolt-speed7-pvs5-v0 = <875000>;
+ opp-microvolt-speed7-pvs6-v0 = <875000>;
+ };
+
+ opp-756000000 {
+ opp-hz = /bits/ 64 <756000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1075000>;
+ opp-microvolt-speed0-pvs1-v0 = <1025000>;
+ opp-microvolt-speed0-pvs3-v0 = <975000>;
+ opp-microvolt-speed0-pvs4-v0 = <962500>;
+ };
+
+ opp-810000000 {
+ opp-hz = /bits/ 64 <810000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1075000>;
+ opp-microvolt-speed0-pvs1-v0 = <1025000>;
+ opp-microvolt-speed0-pvs3-v0 = <975000>;
+ opp-microvolt-speed0-pvs4-v0 = <962500>;
+ opp-microvolt-speed1-pvs0-v0 = <1000000>;
+ opp-microvolt-speed1-pvs1-v0 = <975000>;
+ opp-microvolt-speed1-pvs2-v0 = <937500>;
+ opp-microvolt-speed1-pvs3-v0 = <900000>;
+ opp-microvolt-speed1-pvs4-v0 = <887500>;
+ opp-microvolt-speed1-pvs5-v0 = <887500>;
+ opp-microvolt-speed1-pvs6-v0 = <887500>;
+ opp-microvolt-speed2-pvs0-v0 = <1000000>;
+ opp-microvolt-speed2-pvs1-v0 = <975000>;
+ opp-microvolt-speed2-pvs2-v0 = <937500>;
+ opp-microvolt-speed2-pvs3-v0 = <900000>;
+ opp-microvolt-speed2-pvs4-v0 = <887500>;
+ opp-microvolt-speed2-pvs5-v0 = <887500>;
+ opp-microvolt-speed2-pvs6-v0 = <887500>;
+ opp-microvolt-speed7-pvs0-v0 = <962500>;
+ opp-microvolt-speed7-pvs1-v0 = <937500>;
+ opp-microvolt-speed7-pvs2-v0 = <912500>;
+ opp-microvolt-speed7-pvs3-v0 = <900000>;
+ opp-microvolt-speed7-pvs4-v0 = <887500>;
+ opp-microvolt-speed7-pvs5-v0 = <887500>;
+ opp-microvolt-speed7-pvs6-v0 = <887500>;
+ };
+
+ opp-864000000 {
+ opp-hz = /bits/ 64 <864000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1100000>;
+ opp-microvolt-speed0-pvs1-v0 = <1050000>;
+ opp-microvolt-speed0-pvs3-v0 = <1000000>;
+ opp-microvolt-speed0-pvs4-v0 = <975000>;
+ };
+
+ opp-918000000 {
+ opp-hz = /bits/ 64 <918000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1100000>;
+ opp-microvolt-speed0-pvs1-v0 = <1050000>;
+ opp-microvolt-speed0-pvs3-v0 = <1000000>;
+ opp-microvolt-speed0-pvs4-v0 = <975000>;
+ opp-microvolt-speed1-pvs0-v0 = <1025000>;
+ opp-microvolt-speed1-pvs1-v0 = <1000000>;
+ opp-microvolt-speed1-pvs2-v0 = <950000>;
+ opp-microvolt-speed1-pvs3-v0 = <925000>;
+ opp-microvolt-speed1-pvs4-v0 = <900000>;
+ opp-microvolt-speed1-pvs5-v0 = <900000>;
+ opp-microvolt-speed1-pvs6-v0 = <900000>;
+ opp-microvolt-speed2-pvs0-v0 = <1025000>;
+ opp-microvolt-speed2-pvs1-v0 = <1000000>;
+ opp-microvolt-speed2-pvs2-v0 = <950000>;
+ opp-microvolt-speed2-pvs3-v0 = <925000>;
+ opp-microvolt-speed2-pvs4-v0 = <900000>;
+ opp-microvolt-speed2-pvs5-v0 = <900000>;
+ opp-microvolt-speed2-pvs6-v0 = <900000>;
+ opp-microvolt-speed7-pvs0-v0 = <975000>;
+ opp-microvolt-speed7-pvs1-v0 = <950000>;
+ opp-microvolt-speed7-pvs2-v0 = <925000>;
+ opp-microvolt-speed7-pvs3-v0 = <912500>;
+ opp-microvolt-speed7-pvs4-v0 = <900000>;
+ opp-microvolt-speed7-pvs5-v0 = <900000>;
+ opp-microvolt-speed7-pvs6-v0 = <900000>;
+ };
+
+ opp-972000000 {
+ opp-hz = /bits/ 64 <972000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1125000>;
+ opp-microvolt-speed0-pvs1-v0 = <1075000>;
+ opp-microvolt-speed0-pvs3-v0 = <1025000>;
+ opp-microvolt-speed0-pvs4-v0 = <1000000>;
+ };
+
+ opp-1026000000 {
+ opp-hz = /bits/ 64 <1026000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1125000>;
+ opp-microvolt-speed0-pvs1-v0 = <1075000>;
+ opp-microvolt-speed0-pvs3-v0 = <1025000>;
+ opp-microvolt-speed0-pvs4-v0 = <1000000>;
+ opp-microvolt-speed1-pvs0-v0 = <1037500>;
+ opp-microvolt-speed1-pvs1-v0 = <1012500>;
+ opp-microvolt-speed1-pvs2-v0 = <975000>;
+ opp-microvolt-speed1-pvs3-v0 = <950000>;
+ opp-microvolt-speed1-pvs4-v0 = <925000>;
+ opp-microvolt-speed1-pvs5-v0 = <925000>;
+ opp-microvolt-speed1-pvs6-v0 = <925000>;
+ opp-microvolt-speed2-pvs0-v0 = <1037500>;
+ opp-microvolt-speed2-pvs1-v0 = <1012500>;
+ opp-microvolt-speed2-pvs2-v0 = <975000>;
+ opp-microvolt-speed2-pvs3-v0 = <950000>;
+ opp-microvolt-speed2-pvs4-v0 = <925000>;
+ opp-microvolt-speed2-pvs5-v0 = <925000>;
+ opp-microvolt-speed2-pvs6-v0 = <925000>;
+ opp-microvolt-speed7-pvs0-v0 = <1000000>;
+ opp-microvolt-speed7-pvs1-v0 = <975000>;
+ opp-microvolt-speed7-pvs2-v0 = <950000>;
+ opp-microvolt-speed7-pvs3-v0 = <937500>;
+ opp-microvolt-speed7-pvs4-v0 = <925000>;
+ opp-microvolt-speed7-pvs5-v0 = <925000>;
+ opp-microvolt-speed7-pvs6-v0 = <925000>;
+ };
+
+ opp-1080000000 {
+ opp-hz = /bits/ 64 <1080000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1175000>;
+ opp-microvolt-speed0-pvs1-v0 = <1125000>;
+ opp-microvolt-speed0-pvs3-v0 = <1075000>;
+ opp-microvolt-speed0-pvs4-v0 = <1050000>;
+ };
+
+ opp-1134000000 {
+ opp-hz = /bits/ 64 <1134000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1175000>;
+ opp-microvolt-speed0-pvs1-v0 = <1125000>;
+ opp-microvolt-speed0-pvs3-v0 = <1075000>;
+ opp-microvolt-speed0-pvs4-v0 = <1050000>;
+ opp-microvolt-speed1-pvs0-v0 = <1075000>;
+ opp-microvolt-speed1-pvs1-v0 = <1037500>;
+ opp-microvolt-speed1-pvs2-v0 = <1000000>;
+ opp-microvolt-speed1-pvs3-v0 = <975000>;
+ opp-microvolt-speed1-pvs4-v0 = <950000>;
+ opp-microvolt-speed1-pvs5-v0 = <937500>;
+ opp-microvolt-speed1-pvs6-v0 = <937500>;
+ opp-microvolt-speed2-pvs0-v0 = <1075000>;
+ opp-microvolt-speed2-pvs1-v0 = <1037500>;
+ opp-microvolt-speed2-pvs2-v0 = <1000000>;
+ opp-microvolt-speed2-pvs3-v0 = <975000>;
+ opp-microvolt-speed2-pvs4-v0 = <950000>;
+ opp-microvolt-speed2-pvs5-v0 = <937500>;
+ opp-microvolt-speed2-pvs6-v0 = <937500>;
+ opp-microvolt-speed7-pvs0-v0 = <1025000>;
+ opp-microvolt-speed7-pvs1-v0 = <1000000>;
+ opp-microvolt-speed7-pvs2-v0 = <975000>;
+ opp-microvolt-speed7-pvs3-v0 = <962500>;
+ opp-microvolt-speed7-pvs4-v0 = <950000>;
+ opp-microvolt-speed7-pvs5-v0 = <937500>;
+ opp-microvolt-speed7-pvs6-v0 = <937500>;
+ };
+
+ opp-1188000000 {
+ opp-hz = /bits/ 64 <1188000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1200000>;
+ opp-microvolt-speed0-pvs1-v0 = <1150000>;
+ opp-microvolt-speed0-pvs3-v0 = <1100000>;
+ opp-microvolt-speed0-pvs4-v0 = <1075000>;
+ };
+
+ opp-1242000000 {
+ opp-hz = /bits/ 64 <1242000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1200000>;
+ opp-microvolt-speed0-pvs1-v0 = <1150000>;
+ opp-microvolt-speed0-pvs3-v0 = <1100000>;
+ opp-microvolt-speed0-pvs4-v0 = <1075000>;
+ opp-microvolt-speed1-pvs0-v0 = <1087500>;
+ opp-microvolt-speed1-pvs1-v0 = <1050000>;
+ opp-microvolt-speed1-pvs2-v0 = <1012500>;
+ opp-microvolt-speed1-pvs3-v0 = <987500>;
+ opp-microvolt-speed1-pvs4-v0 = <962500>;
+ opp-microvolt-speed1-pvs5-v0 = <950000>;
+ opp-microvolt-speed1-pvs6-v0 = <950000>;
+ opp-microvolt-speed2-pvs0-v0 = <1087500>;
+ opp-microvolt-speed2-pvs1-v0 = <1050000>;
+ opp-microvolt-speed2-pvs2-v0 = <1012500>;
+ opp-microvolt-speed2-pvs3-v0 = <987500>;
+ opp-microvolt-speed2-pvs4-v0 = <962500>;
+ opp-microvolt-speed2-pvs5-v0 = <950000>;
+ opp-microvolt-speed2-pvs6-v0 = <950000>;
+ opp-microvolt-speed7-pvs0-v0 = <1037500>;
+ opp-microvolt-speed7-pvs1-v0 = <1012500>;
+ opp-microvolt-speed7-pvs2-v0 = <987500>;
+ opp-microvolt-speed7-pvs3-v0 = <975000>;
+ opp-microvolt-speed7-pvs4-v0 = <962500>;
+ opp-microvolt-speed7-pvs5-v0 = <950000>;
+ opp-microvolt-speed7-pvs6-v0 = <950000>;
+ };
+
+ opp-1296000000 {
+ opp-hz = /bits/ 64 <1296000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1225000>;
+ opp-microvolt-speed0-pvs1-v0 = <1175000>;
+ opp-microvolt-speed0-pvs3-v0 = <1125000>;
+ opp-microvolt-speed0-pvs4-v0 = <1100000>;
+ };
+
+ opp-1350000000 {
+ opp-hz = /bits/ 64 <1350000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1225000>;
+ opp-microvolt-speed0-pvs1-v0 = <1175000>;
+ opp-microvolt-speed0-pvs3-v0 = <1125000>;
+ opp-microvolt-speed0-pvs4-v0 = <1100000>;
+ opp-microvolt-speed1-pvs0-v0 = <1125000>;
+ opp-microvolt-speed1-pvs1-v0 = <1087500>;
+ opp-microvolt-speed1-pvs2-v0 = <1037500>;
+ opp-microvolt-speed1-pvs3-v0 = <1000000>;
+ opp-microvolt-speed1-pvs4-v0 = <975000>;
+ opp-microvolt-speed1-pvs5-v0 = <962500>;
+ opp-microvolt-speed1-pvs6-v0 = <962500>;
+ opp-microvolt-speed2-pvs0-v0 = <1125000>;
+ opp-microvolt-speed2-pvs1-v0 = <1087500>;
+ opp-microvolt-speed2-pvs2-v0 = <1037500>;
+ opp-microvolt-speed2-pvs3-v0 = <1000000>;
+ opp-microvolt-speed2-pvs4-v0 = <975000>;
+ opp-microvolt-speed2-pvs5-v0 = <962500>;
+ opp-microvolt-speed2-pvs6-v0 = <962500>;
+ opp-microvolt-speed7-pvs0-v0 = <1062500>;
+ opp-microvolt-speed7-pvs1-v0 = <1037500>;
+ opp-microvolt-speed7-pvs2-v0 = <1012500>;
+ opp-microvolt-speed7-pvs3-v0 = <1000000>;
+ opp-microvolt-speed7-pvs4-v0 = <975000>;
+ opp-microvolt-speed7-pvs5-v0 = <962500>;
+ opp-microvolt-speed7-pvs6-v0 = <962500>;
+ };
+
+ opp-1404000000 {
+ opp-hz = /bits/ 64 <1404000000>;
+ opp-supported-hw = <0x01>;
+ opp-microvolt-speed0-pvs0-v0 = <1237500>;
+ opp-microvolt-speed0-pvs1-v0 = <1187500>;
+ opp-microvolt-speed0-pvs3-v0 = <1137500>;
+ opp-microvolt-speed0-pvs4-v0 = <1112500>;
+ };
+
+ opp-1458000000 {
+ opp-hz = /bits/ 64 <1458000000>;
+ opp-supported-hw = <0x87>;
+ opp-microvolt-speed0-pvs0-v0 = <1237500>;
+ opp-microvolt-speed0-pvs1-v0 = <1187500>;
+ opp-microvolt-speed0-pvs3-v0 = <1137500>;
+ opp-microvolt-speed0-pvs4-v0 = <1112500>;
+ opp-microvolt-speed1-pvs0-v0 = <1150000>;
+ opp-microvolt-speed1-pvs1-v0 = <1112500>;
+ opp-microvolt-speed1-pvs2-v0 = <1075000>;
+ opp-microvolt-speed1-pvs3-v0 = <1037500>;
+ opp-microvolt-speed1-pvs4-v0 = <1000000>;
+ opp-microvolt-speed1-pvs5-v0 = <987500>;
+ opp-microvolt-speed1-pvs6-v0 = <975000>;
+ opp-microvolt-speed2-pvs0-v0 = <1150000>;
+ opp-microvolt-speed2-pvs1-v0 = <1112500>;
+ opp-microvolt-speed2-pvs2-v0 = <1075000>;
+ opp-microvolt-speed2-pvs3-v0 = <1037500>;
+ opp-microvolt-speed2-pvs4-v0 = <1000000>;
+ opp-microvolt-speed2-pvs5-v0 = <987500>;
+ opp-microvolt-speed2-pvs6-v0 = <975000>;
+ opp-microvolt-speed7-pvs0-v0 = <1110000>;
+ opp-microvolt-speed7-pvs1-v0 = <1075000>;
+ opp-microvolt-speed7-pvs2-v0 = <1050000>;
+ opp-microvolt-speed7-pvs3-v0 = <1025000>;
+ opp-microvolt-speed7-pvs4-v0 = <1000000>;
+ opp-microvolt-speed7-pvs5-v0 = <987500>;
+ opp-microvolt-speed7-pvs6-v0 = <975000>;
+ };
+
+ opp-1512000000 {
+ opp-hz = /bits/ 64 <1512000000>;
+ opp-supported-hw = <0x03>;
+ opp-microvolt-speed0-pvs0-v0 = <1250000>;
+ opp-microvolt-speed0-pvs1-v0 = <1200000>;
+ opp-microvolt-speed0-pvs3-v0 = <1150000>;
+ opp-microvolt-speed0-pvs4-v0 = <1125000>;
+ opp-microvolt-speed1-pvs0-v0 = <1162500>;
+ opp-microvolt-speed1-pvs1-v0 = <1125000>;
+ opp-microvolt-speed1-pvs2-v0 = <1087500>;
+ opp-microvolt-speed1-pvs3-v0 = <1050000>;
+ opp-microvolt-speed1-pvs4-v0 = <1012500>;
+ opp-microvolt-speed1-pvs5-v0 = <1000000>;
+ opp-microvolt-speed1-pvs6-v0 = <987500>;
+ };
+
+ opp-1566000000 {
+ opp-hz = /bits/ 64 <1566000000>;
+ opp-supported-hw = <0x84>;
+ opp-microvolt-speed2-pvs0-v0 = <1175000>;
+ opp-microvolt-speed2-pvs1-v0 = <1150000>;
+ opp-microvolt-speed2-pvs2-v0 = <1100000>;
+ opp-microvolt-speed2-pvs3-v0 = <1062500>;
+ opp-microvolt-speed2-pvs4-v0 = <1037500>;
+ opp-microvolt-speed2-pvs5-v0 = <1012500>;
+ opp-microvolt-speed2-pvs6-v0 = <1000000>;
+ opp-microvolt-speed7-pvs0-v0 = <1125000>;
+ opp-microvolt-speed7-pvs1-v0 = <1100000>;
+ opp-microvolt-speed7-pvs2-v0 = <1075000>;
+ opp-microvolt-speed7-pvs3-v0 = <1050000>;
+ opp-microvolt-speed7-pvs4-v0 = <1037500>;
+ opp-microvolt-speed7-pvs5-v0 = <1012500>;
+ opp-microvolt-speed7-pvs6-v0 = <1000000>;
+ };
+
+ opp-1674000000 {
+ opp-hz = /bits/ 64 <1674000000>;
+ opp-supported-hw = <0x84>;
+ opp-microvolt-speed2-pvs0-v0 = <1225000>;
+ opp-microvolt-speed2-pvs1-v0 = <1187500>;
+ opp-microvolt-speed2-pvs2-v0 = <1137500>;
+ opp-microvolt-speed2-pvs3-v0 = <1100000>;
+ opp-microvolt-speed2-pvs4-v0 = <1075000>;
+ opp-microvolt-speed2-pvs5-v0 = <1050000>;
+ opp-microvolt-speed2-pvs6-v0 = <1025000>;
+ opp-microvolt-speed7-pvs0-v0 = <1175000>;
+ opp-microvolt-speed7-pvs1-v0 = <1137500>;
+ opp-microvolt-speed7-pvs2-v0 = <1112500>;
+ opp-microvolt-speed7-pvs3-v0 = <1087500>;
+ opp-microvolt-speed7-pvs4-v0 = <1075000>;
+ opp-microvolt-speed7-pvs5-v0 = <1050000>;
+ opp-microvolt-speed7-pvs6-v0 = <1025000>;
+ };
+
+ opp-1728000000 {
+ opp-hz = /bits/ 64 <1728000000>;
+ opp-supported-hw = <0x04>;
+ opp-microvolt-speed2-pvs0-v0 = <1250000>;
+ opp-microvolt-speed2-pvs1-v0 = <1200000>;
+ opp-microvolt-speed2-pvs2-v0 = <1162500>;
+ opp-microvolt-speed2-pvs3-v0 = <1125000>;
+ opp-microvolt-speed2-pvs4-v0 = <1100000>;
+ opp-microvolt-speed2-pvs5-v0 = <1075000>;
+ opp-microvolt-speed2-pvs6-v0 = <1050000>;
+ };
+
+ opp-1782000000 {
+ opp-hz = /bits/ 64 <1782000000>;
+ opp-supported-hw = <0x80>;
+ opp-microvolt-speed7-pvs0-v0 = <1225000>;
+ opp-microvolt-speed7-pvs1-v0 = <1187500>;
+ opp-microvolt-speed7-pvs2-v0 = <1162500>;
+ opp-microvolt-speed7-pvs3-v0 = <1137500>;
+ opp-microvolt-speed7-pvs4-v0 = <1112500>;
+ opp-microvolt-speed7-pvs5-v0 = <1087500>;
+ opp-microvolt-speed7-pvs6-v0 = <1062500>;
+ };
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -399,27 +978,59 @@
};
saw0: power-controller@2089000 {
- compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
+ compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2", "syscon", "simple-mfd";
reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
- regulator;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ saw0_regulator: regulator@2089000 {
+ compatible = "qcom,apq8064-saw2-v1.1-regulator";
+ regulator-always-on;
+ regulator-min-microvolt = <825000>;
+ regulator-max-microvolt = <1250000>;
+ };
};
saw1: power-controller@2099000 {
- compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
+ compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2", "syscon", "simple-mfd";
reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
- regulator;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ saw1_regulator: regulator@2099000 {
+ compatible = "qcom,apq8064-saw2-v1.1-regulator";
+ regulator-always-on;
+ regulator-min-microvolt = <825000>;
+ regulator-max-microvolt = <1250000>;
+ };
};
saw2: power-controller@20a9000 {
- compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
+ compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2", "syscon", "simple-mfd";
reg = <0x020a9000 0x1000>, <0x02009000 0x1000>;
- regulator;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ saw2_regulator: regulator@20a9000 {
+ compatible = "qcom,apq8064-saw2-v1.1-regulator";
+ regulator-always-on;
+ regulator-min-microvolt = <825000>;
+ regulator-max-microvolt = <1250000>;
+ };
};
saw3: power-controller@20b9000 {
- compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
+ compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2", "syscon", "simple-mfd";
reg = <0x020b9000 0x1000>, <0x02009000 0x1000>;
- regulator;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ saw3_regulator: regulator@20b9000 {
+ compatible = "qcom,apq8064-saw2-v1.1-regulator";
+ regulator-always-on;
+ regulator-min-microvolt = <825000>;
+ regulator-max-microvolt = <1250000>;
+ };
};
sps_sic_non_secure: sps-sic-non-secure@12100000 {
@@ -852,6 +1463,9 @@
tsens_backup: backup_calib {
reg = <0x414 0x10>;
};
+ pvs_efuse: pvs {
+ reg = <0xc0 0x4>;
+ };
};
gcc: clock-controller@900000 {
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index e5ad0708849a..c8e198631d41 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -7,6 +7,9 @@ config DMABOUNCE
bool
select ZONE_DMA
+config KRAIT_L2_ACCESSORS
+ bool
+
config SHARP_LOCOMO
bool
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 3157be413297..219a260bbe5f 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -7,6 +7,7 @@ obj-y += firmware.o
obj-$(CONFIG_SA1111) += sa1111.o
obj-$(CONFIG_DMABOUNCE) += dmabounce.o
+obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o
obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
diff --git a/arch/arm/common/krait-l2-accessors.c b/arch/arm/common/krait-l2-accessors.c
new file mode 100644
index 000000000000..9a97ddadecd6
--- /dev/null
+++ b/arch/arm/common/krait-l2-accessors.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/spinlock.h>
+#include <linux/export.h>
+
+#include <asm/barrier.h>
+#include <asm/krait-l2-accessors.h>
+
+static DEFINE_RAW_SPINLOCK(krait_l2_lock);
+
+void krait_set_l2_indirect_reg(u32 addr, u32 val)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&krait_l2_lock, flags);
+ /*
+ * Select the L2 window by poking l2cpselr, then write to the window
+ * via l2cpdr.
+ */
+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
+ isb();
+ asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val));
+ isb();
+
+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
+}
+EXPORT_SYMBOL(krait_set_l2_indirect_reg);
+
+u32 krait_get_l2_indirect_reg(u32 addr)
+{
+ u32 val;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&krait_l2_lock, flags);
+ /*
+ * Select the L2 window by poking l2cpselr, then read from the window
+ * via l2cpdr.
+ */
+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
+ isb();
+ asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val));
+
+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
+
+ return val;
+}
+EXPORT_SYMBOL(krait_get_l2_indirect_reg);
diff --git a/arch/arm/include/asm/krait-l2-accessors.h b/arch/arm/include/asm/krait-l2-accessors.h
new file mode 100644
index 000000000000..a5f2cdd6445f
--- /dev/null
+++ b/arch/arm/include/asm/krait-l2-accessors.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H
+#define __ASMARM_KRAIT_L2_ACCESSORS_H
+
+extern void krait_set_l2_indirect_reg(u32 addr, u32 val);
+extern u32 krait_get_l2_indirect_reg(u32 addr);
+
+#endif
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index edf2be6fae03..17ea206dbfed 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -282,3 +282,31 @@ config SPMI_PMIC_CLKDIV
Technologies, Inc. SPMI PMIC. It configures the frequency of
clkdiv outputs of the PMIC. These clocks are typically wired
through alternate functions on GPIO pins.
+
+config QCOM_HFPLL
+ tristate "High-Frequency PLL (HFPLL) Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the high-frequency PLLs present on Qualcomm devices.
+ Say Y if you want to support CPU frequency scaling on devices
+ such as MSM8974, APQ8084, etc.
+
+config KPSS_XCC
+ tristate "KPSS Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the Krait ACC and GCC clock controllers. Say Y
+ if you want to support CPU frequency scaling on devices such
+ as MSM8960, APQ8064, etc.
+
+config KRAITCC
+ tristate "Krait Clock Controller"
+ depends on COMMON_CLK_QCOM && ARM
+ select KRAIT_CLOCKS
+ help
+ Support for the Krait CPU clocks on Qualcomm devices.
+ Say Y if you want to support CPU frequency scaling.
+
+config KRAIT_CLOCKS
+ bool
+ select KRAIT_L2_ACCESSORS
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 079be70c6d71..b7ce3cc4a635 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -11,6 +11,8 @@ clk-qcom-y += clk-branch.o
clk-qcom-y += clk-regmap-divider.o
clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += clk-regmap-mux-div.o
+clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
+clk-qcom-y += clk-hfpll.o
clk-qcom-y += reset.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
@@ -44,3 +46,6 @@ obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o
obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
+obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
+obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
+obj-$(CONFIG_KRAITCC) += krait-cc.o
diff --git a/drivers/clk/qcom/clk-hfpll.c b/drivers/clk/qcom/clk-hfpll.c
new file mode 100644
index 000000000000..3c04805f2a55
--- /dev/null
+++ b/drivers/clk/qcom/clk-hfpll.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+
+#include "clk-regmap.h"
+#include "clk-hfpll.h"
+
+#define PLL_OUTCTRL BIT(0)
+#define PLL_BYPASSNL BIT(1)
+#define PLL_RESET_N BIT(2)
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __clk_hfpll_init_once(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+
+ if (likely(h->init_done))
+ return;
+
+ /* Configure PLL parameters for integer mode. */
+ if (hd->config_val)
+ regmap_write(regmap, hd->config_reg, hd->config_val);
+ regmap_write(regmap, hd->m_reg, 0);
+ regmap_write(regmap, hd->n_reg, 1);
+
+ if (hd->user_reg) {
+ u32 regval = hd->user_val;
+ unsigned long rate;
+
+ rate = clk_hw_get_rate(hw);
+
+ /* Pick the right VCO. */
+ if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
+ regval |= hd->user_vco_mask;
+ regmap_write(regmap, hd->user_reg, regval);
+ }
+
+ if (hd->droop_reg)
+ regmap_write(regmap, hd->droop_reg, hd->droop_val);
+
+ h->init_done = true;
+}
+
+static void __clk_hfpll_enable(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 val;
+
+ __clk_hfpll_init_once(hw);
+
+ /* Disable PLL bypass mode. */
+ regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ udelay(10);
+
+ /* De-assert active-low PLL reset. */
+ regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
+
+ /* Wait for PLL to lock. */
+ if (hd->status_reg) {
+ do {
+ regmap_read(regmap, hd->status_reg, &val);
+ } while (!(val & BIT(hd->lock_bit)));
+ } else {
+ udelay(60);
+ }
+
+ /* Enable PLL output. */
+ regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
+}
+
+/* Enable an already-configured HFPLL. */
+static int clk_hfpll_enable(struct clk_hw *hw)
+{
+ unsigned long flags;
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 mode;
+
+ spin_lock_irqsave(&h->lock, flags);
+ regmap_read(regmap, hd->mode_reg, &mode);
+ if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
+ __clk_hfpll_enable(hw);
+ spin_unlock_irqrestore(&h->lock, flags);
+
+ return 0;
+}
+
+static void __clk_hfpll_disable(struct clk_hfpll *h)
+{
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+
+ /*
+ * Disable the PLL output, disable test mode, enable the bypass mode,
+ * and assert the reset.
+ */
+ regmap_update_bits(regmap, hd->mode_reg,
+ PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
+}
+
+static void clk_hfpll_disable(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&h->lock, flags);
+ __clk_hfpll_disable(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ unsigned long rrate;
+
+ rate = clamp(rate, hd->min_rate, hd->max_rate);
+
+ rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
+ if (rrate > hd->max_rate)
+ rrate -= *parent_rate;
+
+ return rrate;
+}
+
+/*
+ * For optimization reasons, assumes no downstream clocks are actively using
+ * it.
+ */
+static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ unsigned long flags;
+ u32 l_val, val;
+ bool enabled;
+
+ l_val = rate / parent_rate;
+
+ spin_lock_irqsave(&h->lock, flags);
+
+ enabled = __clk_is_enabled(hw->clk);
+ if (enabled)
+ __clk_hfpll_disable(h);
+
+ /* Pick the right VCO. */
+ if (hd->user_reg && hd->user_vco_mask) {
+ regmap_read(regmap, hd->user_reg, &val);
+ if (rate <= hd->low_vco_max_rate)
+ val &= ~hd->user_vco_mask;
+ else
+ val |= hd->user_vco_mask;
+ regmap_write(regmap, hd->user_reg, val);
+ }
+
+ regmap_write(regmap, hd->l_reg, l_val);
+
+ if (enabled)
+ __clk_hfpll_enable(hw);
+
+ spin_unlock_irqrestore(&h->lock, flags);
+
+ return 0;
+}
+
+static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 l_val;
+
+ regmap_read(regmap, hd->l_reg, &l_val);
+
+ return l_val * parent_rate;
+}
+
+static void clk_hfpll_init(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 mode, status;
+
+ regmap_read(regmap, hd->mode_reg, &mode);
+ if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
+ __clk_hfpll_init_once(hw);
+ return;
+ }
+
+ if (hd->status_reg) {
+ regmap_read(regmap, hd->status_reg, &status);
+ if (!(status & BIT(hd->lock_bit))) {
+ WARN(1, "HFPLL %s is ON, but not locked!\n",
+ __clk_get_name(hw->clk));
+ clk_hfpll_disable(hw);
+ __clk_hfpll_init_once(hw);
+ }
+ }
+}
+
+static int hfpll_is_enabled(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 mode;
+
+ regmap_read(regmap, hd->mode_reg, &mode);
+ mode &= 0x7;
+ return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
+}
+
+const struct clk_ops clk_ops_hfpll = {
+ .enable = clk_hfpll_enable,
+ .disable = clk_hfpll_disable,
+ .is_enabled = hfpll_is_enabled,
+ .round_rate = clk_hfpll_round_rate,
+ .set_rate = clk_hfpll_set_rate,
+ .recalc_rate = clk_hfpll_recalc_rate,
+ .init = clk_hfpll_init,
+};
+EXPORT_SYMBOL_GPL(clk_ops_hfpll);
diff --git a/drivers/clk/qcom/clk-hfpll.h b/drivers/clk/qcom/clk-hfpll.h
new file mode 100644
index 000000000000..2a57b2fb2f2f
--- /dev/null
+++ b/drivers/clk/qcom/clk-hfpll.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __QCOM_CLK_HFPLL_H__
+#define __QCOM_CLK_HFPLL_H__
+
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include "clk-regmap.h"
+
+struct hfpll_data {
+ u32 mode_reg;
+ u32 l_reg;
+ u32 m_reg;
+ u32 n_reg;
+ u32 user_reg;
+ u32 droop_reg;
+ u32 config_reg;
+ u32 status_reg;
+ u8 lock_bit;
+
+ u32 droop_val;
+ u32 config_val;
+ u32 user_val;
+ u32 user_vco_mask;
+ unsigned long low_vco_max_rate;
+
+ unsigned long min_rate;
+ unsigned long max_rate;
+};
+
+struct clk_hfpll {
+ struct hfpll_data const *d;
+ int init_done;
+
+ struct clk_regmap clkr;
+ spinlock_t lock;
+};
+
+#define to_clk_hfpll(_hw) \
+ container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr)
+
+extern const struct clk_ops clk_ops_hfpll;
+
+#endif
diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c
new file mode 100644
index 000000000000..ee1076cb9001
--- /dev/null
+++ b/drivers/clk/qcom/clk-krait.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+
+#include <asm/krait-l2-accessors.h>
+
+#include "clk-krait.h"
+
+/* Secondary and primary muxes share the same cp15 register */
+static DEFINE_SPINLOCK(krait_clock_reg_lock);
+
+#define LPL_SHIFT 8
+static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
+{
+ unsigned long flags;
+ u32 regval;
+
+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
+ regval = krait_get_l2_indirect_reg(mux->offset);
+ regval &= ~(mux->mask << mux->shift);
+ regval |= (sel & mux->mask) << mux->shift;
+ if (mux->lpl) {
+ regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
+ regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
+ }
+ krait_set_l2_indirect_reg(mux->offset, regval);
+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
+
+ /* Wait for switch to complete. */
+ mb();
+ udelay(1);
+}
+
+static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
+ u32 sel;
+
+ sel = clk_mux_index_to_val(mux->parent_map, 0, index);
+ mux->en_mask = sel;
+ /* Don't touch mux if CPU is off as it won't work */
+ if (__clk_is_enabled(hw->clk))
+ __krait_mux_set_sel(mux, sel);
+
+ mux->reparent = true;
+
+ return 0;
+}
+
+static u8 krait_mux_get_parent(struct clk_hw *hw)
+{
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
+ u32 sel;
+
+ sel = krait_get_l2_indirect_reg(mux->offset);
+ sel >>= mux->shift;
+ sel &= mux->mask;
+ mux->en_mask = sel;
+
+ return clk_mux_val_to_index(hw, mux->parent_map, sel, 0);
+}
+
+const struct clk_ops krait_mux_clk_ops = {
+ .set_parent = krait_mux_set_parent,
+ .get_parent = krait_mux_get_parent,
+ .determine_rate = __clk_mux_determine_rate_closest,
+};
+EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
+
+/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
+static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
+ return DIV_ROUND_UP(*parent_rate, 2);
+}
+
+static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
+ unsigned long flags;
+ u32 val;
+ u32 mask = BIT(d->width) - 1;
+
+ if (d->lpl)
+ mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
+
+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
+ val = krait_get_l2_indirect_reg(d->offset);
+ val &= ~mask;
+ krait_set_l2_indirect_reg(d->offset, val);
+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
+
+ return 0;
+}
+
+static unsigned long
+krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
+ u32 mask = BIT(d->width) - 1;
+ u32 div;
+
+ div = krait_get_l2_indirect_reg(d->offset);
+ div >>= d->shift;
+ div &= mask;
+ div = (div + 1) * 2;
+
+ return DIV_ROUND_UP(parent_rate, div);
+}
+
+const struct clk_ops krait_div2_clk_ops = {
+ .round_rate = krait_div2_round_rate,
+ .set_rate = krait_div2_set_rate,
+ .recalc_rate = krait_div2_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
diff --git a/drivers/clk/qcom/clk-krait.h b/drivers/clk/qcom/clk-krait.h
new file mode 100644
index 000000000000..9120bd2f5297
--- /dev/null
+++ b/drivers/clk/qcom/clk-krait.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __QCOM_CLK_KRAIT_H
+#define __QCOM_CLK_KRAIT_H
+
+#include <linux/clk-provider.h>
+
+struct krait_mux_clk {
+ unsigned int *parent_map;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ bool lpl;
+ u8 safe_sel;
+ u8 old_index;
+ bool reparent;
+
+ struct clk_hw hw;
+ struct notifier_block clk_nb;
+};
+
+#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
+
+extern const struct clk_ops krait_mux_clk_ops;
+
+struct krait_div2_clk {
+ u32 offset;
+ u8 width;
+ u32 shift;
+ bool lpl;
+
+ struct clk_hw hw;
+};
+
+#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
+
+extern const struct clk_ops krait_div2_clk_ops;
+
+#endif
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index 5f61225657ab..33d1bc5c6a46 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -30,6 +30,7 @@
#include "clk-pll.h"
#include "clk-rcg.h"
#include "clk-branch.h"
+#include "clk-hfpll.h"
#include "reset.h"
static struct clk_pll pll0 = {
@@ -113,6 +114,84 @@ static struct clk_regmap pll8_vote = {
},
};
+static struct hfpll_data hfpll0_data = {
+ .mode_reg = 0x3200,
+ .l_reg = 0x3208,
+ .m_reg = 0x320c,
+ .n_reg = 0x3210,
+ .config_reg = 0x3204,
+ .status_reg = 0x321c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3214,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll0 = {
+ .d = &hfpll0_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll0",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
+};
+
+static struct hfpll_data hfpll1_data = {
+ .mode_reg = 0x3240,
+ .l_reg = 0x3248,
+ .m_reg = 0x324c,
+ .n_reg = 0x3250,
+ .config_reg = 0x3244,
+ .status_reg = 0x325c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll1 = {
+ .d = &hfpll1_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll1",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
+};
+
+static struct hfpll_data hfpll_l2_data = {
+ .mode_reg = 0x3300,
+ .l_reg = 0x3308,
+ .m_reg = 0x330c,
+ .n_reg = 0x3310,
+ .config_reg = 0x3304,
+ .status_reg = 0x331c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll_l2 = {
+ .d = &hfpll_l2_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll_l2",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
+};
+
static struct clk_pll pll14 = {
.l_reg = 0x31c4,
.m_reg = 0x31c8,
@@ -2797,6 +2876,9 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
[NSSTCM_CLK] = &nss_tcm_clk.clkr,
+ [PLL9] = &hfpll0.clkr,
+ [PLL10] = &hfpll1.clkr,
+ [PLL12] = &hfpll_l2.clkr,
};
static const struct qcom_reset_map gcc_ipq806x_resets[] = {
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index fd495e0471bb..399474755654 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -30,6 +30,7 @@
#include "clk-pll.h"
#include "clk-rcg.h"
#include "clk-branch.h"
+#include "clk-hfpll.h"
#include "reset.h"
static struct clk_pll pll3 = {
@@ -86,6 +87,164 @@ static struct clk_regmap pll8_vote = {
},
};
+static struct hfpll_data hfpll0_data = {
+ .mode_reg = 0x3200,
+ .l_reg = 0x3208,
+ .m_reg = 0x320c,
+ .n_reg = 0x3210,
+ .config_reg = 0x3204,
+ .status_reg = 0x321c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3214,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll0 = {
+ .d = &hfpll0_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll0",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
+};
+
+static struct hfpll_data hfpll1_8064_data = {
+ .mode_reg = 0x3240,
+ .l_reg = 0x3248,
+ .m_reg = 0x324c,
+ .n_reg = 0x3250,
+ .config_reg = 0x3244,
+ .status_reg = 0x325c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3254,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct hfpll_data hfpll1_data = {
+ .mode_reg = 0x3300,
+ .l_reg = 0x3308,
+ .m_reg = 0x330c,
+ .n_reg = 0x3310,
+ .config_reg = 0x3304,
+ .status_reg = 0x331c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll1 = {
+ .d = &hfpll1_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll1",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
+};
+
+static struct hfpll_data hfpll2_data = {
+ .mode_reg = 0x3280,
+ .l_reg = 0x3288,
+ .m_reg = 0x328c,
+ .n_reg = 0x3290,
+ .config_reg = 0x3284,
+ .status_reg = 0x329c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3294,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll2 = {
+ .d = &hfpll2_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll2",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll2.lock),
+};
+
+static struct hfpll_data hfpll3_data = {
+ .mode_reg = 0x32c0,
+ .l_reg = 0x32c8,
+ .m_reg = 0x32cc,
+ .n_reg = 0x32d0,
+ .config_reg = 0x32c4,
+ .status_reg = 0x32dc,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x32d4,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll3 = {
+ .d = &hfpll3_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll3",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll3.lock),
+};
+
+static struct hfpll_data hfpll_l2_8064_data = {
+ .mode_reg = 0x3300,
+ .l_reg = 0x3308,
+ .m_reg = 0x330c,
+ .n_reg = 0x3310,
+ .config_reg = 0x3304,
+ .status_reg = 0x331c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct hfpll_data hfpll_l2_data = {
+ .mode_reg = 0x3400,
+ .l_reg = 0x3408,
+ .m_reg = 0x340c,
+ .n_reg = 0x3410,
+ .config_reg = 0x3404,
+ .status_reg = 0x341c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3414,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll_l2 = {
+ .d = &hfpll_l2_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll_l2",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
+};
+
static struct clk_pll pll14 = {
.l_reg = 0x31c4,
.m_reg = 0x31c8,
@@ -3107,6 +3266,9 @@ static struct clk_regmap *gcc_msm8960_clks[] = {
[PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
[PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
[RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
+ [PLL9] = &hfpll0.clkr,
+ [PLL10] = &hfpll1.clkr,
+ [PLL12] = &hfpll_l2.clkr,
};
static const struct qcom_reset_map gcc_msm8960_resets[] = {
@@ -3318,6 +3480,11 @@ static struct clk_regmap *gcc_apq8064_clks[] = {
[PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
[PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
[RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
+ [PLL9] = &hfpll0.clkr,
+ [PLL10] = &hfpll1.clkr,
+ [PLL12] = &hfpll_l2.clkr,
+ [PLL16] = &hfpll2.clkr,
+ [PLL17] = &hfpll3.clkr,
};
static const struct qcom_reset_map gcc_apq8064_resets[] = {
@@ -3477,6 +3644,11 @@ static int gcc_msm8960_probe(struct platform_device *pdev)
if (ret)
return ret;
+ if (match->data == &gcc_apq8064_desc) {
+ hfpll1.d = &hfpll1_8064_data;
+ hfpll_l2.d = &hfpll_l2_8064_data;
+ }
+
tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1,
NULL, 0);
if (IS_ERR(tsens))
diff --git a/drivers/clk/qcom/hfpll.c b/drivers/clk/qcom/hfpll.c
new file mode 100644
index 000000000000..a6de7101430c
--- /dev/null
+++ b/drivers/clk/qcom/hfpll.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include "clk-regmap.h"
+#include "clk-hfpll.h"
+
+static const struct hfpll_data hdata = {
+ .mode_reg = 0x00,
+ .l_reg = 0x04,
+ .m_reg = 0x08,
+ .n_reg = 0x0c,
+ .user_reg = 0x10,
+ .config_reg = 0x14,
+ .config_val = 0x430405d,
+ .status_reg = 0x1c,
+ .lock_bit = 16,
+
+ .user_val = 0x8,
+ .user_vco_mask = 0x100000,
+ .low_vco_max_rate = 1248000000,
+ .min_rate = 537600000UL,
+ .max_rate = 2900000000UL,
+};
+
+static const struct of_device_id qcom_hfpll_match_table[] = {
+ { .compatible = "qcom,hfpll" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
+
+static const struct regmap_config hfpll_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x30,
+ .fast_io = true,
+};
+
+static int qcom_hfpll_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ void __iomem *base;
+ struct regmap *regmap;
+ struct clk_hfpll *h;
+ struct clk_init_data init = {
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_ops_hfpll,
+ };
+
+ h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ if (of_property_read_string_index(dev->of_node, "clock-output-names",
+ 0, &init.name))
+ return -ENODEV;
+
+ h->d = &hdata;
+ h->clkr.hw.init = &init;
+ spin_lock_init(&h->lock);
+
+ return devm_clk_register_regmap(&pdev->dev, &h->clkr);
+}
+
+static struct platform_driver qcom_hfpll_driver = {
+ .probe = qcom_hfpll_probe,
+ .driver = {
+ .name = "qcom-hfpll",
+ .of_match_table = qcom_hfpll_match_table,
+ },
+};
+module_platform_driver(qcom_hfpll_driver);
+
+MODULE_DESCRIPTION("QCOM HFPLL Clock Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:qcom-hfpll");
diff --git a/drivers/clk/qcom/kpss-xcc.c b/drivers/clk/qcom/kpss-xcc.c
new file mode 100644
index 000000000000..8590b5edd19d
--- /dev/null
+++ b/drivers/clk/qcom/kpss-xcc.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+static const char *aux_parents[] = {
+ "pll8_vote",
+ "pxo",
+};
+
+static unsigned int aux_parent_map[] = {
+ 3,
+ 0,
+};
+
+static const struct of_device_id kpss_xcc_match_table[] = {
+ { .compatible = "qcom,kpss-acc-v1", .data = (void *)1UL },
+ { .compatible = "qcom,kpss-gcc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, kpss_xcc_match_table);
+
+static int kpss_xcc_driver_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *id;
+ struct clk *clk;
+ struct resource *res;
+ void __iomem *base;
+ const char *name;
+
+ id = of_match_device(kpss_xcc_match_table, &pdev->dev);
+ if (!id)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ if (id->data) {
+ if (of_property_read_string_index(pdev->dev.of_node,
+ "clock-output-names",
+ 0, &name))
+ return -ENODEV;
+ base += 0x14;
+ } else {
+ name = "acpu_l2_aux";
+ base += 0x28;
+ }
+
+ clk = clk_register_mux_table(&pdev->dev, name, aux_parents,
+ ARRAY_SIZE(aux_parents), 0, base, 0, 0x3,
+ 0, aux_parent_map, NULL);
+
+ platform_set_drvdata(pdev, clk);
+
+ return PTR_ERR_OR_ZERO(clk);
+}
+
+static int kpss_xcc_driver_remove(struct platform_device *pdev)
+{
+ clk_unregister_mux(platform_get_drvdata(pdev));
+ return 0;
+}
+
+static struct platform_driver kpss_xcc_driver = {
+ .probe = kpss_xcc_driver_probe,
+ .remove = kpss_xcc_driver_remove,
+ .driver = {
+ .name = "kpss-xcc",
+ .of_match_table = kpss_xcc_match_table,
+ },
+};
+module_platform_driver(kpss_xcc_driver);
+
+MODULE_DESCRIPTION("Krait Processor Sub System (KPSS) Clock Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kpss-xcc");
diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c
new file mode 100644
index 000000000000..4d4b657d33c3
--- /dev/null
+++ b/drivers/clk/qcom/krait-cc.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+
+#include "clk-krait.h"
+
+static unsigned int sec_mux_map[] = {
+ 2,
+ 0,
+};
+
+static unsigned int pri_mux_map[] = {
+ 1,
+ 2,
+ 0,
+};
+
+/*
+ * Notifier function for switching the muxes to safe parent
+ * while the hfpll is getting reprogrammed.
+ */
+static int krait_notifier_cb(struct notifier_block *nb,
+ unsigned long event,
+ void *data)
+{
+ int ret = 0;
+ struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk,
+ clk_nb);
+ /* Switch to safe parent */
+ if (event == PRE_RATE_CHANGE) {
+ mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw);
+ ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel);
+ mux->reparent = false;
+ /*
+ * By the time POST_RATE_CHANGE notifier is called,
+ * clk framework itself would have changed the parent for the new rate.
+ * Only otherwise, put back to the old parent.
+ */
+ } else if (event == POST_RATE_CHANGE) {
+ if (!mux->reparent)
+ ret = krait_mux_clk_ops.set_parent(&mux->hw,
+ mux->old_index);
+ }
+
+ return notifier_from_errno(ret);
+}
+
+static int krait_notifier_register(struct device *dev, struct clk *clk,
+ struct krait_mux_clk *mux)
+{
+ int ret = 0;
+
+ mux->clk_nb.notifier_call = krait_notifier_cb;
+ ret = clk_notifier_register(clk, &mux->clk_nb);
+ if (ret)
+ dev_err(dev, "failed to register clock notifier: %d\n", ret);
+
+ return ret;
+}
+
+static int
+krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
+{
+ struct krait_div2_clk *div;
+ struct clk_init_data init = {
+ .num_parents = 1,
+ .ops = &krait_div2_clk_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ const char *p_names[1];
+ struct clk *clk;
+
+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return -ENOMEM;
+
+ div->width = 2;
+ div->shift = 6;
+ div->lpl = id >= 0;
+ div->offset = offset;
+ div->hw.init = &init;
+
+ init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
+ if (!init.name)
+ return -ENOMEM;
+
+ init.parent_names = p_names;
+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
+ if (!p_names[0]) {
+ kfree(init.name);
+ return -ENOMEM;
+ }
+
+ clk = devm_clk_register(dev, &div->hw);
+ kfree(p_names[0]);
+ kfree(init.name);
+
+ return PTR_ERR_OR_ZERO(clk);
+}
+
+static int
+krait_add_sec_mux(struct device *dev, int id, const char *s,
+ unsigned int offset, bool unique_aux)
+{
+ int ret;
+ struct krait_mux_clk *mux;
+ static const char *sec_mux_list[] = {
+ "acpu_aux",
+ "qsb",
+ };
+ struct clk_init_data init = {
+ .parent_names = sec_mux_list,
+ .num_parents = ARRAY_SIZE(sec_mux_list),
+ .ops = &krait_mux_clk_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ struct clk *clk;
+
+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return -ENOMEM;
+
+ mux->offset = offset;
+ mux->lpl = id >= 0;
+ mux->mask = 0x3;
+ mux->shift = 2;
+ mux->parent_map = sec_mux_map;
+ mux->hw.init = &init;
+ mux->safe_sel = 0;
+
+ init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
+ if (!init.name)
+ return -ENOMEM;
+
+ if (unique_aux) {
+ sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s);
+ if (!sec_mux_list[0]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_aux;
+ }
+ }
+
+ clk = devm_clk_register(dev, &mux->hw);
+
+ ret = krait_notifier_register(dev, clk, mux);
+ if (ret)
+ goto unique_aux;
+
+unique_aux:
+ if (unique_aux)
+ kfree(sec_mux_list[0]);
+err_aux:
+ kfree(init.name);
+ return PTR_ERR_OR_ZERO(clk);
+}
+
+static struct clk *
+krait_add_pri_mux(struct device *dev, int id, const char *s,
+ unsigned int offset)
+{
+ int ret;
+ struct krait_mux_clk *mux;
+ const char *p_names[3];
+ struct clk_init_data init = {
+ .parent_names = p_names,
+ .num_parents = ARRAY_SIZE(p_names),
+ .ops = &krait_mux_clk_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ struct clk *clk;
+
+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ mux->mask = 0x3;
+ mux->shift = 0;
+ mux->offset = offset;
+ mux->lpl = id >= 0;
+ mux->parent_map = pri_mux_map;
+ mux->hw.init = &init;
+ mux->safe_sel = 2;
+
+ init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
+ if (!init.name)
+ return ERR_PTR(-ENOMEM);
+
+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
+ if (!p_names[0]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_p0;
+ }
+
+ p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
+ if (!p_names[1]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_p1;
+ }
+
+ p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
+ if (!p_names[2]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_p2;
+ }
+
+ clk = devm_clk_register(dev, &mux->hw);
+
+ ret = krait_notifier_register(dev, clk, mux);
+ if (ret)
+ goto err_p3;
+err_p3:
+ kfree(p_names[2]);
+err_p2:
+ kfree(p_names[1]);
+err_p1:
+ kfree(p_names[0]);
+err_p0:
+ kfree(init.name);
+ return clk;
+}
+
+/* id < 0 for L2, otherwise id == physical CPU number */
+static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
+{
+ int ret;
+ unsigned int offset;
+ void *p = NULL;
+ const char *s;
+ struct clk *clk;
+
+ if (id >= 0) {
+ offset = 0x4501 + (0x1000 * id);
+ s = p = kasprintf(GFP_KERNEL, "%d", id);
+ if (!s)
+ return ERR_PTR(-ENOMEM);
+ } else {
+ offset = 0x500;
+ s = "_l2";
+ }
+
+ ret = krait_add_div(dev, id, s, offset);
+ if (ret) {
+ clk = ERR_PTR(ret);
+ goto err;
+ }
+
+ ret = krait_add_sec_mux(dev, id, s, offset, unique_aux);
+ if (ret) {
+ clk = ERR_PTR(ret);
+ goto err;
+ }
+
+ clk = krait_add_pri_mux(dev, id, s, offset);
+err:
+ kfree(p);
+ return clk;
+}
+
+static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data)
+{
+ unsigned int idx = clkspec->args[0];
+ struct clk **clks = data;
+
+ if (idx >= 5) {
+ pr_err("%s: invalid clock index %d\n", __func__, idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clks[idx] ? : ERR_PTR(-ENODEV);
+}
+
+static const struct of_device_id krait_cc_match_table[] = {
+ { .compatible = "qcom,krait-cc-v1", (void *)1UL },
+ { .compatible = "qcom,krait-cc-v2" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, krait_cc_match_table);
+
+static int krait_cc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *id;
+ unsigned long cur_rate, aux_rate;
+ int cpu;
+ struct clk *clk;
+ struct clk **clks;
+ struct clk *l2_pri_mux_clk;
+
+ id = of_match_device(krait_cc_match_table, dev);
+ if (!id)
+ return -ENODEV;
+
+ /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
+ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (!id->data) {
+ clk = clk_register_fixed_factor(dev, "acpu_aux",
+ "gpll0_vote", 0, 1, 2);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+
+ /* Krait configurations have at most 4 CPUs and one L2 */
+ clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu) {
+ clk = krait_add_clks(dev, cpu, id->data);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clks[cpu] = clk;
+ }
+
+ l2_pri_mux_clk = krait_add_clks(dev, -1, id->data);
+ if (IS_ERR(l2_pri_mux_clk))
+ return PTR_ERR(l2_pri_mux_clk);
+ clks[4] = l2_pri_mux_clk;
+
+ /*
+ * We don't want the CPU or L2 clocks to be turned off at late init
+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
+ * that the clocks have already been prepared and enabled by the time
+ * they take over.
+ */
+ for_each_online_cpu(cpu) {
+ clk_prepare_enable(l2_pri_mux_clk);
+ WARN(clk_prepare_enable(clks[cpu]),
+ "Unable to turn on CPU%d clock", cpu);
+ }
+
+ /*
+ * Force reinit of HFPLLs and muxes to overwrite any potential
+ * incorrect configuration of HFPLLs and muxes by the bootloader.
+ * While at it, also make sure the cores are running at known rates
+ * and print the current rate.
+ *
+ * The clocks are set to aux clock rate first to make sure the
+ * secondary mux is not sourcing off of QSB. The rate is then set to
+ * two different rates to force a HFPLL reinit under all
+ * circumstances.
+ */
+ cur_rate = clk_get_rate(l2_pri_mux_clk);
+ aux_rate = 384000000;
+ if (cur_rate == 1) {
+ pr_info("L2 @ QSB rate. Forcing new rate.\n");
+ cur_rate = aux_rate;
+ }
+ clk_set_rate(l2_pri_mux_clk, aux_rate);
+ clk_set_rate(l2_pri_mux_clk, 2);
+ clk_set_rate(l2_pri_mux_clk, cur_rate);
+ pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000);
+ for_each_possible_cpu(cpu) {
+ clk = clks[cpu];
+ cur_rate = clk_get_rate(clk);
+ if (cur_rate == 1) {
+ pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
+ cur_rate = aux_rate;
+ }
+
+ clk_set_rate(clk, aux_rate);
+ clk_set_rate(clk, 2);
+ clk_set_rate(clk, cur_rate);
+ pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000);
+ }
+
+ of_clk_add_provider(dev->of_node, krait_of_get, clks);
+
+ return 0;
+}
+
+static struct platform_driver krait_cc_driver = {
+ .probe = krait_cc_probe,
+ .driver = {
+ .name = "krait-cc",
+ .of_match_table = krait_cc_match_table,
+ },
+};
+module_platform_driver(krait_cc_driver);
+
+MODULE_DESCRIPTION("Krait CPU Clock Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:krait-cc");
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0cd8eb76ad59..442ef1f74c5a 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -121,6 +121,16 @@ config ARM_QCOM_CPUFREQ_KRYO
If in doubt, say N.
+config ARM_QCOM_CPUFREQ
+ bool "CPUfreq driver for the QCOM SoCs with KRAIT processors"
+ depends on ARCH_QCOM
+ select PM_OPP
+ help
+ This enables the CPUFreq driver for Qualcomm SoCs with
+ KRAIT processors.
+
+ If in doubt, say N.
+
config ARM_S3C_CPUFREQ
bool
help
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index c1ffeabe4ecf..c08c2d62a6fa 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
+obj-$(CONFIG_ARM_QCOM_CPUFREQ) += qcom-cpufreq.o
obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 1b6230ac364d..9739a06b4338 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -129,6 +129,11 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "ti,am43", },
{ .compatible = "ti,dra7", },
+ { .compatible = "qcom,ipq8064", },
+ { .compatible = "qcom,apq8064", },
+ { .compatible = "qcom,msm8974", },
+ { .compatible = "qcom,msm8960", },
+
{ }
};
diff --git a/drivers/cpufreq/qcom-cpufreq.c b/drivers/cpufreq/qcom-cpufreq.c
new file mode 100644
index 000000000000..1d4ab54f2f64
--- /dev/null
+++ b/drivers/cpufreq/qcom-cpufreq.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+
+static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver,
+ struct nvmem_cell *pvs_nvmem, u8 *buf)
+{
+ u32 pte_efuse;
+
+ pte_efuse = *((u32 *)buf);
+
+ *speed = pte_efuse & 0xf;
+ if (*speed == 0xf)
+ *speed = (pte_efuse >> 4) & 0xf;
+
+ if (*speed == 0xf) {
+ *speed = 0;
+ pr_warn("Speed bin: Defaulting to %d\n", *speed);
+ } else {
+ pr_info("Speed bin: %d\n", *speed);
+ }
+
+ *pvs = (pte_efuse >> 10) & 0x7;
+ if (*pvs == 0x7)
+ *pvs = (pte_efuse >> 13) & 0x7;
+
+ if (*pvs == 0x7) {
+ *pvs = 0;
+ pr_warn("PVS bin: Defaulting to %d\n", *pvs);
+ } else {
+ pr_info("PVS bin: %d\n", *pvs);
+ }
+
+ kfree(buf);
+}
+
+static void __init get_krait_bin_format_b(int *speed, int *pvs, int *pvs_ver,
+ struct nvmem_cell *pvs_nvmem, u8 *buf)
+{
+ u32 pte_efuse, redundant_sel;
+
+ pte_efuse = *((u32 *)buf);
+ redundant_sel = (pte_efuse >> 24) & 0x7;
+ *speed = pte_efuse & 0x7;
+
+ /* 4 bits of PVS are in efuse register bits 31, 8-6. */
+ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
+ *pvs_ver = (pte_efuse >> 4) & 0x3;
+
+ switch (redundant_sel) {
+ case 1:
+ *speed = (pte_efuse >> 27) & 0xf;
+ break;
+ case 2:
+ *pvs = (pte_efuse >> 27) & 0xf;
+ break;
+ }
+
+ /* Check SPEED_BIN_BLOW_STATUS */
+ if (pte_efuse & BIT(3)) {
+ pr_info("Speed bin: %d\n", *speed);
+ } else {
+ pr_warn("Speed bin not set. Defaulting to 0!\n");
+ *speed = 0;
+ }
+
+ /* Check PVS_BLOW_STATUS */
+ pte_efuse = *(((u32 *)buf) + 4);
+ if (pte_efuse) {
+ pr_info("PVS bin: %d\n", *pvs);
+ } else {
+ pr_warn("PVS bin not set. Defaulting to 0!\n");
+ *pvs = 0;
+ }
+
+ pr_info("PVS version: %d\n", *pvs_ver);
+ kfree(buf);
+}
+
+static int __init qcom_cpufreq_populate_opps(struct nvmem_cell *pvs_nvmem,
+ struct opp_table **tbl1,
+ struct opp_table **tbl2)
+{
+ int speed = 0, pvs = 0, pvs_ver = 0, cpu, ret;
+ struct device *cpu_dev;
+ u8 *buf;
+ size_t len;
+ char pvs_name[] = "speedXX-pvsXX-vXX";
+ u32 hw_version;
+
+ buf = nvmem_cell_read(pvs_nvmem, &len);
+ if (len == 4)
+ get_krait_bin_format_a(&speed, &pvs, &pvs_ver, pvs_nvmem, buf);
+ else if (len == 8)
+ get_krait_bin_format_b(&speed, &pvs, &pvs_ver, pvs_nvmem, buf);
+ else
+ pr_warn("Unable to read nvmem data. Defaulting to 0!\n");
+
+ snprintf(pvs_name, sizeof(pvs_name), "speed%d-pvs%d-v%d",
+ speed, pvs, pvs_ver);
+
+ hw_version = (1 << speed);
+
+ for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
+ cpu_dev = get_cpu_device(cpu);
+ if (!cpu_dev)
+ return -ENODEV;
+
+ tbl1[cpu] = dev_pm_opp_set_prop_name(cpu_dev, pvs_name);
+ if (IS_ERR(tbl1[cpu])) {
+ ret = PTR_ERR(tbl1[cpu]);
+ tbl1[cpu] = 0;
+ pr_warn("failed to add OPP name %s\n", pvs_name);
+ return ret;
+ }
+
+ tbl2[cpu] = dev_pm_opp_set_supported_hw(cpu_dev, &hw_version,
+ 1);
+ if (IS_ERR(tbl2[cpu])) {
+ ret = PTR_ERR(tbl2[cpu]);
+ tbl2[cpu] = 0;
+ pr_warn("failed to set supported hw version\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __init qcom_cpufreq_driver_init(void)
+{
+ struct platform_device *pdev;
+ struct device *cpu_dev;
+ struct device_node *np;
+ struct nvmem_cell *pvs_nvmem;
+ struct opp_table *tbl1[NR_CPUS] = { NULL }, *tbl2[NR_CPUS] = { NULL };
+ int ret, cpu = 0;
+
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev)
+ return -ENODEV;
+
+ np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
+ if (!np)
+ return -ENOENT;
+
+ if (!of_device_is_compatible(np, "operating-points-v2-krait-cpu")) {
+ ret = -ENOENT;
+ goto free_np;
+ }
+
+ pvs_nvmem = of_nvmem_cell_get(np, NULL);
+ if (IS_ERR(pvs_nvmem)) {
+ dev_err(cpu_dev, "Could not get nvmem cell\n");
+ ret = PTR_ERR(pvs_nvmem);
+ goto free_np;
+ }
+
+ ret = qcom_cpufreq_populate_opps(pvs_nvmem, tbl1, tbl2);
+ if (ret)
+ goto free_opp_name;
+
+ pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto free_opp_name;
+ }
+
+ of_node_put(np);
+
+ return 0;
+
+free_opp_name:
+ while (tbl1[cpu]) {
+ dev_pm_opp_put_prop_name(tbl1[cpu]);
+ cpu++;
+ }
+
+ cpu = 0;
+ while (tbl2[cpu]) {
+ dev_pm_opp_put_supported_hw(tbl2[cpu]);
+ cpu++;
+ }
+
+free_np:
+ of_node_put(np);
+
+ return ret;
+}
+late_initcall(qcom_cpufreq_driver_init);
+
+MODULE_DESCRIPTION("Qualcomm CPUfreq driver");
+MODULE_AUTHOR("Stephen Boyd <sboyd@codeaurora.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/clock/qcom,gcc-msm8960.h b/include/dt-bindings/clock/qcom,gcc-msm8960.h
index 7d20eedfee98..e02742fc81cc 100644
--- a/include/dt-bindings/clock/qcom,gcc-msm8960.h
+++ b/include/dt-bindings/clock/qcom,gcc-msm8960.h
@@ -319,5 +319,7 @@
#define CE3_SRC 303
#define CE3_CORE_CLK 304
#define CE3_H_CLK 305
+#define PLL16 306
+#define PLL17 307
#endif