summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-07-26 19:55:45 -0600
committerLinux Build Service Account <lnxbuild@localhost>2016-07-26 19:55:46 -0600
commit35e3dabda5a617debff12cbc17c0cb066928f921 (patch)
treea790e92063e2193593488d4874102f763a740a8b
parent6385cefa179bb87fff0f9e041075280f119b2554 (diff)
parentbb02457c09a7e64ac886a8063c8728c8ce6f1d07 (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.txt10
-rw-r--r--Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt19
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt.dtsi62
-rw-r--r--drivers/clk/msm/clock-osm.c333
-rw-r--r--drivers/regulator/cpr3-regulator.c24
-rw-r--r--drivers/regulator/cpr3-regulator.h9
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c73
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);