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