diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-07-26 19:55:45 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-07-26 19:55:46 -0600 |
| commit | 35e3dabda5a617debff12cbc17c0cb066928f921 (patch) | |
| tree | a790e92063e2193593488d4874102f763a740a8b | |
| parent | 6385cefa179bb87fff0f9e041075280f119b2554 (diff) | |
| parent | bb02457c09a7e64ac886a8063c8728c8ce6f1d07 (diff) | |
Promotion of kernel.lnx.4.4-160726.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1021659 I322b9b57ec89f5cdc75336d83010ff89a6bb5726 ARM: dts: msm: update frequency to ACC level mappings fo
1043040 I9499497cb558efcf3c73e7145ce65d3f129be696 clk: osm: msm: add support for DxFSM workaround
1021656 Icf4b640ec2c330b0d9721d3494297e2d8445c9b6 regulator: cprh-kbss-regulator: add support for APM cros
1045435 I5e41ce376c694736128ceb051db86f93467fdaea clk: msm: osm: add workaround for C2D/C3 + D2D collapse
1021656 1030444 Iebeb45eaa2503bd5be19f00938d0dbec1163c5a5 ARM: dts: msm: specify APM threshold voltage in OSM for
1039560 Id2811c67a423c82201993b3119647a3d4caf4517 ARM: dts: msm: put ipa3 in smmu s1-bypass on msmcobalt
1021659 I178fb226f4eec4c188f11e9e868a575c70ad58ae clk: msm: osm: support PLL droop detector workaround
1021656 1030444 Iac04f6db8e85b3651a33b6c9bff667365cae891d clk: msm: osm: add support for APM crossover corner
Change-Id: Idedae9661ff2343e37e898c5ae0ef53420055c78
CRs-Fixed: 1039560, 1030444, 1021656, 1043040, 1021659, 1045435
| -rw-r--r-- | Documentation/devicetree/bindings/arm/msm/qcom,osm.txt | 10 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt | 19 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi | 2 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msmcobalt.dtsi | 62 | ||||
| -rw-r--r-- | drivers/clk/msm/clock-osm.c | 333 | ||||
| -rw-r--r-- | drivers/regulator/cpr3-regulator.c | 24 | ||||
| -rw-r--r-- | drivers/regulator/cpr3-regulator.h | 9 | ||||
| -rw-r--r-- | drivers/regulator/cprh-kbss-regulator.c | 73 |
8 files changed, 364 insertions, 168 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt index 2bd7653af5a3..cee9b942a9e3 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt @@ -182,6 +182,14 @@ Properties: command register for each of the two clusters managed by the OSM controller. +- qcom,apm-threshold-voltage + Usage: required + Value type: <u32> + Definition: Specifies the APM threshold voltage in microvolts. If the + VDD_APCC supply voltage is above or at this level, then the + APM is switched to use VDD_APCC. If VDD_APCC is below + this level, then the APM is switched to use VDD_MX. + - qcom,apm-mode-ctl Usage: required Value type: <prop-encoded-array> @@ -392,6 +400,8 @@ Example: qcom,apm-ctrl-status = <0x179d000c 0x179d0018>; + qcom,apm-threshold-voltage = <832000>; + qcom,pwrcl-apcs-mem-acc-cfg = <0x179d1360 0x179d1364 0x179d1364>; qcom,perfcl-apcs-mem-acc-cfg = diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt index b9143cfc2587..833fb645b92a 100644 --- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt @@ -42,10 +42,21 @@ KBSS specific properties: - qcom,apm-threshold-voltage Usage: optional Value type: <u32> - Definition: Specifies the APM threshold voltage in microvolts. If the - VDD_APCC supply voltage is above this level, then the APM is - switched to use VDD_APCC. If VDD_APCC is below this level, - then the APM is switched to use VDD_MX. + Definition: Specifies the APM threshold voltage in microvolts. The + floor to ceiling range for every corner is adjusted to ensure + it does not intersect this voltage. The value of this property + must match with the APM threshold voltage defined in the OSM + device to ensure that if the VDD_APCC supply voltage is above + this level, then the APM is switched to use VDD_APCC and if + VDD_APCC is below this level, then the APM is switched to use + VDD_MX. + +- qcom,apm-crossover-voltage + Usage: required if qcom,apm-threshold-voltage is specified + Value type: <u32> + Definition: Specifies the APM crossover voltage in microvolts which + corresponds to the voltage the VDD supply must be set at + during an APM switch transition. - qcom,apm-hysteresis-voltage Usage: optional diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 12ee61b34d8c..5833b30d1fd1 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -576,6 +576,7 @@ qcom,cpr-voltage-settling-time = <1760>; qcom,apm-threshold-voltage = <832000>; + qcom,apm-crossover-voltage = <880000>; qcom,apm-hysteresis-voltage = <32000>; qcom,voltage-step = <4000>; qcom,voltage-base = <352000>; @@ -737,6 +738,7 @@ qcom,cpr-voltage-settling-time = <1760>; qcom,apm-threshold-voltage = <832000>; + qcom,apm-crossover-voltage = <880000>; qcom,apm-hysteresis-voltage = <32000>; qcom,voltage-step = <4000>; qcom,voltage-base = <352000>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index e748783b0c7d..5dc530ea8494 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -804,21 +804,21 @@ < 576000000 0x0504001e 0x03200020 0x1 >, < 633600000 0x05040021 0x03200020 0x1 >, < 710400000 0x05040025 0x03200020 0x1 >, - < 806400000 0x0504002a 0x04200020 0x2 >, - < 883200000 0x0404002e 0x04250025 0x2 >, - < 960000000 0x04040032 0x05280028 0x2 >, - < 1036800000 0x04040036 0x052b002b 0x3 >, - < 1113600000 0x0404003a 0x052e002e 0x3 >, - < 1190400000 0x0404003e 0x06320032 0x3 >, - < 1248000000 0x04040041 0x06340034 0x3 >, - < 1324800000 0x04040045 0x06370037 0x3 >, - < 1401600000 0x04040049 0x073a003a 0x3 >, - < 1478400000 0x0404004d 0x073e003e 0x3 >, - < 1574400000 0x04040052 0x08420042 0x4 >, - < 1651200000 0x04040056 0x08450045 0x4 >, - < 1728000000 0x0404005a 0x08480048 0x4 >, - < 1804800000 0x0404005e 0x094b004b 0x4 >, - < 1881600000 0x04040062 0x094e004e 0x4 >; + < 806400000 0x0504002a 0x04200020 0x1 >, + < 883200000 0x0404002e 0x04250025 0x1 >, + < 960000000 0x04040032 0x05280028 0x1 >, + < 1036800000 0x04040036 0x052b002b 0x2 >, + < 1113600000 0x0404003a 0x052e002e 0x2 >, + < 1190400000 0x0404003e 0x06320032 0x2 >, + < 1248000000 0x04040041 0x06340034 0x2 >, + < 1324800000 0x04040045 0x06370037 0x2 >, + < 1401600000 0x04040049 0x073a003a 0x2 >, + < 1478400000 0x0404004d 0x073e003e 0x2 >, + < 1574400000 0x04040052 0x08420042 0x3 >, + < 1651200000 0x04040056 0x08450045 0x3 >, + < 1728000000 0x0404005a 0x08480048 0x3 >, + < 1804800000 0x0404005e 0x094b004b 0x3 >, + < 1881600000 0x04040062 0x094e004e 0x3 >; qcom,perfcl-speedbin0-v0 = < 300000000 0x0004000f 0x01200020 0x1 >, @@ -888,6 +888,7 @@ <0x8fff0036 0x8fff003a 0x0fff0036>, <0x8fff003d 0x8fff0041 0x0fff003d>; + qcom,apm-threshold-voltage = <832000>; qcom,boost-fsm-en; qcom,safe-fsm-en; qcom,ps-fsm-en; @@ -900,13 +901,11 @@ qcom,perfcl-apcs-mem-acc-cfg = <0x179d1368 0x179d136C 0x179d1370>; qcom,pwrcl-apcs-mem-acc-val = - <0x00000000 0x10000000 0x10000000>, - <0x00000000 0x10000000 0x10000000>, + <0x00000000 0x80000000 0x80000000>, <0x00000000 0x00000000 0x00000000>, <0x00000000 0x00000001 0x00000001>; qcom,perfcl-apcs-mem-acc-val = - <0x00000000 0x00000000 0x10000000>, - <0x00000000 0x00000000 0x10000000>, + <0x00000000 0x00000000 0x80000000>, <0x00000000 0x00000000 0x00000000>, <0x00000000 0x00000000 0x00000001>; @@ -966,8 +965,12 @@ qcom,do-not-use-ch-gsi-20; qcom,ipa-wdi2; qcom,use-64-bit-dma-mask; - clock-names = "core_clk"; - clocks = <&clock_gcc clk_ipa_clk>; + clocks = <&clock_gcc clk_ipa_clk>, + <&clock_gcc clk_aggre2_noc_clk>; + clock-names = "core_clk", "smmu_clk"; + qcom,arm-smmu; + qcom,smmu-disable-htw; + qcom,smmu-s1-bypass; qcom,msm-bus,name = "ipa"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <3>; @@ -1074,6 +1077,23 @@ compatible = "qcom,smp2pgpio-map-ipa-1-in"; gpios = <&smp2pgpio_ipa_1_in 0 0>; }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&anoc2_smmu 0x18e0>; + qcom,iova-mapping = <0x10000000 0x40000000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&anoc2_smmu 0x18e1>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&anoc2_smmu 0x18e2>; + qcom,iova-mapping = <0x40000000 0x20000000>; + }; }; qcom,ipa_fws@1e08000 { diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index 598e52b54c99..9d605503520f 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -75,8 +75,7 @@ enum clk_osm_trace_packet_id { #define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n))) #define MEM_ACC_SEQ_CONST(n) (n) #define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40)) -#define MEM_ACC_SEQ_REG_VAL_START(n) \ - ((n) < 8 ? SEQ_REG(4 + (n)) : SEQ_REG(60 + (n) - 8)) +#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n))) #define OSM_TABLE_SIZE 40 #define MAX_CLUSTER_CNT 2 @@ -125,6 +124,7 @@ enum clk_osm_trace_packet_id { #define SPM_CC_CTRL 0x1028 #define SPM_CC_HYSTERESIS 0x101C #define SPM_CORE_RET_MAPPING 0x1024 +#define CFG_DELAY_VAL_3 0x12C #define LLM_FREQ_VOTE_HYSTERESIS 0x102C #define LLM_VOLT_VOTE_HYSTERESIS 0x1030 @@ -184,11 +184,11 @@ enum clk_osm_trace_packet_id { #define MAX_INSTRUCTIONS 256 #define MAX_BR_INSTRUCTIONS 49 -#define MAX_MEM_ACC_LEVELS 4 +#define MAX_MEM_ACC_LEVELS 3 #define MAX_MEM_ACC_VAL_PER_LEVEL 3 #define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \ MAX_MEM_ACC_VAL_PER_LEVEL) -#define MEM_ACC_READ_MASK 0x7 +#define MEM_ACC_APM_READ_MASK 0xff #define TRACE_CTRL 0x1F38 #define TRACE_CTRL_EN_MASK BIT(0) @@ -203,6 +203,11 @@ enum clk_osm_trace_packet_id { #define PERIODIC_TRACE_MAX_NS 21474836475 #define PERIODIC_TRACE_DEFAULT_NS 1000000 +#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408 +#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f +#define PLL_DD_D0_USER_CTL_LO 0x17916208 +#define PLL_DD_D1_USER_CTL_LO 0x17816208 + static void __iomem *virt_base; #define lmh_lite_clk_src_source_val 1 @@ -222,50 +227,48 @@ static void __iomem *virt_base; static u32 seq_instr[] = { 0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491, - 0x700a500b, 0x70005001, 0x390938c8, 0xcb44c833, 0xce56cd54, - 0x341336e0, 0xadba0000, 0x10004000, 0x70005001, 0x1000500c, - 0xc792c5a1, 0x501625e1, 0x3da335a2, 0x50170006, 0x50150006, - 0xafb9c633, 0xacb31000, 0xacb41000, 0x1000c422, 0x500baefc, - 0x5001700a, 0xaefd7000, 0x700b5010, 0x700c5012, 0xadb9ad41, - 0x181b0000, 0x500f500c, 0x34135011, 0x84b9181b, 0xbd808539, - 0x2ba40003, 0x0006a001, 0x10007105, 0x1000500e, 0x1c0a500c, - 0x3b181c01, 0x3b431c06, 0x10001c07, 0x39831c06, 0x500c1c07, - 0x1c0a1c02, 0x10000000, 0x70015002, 0x10000000, 0x50038103, - 0x50047002, 0x10007003, 0x39853b44, 0x50038104, 0x40037002, - 0x70095005, 0xb1c0a146, 0x238b0003, 0x10004005, 0x848b8308, - 0x1000850c, 0x848e830d, 0x1000850c, 0x3a4c5006, 0x3a8f39cd, - 0x40063ad0, 0x50071000, 0x2c127006, 0x4007a00f, 0x71050006, - 0x1000700d, 0x1c1aa964, 0x700d4007, 0x50071000, 0x1c167006, - 0x50125010, 0x40072411, 0x4007700d, 0xa00f1000, 0x0006a821, - 0x40077105, 0x500c700d, 0x1c1591ad, 0x5011500f, 0x10000000, - 0x500c2bd4, 0x0006a00f, 0x10007105, 0xa821a00f, 0x70050006, - 0x91ad500c, 0x500f1c15, 0x10005011, 0x1c162bce, 0x50125010, - 0xa82aa022, 0x71050006, 0x1c1591a6, 0x5011500f, 0x5014500c, - 0x0006a00f, 0x00007105, 0x91a41000, 0x22175013, 0x1c1aa963, - 0x22171000, 0x1c1aa963, 0x50081000, 0x40087007, 0x1c1aa963, - 0x70085009, 0x10004009, 0x850c848e, 0x0003b1c0, 0x400d2b99, - 0x500d1000, 0xabaf1000, 0x853184b0, 0x0003bb80, 0xa0371000, - 0x71050006, 0x85481000, 0xbf8084c3, 0x2ba80003, 0xbf8084c2, - 0x2ba70003, 0xbf8084c1, 0x2ba60003, 0x8ec71000, 0xc6dd8dc3, - 0x8c1625ec, 0x8d498c97, 0x8ec61c00, 0xc6dd8dc2, 0x8c1325ec, - 0x8d158c94, 0x8ec51c00, 0xc6dd8dc1, 0x8c1025ec, 0x8d128c91, - 0x8dc01c00, 0x182cc633, 0x84c08548, 0x0003bf80, 0x84c12ba9, - 0x0003bf80, 0x84c22baa, 0x0003bf80, 0x10002bab, 0x8dc08ec4, - 0x25ecc6dd, 0x8c948c13, 0x1c008d15, 0x8dc18ec5, 0x25ecc6dd, - 0x8c978c16, 0x1c008d49, 0x8dc28ec6, 0x25ecc6dd, 0x8ccb8c4a, - 0x1c008d4c, 0xc6338dc3, 0x1000af9b, 0xa759a79a, 0x1000a718, + 0x700a500b, 0x5001aefc, 0xaefd7000, 0x390938c8, 0xcb44c833, + 0xce56cd54, 0x341336e0, 0xa4baadba, 0xb480a493, 0x10004000, + 0x70005001, 0x1000500c, 0xc792c5a1, 0x501625e1, 0x3da335a2, + 0x50170006, 0x50150006, 0x1000c633, 0x1000acb3, 0xc422acb4, + 0xaefc1000, 0x700a500b, 0x70005001, 0x5010aefd, 0x5012700b, + 0xad41700c, 0x84e5adb9, 0xb3808566, 0x239b0003, 0x856484e3, + 0xb9800007, 0x2bad0003, 0xac3aa20b, 0x0003181b, 0x0003bb40, + 0xa30d239b, 0x500c181b, 0x5011500f, 0x181b3413, 0x853984b9, + 0x0003bd80, 0xa0012ba4, 0x72050803, 0x500e1000, 0x500c1000, + 0x1c011c0a, 0x3b181c06, 0x1c073b43, 0x1c061000, 0x1c073983, + 0x1c02500c, 0x10001c0a, 0x70015002, 0x81031000, 0x70025003, + 0x70035004, 0x3b441000, 0x81553985, 0x70025003, 0x50054003, + 0xa1467009, 0x0003b1c0, 0x4005238b, 0x835a1000, 0x855c84db, + 0x1000a51f, 0x84de835d, 0xa52c855c, 0x50061000, 0x39cd3a4c, + 0x3ad03a8f, 0x10004006, 0x70065007, 0xa00f2c12, 0x08034007, + 0xaefc7205, 0xaefd700d, 0xa9641000, 0x40071c1a, 0x700daefc, + 0x1000aefd, 0x70065007, 0x50101c16, 0x40075012, 0x700daefc, + 0x2411aefd, 0xa8211000, 0x0803a00f, 0x500c7005, 0x1c1591e0, + 0x500f5014, 0x10005011, 0x500c2bd4, 0x0803a00f, 0x10007205, + 0xa00fa9d1, 0x0803a821, 0xa9d07005, 0x91e0500c, 0x500f1c15, + 0x10005011, 0x1c162bce, 0x50125010, 0xa022a82a, 0x70050803, + 0x1c1591df, 0x5011500f, 0x5014500c, 0x0803a00f, 0x10007205, + 0x501391a4, 0x22172217, 0x70075008, 0xa9634008, 0x1c1a0006, + 0x70085009, 0x10004009, 0x00008ed9, 0x3e05c8dd, 0x1c033604, + 0xabaf1000, 0x856284e1, 0x0003bb80, 0x1000239f, 0x0803a037, + 0x10007205, 0x8dc61000, 0x38a71c2a, 0x1c2a8dc4, 0x100038a6, + 0x1c2a8dc5, 0x8dc73867, 0x38681c2a, 0x8c491000, 0x8d4b8cca, + 0x10001c00, 0x8ccd8c4c, 0x1c008d4e, 0x8c4f1000, 0x8d518cd0, + 0x10001c00, 0xa759a79a, 0x1000a718, 0xbf80af9b, 0x00001000, }; static u32 seq_br_instr[] = { - 0x28c, 0x1e6, 0x238, 0xd0, 0xec, - 0xf4, 0xbc, 0xc4, 0x9c, 0xac, - 0xfc, 0xe2, 0x154, 0x174, 0x17c, - 0x10a, 0x126, 0x13a, 0x11c, 0x98, - 0x160, 0x1a6, 0x19a, 0x1ae, 0x1c0, - 0x1ce, 0x1d2, 0x30, 0x60, 0x86, - 0x7c, 0x1d8, 0x34, 0x3c, 0x56, - 0x5a, 0x1de, 0x2e, 0x222, 0x212, - 0x202, 0x254, 0x264, 0x274, 0x288, + 0x248, 0x20e, 0x21c, 0xf6, 0x112, + 0x11c, 0xe4, 0xea, 0xc6, 0xd6, + 0x126, 0x108, 0x184, 0x1a8, 0x1b0, + 0x134, 0x158, 0x16e, 0x14a, 0xc2, + 0x190, 0x1d2, 0x1cc, 0x1d4, 0x1e8, + 0x0, 0x1f6, 0x32, 0x66, 0xb0, + 0xa6, 0x1fc, 0x3c, 0x44, 0x5c, + 0x60, 0x204, 0x30, 0x22a, 0x234, + 0x23e, 0x0, 0x250, 0x0, 0x0, 0x9a, + 0x20c, }; DEFINE_EXT_CLK(xo_ao, NULL); @@ -298,6 +301,7 @@ struct clk_osm { u32 cluster_num; u32 irq; u32 apm_crossover_vc; + u32 apm_threshold_vc; u32 cycle_counter_reads; u32 cycle_counter_delay; u32 cycle_counter_factor; @@ -551,8 +555,8 @@ static void clk_osm_print_osm_table(struct clk_osm *c) lval, table[i].spare_data); } - pr_debug("APM crossover corner: %d\n", - c->apm_crossover_vc); + pr_debug("APM threshold corner=%d, crossover corner=%d\n", + c->apm_threshold_vc, c->apm_crossover_vc); } static int clk_osm_get_lut(struct platform_device *pdev, @@ -1116,10 +1120,21 @@ exit: static int clk_osm_resolve_crossover_corners(struct clk_osm *c, struct platform_device *pdev) { + struct regulator *regulator = c->vdd_reg; struct dev_pm_opp *opp; unsigned long freq = 0; - int vc, rc = 0; + int vc, i, threshold, rc = 0; + u32 corner_volt, data; + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,apm-threshold-voltage", + &threshold); + if (rc) { + pr_info("qcom,apm-threshold-voltage property not specified\n"); + return rc; + } + + /* Determine crossover virtual corner */ rcu_read_lock(); opp = dev_pm_opp_find_freq_exact(&c->vdd_dev->dev, freq, true); if (IS_ERR(opp)) { @@ -1138,6 +1153,48 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c, vc--; c->apm_crossover_vc = vc; + /* Determine threshold virtual corner */ + for (i = 0; i < OSM_TABLE_SIZE; i++) { + freq = c->osm_table[i].frequency; + /* + * Only frequencies that are supported across all configurations + * are present in the OPP table associated with the regulator + * device. + */ + data = (c->osm_table[i].freq_data & GENMASK(18, 16)) >> 16; + if (data != MAX_CONFIG) + continue; + + rcu_read_lock(); + opp = dev_pm_opp_find_freq_exact(&c->vdd_dev->dev, freq, true); + if (IS_ERR(opp)) { + rc = PTR_ERR(opp); + if (rc == -ERANGE) + pr_err("Frequency %lu not found\n", freq); + goto exit; + } + + vc = dev_pm_opp_get_voltage(opp); + if (!vc) { + pr_err("No virtual corner found for frequency %lu\n", + freq); + rc = -ERANGE; + goto exit; + } + + rcu_read_unlock(); + + corner_volt = regulator_list_corner_voltage(regulator, vc); + + /* CPR virtual corners are zero-based numbered */ + vc--; + + if (corner_volt >= threshold) { + c->apm_threshold_vc = vc; + break; + } + } + return 0; exit: rcu_read_unlock(); @@ -1413,55 +1470,77 @@ static void clk_osm_program_apm_regs(struct clk_osm *c) */ clk_osm_write_reg(c, c->apm_mode_ctl, SEQ_REG(2)); - /* Program mode value to switch APM from VDD_APCC to VDD_MX */ - clk_osm_write_reg(c, APM_MX_MODE, SEQ_REG(22)); - - /* Program mode value to switch APM from VDD_MX to VDD_APCC */ - clk_osm_write_reg(c, APM_APC_MODE, SEQ_REG(25)); - /* Program address of controller status register */ clk_osm_write_reg(c, c->apm_ctrl_status, SEQ_REG(3)); - /* Program mask used to determine status of APM power supply switch */ - clk_osm_write_reg(c, APM_MODE_SWITCH_MASK, SEQ_REG(24)); + /* Program mode value to switch APM from VDD_APCC to VDD_MX */ + clk_osm_write_reg(c, APM_MX_MODE, SEQ_REG(77)); /* Program value used to determine current APM power supply is VDD_MX */ - clk_osm_write_reg(c, APM_MX_MODE_VAL, SEQ_REG(23)); + clk_osm_write_reg(c, APM_MX_MODE_VAL, SEQ_REG(78)); + + /* Program mask used to determine status of APM power supply switch */ + clk_osm_write_reg(c, APM_MODE_SWITCH_MASK, SEQ_REG(79)); + + /* Program mode value to switch APM from VDD_MX to VDD_APCC */ + clk_osm_write_reg(c, APM_APC_MODE, SEQ_REG(80)); /* * Program value used to determine current APM power supply * is VDD_APCC */ - clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(26)); + clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(81)); } static void clk_osm_program_mem_acc_regs(struct clk_osm *c) { - int i; + int i, curr_level, j = 0; + int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0}; - if (!c->secure_init) - return; + curr_level = c->osm_table[0].spare_data; + for (i = 0; i < c->num_entries; i++) { + if (curr_level == MAX_MEM_ACC_LEVELS) + break; - clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(50), - SEQ_REG(49)); - clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(50)); - clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51)); - clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52)); - clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53)); - clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54)); - clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(0), SEQ_REG(55)); - clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(1), SEQ_REG(56)); - clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(2), SEQ_REG(57)); - clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(3), SEQ_REG(58)); - clk_osm_write_reg(c, MEM_ACC_READ_MASK, SEQ_REG(59)); - - for (i = 0; i < MAX_MEM_ACC_VALUES; i++) - clk_osm_write_reg(c, c->apcs_mem_acc_val[i], - MEM_ACC_SEQ_REG_VAL_START(i)); - - for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++) - clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i], - MEM_ACC_SEQ_REG_CFG_START(i)); + if (c->osm_table[i].spare_data != curr_level) { + mem_acc_level_map[j++] = i - 1; + curr_level = c->osm_table[i].spare_data; + } + } + + if (c->secure_init) { + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54)); + clk_osm_write_reg(c, MEM_ACC_APM_READ_MASK, SEQ_REG(59)); + clk_osm_write_reg(c, mem_acc_level_map[0], SEQ_REG(55)); + clk_osm_write_reg(c, mem_acc_level_map[0] + 1, SEQ_REG(56)); + clk_osm_write_reg(c, mem_acc_level_map[1], SEQ_REG(57)); + clk_osm_write_reg(c, mem_acc_level_map[1] + 1, SEQ_REG(58)); + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(28), + SEQ_REG(49)); + + for (i = 0; i < MAX_MEM_ACC_VALUES; i++) + clk_osm_write_reg(c, c->apcs_mem_acc_val[i], + MEM_ACC_SEQ_REG_VAL_START(i)); + + for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++) + clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i], + MEM_ACC_SEQ_REG_CFG_START(i)); + } else { + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55), + mem_acc_level_map[0]); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56), + mem_acc_level_map[0] + 1); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57), + mem_acc_level_map[1]); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58), + mem_acc_level_map[1] + 1); + /* SEQ_REG(49) = SEQ_REG(28) init by TZ */ + } + + return; } void clk_osm_setup_sequencer(struct clk_osm *c) @@ -1500,10 +1579,12 @@ static void clk_osm_setup_cycle_counters(struct clk_osm *c) static void clk_osm_setup_osm_was(struct clk_osm *c) { + u32 cc_hyst; u32 val; val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); val |= IGNORE_PLL_LOCK_MASK; + cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS); if (c->secure_init) { clk_osm_write_reg(c, val, SEQ_REG(47)); @@ -1518,10 +1599,51 @@ static void clk_osm_setup_osm_was(struct clk_osm *c) clk_osm_write_reg(c, 0x0, SEQ_REG(45)); clk_osm_write_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG, SEQ_REG(46)); + + /* C2D/C3 + D2D workaround */ + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SPM_CC_HYSTERESIS, + SEQ_REG(6)); + clk_osm_write_reg(c, cc_hyst, SEQ_REG(7)); + + /* Droop detector PLL lock detect workaround */ + clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_ENABLE, SEQ_REG(4)); + clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_DISABLE, SEQ_REG(5)); + clk_osm_write_reg(c, c->cluster_num == 0 ? PLL_DD_D0_USER_CTL_LO + : PLL_DD_D1_USER_CTL_LO, SEQ_REG(21)); + + /* PLL lock detect and HMSS AHB clock workaround */ + clk_osm_write_reg(c, 0x640, CFG_DELAY_VAL_3); + + /* DxFSM workaround */ + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911200 : + 0x17811200, SEQ_REG(22)); + clk_osm_write_reg(c, 0x80800, SEQ_REG(23)); + clk_osm_write_reg(c, 0x179D1100, SEQ_REG(24)); + clk_osm_write_reg(c, 0x11f, SEQ_REG(25)); + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17912000 : + 0x17811290, SEQ_REG(26)); + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911290 : + 0x17811290, SEQ_REG(20)); + clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17811290 : + 0x17911290, SEQ_REG(32)); + clk_osm_write_reg(c, 0x179D4020, SEQ_REG(35)); + clk_osm_write_reg(c, 0x11f, SEQ_REG(25)); + clk_osm_write_reg(c, 0xa, SEQ_REG(86)); + clk_osm_write_reg(c, 0xe, SEQ_REG(87)); + clk_osm_write_reg(c, 0x00400000, SEQ_REG(88)); + clk_osm_write_reg(c, 0x00700000, SEQ_REG(89)); } else { scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(47), val); val &= ~IGNORE_PLL_LOCK_MASK; scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(48), val); + + /* C2D/C3 + D2D workaround */ + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(7), + cc_hyst); + + /* Droop detector PLL lock detect workaround */ + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(4), + PLL_DD_USER_CTL_LO_ENABLE); } if (c->cluster_num == 0) { @@ -1671,18 +1793,15 @@ static void clk_osm_do_additional_setup(struct clk_osm *c, /* APM Programming */ clk_osm_program_apm_regs(c); - /* MEM-ACC Programming */ - clk_osm_program_mem_acc_regs(c); - /* GFMUX Programming */ clk_osm_write_reg(c, c->apcs_cfg_rcgr, SEQ_REG(16)); - clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17)); - clk_osm_write_reg(c, PLL_EARLY_SEL, SEQ_REG(20)); - clk_osm_write_reg(c, PLL_MAIN_SEL, SEQ_REG(32)); clk_osm_write_reg(c, c->apcs_cmd_rcgr, SEQ_REG(33)); clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(34)); - clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(35)); - clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(36)); + clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17)); + clk_osm_write_reg(c, PLL_EARLY_SEL, SEQ_REG(82)); + clk_osm_write_reg(c, PLL_MAIN_SEL, SEQ_REG(83)); + clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(84)); + clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(85)); pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr), ARRAY_SIZE(seq_br_instr)); @@ -1693,17 +1812,43 @@ static void clk_osm_do_additional_setup(struct clk_osm *c, static void clk_osm_apm_vc_setup(struct clk_osm *c) { /* - * APM crossover virtual corner at which the switch - * from APC to MX and vice-versa should take place. + * APM crossover virtual corner corresponds to switching + * voltage during APM transition. APM threshold virtual + * corner is the first corner which requires switch + * sequence of APM from MX to APC. */ if (c->secure_init) { - clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(1)); + clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(1)); + clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(72)); + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1), + SEQ_REG(8)); + clk_osm_write_reg(c, c->apm_threshold_vc, + SEQ_REG(15)); + clk_osm_write_reg(c, c->apm_threshold_vc != 0 ? + c->apm_threshold_vc - 1 : 0xff, + SEQ_REG(31)); + clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6, + SEQ_REG(73)); + clk_osm_write_reg(c, 0x39 | c->apm_threshold_vc << 6, + SEQ_REG(76)); /* Ensure writes complete before returning */ mb(); } else { scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1), + c->apm_threshold_vc); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72), c->apm_crossover_vc); + /* SEQ_REG(8) = address of SEQ_REG(1) init by TZ */ + clk_osm_write_reg(c, c->apm_threshold_vc, + SEQ_REG(15)); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31), + c->apm_threshold_vc != 0 ? + c->apm_threshold_vc - 1 : 0xff); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73), + 0x3b | c->apm_threshold_vc << 6); + scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76), + 0x39 | c->apm_threshold_vc << 6); } } @@ -2412,6 +2557,10 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) clk_osm_do_additional_setup(&pwrcl_clk, pdev); clk_osm_do_additional_setup(&perfcl_clk, pdev); + /* MEM-ACC Programming */ + clk_osm_program_mem_acc_regs(&pwrcl_clk); + clk_osm_program_mem_acc_regs(&perfcl_clk); + /* Program APM crossover corners */ clk_osm_apm_vc_setup(&pwrcl_clk); clk_osm_apm_vc_setup(&perfcl_clk); diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c index c13e811a5d71..78c5c47e4e8b 100644 --- a/drivers/regulator/cpr3-regulator.c +++ b/drivers/regulator/cpr3-regulator.c @@ -1109,10 +1109,18 @@ static int cpr3_regulator_init_cprh_corners(struct cpr3_regulator *vreg) } if (ro_sel == INT_MAX) { - cpr3_err(vreg, "corner=%d has invalid RO select value\n", - i); - rc = -EINVAL; - goto free_base_quots; + if (!corner->proc_freq) { + /* + * Corner is not used as active DCVS set point + * select RO 0 arbitrarily. + */ + ro_sel = 0; + } else { + cpr3_err(vreg, "corner=%d has invalid RO select value\n", + i); + rc = -EINVAL; + goto free_base_quots; + } } open_loop_volt_steps = DIV_ROUND_UP(corner->open_loop_volt - @@ -1121,9 +1129,11 @@ static int cpr3_regulator_init_cprh_corners(struct cpr3_regulator *vreg) floor_volt_steps = DIV_ROUND_UP(corner->floor_volt - ctrl->base_volt, ctrl->step_volt); - delta_quot_steps = DIV_ROUND_UP(corner->target_quot[ro_sel] - - base_quots[ro_sel], - CPRH_DELTA_QUOT_STEP_FACTOR); + delta_quot_steps = corner->proc_freq ? + DIV_ROUND_UP(corner->target_quot[ro_sel] - + base_quots[ro_sel], + CPRH_DELTA_QUOT_STEP_FACTOR) : + 0; if (open_loop_volt_steps > CPRH_CORNER_INIT_VOLTAGE_MAX_VALUE || floor_volt_steps > CPRH_CORNER_FLOOR_VOLTAGE_MAX_VALUE || diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index d750b70519d1..3ddc1dc3c982 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.h @@ -572,7 +572,13 @@ struct cpr3_panic_regs_info { * when hardware closed-loop attempts to exceed the ceiling * voltage * @apm: Handle to the array power mux (APM) - * @apm_threshold_volt: APM threshold voltage in microvolts + * @apm_threshold_volt: Voltage in microvolts which defines the threshold + * voltage to determine the APM supply selection for + * each corner + * @apm_crossover_volt: Voltage in microvolts corresponding to the voltage that + * the VDD supply must be set to while an APM switch is in + * progress. This element must be initialized for CPRh + * controllers when an APM threshold voltage is defined * @apm_adj_volt: Minimum difference between APM threshold voltage and * open-loop voltage which allows the APM threshold voltage * to be used as a ceiling @@ -736,6 +742,7 @@ struct cpr3_controller { int ceiling_irq; struct msm_apm_ctrl_dev *apm; int apm_threshold_volt; + int apm_crossover_volt; int apm_adj_volt; enum msm_apm_supply apm_high_supply; enum msm_apm_supply apm_low_supply; diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c index ffd3db1a6dff..dfdd6921fed5 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -697,61 +697,38 @@ free_temp: } /** - * cprh_kbss_apm_threshold_as_corner() - introduce a corner whose floor, open-loop, - * and ceiling voltages correspond to the APM threshold voltage. + * cprh_kbss_apm_crossover_as_corner() - introduce a corner whose floor, + * open-loop, and ceiling voltages correspond to the APM + * crossover voltage. * @vreg: Pointer to the CPR3 regulator * * The APM corner is utilized as a crossover corner by OSM and CPRh - * hardware to determine the correct APM supply selection for the - * rest of the corners. This function must be called after all other - * functions which load per-corner values. + * hardware to set the VDD supply voltage during the APM switch + * routine. * * Return: 0 on success, errno on failure */ -static int cprh_kbss_apm_threshold_as_corner(struct cpr3_regulator *vreg) +static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg) { struct cpr3_controller *ctrl = vreg->thread->ctrl; struct cpr3_corner *corner; - struct cprh_corner_band *corner_band; - int i, threshold, apm_corner = 0; - if (!ctrl->apm_threshold_volt) { - /* APM voltage threshold corner not required. */ + if (!ctrl->apm_crossover_volt) { + /* APM voltage crossover corner not required. */ return 0; } - threshold = ctrl->apm_threshold_volt; - vreg->corner_count++; - - for (i = vreg->corner_count - 1; i >= 1; i--) { - corner = &vreg->corner[i]; - - if (threshold >= vreg->corner[i - 1].open_loop_volt) { - apm_corner = i; - break; - } - - memcpy(corner, &vreg->corner[i - 1], sizeof(*corner)); - } - - corner = &vreg->corner[apm_corner]; - corner->proc_freq = 0; - corner->floor_volt = threshold; - corner->ceiling_volt = threshold; - corner->open_loop_volt = threshold; - corner->use_open_loop = true; - cpr3_info(vreg, "APM threshold corner=%d, open-loop=%d\n", - apm_corner, threshold); - + corner = &vreg->corner[vreg->corner_count]; /* - * Update corner band mappings to account for the inserted - * APM crossover corner. + * 0 MHz indicates this corner is not to be + * used as active DCVS set point. */ - for (i = 0; i < vreg->corner_band_count; i++) { - corner_band = &vreg->corner_band[i]; - if (corner_band->corner >= apm_corner) - corner_band->corner++; - } + corner->proc_freq = 0; + corner->floor_volt = ctrl->apm_crossover_volt; + corner->ceiling_volt = ctrl->apm_crossover_volt; + corner->open_loop_volt = ctrl->apm_crossover_volt; + corner->use_open_loop = true; + vreg->corner_count++; return 0; } @@ -1203,9 +1180,9 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg) return -EINVAL; } - rc = cprh_kbss_apm_threshold_as_corner(vreg); + rc = cprh_kbss_apm_crossover_as_corner(vreg); if (rc) { - cpr3_err(vreg, "unable to introduce APM voltage threshold corner\n, rc=%d\n", + cpr3_err(vreg, "unable to introduce APM voltage crossover corner, rc=%d\n", rc); return rc; } @@ -1288,8 +1265,18 @@ static int cprh_kbss_init_controller(struct cpr3_controller *ctrl) rc = of_property_read_u32(ctrl->dev->of_node, "qcom,apm-threshold-voltage", &ctrl->apm_threshold_volt); - if (rc) + if (rc) { cpr3_debug(ctrl, "qcom,apm-threshold-voltage not specified\n"); + } else { + rc = of_property_read_u32(ctrl->dev->of_node, + "qcom,apm-crossover-voltage", + &ctrl->apm_crossover_volt); + if (rc) { + cpr3_err(ctrl, "error reading property qcom,apm-crossover-voltage, rc=%d\n", + rc); + return rc; + } + } of_property_read_u32(ctrl->dev->of_node, "qcom,apm-hysteresis-voltage", &ctrl->apm_adj_volt); |
