forked from Minki/linux
Merge branch 'pm-cpufreq'
* pm-cpufreq: (25 commits) dt-bindings: cpufreq: Document operating-points-v2-kryo-cpu cpufreq: Add Kryo CPU scaling driver cpufreq: Use static SRCU initializer kernel/SRCU: provide a static initializer cpufreq: Fix new policy initialization during limits updates via sysfs cpufreq: tegra20: Wrap cpufreq into platform driver cpufreq: tegra20: Allow cpufreq driver to be built as loadable module cpufreq: tegra20: Check if this is Tegra20 machine cpufreq: tegra20: Remove unneeded variable initialization cpufreq: tegra20: Remove unnecessary parentheses cpufreq: tegra20: Remove unneeded check in tegra_cpu_init cpufreq: tegra20: Release clocks properly cpufreq: tegra20: Remove EMC clock usage cpufreq: tegra20: Clean up included headers cpufreq: tegra20: Clean up whitespaces in the code cpufreq: tegra20: Change module description Revert "cpufreq: rcar: Add support for R8A7795 SoC" Revert "cpufreq: dt: Add r8a7796 support to to use generic cpufreq driver" cpufreq: intel_pstate: allow trace in passive mode cpufreq: optimize cpufreq_notify_transition() ...
This commit is contained in:
commit
e27f84e163
680
Documentation/devicetree/bindings/opp/kryo-cpufreq.txt
Normal file
680
Documentation/devicetree/bindings/opp/kryo-cpufreq.txt
Normal file
@ -0,0 +1,680 @@
|
||||
Qualcomm Technologies, Inc. KRYO CPUFreq and OPP bindings
|
||||
===================================
|
||||
|
||||
In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996
|
||||
that have KRYO processors, the CPU ferequencies subset and voltage value
|
||||
of each OPP varies based on the silicon variant in use.
|
||||
Qualcomm Technologies, Inc. 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 (existing HW bitmap).
|
||||
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.
|
||||
|
||||
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-kryo-cpu' for apq8096 and msm8996.
|
||||
- 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
|
||||
value pair.
|
||||
Please refer the for nvmem-cells
|
||||
bindings Documentation/devicetree/bindings/nvmem/nvmem.txt
|
||||
and also examples below.
|
||||
|
||||
In every OPP node:
|
||||
- opp-supported-hw: A single 32 bit bitmap value, representing compatible HW.
|
||||
Bitmap:
|
||||
0: MSM8996 V3, speedbin 0
|
||||
1: MSM8996 V3, speedbin 1
|
||||
2: MSM8996 V3, speedbin 2
|
||||
3: unused
|
||||
4: MSM8996 SG, speedbin 0
|
||||
5: MSM8996 SG, speedbin 1
|
||||
6: MSM8996 SG, speedbin 2
|
||||
7-31: unused
|
||||
|
||||
Example 1:
|
||||
---------
|
||||
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
CPU0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 0>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster0_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_0>;
|
||||
L2_0: l2-cache {
|
||||
compatible = "cache";
|
||||
cache-level = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x1>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 0>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster0_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_0>;
|
||||
};
|
||||
|
||||
CPU2: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 1>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster1_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_1>;
|
||||
L2_1: l2-cache {
|
||||
compatible = "cache";
|
||||
cache-level = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU3: cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x101>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 1>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster1_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_1>;
|
||||
};
|
||||
|
||||
cpu-map {
|
||||
cluster0 {
|
||||
core0 {
|
||||
cpu = <&CPU0>;
|
||||
};
|
||||
|
||||
core1 {
|
||||
cpu = <&CPU1>;
|
||||
};
|
||||
};
|
||||
|
||||
cluster1 {
|
||||
core0 {
|
||||
cpu = <&CPU2>;
|
||||
};
|
||||
|
||||
core1 {
|
||||
cpu = <&CPU3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cluster0_opp: opp_table0 {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
nvmem-cells = <&speedbin_efuse>;
|
||||
opp-shared;
|
||||
|
||||
opp-307200000 {
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-384000000 {
|
||||
opp-hz = /bits/ 64 <384000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-422400000 {
|
||||
opp-hz = /bits/ 64 <422400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-460800000 {
|
||||
opp-hz = /bits/ 64 <460800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-480000000 {
|
||||
opp-hz = /bits/ 64 <480000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-537600000 {
|
||||
opp-hz = /bits/ 64 <537600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-556800000 {
|
||||
opp-hz = /bits/ 64 <556800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-614400000 {
|
||||
opp-hz = /bits/ 64 <614400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-652800000 {
|
||||
opp-hz = /bits/ 64 <652800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-691200000 {
|
||||
opp-hz = /bits/ 64 <691200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-729600000 {
|
||||
opp-hz = /bits/ 64 <729600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-768000000 {
|
||||
opp-hz = /bits/ 64 <768000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-844800000 {
|
||||
opp-hz = /bits/ 64 <844800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-902400000 {
|
||||
opp-hz = /bits/ 64 <902400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-960000000 {
|
||||
opp-hz = /bits/ 64 <960000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-979200000 {
|
||||
opp-hz = /bits/ 64 <979200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1036800000 {
|
||||
opp-hz = /bits/ 64 <1036800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1056000000 {
|
||||
opp-hz = /bits/ 64 <1056000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1113600000 {
|
||||
opp-hz = /bits/ 64 <1113600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1132800000 {
|
||||
opp-hz = /bits/ 64 <1132800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1190400000 {
|
||||
opp-hz = /bits/ 64 <1190400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1209600000 {
|
||||
opp-hz = /bits/ 64 <1209600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1228800000 {
|
||||
opp-hz = /bits/ 64 <1228800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1286400000 {
|
||||
opp-hz = /bits/ 64 <1286400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1324800000 {
|
||||
opp-hz = /bits/ 64 <1324800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x5>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1363200000 {
|
||||
opp-hz = /bits/ 64 <1363200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x72>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1401600000 {
|
||||
opp-hz = /bits/ 64 <1401600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x5>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1440000000 {
|
||||
opp-hz = /bits/ 64 <1440000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1478400000 {
|
||||
opp-hz = /bits/ 64 <1478400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1497600000 {
|
||||
opp-hz = /bits/ 64 <1497600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x4>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1516800000 {
|
||||
opp-hz = /bits/ 64 <1516800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1593600000 {
|
||||
opp-hz = /bits/ 64 <1593600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x71>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1996800000 {
|
||||
opp-hz = /bits/ 64 <1996800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x20>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2188800000 {
|
||||
opp-hz = /bits/ 64 <2188800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
};
|
||||
|
||||
cluster1_opp: opp_table1 {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
nvmem-cells = <&speedbin_efuse>;
|
||||
opp-shared;
|
||||
|
||||
opp-307200000 {
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-384000000 {
|
||||
opp-hz = /bits/ 64 <384000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-403200000 {
|
||||
opp-hz = /bits/ 64 <403200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-460800000 {
|
||||
opp-hz = /bits/ 64 <460800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-480000000 {
|
||||
opp-hz = /bits/ 64 <480000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-537600000 {
|
||||
opp-hz = /bits/ 64 <537600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-556800000 {
|
||||
opp-hz = /bits/ 64 <556800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-614400000 {
|
||||
opp-hz = /bits/ 64 <614400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-652800000 {
|
||||
opp-hz = /bits/ 64 <652800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-691200000 {
|
||||
opp-hz = /bits/ 64 <691200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-729600000 {
|
||||
opp-hz = /bits/ 64 <729600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-748800000 {
|
||||
opp-hz = /bits/ 64 <748800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-806400000 {
|
||||
opp-hz = /bits/ 64 <806400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-825600000 {
|
||||
opp-hz = /bits/ 64 <825600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-883200000 {
|
||||
opp-hz = /bits/ 64 <883200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-902400000 {
|
||||
opp-hz = /bits/ 64 <902400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-940800000 {
|
||||
opp-hz = /bits/ 64 <940800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-979200000 {
|
||||
opp-hz = /bits/ 64 <979200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1036800000 {
|
||||
opp-hz = /bits/ 64 <1036800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1056000000 {
|
||||
opp-hz = /bits/ 64 <1056000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1113600000 {
|
||||
opp-hz = /bits/ 64 <1113600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1132800000 {
|
||||
opp-hz = /bits/ 64 <1132800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1190400000 {
|
||||
opp-hz = /bits/ 64 <1190400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1209600000 {
|
||||
opp-hz = /bits/ 64 <1209600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1248000000 {
|
||||
opp-hz = /bits/ 64 <1248000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1286400000 {
|
||||
opp-hz = /bits/ 64 <1286400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1324800000 {
|
||||
opp-hz = /bits/ 64 <1324800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1363200000 {
|
||||
opp-hz = /bits/ 64 <1363200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1401600000 {
|
||||
opp-hz = /bits/ 64 <1401600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1440000000 {
|
||||
opp-hz = /bits/ 64 <1440000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1478400000 {
|
||||
opp-hz = /bits/ 64 <1478400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1516800000 {
|
||||
opp-hz = /bits/ 64 <1516800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1555200000 {
|
||||
opp-hz = /bits/ 64 <1555200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1593600000 {
|
||||
opp-hz = /bits/ 64 <1593600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1632000000 {
|
||||
opp-hz = /bits/ 64 <1632000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1670400000 {
|
||||
opp-hz = /bits/ 64 <1670400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1708800000 {
|
||||
opp-hz = /bits/ 64 <1708800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1747200000 {
|
||||
opp-hz = /bits/ 64 <1747200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1785600000 {
|
||||
opp-hz = /bits/ 64 <1785600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1804800000 {
|
||||
opp-hz = /bits/ 64 <1804800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x6>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1824000000 {
|
||||
opp-hz = /bits/ 64 <1824000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x71>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1900800000 {
|
||||
opp-hz = /bits/ 64 <1900800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x74>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1920000000 {
|
||||
opp-hz = /bits/ 64 <1920000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1977600000 {
|
||||
opp-hz = /bits/ 64 <1977600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x30>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1996800000 {
|
||||
opp-hz = /bits/ 64 <1996800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2054400000 {
|
||||
opp-hz = /bits/ 64 <2054400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x30>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2073600000 {
|
||||
opp-hz = /bits/ 64 <2073600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2150400000 {
|
||||
opp-hz = /bits/ 64 <2150400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x31>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2246400000 {
|
||||
opp-hz = /bits/ 64 <2246400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2342400000 {
|
||||
opp-hz = /bits/ 64 <2342400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
};
|
||||
|
||||
....
|
||||
|
||||
reserved-memory {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
....
|
||||
smem_mem: smem-mem@86000000 {
|
||||
reg = <0x0 0x86000000 0x0 0x200000>;
|
||||
no-map;
|
||||
};
|
||||
....
|
||||
};
|
||||
|
||||
smem {
|
||||
compatible = "qcom,smem";
|
||||
memory-region = <&smem_mem>;
|
||||
hwlocks = <&tcsr_mutex 3>;
|
||||
};
|
||||
|
||||
soc {
|
||||
....
|
||||
qfprom: qfprom@74000 {
|
||||
compatible = "qcom,qfprom";
|
||||
reg = <0x00074000 0x8ff>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
....
|
||||
speedbin_efuse: speedbin@133 {
|
||||
reg = <0x133 0x1>;
|
||||
bits = <5 3>;
|
||||
};
|
||||
};
|
||||
};
|
@ -11654,6 +11654,13 @@ F: Documentation/devicetree/bindings/media/qcom,camss.txt
|
||||
F: Documentation/media/v4l-drivers/qcom_camss.rst
|
||||
F: drivers/media/platform/qcom/camss-8x16/
|
||||
|
||||
QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
|
||||
M: Ilia Lin <ilia.lin@gmail.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/opp/kryo-cpufreq.txt
|
||||
F: drivers/cpufreq/qcom-cpufreq-kryo.c
|
||||
|
||||
QUALCOMM EMAC GIGABIT ETHERNET DRIVER
|
||||
M: Timur Tabi <timur@codeaurora.org>
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -124,6 +124,17 @@ config ARM_OMAP2PLUS_CPUFREQ
|
||||
depends on ARCH_OMAP2PLUS
|
||||
default ARCH_OMAP2PLUS
|
||||
|
||||
config ARM_QCOM_CPUFREQ_KRYO
|
||||
bool "Qualcomm Kryo based CPUFreq"
|
||||
depends on ARM64
|
||||
depends on QCOM_QFPROM
|
||||
depends on QCOM_SMEM
|
||||
select PM_OPP
|
||||
help
|
||||
This adds the CPUFreq driver for Qualcomm Kryo SoC based boards.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_S3C_CPUFREQ
|
||||
bool
|
||||
help
|
||||
@ -264,7 +275,7 @@ config ARM_TANGO_CPUFREQ
|
||||
default y
|
||||
|
||||
config ARM_TEGRA20_CPUFREQ
|
||||
bool "Tegra20 CPUFreq support"
|
||||
tristate "Tegra20 CPUFreq support"
|
||||
depends on ARCH_TEGRA
|
||||
default y
|
||||
help
|
||||
|
@ -65,6 +65,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
|
||||
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_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "cpufreq-dt.h"
|
||||
|
||||
/* Power management in North Bridge register set */
|
||||
#define ARMADA_37XX_NB_L0L1 0x18
|
||||
#define ARMADA_37XX_NB_L2L3 0x1C
|
||||
@ -56,6 +58,16 @@
|
||||
*/
|
||||
#define LOAD_LEVEL_NR 4
|
||||
|
||||
struct armada37xx_cpufreq_state {
|
||||
struct regmap *regmap;
|
||||
u32 nb_l0l1;
|
||||
u32 nb_l2l3;
|
||||
u32 nb_dyn_mod;
|
||||
u32 nb_cpu_load;
|
||||
};
|
||||
|
||||
static struct armada37xx_cpufreq_state *armada37xx_cpufreq_state;
|
||||
|
||||
struct armada_37xx_dvfs {
|
||||
u32 cpu_freq_max;
|
||||
u8 divider[LOAD_LEVEL_NR];
|
||||
@ -136,7 +148,7 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
|
||||
clk_set_parent(clk, parent);
|
||||
}
|
||||
|
||||
static void __init armada37xx_cpufreq_disable_dvfs(struct regmap *base)
|
||||
static void armada37xx_cpufreq_disable_dvfs(struct regmap *base)
|
||||
{
|
||||
unsigned int reg = ARMADA_37XX_NB_DYN_MOD,
|
||||
mask = ARMADA_37XX_NB_DFS_EN;
|
||||
@ -162,10 +174,47 @@ static void __init armada37xx_cpufreq_enable_dvfs(struct regmap *base)
|
||||
regmap_update_bits(base, reg, mask, mask);
|
||||
}
|
||||
|
||||
static int armada37xx_cpufreq_suspend(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct armada37xx_cpufreq_state *state = armada37xx_cpufreq_state;
|
||||
|
||||
regmap_read(state->regmap, ARMADA_37XX_NB_L0L1, &state->nb_l0l1);
|
||||
regmap_read(state->regmap, ARMADA_37XX_NB_L2L3, &state->nb_l2l3);
|
||||
regmap_read(state->regmap, ARMADA_37XX_NB_CPU_LOAD,
|
||||
&state->nb_cpu_load);
|
||||
regmap_read(state->regmap, ARMADA_37XX_NB_DYN_MOD, &state->nb_dyn_mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada37xx_cpufreq_resume(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct armada37xx_cpufreq_state *state = armada37xx_cpufreq_state;
|
||||
|
||||
/* Ensure DVFS is disabled otherwise the following registers are RO */
|
||||
armada37xx_cpufreq_disable_dvfs(state->regmap);
|
||||
|
||||
regmap_write(state->regmap, ARMADA_37XX_NB_L0L1, state->nb_l0l1);
|
||||
regmap_write(state->regmap, ARMADA_37XX_NB_L2L3, state->nb_l2l3);
|
||||
regmap_write(state->regmap, ARMADA_37XX_NB_CPU_LOAD,
|
||||
state->nb_cpu_load);
|
||||
|
||||
/*
|
||||
* NB_DYN_MOD register is the one that actually enable back DVFS if it
|
||||
* was enabled before the suspend operation. This must be done last
|
||||
* otherwise other registers are not writable.
|
||||
*/
|
||||
regmap_write(state->regmap, ARMADA_37XX_NB_DYN_MOD, state->nb_dyn_mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init armada37xx_cpufreq_driver_init(void)
|
||||
{
|
||||
struct cpufreq_dt_platform_data pdata;
|
||||
struct armada_37xx_dvfs *dvfs;
|
||||
struct platform_device *pdev;
|
||||
unsigned long freq;
|
||||
unsigned int cur_frequency;
|
||||
struct regmap *nb_pm_base;
|
||||
struct device *cpu_dev;
|
||||
@ -207,33 +256,58 @@ static int __init armada37xx_cpufreq_driver_init(void)
|
||||
}
|
||||
|
||||
dvfs = armada_37xx_cpu_freq_info_get(cur_frequency);
|
||||
if (!dvfs)
|
||||
if (!dvfs) {
|
||||
clk_put(clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
armada37xx_cpufreq_state = kmalloc(sizeof(*armada37xx_cpufreq_state),
|
||||
GFP_KERNEL);
|
||||
if (!armada37xx_cpufreq_state) {
|
||||
clk_put(clk);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
armada37xx_cpufreq_state->regmap = nb_pm_base;
|
||||
|
||||
armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider);
|
||||
clk_put(clk);
|
||||
|
||||
for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR;
|
||||
load_lvl++) {
|
||||
unsigned long freq = cur_frequency / dvfs->divider[load_lvl];
|
||||
freq = cur_frequency / dvfs->divider[load_lvl];
|
||||
|
||||
ret = dev_pm_opp_add(cpu_dev, freq, 0);
|
||||
if (ret) {
|
||||
/* clean-up the already added opp before leaving */
|
||||
while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) {
|
||||
freq = cur_frequency / dvfs->divider[load_lvl];
|
||||
dev_pm_opp_remove(cpu_dev, freq);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto remove_opp;
|
||||
}
|
||||
|
||||
/* Now that everything is setup, enable the DVFS at hardware level */
|
||||
armada37xx_cpufreq_enable_dvfs(nb_pm_base);
|
||||
|
||||
pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
|
||||
pdata.suspend = armada37xx_cpufreq_suspend;
|
||||
pdata.resume = armada37xx_cpufreq_resume;
|
||||
|
||||
return PTR_ERR_OR_ZERO(pdev);
|
||||
pdev = platform_device_register_data(NULL, "cpufreq-dt", -1, &pdata,
|
||||
sizeof(pdata));
|
||||
ret = PTR_ERR_OR_ZERO(pdev);
|
||||
if (ret)
|
||||
goto disable_dvfs;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_dvfs:
|
||||
armada37xx_cpufreq_disable_dvfs(nb_pm_base);
|
||||
remove_opp:
|
||||
/* clean-up the already added opp before leaving */
|
||||
while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) {
|
||||
freq = cur_frequency / dvfs->divider[load_lvl];
|
||||
dev_pm_opp_remove(cpu_dev, freq);
|
||||
}
|
||||
|
||||
kfree(armada37xx_cpufreq_state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* late_initcall, to guarantee the driver is loaded after A37xx clock driver */
|
||||
late_initcall(armada37xx_cpufreq_driver_init);
|
||||
|
@ -66,8 +66,6 @@ static const struct of_device_id whitelist[] __initconst = {
|
||||
{ .compatible = "renesas,r8a7792", },
|
||||
{ .compatible = "renesas,r8a7793", },
|
||||
{ .compatible = "renesas,r8a7794", },
|
||||
{ .compatible = "renesas,r8a7795", },
|
||||
{ .compatible = "renesas,r8a7796", },
|
||||
{ .compatible = "renesas,sh73a0", },
|
||||
|
||||
{ .compatible = "rockchip,rk2928", },
|
||||
@ -118,6 +116,9 @@ static const struct of_device_id blacklist[] __initconst = {
|
||||
|
||||
{ .compatible = "nvidia,tegra124", },
|
||||
|
||||
{ .compatible = "qcom,apq8096", },
|
||||
{ .compatible = "qcom,msm8996", },
|
||||
|
||||
{ .compatible = "st,stih407", },
|
||||
{ .compatible = "st,stih410", },
|
||||
|
||||
|
@ -346,8 +346,14 @@ static int dt_cpufreq_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (data && data->have_governor_per_policy)
|
||||
dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY;
|
||||
if (data) {
|
||||
if (data->have_governor_per_policy)
|
||||
dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY;
|
||||
|
||||
dt_cpufreq_driver.resume = data->resume;
|
||||
if (data->suspend)
|
||||
dt_cpufreq_driver.suspend = data->suspend;
|
||||
}
|
||||
|
||||
ret = cpufreq_register_driver(&dt_cpufreq_driver);
|
||||
if (ret)
|
||||
|
@ -12,8 +12,13 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct cpufreq_policy;
|
||||
|
||||
struct cpufreq_dt_platform_data {
|
||||
bool have_governor_per_policy;
|
||||
|
||||
int (*suspend)(struct cpufreq_policy *policy);
|
||||
int (*resume)(struct cpufreq_policy *policy);
|
||||
};
|
||||
|
||||
#endif /* __CPUFREQ_DT_H__ */
|
||||
|
@ -89,16 +89,7 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy);
|
||||
* The mutex locks both lists.
|
||||
*/
|
||||
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
|
||||
static struct srcu_notifier_head cpufreq_transition_notifier_list;
|
||||
|
||||
static bool init_cpufreq_transition_notifier_list_called;
|
||||
static int __init init_cpufreq_transition_notifier_list(void)
|
||||
{
|
||||
srcu_init_notifier_head(&cpufreq_transition_notifier_list);
|
||||
init_cpufreq_transition_notifier_list_called = true;
|
||||
return 0;
|
||||
}
|
||||
pure_initcall(init_cpufreq_transition_notifier_list);
|
||||
SRCU_NOTIFIER_HEAD_STATIC(cpufreq_transition_notifier_list);
|
||||
|
||||
static int off __read_mostly;
|
||||
static int cpufreq_disabled(void)
|
||||
@ -300,8 +291,19 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
struct cpufreq_freqs *freqs, unsigned int state)
|
||||
/**
|
||||
* cpufreq_notify_transition - Notify frequency transition and adjust_jiffies.
|
||||
* @policy: cpufreq policy to enable fast frequency switching for.
|
||||
* @freqs: contain details of the frequency update.
|
||||
* @state: set to CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE.
|
||||
*
|
||||
* This function calls the transition notifiers and the "adjust_jiffies"
|
||||
* function. It is called twice on all CPU frequency changes that have
|
||||
* external effects.
|
||||
*/
|
||||
static void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
struct cpufreq_freqs *freqs,
|
||||
unsigned int state)
|
||||
{
|
||||
BUG_ON(irqs_disabled());
|
||||
|
||||
@ -313,52 +315,42 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
state, freqs->new);
|
||||
|
||||
switch (state) {
|
||||
|
||||
case CPUFREQ_PRECHANGE:
|
||||
/* detect if the driver reported a value as "old frequency"
|
||||
/*
|
||||
* Detect if the driver reported a value as "old frequency"
|
||||
* which is not equal to what the cpufreq core thinks is
|
||||
* "old frequency".
|
||||
*/
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
if ((policy) && (policy->cpu == freqs->cpu) &&
|
||||
(policy->cur) && (policy->cur != freqs->old)) {
|
||||
if (policy->cur && (policy->cur != freqs->old)) {
|
||||
pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
|
||||
freqs->old, policy->cur);
|
||||
freqs->old = policy->cur;
|
||||
}
|
||||
}
|
||||
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
||||
CPUFREQ_PRECHANGE, freqs);
|
||||
|
||||
for_each_cpu(freqs->cpu, policy->cpus) {
|
||||
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
||||
CPUFREQ_PRECHANGE, freqs);
|
||||
}
|
||||
|
||||
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
|
||||
break;
|
||||
|
||||
case CPUFREQ_POSTCHANGE:
|
||||
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
|
||||
pr_debug("FREQ: %lu - CPU: %lu\n",
|
||||
(unsigned long)freqs->new, (unsigned long)freqs->cpu);
|
||||
trace_cpu_frequency(freqs->new, freqs->cpu);
|
||||
cpufreq_stats_record_transition(policy, freqs->new);
|
||||
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
||||
CPUFREQ_POSTCHANGE, freqs);
|
||||
if (likely(policy) && likely(policy->cpu == freqs->cpu))
|
||||
policy->cur = freqs->new;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pr_debug("FREQ: %u - CPUs: %*pbl\n", freqs->new,
|
||||
cpumask_pr_args(policy->cpus));
|
||||
|
||||
/**
|
||||
* cpufreq_notify_transition - call notifier chain and adjust_jiffies
|
||||
* on frequency transition.
|
||||
*
|
||||
* This function calls the transition notifiers and the "adjust_jiffies"
|
||||
* function. It is called twice on all CPU frequency changes that have
|
||||
* external effects.
|
||||
*/
|
||||
static void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
struct cpufreq_freqs *freqs, unsigned int state)
|
||||
{
|
||||
for_each_cpu(freqs->cpu, policy->cpus)
|
||||
__cpufreq_notify_transition(policy, freqs, state);
|
||||
for_each_cpu(freqs->cpu, policy->cpus) {
|
||||
trace_cpu_frequency(freqs->new, freqs->cpu);
|
||||
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
||||
CPUFREQ_POSTCHANGE, freqs);
|
||||
}
|
||||
|
||||
cpufreq_stats_record_transition(policy, freqs->new);
|
||||
policy->cur = freqs->new;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do post notifications when there are chances that transition has failed */
|
||||
@ -696,6 +688,8 @@ static ssize_t store_##file_name \
|
||||
struct cpufreq_policy new_policy; \
|
||||
\
|
||||
memcpy(&new_policy, policy, sizeof(*policy)); \
|
||||
new_policy.min = policy->user_policy.min; \
|
||||
new_policy.max = policy->user_policy.max; \
|
||||
\
|
||||
ret = sscanf(buf, "%u", &new_policy.object); \
|
||||
if (ret != 1) \
|
||||
@ -1764,8 +1758,6 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
|
||||
if (cpufreq_disabled())
|
||||
return -EINVAL;
|
||||
|
||||
WARN_ON(!init_cpufreq_transition_notifier_list_called);
|
||||
|
||||
switch (list) {
|
||||
case CPUFREQ_TRANSITION_NOTIFIER:
|
||||
mutex_lock(&cpufreq_fast_switch_lock);
|
||||
|
@ -1939,13 +1939,51 @@ static int intel_cpufreq_verify_policy(struct cpufreq_policy *policy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use of trace in passive mode:
|
||||
*
|
||||
* In passive mode the trace core_busy field (also known as the
|
||||
* performance field, and lablelled as such on the graphs; also known as
|
||||
* core_avg_perf) is not needed and so is re-assigned to indicate if the
|
||||
* driver call was via the normal or fast switch path. Various graphs
|
||||
* output from the intel_pstate_tracer.py utility that include core_busy
|
||||
* (or performance or core_avg_perf) have a fixed y-axis from 0 to 100%,
|
||||
* so we use 10 to indicate the the normal path through the driver, and
|
||||
* 90 to indicate the fast switch path through the driver.
|
||||
* The scaled_busy field is not used, and is set to 0.
|
||||
*/
|
||||
|
||||
#define INTEL_PSTATE_TRACE_TARGET 10
|
||||
#define INTEL_PSTATE_TRACE_FAST_SWITCH 90
|
||||
|
||||
static void intel_cpufreq_trace(struct cpudata *cpu, unsigned int trace_type, int old_pstate)
|
||||
{
|
||||
struct sample *sample;
|
||||
|
||||
if (!trace_pstate_sample_enabled())
|
||||
return;
|
||||
|
||||
if (!intel_pstate_sample(cpu, ktime_get()))
|
||||
return;
|
||||
|
||||
sample = &cpu->sample;
|
||||
trace_pstate_sample(trace_type,
|
||||
0,
|
||||
old_pstate,
|
||||
cpu->pstate.current_pstate,
|
||||
sample->mperf,
|
||||
sample->aperf,
|
||||
sample->tsc,
|
||||
get_avg_frequency(cpu),
|
||||
fp_toint(cpu->iowait_boost * 100));
|
||||
}
|
||||
|
||||
static int intel_cpufreq_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
struct cpudata *cpu = all_cpu_data[policy->cpu];
|
||||
struct cpufreq_freqs freqs;
|
||||
int target_pstate;
|
||||
int target_pstate, old_pstate;
|
||||
|
||||
update_turbo_state();
|
||||
|
||||
@ -1965,12 +2003,14 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy,
|
||||
break;
|
||||
}
|
||||
target_pstate = intel_pstate_prepare_request(cpu, target_pstate);
|
||||
old_pstate = cpu->pstate.current_pstate;
|
||||
if (target_pstate != cpu->pstate.current_pstate) {
|
||||
cpu->pstate.current_pstate = target_pstate;
|
||||
wrmsrl_on_cpu(policy->cpu, MSR_IA32_PERF_CTL,
|
||||
pstate_funcs.get_val(cpu, target_pstate));
|
||||
}
|
||||
freqs.new = target_pstate * cpu->pstate.scaling;
|
||||
intel_cpufreq_trace(cpu, INTEL_PSTATE_TRACE_TARGET, old_pstate);
|
||||
cpufreq_freq_transition_end(policy, &freqs, false);
|
||||
|
||||
return 0;
|
||||
@ -1980,13 +2020,15 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq)
|
||||
{
|
||||
struct cpudata *cpu = all_cpu_data[policy->cpu];
|
||||
int target_pstate;
|
||||
int target_pstate, old_pstate;
|
||||
|
||||
update_turbo_state();
|
||||
|
||||
target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling);
|
||||
target_pstate = intel_pstate_prepare_request(cpu, target_pstate);
|
||||
old_pstate = cpu->pstate.current_pstate;
|
||||
intel_pstate_update_pstate(cpu, target_pstate);
|
||||
intel_cpufreq_trace(cpu, INTEL_PSTATE_TRACE_FAST_SWITCH, old_pstate);
|
||||
return target_pstate * cpu->pstate.scaling;
|
||||
}
|
||||
|
||||
|
212
drivers/cpufreq/qcom-cpufreq-kryo.c
Normal file
212
drivers/cpufreq/qcom-cpufreq-kryo.c
Normal file
@ -0,0 +1,212 @@
|
||||
// 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,
|
||||
};
|
||||
|
||||
static enum _msm8996_version __init 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};
|
||||
struct platform_device *cpufreq_dt_pdev;
|
||||
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 (NULL == cpu_dev)
|
||||
ret = -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 (IS_ERR(np))
|
||||
return PTR_ERR(np);
|
||||
|
||||
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)) {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 struct platform_driver qcom_cpufreq_kryo_driver = {
|
||||
.probe = qcom_cpufreq_kryo_probe,
|
||||
.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;
|
||||
|
||||
ret = PTR_ERR_OR_ZERO(platform_device_register_simple(
|
||||
"qcom-cpufreq-kryo", -1, NULL, 0));
|
||||
if (0 == ret)
|
||||
return 0;
|
||||
|
||||
platform_driver_unregister(&qcom_cpufreq_kryo_driver);
|
||||
return ret;
|
||||
}
|
||||
module_init(qcom_cpufreq_kryo_init);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -143,7 +143,7 @@ static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
|
||||
{
|
||||
unsigned long clkdiv, camdiv;
|
||||
|
||||
s3c_freq_dbg("%s: divsiors: h=%d, p=%d\n", __func__,
|
||||
s3c_freq_dbg("%s: divisors: h=%d, p=%d\n", __func__,
|
||||
cfg->divs.h_divisor, cfg->divs.p_divisor);
|
||||
|
||||
clkdiv = __raw_readl(S3C2410_CLKDIVN);
|
||||
|
@ -252,7 +252,7 @@ EXPORT_SYMBOL_GPL(speedstep_get_frequency);
|
||||
*********************************************************************/
|
||||
|
||||
/* Keep in sync with the x86_cpu_id tables in the different modules */
|
||||
unsigned int speedstep_detect_processor(void)
|
||||
enum speedstep_processor speedstep_detect_processor(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
u32 ebx, msr_lo, msr_hi;
|
||||
|
@ -16,16 +16,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
static struct cpufreq_frequency_table freq_table[] = {
|
||||
{ .frequency = 216000 },
|
||||
@ -39,25 +36,27 @@ static struct cpufreq_frequency_table freq_table[] = {
|
||||
{ .frequency = CPUFREQ_TABLE_END },
|
||||
};
|
||||
|
||||
#define NUM_CPUS 2
|
||||
|
||||
static struct clk *cpu_clk;
|
||||
static struct clk *pll_x_clk;
|
||||
static struct clk *pll_p_clk;
|
||||
static struct clk *emc_clk;
|
||||
static bool pll_x_prepared;
|
||||
struct tegra20_cpufreq {
|
||||
struct device *dev;
|
||||
struct cpufreq_driver driver;
|
||||
struct clk *cpu_clk;
|
||||
struct clk *pll_x_clk;
|
||||
struct clk *pll_p_clk;
|
||||
bool pll_x_prepared;
|
||||
};
|
||||
|
||||
static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000;
|
||||
struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
|
||||
unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000;
|
||||
|
||||
/*
|
||||
* Don't switch to intermediate freq if:
|
||||
* - we are already at it, i.e. policy->cur == ifreq
|
||||
* - index corresponds to ifreq
|
||||
*/
|
||||
if ((freq_table[index].frequency == ifreq) || (policy->cur == ifreq))
|
||||
if (freq_table[index].frequency == ifreq || policy->cur == ifreq)
|
||||
return 0;
|
||||
|
||||
return ifreq;
|
||||
@ -66,6 +65,7 @@ static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy,
|
||||
static int tegra_target_intermediate(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -78,47 +78,37 @@ static int tegra_target_intermediate(struct cpufreq_policy *policy,
|
||||
* Also, we wouldn't be using pll_x anymore and must not take extra
|
||||
* reference to it, as it can be disabled now to save some power.
|
||||
*/
|
||||
clk_prepare_enable(pll_x_clk);
|
||||
clk_prepare_enable(cpufreq->pll_x_clk);
|
||||
|
||||
ret = clk_set_parent(cpu_clk, pll_p_clk);
|
||||
ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk);
|
||||
if (ret)
|
||||
clk_disable_unprepare(pll_x_clk);
|
||||
clk_disable_unprepare(cpufreq->pll_x_clk);
|
||||
else
|
||||
pll_x_prepared = true;
|
||||
cpufreq->pll_x_prepared = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
|
||||
unsigned long rate = freq_table[index].frequency;
|
||||
unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Vote on memory bus frequency based on cpu frequency
|
||||
* This sets the minimum frequency, display or avp may request higher
|
||||
*/
|
||||
if (rate >= 816000)
|
||||
clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
|
||||
else if (rate >= 456000)
|
||||
clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
|
||||
else
|
||||
clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
|
||||
unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* target freq == pll_p, don't need to take extra reference to pll_x_clk
|
||||
* as it isn't used anymore.
|
||||
*/
|
||||
if (rate == ifreq)
|
||||
return clk_set_parent(cpu_clk, pll_p_clk);
|
||||
return clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk);
|
||||
|
||||
ret = clk_set_rate(pll_x_clk, rate * 1000);
|
||||
ret = clk_set_rate(cpufreq->pll_x_clk, rate * 1000);
|
||||
/* Restore to earlier frequency on error, i.e. pll_x */
|
||||
if (ret)
|
||||
pr_err("Failed to change pll_x to %lu\n", rate);
|
||||
dev_err(cpufreq->dev, "Failed to change pll_x to %lu\n", rate);
|
||||
|
||||
ret = clk_set_parent(cpu_clk, pll_x_clk);
|
||||
ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_x_clk);
|
||||
/* This shouldn't fail while changing or restoring */
|
||||
WARN_ON(ret);
|
||||
|
||||
@ -126,9 +116,9 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
* Drop count to pll_x clock only if we switched to intermediate freq
|
||||
* earlier while transitioning to a target frequency.
|
||||
*/
|
||||
if (pll_x_prepared) {
|
||||
clk_disable_unprepare(pll_x_clk);
|
||||
pll_x_prepared = false;
|
||||
if (cpufreq->pll_x_prepared) {
|
||||
clk_disable_unprepare(cpufreq->pll_x_clk);
|
||||
cpufreq->pll_x_prepared = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -136,81 +126,111 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
|
||||
static int tegra_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
|
||||
int ret;
|
||||
|
||||
if (policy->cpu >= NUM_CPUS)
|
||||
return -EINVAL;
|
||||
|
||||
clk_prepare_enable(emc_clk);
|
||||
clk_prepare_enable(cpu_clk);
|
||||
clk_prepare_enable(cpufreq->cpu_clk);
|
||||
|
||||
/* FIXME: what's the actual transition time? */
|
||||
ret = cpufreq_generic_init(policy, freq_table, 300 * 1000);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(cpu_clk);
|
||||
clk_disable_unprepare(emc_clk);
|
||||
clk_disable_unprepare(cpufreq->cpu_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
policy->clk = cpu_clk;
|
||||
policy->clk = cpufreq->cpu_clk;
|
||||
policy->suspend_freq = freq_table[0].frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
clk_disable_unprepare(cpu_clk);
|
||||
clk_disable_unprepare(emc_clk);
|
||||
struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
|
||||
|
||||
clk_disable_unprepare(cpufreq->cpu_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver tegra_cpufreq_driver = {
|
||||
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.get_intermediate = tegra_get_intermediate,
|
||||
.target_intermediate = tegra_target_intermediate,
|
||||
.target_index = tegra_target,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = tegra_cpu_init,
|
||||
.exit = tegra_cpu_exit,
|
||||
.name = "tegra",
|
||||
.attr = cpufreq_generic_attr,
|
||||
.suspend = cpufreq_generic_suspend,
|
||||
};
|
||||
|
||||
static int __init tegra_cpufreq_init(void)
|
||||
static int tegra20_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
cpu_clk = clk_get_sys(NULL, "cclk");
|
||||
if (IS_ERR(cpu_clk))
|
||||
return PTR_ERR(cpu_clk);
|
||||
struct tegra20_cpufreq *cpufreq;
|
||||
int err;
|
||||
|
||||
pll_x_clk = clk_get_sys(NULL, "pll_x");
|
||||
if (IS_ERR(pll_x_clk))
|
||||
return PTR_ERR(pll_x_clk);
|
||||
cpufreq = devm_kzalloc(&pdev->dev, sizeof(*cpufreq), GFP_KERNEL);
|
||||
if (!cpufreq)
|
||||
return -ENOMEM;
|
||||
|
||||
pll_p_clk = clk_get_sys(NULL, "pll_p");
|
||||
if (IS_ERR(pll_p_clk))
|
||||
return PTR_ERR(pll_p_clk);
|
||||
cpufreq->cpu_clk = clk_get_sys(NULL, "cclk");
|
||||
if (IS_ERR(cpufreq->cpu_clk))
|
||||
return PTR_ERR(cpufreq->cpu_clk);
|
||||
|
||||
emc_clk = clk_get_sys("cpu", "emc");
|
||||
if (IS_ERR(emc_clk)) {
|
||||
clk_put(cpu_clk);
|
||||
return PTR_ERR(emc_clk);
|
||||
cpufreq->pll_x_clk = clk_get_sys(NULL, "pll_x");
|
||||
if (IS_ERR(cpufreq->pll_x_clk)) {
|
||||
err = PTR_ERR(cpufreq->pll_x_clk);
|
||||
goto put_cpu;
|
||||
}
|
||||
|
||||
return cpufreq_register_driver(&tegra_cpufreq_driver);
|
||||
cpufreq->pll_p_clk = clk_get_sys(NULL, "pll_p");
|
||||
if (IS_ERR(cpufreq->pll_p_clk)) {
|
||||
err = PTR_ERR(cpufreq->pll_p_clk);
|
||||
goto put_pll_x;
|
||||
}
|
||||
|
||||
cpufreq->dev = &pdev->dev;
|
||||
cpufreq->driver.get = cpufreq_generic_get;
|
||||
cpufreq->driver.attr = cpufreq_generic_attr;
|
||||
cpufreq->driver.init = tegra_cpu_init;
|
||||
cpufreq->driver.exit = tegra_cpu_exit;
|
||||
cpufreq->driver.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK;
|
||||
cpufreq->driver.verify = cpufreq_generic_frequency_table_verify;
|
||||
cpufreq->driver.suspend = cpufreq_generic_suspend;
|
||||
cpufreq->driver.driver_data = cpufreq;
|
||||
cpufreq->driver.target_index = tegra_target;
|
||||
cpufreq->driver.get_intermediate = tegra_get_intermediate;
|
||||
cpufreq->driver.target_intermediate = tegra_target_intermediate;
|
||||
snprintf(cpufreq->driver.name, CPUFREQ_NAME_LEN, "tegra");
|
||||
|
||||
err = cpufreq_register_driver(&cpufreq->driver);
|
||||
if (err)
|
||||
goto put_pll_p;
|
||||
|
||||
platform_set_drvdata(pdev, cpufreq);
|
||||
|
||||
return 0;
|
||||
|
||||
put_pll_p:
|
||||
clk_put(cpufreq->pll_p_clk);
|
||||
put_pll_x:
|
||||
clk_put(cpufreq->pll_x_clk);
|
||||
put_cpu:
|
||||
clk_put(cpufreq->cpu_clk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit tegra_cpufreq_exit(void)
|
||||
static int tegra20_cpufreq_remove(struct platform_device *pdev)
|
||||
{
|
||||
cpufreq_unregister_driver(&tegra_cpufreq_driver);
|
||||
clk_put(emc_clk);
|
||||
clk_put(cpu_clk);
|
||||
struct tegra20_cpufreq *cpufreq = platform_get_drvdata(pdev);
|
||||
|
||||
cpufreq_unregister_driver(&cpufreq->driver);
|
||||
|
||||
clk_put(cpufreq->pll_p_clk);
|
||||
clk_put(cpufreq->pll_x_clk);
|
||||
clk_put(cpufreq->cpu_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tegra20_cpufreq_driver = {
|
||||
.probe = tegra20_cpufreq_probe,
|
||||
.remove = tegra20_cpufreq_remove,
|
||||
.driver = {
|
||||
.name = "tegra20-cpufreq",
|
||||
},
|
||||
};
|
||||
module_platform_driver(tegra20_cpufreq_driver);
|
||||
|
||||
MODULE_ALIAS("platform:tegra20-cpufreq");
|
||||
MODULE_AUTHOR("Colin Cross <ccross@android.com>");
|
||||
MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra20 cpufreq driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(tegra_cpufreq_init);
|
||||
module_exit(tegra_cpufreq_exit);
|
||||
|
@ -43,9 +43,7 @@
|
||||
* in srcu_notifier_call_chain(): no cache bounces and no memory barriers.
|
||||
* As compensation, srcu_notifier_chain_unregister() is rather expensive.
|
||||
* SRCU notifier chains should be used when the chain will be called very
|
||||
* often but notifier_blocks will seldom be removed. Also, SRCU notifier
|
||||
* chains are slightly more difficult to use because they require special
|
||||
* runtime initialization.
|
||||
* often but notifier_blocks will seldom be removed.
|
||||
*/
|
||||
|
||||
struct notifier_block;
|
||||
@ -91,7 +89,7 @@ struct srcu_notifier_head {
|
||||
(name)->head = NULL; \
|
||||
} while (0)
|
||||
|
||||
/* srcu_notifier_heads must be initialized and cleaned up dynamically */
|
||||
/* srcu_notifier_heads must be cleaned up dynamically */
|
||||
extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
|
||||
#define srcu_cleanup_notifier_head(name) \
|
||||
cleanup_srcu_struct(&(name)->srcu);
|
||||
@ -104,7 +102,13 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
|
||||
.head = NULL }
|
||||
#define RAW_NOTIFIER_INIT(name) { \
|
||||
.head = NULL }
|
||||
/* srcu_notifier_heads cannot be initialized statically */
|
||||
|
||||
#define SRCU_NOTIFIER_INIT(name, pcpu) \
|
||||
{ \
|
||||
.mutex = __MUTEX_INITIALIZER(name.mutex), \
|
||||
.head = NULL, \
|
||||
.srcu = __SRCU_STRUCT_INIT(name.srcu, pcpu), \
|
||||
}
|
||||
|
||||
#define ATOMIC_NOTIFIER_HEAD(name) \
|
||||
struct atomic_notifier_head name = \
|
||||
@ -116,6 +120,26 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
|
||||
struct raw_notifier_head name = \
|
||||
RAW_NOTIFIER_INIT(name)
|
||||
|
||||
#ifdef CONFIG_TREE_SRCU
|
||||
#define _SRCU_NOTIFIER_HEAD(name, mod) \
|
||||
static DEFINE_PER_CPU(struct srcu_data, \
|
||||
name##_head_srcu_data); \
|
||||
mod struct srcu_notifier_head name = \
|
||||
SRCU_NOTIFIER_INIT(name, name##_head_srcu_data)
|
||||
|
||||
#else
|
||||
#define _SRCU_NOTIFIER_HEAD(name, mod) \
|
||||
mod struct srcu_notifier_head name = \
|
||||
SRCU_NOTIFIER_INIT(name, name)
|
||||
|
||||
#endif
|
||||
|
||||
#define SRCU_NOTIFIER_HEAD(name) \
|
||||
_SRCU_NOTIFIER_HEAD(name, /* not static */)
|
||||
|
||||
#define SRCU_NOTIFIER_HEAD_STATIC(name) \
|
||||
_SRCU_NOTIFIER_HEAD(name, static)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
|
||||
|
@ -43,7 +43,7 @@ struct srcu_struct {
|
||||
|
||||
void srcu_drive_gp(struct work_struct *wp);
|
||||
|
||||
#define __SRCU_STRUCT_INIT(name) \
|
||||
#define __SRCU_STRUCT_INIT(name, __ignored) \
|
||||
{ \
|
||||
.srcu_wq = __SWAIT_QUEUE_HEAD_INITIALIZER(name.srcu_wq), \
|
||||
.srcu_cb_tail = &name.srcu_cb_head, \
|
||||
@ -56,9 +56,9 @@ void srcu_drive_gp(struct work_struct *wp);
|
||||
* Tree SRCU, which needs some per-CPU data.
|
||||
*/
|
||||
#define DEFINE_SRCU(name) \
|
||||
struct srcu_struct name = __SRCU_STRUCT_INIT(name)
|
||||
struct srcu_struct name = __SRCU_STRUCT_INIT(name, name)
|
||||
#define DEFINE_STATIC_SRCU(name) \
|
||||
static struct srcu_struct name = __SRCU_STRUCT_INIT(name)
|
||||
static struct srcu_struct name = __SRCU_STRUCT_INIT(name, name)
|
||||
|
||||
void synchronize_srcu(struct srcu_struct *sp);
|
||||
|
||||
|
@ -104,9 +104,9 @@ struct srcu_struct {
|
||||
#define SRCU_STATE_SCAN1 1
|
||||
#define SRCU_STATE_SCAN2 2
|
||||
|
||||
#define __SRCU_STRUCT_INIT(name) \
|
||||
#define __SRCU_STRUCT_INIT(name, pcpu_name) \
|
||||
{ \
|
||||
.sda = &name##_srcu_data, \
|
||||
.sda = &pcpu_name, \
|
||||
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
|
||||
.srcu_gp_seq_needed = 0 - 1, \
|
||||
__SRCU_DEP_MAP_INIT(name) \
|
||||
@ -133,7 +133,7 @@ struct srcu_struct {
|
||||
*/
|
||||
#define __DEFINE_SRCU(name, is_static) \
|
||||
static DEFINE_PER_CPU(struct srcu_data, name##_srcu_data);\
|
||||
is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name)
|
||||
is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name, name##_srcu_data)
|
||||
#define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */)
|
||||
#define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user