diff options
author | Linaro CI <ci_notify@linaro.org> | 2019-01-15 11:56:41 +0000 |
---|---|---|
committer | Linaro CI <ci_notify@linaro.org> | 2019-01-15 11:56:41 +0000 |
commit | 48e01452e7d2a55f58ed9cde7a62045c95e8d2f4 (patch) | |
tree | f5a23ff325a6ac3e597cd9309a5e13100a82d10c | |
parent | efd69074cd4f4b93b266611d12ff15dc6f0ec8b2 (diff) | |
parent | 9bde3651f3585ec358dfff6e5bc824413e59c524 (diff) |
Merge remote-tracking branch 'apq8064-cpufreq/qcomlt-apq8064-cpufreq' into integration-linux-qcomlt
-rw-r--r-- | Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt (renamed from Documentation/devicetree/bindings/opp/kryo-cpufreq.txt) | 7 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom-apq8064.dtsi | 630 | ||||
-rw-r--r-- | drivers/cpufreq/Kconfig.arm | 6 | ||||
-rw-r--r-- | drivers/cpufreq/Makefile | 2 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-dt-platdev.c | 5 | ||||
-rw-r--r-- | drivers/cpufreq/qcom-cpufreq-kryo.c | 233 | ||||
-rw-r--r-- | drivers/cpufreq/qcom-cpufreq-nvmem.c | 388 |
7 files changed, 1023 insertions, 248 deletions
diff --git a/Documentation/devicetree/bindings/opp/kryo-cpufreq.txt b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt index c2127b96805a..7bc0f1a23ac5 100644 --- a/Documentation/devicetree/bindings/opp/kryo-cpufreq.txt +++ b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt @@ -19,7 +19,8 @@ In 'cpus' nodes: In 'operating-points-v2' table: - compatible: Should be - - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996. + - 'operating-points-v2-qcom-cpu' for apq8096, msm8996, msm8974, + apq8064, msm8960 and ipq8074. - nvmem-cells: A phandle pointing to a nvmem-cells node representing the efuse registers that has information about the speedbin that is used to select the right frequency/voltage @@ -127,7 +128,7 @@ Example 1: }; cluster0_opp: opp_table0 { - compatible = "operating-points-v2-kryo-cpu"; + compatible = "operating-points-v2-qcom-cpu"; nvmem-cells = <&speedbin_efuse>; opp-shared; @@ -338,7 +339,7 @@ Example 1: }; cluster1_opp: opp_table1 { - compatible = "operating-points-v2-kryo-cpu"; + compatible = "operating-points-v2-qcom-cpu"; nvmem-cells = <&speedbin_efuse>; opp-shared; diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi index 48c3cf427610..b2ba1cf4ade2 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/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 688f10227793..a55db1015078 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -103,9 +103,9 @@ config ARM_OMAP2PLUS_CPUFREQ depends on ARCH_OMAP2PLUS default ARCH_OMAP2PLUS -config ARM_QCOM_CPUFREQ_KRYO - tristate "Qualcomm Kryo based CPUFreq" - depends on ARM64 +config ARM_QCOM_CPUFREQ_NVMEM + tristate "Qualcomm nvmem based CPUFreq" + depends on ARCH_QCOM depends on QCOM_QFPROM depends on QCOM_SMEM select PM_OPP diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 08c071be2491..e127a5c36cf3 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -62,7 +62,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_HW) += qcom-cpufreq-hw.o -obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.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 b1c5468dca16..272141eed647 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -132,6 +132,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-kryo.c b/drivers/cpufreq/qcom-cpufreq-kryo.c deleted file mode 100644 index 2a3675c24032..000000000000 --- a/drivers/cpufreq/qcom-cpufreq-kryo.c +++ /dev/null @@ -1,233 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. - */ - -/* - * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors, - * the CPU frequency subset and voltage value of each OPP varies - * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables - * defines the voltage and frequency value based on the msm-id in SMEM - * and speedbin blown in the efuse combination. - * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC - * to provide the OPP framework with required information. - * This is used to determine the voltage and frequency value for each OPP of - * operating-points-v2 table when it is parsed by the OPP framework. - */ - -#include <linux/cpu.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/kernel.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> -#include <linux/soc/qcom/smem.h> - -#define MSM_ID_SMEM 137 - -enum _msm_id { - MSM8996V3 = 0xF6ul, - APQ8096V3 = 0x123ul, - MSM8996SG = 0x131ul, - APQ8096SG = 0x138ul, -}; - -enum _msm8996_version { - MSM8996_V3, - MSM8996_SG, - NUM_OF_MSM8996_VERSIONS, -}; - -struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev; - -static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void) -{ - size_t len; - u32 *msm_id; - enum _msm8996_version version; - - msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len); - if (IS_ERR(msm_id)) - return NUM_OF_MSM8996_VERSIONS; - - /* The first 4 bytes are format, next to them is the actual msm-id */ - msm_id++; - - switch ((enum _msm_id)*msm_id) { - case MSM8996V3: - case APQ8096V3: - version = MSM8996_V3; - break; - case MSM8996SG: - case APQ8096SG: - version = MSM8996_SG; - break; - default: - version = NUM_OF_MSM8996_VERSIONS; - } - - return version; -} - -static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) -{ - struct opp_table *opp_tables[NR_CPUS] = {0}; - enum _msm8996_version msm8996_version; - struct nvmem_cell *speedbin_nvmem; - struct device_node *np; - struct device *cpu_dev; - unsigned cpu; - u8 *speedbin; - u32 versions; - size_t len; - int ret; - - cpu_dev = get_cpu_device(0); - if (!cpu_dev) - return -ENODEV; - - msm8996_version = qcom_cpufreq_kryo_get_msm_id(); - if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { - dev_err(cpu_dev, "Not Snapdragon 820/821!"); - return -ENODEV; - } - - np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); - if (!np) - return -ENOENT; - - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); - if (!ret) { - of_node_put(np); - return -ENOENT; - } - - speedbin_nvmem = of_nvmem_cell_get(np, NULL); - of_node_put(np); - if (IS_ERR(speedbin_nvmem)) { - if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER) - dev_err(cpu_dev, "Could not get nvmem cell: %ld\n", - PTR_ERR(speedbin_nvmem)); - return PTR_ERR(speedbin_nvmem); - } - - speedbin = nvmem_cell_read(speedbin_nvmem, &len); - nvmem_cell_put(speedbin_nvmem); - if (IS_ERR(speedbin)) - return PTR_ERR(speedbin); - - switch (msm8996_version) { - case MSM8996_V3: - versions = 1 << (unsigned int)(*speedbin); - break; - case MSM8996_SG: - versions = 1 << ((unsigned int)(*speedbin) + 4); - break; - default: - BUG(); - break; - } - kfree(speedbin); - - for_each_possible_cpu(cpu) { - cpu_dev = get_cpu_device(cpu); - if (NULL == cpu_dev) { - ret = -ENODEV; - goto free_opp; - } - - opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev, - &versions, 1); - if (IS_ERR(opp_tables[cpu])) { - ret = PTR_ERR(opp_tables[cpu]); - dev_err(cpu_dev, "Failed to set supported hardware\n"); - goto free_opp; - } - } - - cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, - NULL, 0); - if (!IS_ERR(cpufreq_dt_pdev)) - return 0; - - ret = PTR_ERR(cpufreq_dt_pdev); - dev_err(cpu_dev, "Failed to register platform device\n"); - -free_opp: - for_each_possible_cpu(cpu) { - if (IS_ERR_OR_NULL(opp_tables[cpu])) - break; - dev_pm_opp_put_supported_hw(opp_tables[cpu]); - } - - return ret; -} - -static int qcom_cpufreq_kryo_remove(struct platform_device *pdev) -{ - platform_device_unregister(cpufreq_dt_pdev); - return 0; -} - -static struct platform_driver qcom_cpufreq_kryo_driver = { - .probe = qcom_cpufreq_kryo_probe, - .remove = qcom_cpufreq_kryo_remove, - .driver = { - .name = "qcom-cpufreq-kryo", - }, -}; - -static const struct of_device_id qcom_cpufreq_kryo_match_list[] __initconst = { - { .compatible = "qcom,apq8096", }, - { .compatible = "qcom,msm8996", }, - {} -}; - -/* - * Since the driver depends on smem and nvmem drivers, which may - * return EPROBE_DEFER, all the real activity is done in the probe, - * which may be defered as well. The init here is only registering - * the driver and the platform device. - */ -static int __init qcom_cpufreq_kryo_init(void) -{ - struct device_node *np = of_find_node_by_path("/"); - const struct of_device_id *match; - int ret; - - if (!np) - return -ENODEV; - - match = of_match_node(qcom_cpufreq_kryo_match_list, np); - of_node_put(np); - if (!match) - return -ENODEV; - - ret = platform_driver_register(&qcom_cpufreq_kryo_driver); - if (unlikely(ret < 0)) - return ret; - - kryo_cpufreq_pdev = platform_device_register_simple( - "qcom-cpufreq-kryo", -1, NULL, 0); - ret = PTR_ERR_OR_ZERO(kryo_cpufreq_pdev); - if (0 == ret) - return 0; - - platform_driver_unregister(&qcom_cpufreq_kryo_driver); - return ret; -} -module_init(qcom_cpufreq_kryo_init); - -static void __exit qcom_cpufreq_kryo_exit(void) -{ - platform_device_unregister(kryo_cpufreq_pdev); - platform_driver_unregister(&qcom_cpufreq_kryo_driver); -} -module_exit(qcom_cpufreq_kryo_exit); - -MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c new file mode 100644 index 000000000000..fa7e1c6c6a85 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +/* + * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors, + * the CPU frequency subset and voltage value of each OPP varies + * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables + * defines the voltage and frequency value based on the msm-id in SMEM + * and speedbin blown in the efuse combination. + * The qcom-cpufreq driver reads the msm-id and efuse value from the SoC + * to provide the OPP framework with required information. + * This is used to determine the voltage and frequency value for each OPP of + * operating-points-v2 table when it is parsed by the OPP framework. + */ + +#include <linux/cpu.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> +#include <linux/soc/qcom/smem.h> + +#define MSM_ID_SMEM 137 + +enum _msm_id { + MSM8996V3 = 0xF6ul, + APQ8096V3 = 0x123ul, + MSM8996SG = 0x131ul, + APQ8096SG = 0x138ul, +}; + +enum _msm8996_version { + MSM8996_V3, + MSM8996_SG, + NUM_OF_MSM8996_VERSIONS, +}; + +static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; + +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); + pte_efuse &= BIT(21); + 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 enum _msm8996_version qcom_cpufreq_get_msm_id(void) +{ + size_t len; + u32 *msm_id; + enum _msm8996_version version; + + msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len); + if (IS_ERR(msm_id)) + return NUM_OF_MSM8996_VERSIONS; + + /* The first 4 bytes are format, next to them is the actual msm-id */ + msm_id++; + + switch ((enum _msm_id)*msm_id) { + case MSM8996V3: + case APQ8096V3: + version = MSM8996_V3; + break; + case MSM8996SG: + case APQ8096SG: + version = MSM8996_SG; + break; + default: + version = NUM_OF_MSM8996_VERSIONS; + } + + return version; +} + +static int qcom_cpufreq_krait_name_version(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, + char **name, + u32 *versions) +{ + int speed = 0, pvs = 0, pvs_ver = 0; + u8 *buf; + size_t len; + + buf = nvmem_cell_read(speedbin_nvmem, &len); + if (len == 4) { + get_krait_bin_format_a(&speed, &pvs, &pvs_ver, + speedbin_nvmem, buf); + } else if (len == 8) { + get_krait_bin_format_b(&speed, &pvs, &pvs_ver, + speedbin_nvmem, buf); + } else { + dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n"); + return -ENODEV; + } + + snprintf(*name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d", + speed, pvs, pvs_ver); + + *versions = (1 << speed); + + return 0; +} + +static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, + char **pvs_name, + u32 *versions) +{ + size_t len; + u8 *speedbin; + enum _msm8996_version msm8996_version; + + *pvs_name = NULL; + msm8996_version = qcom_cpufreq_get_msm_id(); + if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { + dev_err(cpu_dev, "Not Snapdragon 820/821!"); + return -ENODEV; + } + + speedbin = nvmem_cell_read(speedbin_nvmem, &len); + if (IS_ERR(speedbin)) + return PTR_ERR(speedbin); + + switch (msm8996_version) { + case MSM8996_V3: + *versions = 1 << (unsigned int)(*speedbin); + break; + case MSM8996_SG: + *versions = 1 << ((unsigned int)(*speedbin) + 4); + break; + default: + BUG(); + break; + } + + kfree(speedbin); + return 0; +} + +static int qcom_cpufreq_probe(struct platform_device *pdev) +{ + struct opp_table *tbl1[NR_CPUS] = { NULL }, *tbl2[NR_CPUS] = { NULL }; + int (*get_version)(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, + char **name, int *versions); + struct nvmem_cell *speedbin_nvmem; + struct device_node *np; + struct device *cpu_dev; + unsigned cpu; + u32 versions; + const struct of_device_id *match; + char *pvs_name = "speedXX-pvsXX-vXX"; + int ret; + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) + return -ENODEV; + + match = pdev->dev.platform_data; + get_version = match->data; + if (!get_version) + return -ENODEV; + + np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); + if (!np) + return -ENOENT; + + ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); + if (!ret) { + of_node_put(np); + return -ENOENT; + } + + speedbin_nvmem = of_nvmem_cell_get(np, NULL); + of_node_put(np); + if (IS_ERR(speedbin_nvmem)) { + if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER) + dev_err(cpu_dev, "Could not get nvmem cell: %ld\n", + PTR_ERR(speedbin_nvmem)); + return PTR_ERR(speedbin_nvmem); + } + + ret = get_version(cpu_dev, speedbin_nvmem, &pvs_name, &versions); + nvmem_cell_put(speedbin_nvmem); + if (ret) + return ret; + + for_each_possible_cpu(cpu) { + cpu_dev = get_cpu_device(cpu); + if (NULL == cpu_dev) { + ret = -ENODEV; + goto free_opp; + } + + if (pvs_name) { + tbl1[cpu] = dev_pm_opp_set_prop_name(cpu_dev, pvs_name); + if (IS_ERR(tbl1[cpu])) { + ret = PTR_ERR(tbl1[cpu]); + dev_err(cpu_dev, "Failed to add OPP name %s\n", + pvs_name); + goto free_opp; + } + } + + tbl2[cpu] = dev_pm_opp_set_supported_hw(cpu_dev, &versions, 1); + if (IS_ERR(tbl2[cpu])) { + ret = PTR_ERR(tbl2[cpu]); + dev_err(cpu_dev, "Failed to set supported hardware\n"); + goto free_opp; + } + } + + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) + return 0; + + ret = PTR_ERR(cpufreq_dt_pdev); + dev_err(cpu_dev, "Failed to register platform device\n"); + +free_opp: + for_each_possible_cpu(cpu) { + if (IS_ERR_OR_NULL(tbl1[cpu])) + break; + dev_pm_opp_put_prop_name(tbl1[cpu]); + } + + for_each_possible_cpu(cpu) { + if (IS_ERR_OR_NULL(tbl2[cpu])) + break; + dev_pm_opp_put_supported_hw(tbl2[cpu]); + } + + return ret; +} + +static int qcom_cpufreq_remove(struct platform_device *pdev) +{ + platform_device_unregister(cpufreq_dt_pdev); + return 0; +} + +static struct platform_driver qcom_cpufreq_driver = { + .probe = qcom_cpufreq_probe, + .remove = qcom_cpufreq_remove, + .driver = { + .name = "qcom-cpufreq", + }, +}; + +static const struct of_device_id qcom_cpufreq_match_list[] __initconst = { + { .compatible = "qcom,apq8096", + .data = qcom_cpufreq_kryo_name_version}, + { .compatible = "qcom,msm8996", + .data = qcom_cpufreq_kryo_name_version}, + { .compatible = "qcom,ipq8064", + .data = qcom_cpufreq_krait_name_version }, + { .compatible = "qcom,apq8064", + .data = qcom_cpufreq_krait_name_version }, + { .compatible = "qcom,msm8974", + .data = qcom_cpufreq_krait_name_version }, + { .compatible = "qcom,msm8960", + .data = qcom_cpufreq_krait_name_version }, + {}, +}; + +/* + * Since the driver depends on smem and nvmem drivers, which may + * return EPROBE_DEFER, all the real activity is done in the probe, + * which may be defered as well. The init here is only registering + * the driver and the platform device. + */ +static int __init qcom_cpufreq_init(void) +{ + struct device_node *np = of_find_node_by_path("/"); + const struct of_device_id *match; + int ret; + + if (!np) + return -ENODEV; + + match = of_match_node(qcom_cpufreq_match_list, np); + of_node_put(np); + if (!match) + return -ENODEV; + + ret = platform_driver_register(&qcom_cpufreq_driver); + if (unlikely(ret < 0)) + return ret; + + cpufreq_pdev = platform_device_register_data(NULL, "qcom-cpufreq", + -1, match, sizeof(*match)); + ret = PTR_ERR_OR_ZERO(cpufreq_pdev); + if (0 == ret) + return 0; + + platform_driver_unregister(&qcom_cpufreq_driver); + return ret; +} +module_init(qcom_cpufreq_init); + +static void __exit qcom_cpufreq_exit(void) +{ + platform_device_unregister(cpufreq_pdev); + platform_driver_unregister(&qcom_cpufreq_driver); +} +module_exit(qcom_cpufreq_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. CPUfreq driver"); +MODULE_LICENSE("GPL v2"); |