Merge "msm: mdss: Parse ping pong register from device tree"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
new file mode 100644
index 0000000..3a29004
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -0,0 +1,69 @@
+Qualcomm CPR (Core Power Reduction) Regulator
+
+CPR regulator device is for Qualcomm RBCPR (RapidBridge CPR) on
+ application processor core. It takes voltage corner level
+ as input and converts it to actual voltage based on the
+ suggestions from factory production process. When CPR is
+ enabled for application processer core, it will suggest
+ scaling the voltage up or down for best performance and
+ power of the core. The scaling based on factory production
+ process is called PVS (Process Voltage Scaling) with efuse
+ bits to indicate what bin (and voltage range) a chip is in.
+
+Required properties:
+- compatible: Must be "qcom,cpr-regulator"
+- reg: Register addresses for RBCPR and efuse
+- reg-names: Register names. Must be "rbcpr" and "efuse_phys"
+- regulator-name: A string used to describe the regulator
+- regulator-min-microvolt: Minimum corner value as min constraint, which
+ should be 1 for SVS corner
+- regulator-max-microvolt: Maximum corner value as max constraint, which
+ should be 4 for SUPER_TURBO or 3 for TURBO
+- qcom,num-efuse-bits: The number of bits used in efuse memory to
+ represent total number of PVS bins. It should
+ not exceed a maximum of 5 for total number of
+ 32 bins.
+- qcom,efuse-bit-pos: A list of integers whose length must equal
+ to qcom,num-efuse-bits and each integer indicates
+ bit position in efuse memory from LSB to MSB
+- qcom,pvs-bin-process: A list of integers whose length is equal to 2 to
+ the power of qcom,num-efuse-bits. The location or
+ 0-based index of an element in the list corresponds
+ to the bin number. The value of each integer
+ corresponds to the PVS process speed of the APC
+ silicon for a chip with one of these cases:
+ 1 = APC_PVS_SLOW
+ 2 = APC_PVS_NOM
+ 3 = APC_PVS_FAST
+ 0 or other values = No PVS
+- qcom,pvs-corner-ceiling-slow: Ceiling voltages of all corners for APC_PVS_SLOW
+- qcom,pvs-corner-ceiling-nom: Ceiling voltages of all corners for APC_PVS_NOM
+- qcom,pvs-corner-ceiling-fast: Ceiling voltages of all corners for APC_PVS_FAST
+ The ceiling voltages for each of above three
+ properties may look like this:
+ 0 (SVS voltage): 1050000 uV
+ 1 (NORMAL voltage): 1150000 uV
+ 2 (TURBO voltage): 1275000 uV
+ 3 (SUPER_TURBO voltage): 1275000 uV
+- vdd-apc-supply: Regulator to supply VDD APC power
+
+Example:
+ apc_vreg_corner: regulator@f9018000 {
+ status = "okay";
+ compatible = "qcom,cpr-regulator";
+ reg = <0xf9018000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "rbcpr", "efuse_phys";
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <4>;
+ qcom,num-efuse-bits = <5>;
+ qcom,efuse-bit-pos = <6 7 8 9 10>;
+ qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ vdd-apc-supply = <&pm8226_s2>;
+ };
+
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 5bf6b8b..0422b57 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -105,6 +105,9 @@
settings used to setup MDSS QoS for best performance.
The key used should be offset from "mdp_phys" register
defined in reg property.
+- qcom,mdss-rot-block-size: The size of a memory block (in pixels) to be used
+ by the rotator. If this property is not specified,
+ then a default value of 128 pixels would be used.
Optional subnodes:
Child nodes representing the frame buffer virtual devices.
@@ -137,6 +140,7 @@
qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
qcom,mdss-pipe-dma-fetch-id = <10 13>;
qcom,mdss-smp-data = <22 4096>;
+ qcom,mdss-rot-block-size = <64>;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
0x00000900 0x0000A00>;
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 86b3ccb..acd0ae3 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -10,8 +10,7 @@
- reg: Pairs of physical base addresses and region sizes of
memory mapped registers.
- reg-names: Names of the bases for the above registers. "qdsp6_base",
- "halt_base", "rmb_base", "restart_reg", and
- "metadata_base" are expected.
+ "halt_base", "rmb_base", and "restart_reg" are expected.
- interrupts: The modem watchdog interrupt
- vdd_mss-supply: Reference to the regulator that supplies the processor.
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
@@ -34,10 +33,9 @@
reg = <0xfc880000 0x100>,
<0xfd485000 0x400>,
<0xfc820000 0x020>,
- <0xfc401680 0x004>,
- <0x0d1f0000 0x4000>;
+ <0xfc401680 0x004>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", metadata_base";
+ "restart_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8841_s3>;
vdd_cx-supply = <&pm8841_s2>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 2832693..f5465a4 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -45,8 +45,8 @@
battery temperature of 250 decidegree
Celsius, state of charge to be 50%
and disable charging.
-- qcom,chg-warm-bat-degc: Warm battery temperature in degC.
-- qcom,chg-cool-bat-degc: Cool battery temperature in degC.
+- qcom,chg-warm-bat-decidegc: Warm battery temperature in decidegC.
+- qcom,chg-cool-bat-decidegc: Cool battery temperature in decidegC.
Note that if both warm and cool battery
temperatures are set, the corresponding
ibatmax and bat-mv properties are
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index f1f4e94..3854598 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -20,6 +20,13 @@
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+Optional properties:
+- qcom,thermal-node : If present a thermal node is created and the channel is registered as
+ part of the thermal sysfs which allows clients to use the thermal framework
+ to set temperature thresholds and receive notification when the temperature
+ crosses a set threshold, read temperature and enable/set trip types supported
+ by the thermal framework.
+
Channel nodes
NOTE: Atleast one Channel node is required.
@@ -105,7 +112,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
- /* Channel Node */
+ /* Channel Node to be registered as part of thermal sysfs */
chan@b5 {
label = "pa_therm1";
reg = <0xb5>;
@@ -116,5 +123,19 @@
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
};
+
+ /* Channel Node */
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x78>;
+ };
};
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index effc7c5..e2b6a66 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -342,6 +342,17 @@
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
};
+
+ chan@c {
+ label = "ref_buf_625mv";
+ reg = <0xc>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
};
iadc@3600 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index d174157..9761e01 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -175,10 +175,10 @@
qcom,chg-ibatmax-ma = <1500>;
qcom,chg-ibatsafe-ma = <1500>;
qcom,chg-thermal-mitigation = <1500 700 600 325>;
- qcom,chg-cool-bat-degc = <10>;
+ qcom,chg-cool-bat-decidegc = <100>;
qcom,chg-cool-bat-mv = <4100>;
qcom,chg-ibatmax-warm-ma = <350>;
- qcom,chg-warm-bat-degc = <45>;
+ qcom,chg-warm-bat-decidegc = <450>;
qcom,chg-warm-bat-mv = <4100>;
qcom,chg-ibatmax-cool-ma = <350>;
qcom,chg-vbatdet-delta-mv = <350>;
@@ -830,6 +830,30 @@
qcom,btm-channel-number = <0x68>;
};
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x88>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x90>;
+ };
+
chan@b5 {
label = "pa_therm1";
reg = <0xb5>;
@@ -840,6 +864,7 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
};
chan@b7 {
@@ -852,6 +877,7 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
};
chan@b4 {
@@ -864,6 +890,20 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x80>;
+ qcom,thermal-node;
+ };
+
+ chan@b3 {
+ label = "msm_therm";
+ reg = <0xb3>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x98>;
+ qcom,thermal-node;
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 750e591..3c41e9e 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -1012,8 +1012,8 @@
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 04b7c7e..8d8aa79 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -196,7 +196,7 @@
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 06fcb21..7ab76f1 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -35,6 +35,7 @@
qcom,mdss-pingpong-off = <0x00021B00>;
qcom,mdss-wb-off = <0x00011100 0x00013100>;
qcom,mdss-intf-off = <0x00000000 0x00021300>;
+ qcom,mdss-rot-block-size = <64>;
qcom,vbif-settings = <0x004 0x00000001>,
<0x0D8 0x00000707>,
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index be831b4..32d9a95 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -189,7 +189,7 @@
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index 6bd5ea9..ae97be9 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -192,7 +192,7 @@
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 448a5be..9c21707 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -24,6 +24,29 @@
};
};
+/* CPR controlled regulator */
+
+/ {
+ apc_vreg_corner: regulator@f9018000 {
+ status = "okay";
+ compatible = "qcom,cpr-regulator";
+ reg = <0xf9018000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "rbcpr", "efuse_phys";
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <4>;
+ qcom,num-efuse-bits = <5>;
+ qcom,efuse-bit-pos = <6 7 8 9 10>;
+ qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ vdd-apc-supply = <&pm8226_s2>;
+ };
+};
+
/* RPM controlled regulators: */
&rpm_bus {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 2538317..25c534b 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -409,6 +409,15 @@
gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
qcom,has_pronto_hw;
};
+
+ qcom,msm-adsp-sensors {
+ compatible = "qcom,msm-adsp-sensors";
+ qcom,src-id = <11>;
+ qcom,dst-id = <604>;
+ qcom,ab = <32505856>;
+ qcom,ib = <32505856>;
+ };
+
qcom,wdt@f9017000 {
compatible = "qcom,msm-watchdog";
reg = <0xf9017000 0x1000>;
@@ -636,10 +645,9 @@
<0xfd485000 0x400>,
<0xfc820000 0x020>,
<0xfc401680 0x004>,
- <0x0d1fc000 0x4000>,
<0xfd485194 0x4>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "metadata_base", "cxrail_bhs_reg";
+ "restart_reg", "cxrail_bhs_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8226_s1>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 407104f..d945619 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -440,10 +440,9 @@
<0xfd485000 0x400>,
<0xfc820000 0x020>,
<0xfc401680 0x004>,
- <0x0d1fc000 0x4000>,
<0xfd485194 0x4>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "metadata_base", "cxrail_bhs_reg";
+ "restart_reg", "cxrail_bhs_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8110_s1>;
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index 8f58c3e..828e7ae 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1166,8 +1166,8 @@
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
};
mas-ampss-m1 {
@@ -1180,8 +1180,8 @@
qcom,qport = <1>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 9d98476..adab873 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -316,6 +316,8 @@
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -349,8 +351,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 2ddc61d..e70d5d8 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -296,6 +296,8 @@
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -329,8 +331,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index a10d1d6..8a8a8b7 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -768,6 +768,8 @@
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -790,8 +792,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 6011d52..d61de02 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -267,6 +267,8 @@
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <800 500000>;
@@ -300,8 +302,6 @@
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index b125138..05451671 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -520,4 +520,15 @@
gpio = <&pm8941_mpps 5 0>;
enable-active-high;
};
+
+ /*
+ * vph_pwr_vreg represents the unregulated battery voltage supply
+ * VPH_PWR that is present whenever the device is powered on.
+ */
+ vph_pwr_vreg: vph_pwr_vreg {
+ compatible = "regulator-fixed";
+ status = "disabled";
+ regulator-name = "vph_pwr";
+ regulator-always-on;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 9102770..7557657 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -989,10 +989,9 @@
reg = <0xfc880000 0x100>,
<0xfd485000 0x400>,
<0xfc820000 0x020>,
- <0xfc401680 0x004>,
- <0x0d1fc000 0x4000>;
+ <0xfc401680 0x004>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "metadata_base";
+ "restart_reg";
interrupts = <0 24 1>;
vdd_mss-supply = <&pm8841_s3>;
@@ -1118,9 +1117,9 @@
qcom,ipi-ping;
};
- qcom,tz-log@fc03000 {
+ qcom,tz-log@fe805720 {
compatible = "qcom,tz-log";
- reg = <0x0fc03000 0x1000>;
+ reg = <0xfe805720 0x1000>;
};
qcom,venus@fdce0000 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index b06419d..3dbc95d 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -189,6 +189,7 @@
qcom,dst-bam-pipe-index = <3>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe4 {
label = "hsic-ipa-in-1";
@@ -201,6 +202,7 @@
qcom,dst-bam-pipe-index = <4>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe5 {
label = "hsic-ipa-in-2";
@@ -213,6 +215,7 @@
qcom,dst-bam-pipe-index = <5>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe6 {
label = "hsic-ipa-in-3";
@@ -225,6 +228,7 @@
qcom,dst-bam-pipe-index = <6>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
qcom,pipe7 {
label = "hsic-ipa-out-0";
@@ -237,6 +241,7 @@
qcom,src-bam-pipe-index = <7>;
qcom,data-fifo-size = <0xD480>;
qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,reset-bam-on-connect;
};
};
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
deleted file mode 100644
index d925ab3..0000000
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ /dev/null
@@ -1,376 +0,0 @@
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-perf"
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X30=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG3=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RPC_WATCHDOG=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_QSD_AUDIO is not set
-CONFIG_MSM_MEMORY_LOW_POWER_MODE=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
-CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
-CONFIG_MSM_MULTIMEDIA_USE_ION=y
-CONFIG_MSM_RPC_PMIC=y
-CONFIG_MSM_RPC_USB=y
-CONFIG_MSM_RPC_PMAPP=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NETFILTER_TPROXY=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_LOG=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFLOG=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
-CONFIG_NETFILTER_XT_MATCH_SOCKET=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_SFQ=y
-CONFIG_NET_SCH_TBF=y
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_INGRESS=y
-CONFIG_NET_CLS_BASIC=y
-CONFIG_NET_CLS_TCINDEX=y
-CONFIG_NET_CLS_FW=y
-CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_FLOW=m
-CONFIG_NET_EMATCH=y
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_MIRRED=y
-CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=y
-# CONFIG_CFG80211_WEXT is not set
-CONFIG_RFKILL=y
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8XXX_UPL=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_TUN=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-CONFIG_LIBRA_SDIOIF=m
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM=y
-CONFIG_TOUCHSCREEN_TSC2007=y
-CONFIG_TOUCHSCREEN_CY8C_TS=y
-CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-CONFIG_BOSCH_BMA150=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_QUP=y
-CONFIG_I2C_SSBI=y
-CONFIG_SPI=y
-CONFIG_SPI_QSD=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-CONFIG_SENSORS_MSM_ADC=y
-CONFIG_THERMAL=y
-CONFIG_THERMAL_MSM_POPMEM=y
-CONFIG_PMIC8058=y
-CONFIG_MARIMBA_CORE=y
-CONFIG_MARIMBA_CODEC=y
-CONFIG_TIMPANI_CODEC=y
-# CONFIG_MFD_PM8XXX_DEBUG is not set
-# CONFIG_MFD_PM8XXX_PWM is not set
-# CONFIG_MFD_PM8XXX_MISC is not set
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_VIDEO_DEV=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_RADIO_TAVARUA=y
-CONFIG_ION=y
-CONFIG_ION_MSM=y
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_LOGO=y
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP40=y
-CONFIG_FB_MSM_OVERLAY=y
-CONFIG_FB_MSM_NO_MDP_PIPE_CTRL=y
-CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_SPI is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM7KV2_SOC=y
-CONFIG_SND_MVS_SOC=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_MAGICMOUSE=y
-CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
-CONFIG_USB_MSM_ACA=y
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_TEST=m
-CONFIG_MMC_MSM=y
-# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
-CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
-CONFIG_MMC_MSM_SDC3_SUPPORT=y
-CONFIG_MMC_MSM_SDC4_SUPPORT=y
-CONFIG_LEDS_PMIC8058=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_MSM_SSBI=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_FUSE_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
deleted file mode 100644
index 9eea95c..0000000
--- a/arch/arm/configs/msm7630_defconfig
+++ /dev/null
@@ -1,381 +0,0 @@
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X30=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG3=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RPC_WATCHDOG=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_QSD_AUDIO is not set
-CONFIG_MSM_MEMORY_LOW_POWER_MODE=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
-CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
-CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
-CONFIG_MSM_MULTIMEDIA_USE_ION=y
-CONFIG_MSM_RPC_PMIC=y
-CONFIG_MSM_RPC_USB=y
-CONFIG_MSM_RPC_PMAPP=y
-CONFIG_STRICT_MEMORY_RWX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NETFILTER_TPROXY=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_LOG=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFLOG=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
-CONFIG_NETFILTER_XT_MATCH_SOCKET=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_SFQ=y
-CONFIG_NET_SCH_TBF=y
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_INGRESS=y
-CONFIG_NET_CLS_BASIC=y
-CONFIG_NET_CLS_TCINDEX=y
-CONFIG_NET_CLS_FW=y
-CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_FLOW=m
-CONFIG_NET_EMATCH=y
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_MIRRED=y
-CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=y
-# CONFIG_CFG80211_WEXT is not set
-CONFIG_RFKILL=y
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_HAPTIC_ISA1200=y
-CONFIG_PMIC8XXX_UPL=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_TUN=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-CONFIG_LIBRA_SDIOIF=m
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM=y
-CONFIG_TOUCHSCREEN_TSC2007=y
-CONFIG_TOUCHSCREEN_CY8C_TS=y
-CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-CONFIG_BOSCH_BMA150=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_QUP=y
-CONFIG_I2C_SSBI=y
-CONFIG_SPI=y
-CONFIG_SPI_QSD=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-CONFIG_SENSORS_MSM_ADC=y
-CONFIG_THERMAL=y
-CONFIG_THERMAL_MSM_POPMEM=y
-CONFIG_PMIC8058=y
-CONFIG_MARIMBA_CORE=y
-CONFIG_MARIMBA_CODEC=y
-CONFIG_TIMPANI_CODEC=y
-# CONFIG_MFD_PM8XXX_DEBUG is not set
-# CONFIG_MFD_PM8XXX_PWM is not set
-# CONFIG_MFD_PM8XXX_MISC is not set
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_VIDEO_DEV=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_RADIO_TAVARUA=y
-CONFIG_ION=y
-CONFIG_ION_MSM=y
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_LOGO=y
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP40=y
-CONFIG_FB_MSM_OVERLAY=y
-CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_SPI is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM7KV2_SOC=y
-CONFIG_SND_MVS_SOC=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
-CONFIG_USB_MSM_ACA=y
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_TEST=m
-CONFIG_MMC_MSM=y
-# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
-CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
-CONFIG_MMC_MSM_SDC3_SUPPORT=y
-CONFIG_MMC_MSM_SDC4_SUPPORT=y
-CONFIG_LEDS_PMIC8058=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_MSM_SSBI=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_FUSE_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_SCHEDSTATS=y
-CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_SLAB=y
-CONFIG_DEBUG_SLAB_LEAK=y
-# CONFIG_DEBUG_PREEMPT is not set
-CONFIG_PROVE_LOCKING=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2a6ba73..cb15c2e 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -57,6 +57,7 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
@@ -272,6 +273,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 618668f..ac51e25 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -465,6 +465,7 @@
select MSM_RPM_REGULATOR_SMD
select MSM_SPM_REGULATOR
select MSM_JTAG_MM if CORESIGHT_ETM
+ select MSM_CPR_REGULATOR
endmenu
choice
@@ -2912,4 +2913,15 @@
bool "Configure XPU violations as fatal errors"
help
Select if XPU violations have to be configured as fatal errors.
+
+config MSM_CPR_REGULATOR
+ bool "RBCPR regulator driver for APC"
+ depends on REGULATOR
+ depends on OF
+ help
+ Compile in RBCPR (RapidBridge Core Power Reduction) driver to support
+ corner vote for APC power rail. The driver takes PTE process voltage
+ suggestions in efuse as initial settings. It converts corner vote
+ to voltage value before writing to a voltage regulator API, such as
+ that provided by spm-regulator driver.
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d3acbc7..d07b094 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -422,3 +422,4 @@
obj-$(CONFIG_MSM_CPU_PWRCTL) += msm_cpu_pwrctl.o
obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
+obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index a1ed251..5ab4a53 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -475,6 +475,9 @@
.low_voltage_calc_ms = 1000,
.alarm_low_mv = 3400,
.alarm_high_mv = 4000,
+ .high_ocv_correction_limit_uv = 50,
+ .low_ocv_correction_limit_uv = 100,
+ .hold_soc_est = 3,
};
static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 48abd35..42bde8f 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1887,7 +1887,7 @@
static struct gpiomux_setting mdm2ap_status_gpio_run_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_NONE,
};
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 4f398f4..ef65613 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -478,6 +478,9 @@
.low_voltage_calc_ms = 1000,
.alarm_low_mv = 3400,
.alarm_high_mv = 4000,
+ .high_ocv_correction_limit_uv = 50,
+ .low_ocv_correction_limit_uv = 100,
+ .hold_soc_est = 3,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 1aa7508..bf8f895 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -243,25 +243,25 @@
static struct gpiomux_setting ap2mdm_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_4MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting mdm2ap_status_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_NONE,
};
static struct gpiomux_setting mdm2ap_errfatal_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_16MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_4MA,
.pull = GPIOMUX_PULL_DOWN,
};
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 8c16984..c87d966 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -435,6 +435,9 @@
.low_voltage_calc_ms = 1000,
.alarm_low_mv = 3400,
.alarm_high_mv = 4000,
+ .high_ocv_correction_limit_uv = 50,
+ .low_ocv_correction_limit_uv = 100,
+ .hold_soc_est = 3,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1f522a1..413927c 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -1350,17 +1350,6 @@
},
};
-static struct branch_clk gcc_noc_conf_xpu_ahb_clk = {
- .cbcr_reg = NOC_CONF_XPU_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[GCC_BASE],
- .c = {
- .dbg_name = "gcc_noc_conf_xpu_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(gcc_noc_conf_xpu_ahb_clk.c),
- },
-};
-
static struct branch_clk gcc_pdm2_clk = {
.cbcr_reg = PDM2_CBCR,
.has_sibling = 0,
@@ -1574,7 +1563,6 @@
static struct measure_mux_entry measure_mux_GCC[] = {
{ &gcc_periph_noc_ahb_clk.c, GCC_BASE, 0x0010 },
- { &gcc_noc_conf_xpu_ahb_clk.c, GCC_BASE, 0x0018 },
{ &gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030 },
{ &gcc_mss_q6_bimc_axi_clk.c, GCC_BASE, 0x0031 },
{ &gcc_usb_hsic_ahb_clk.c, GCC_BASE, 0x0058 },
@@ -2817,6 +2805,13 @@
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mss_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_wlan_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &xo.c);
+
+
#ifdef CONFIG_DEBUG_FS
static int measure_clk_set_parent(struct clk *c, struct clk *parent)
{
@@ -3027,20 +3022,20 @@
CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
/* PIL-LPASS */
- CLK_LOOKUP("xo", xo.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("xo", cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("reg_clk", q6ss_ahbm_clk.c, "fe200000.qcom,lpass"),
/* PIL-MODEM */
- CLK_LOOKUP("xo", xo.c, "fc880000.qcom,mss"),
+ CLK_LOOKUP("xo", cxo_pil_mss_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
/* PIL-PRONTO */
- CLK_LOOKUP("xo", xo.c, "fb21b000.qcom,pronto"),
+ CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
/* PIL-VENUS */
CLK_LOOKUP("src_clk", vcodec0_clk_src.c, "fdce0000.qcom,venus"),
@@ -3055,8 +3050,8 @@
CLK_LOOKUP("a7sspll", a7sspll.c, "f9011050.qcom,acpuclk"),
/* WCNSS CLOCKS */
- CLK_LOOKUP("xo", xo.c, "fb000000.qcom,wcnss-wlan"),
- CLK_LOOKUP("rf_clk", cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("xo", cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("rf_clk", cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
/* BUS DRIVER */
CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
@@ -3141,7 +3136,7 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
/* HSUSB-OTG Clocks */
- CLK_LOOKUP("xo", xo.c, "f9a55000.usb"),
+ CLK_LOOKUP("xo", cxo_otg_clk.c, "f9a55000.usb"),
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 2879b49..8bdc496 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -32,7 +32,7 @@
* When enabling/disabling a clock, check the halt bit up to this number
* number of times (with a 1 us delay in between) before continuing.
*/
-#define HALT_CHECK_MAX_LOOPS 200
+#define HALT_CHECK_MAX_LOOPS 500
/* For clock without halt checking, wait this long after enables/disables. */
#define HALT_CHECK_DELAY_US 10
@@ -40,7 +40,7 @@
* When updating an RCG configuration, check the update bit up to this number
* number of times (with a 1 us delay in between) before continuing.
*/
-#define UPDATE_CHECK_MAX_LOOPS 200
+#define UPDATE_CHECK_MAX_LOOPS 500
DEFINE_SPINLOCK(local_clock_reg_lock);
struct clk_freq_tbl rcg_dummy_freq = F_END;
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
index e7eca7b..f2c8d58 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.c
+++ b/arch/arm/mach-msm/clock-mdss-8226.c
@@ -111,7 +111,7 @@
static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
{
if (pll_initialized) {
- pll_pclk_rate = (rate * 3) / 2;
+ pll_pclk_rate = rate;
pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
return 0;
} else {
@@ -148,7 +148,7 @@
REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
- REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+ REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 8e7f1fa..d866874 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -193,7 +193,7 @@
static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
{
if (pll_initialized) {
- pll_pclk_rate = (rate * 3) / 2;
+ pll_pclk_rate = rate;
pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
return 0;
} else {
@@ -230,7 +230,7 @@
REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
- REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+ REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 51d895a..13041b1 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -80,12 +80,14 @@
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- if (v->is_branch)
- return 0;
-
mutex_lock(&voter_clk_lock);
parent = clk->parent;
+ if (v->is_branch) {
+ v->enabled = true;
+ goto out;
+ }
+
/*
* Increase the rate if this clock is voting for a higher rate
* than the current rate.
@@ -109,8 +111,6 @@
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- if (v->is_branch)
- return;
mutex_lock(&voter_clk_lock);
parent = clk->parent;
@@ -120,12 +120,16 @@
* the highest rate.
*/
v->enabled = false;
+ if (v->is_branch)
+ goto out;
+
new_rate = voter_clk_aggregate_rate(parent);
cur_rate = max(new_rate, clk->rate);
if (new_rate < cur_rate)
clk_set_rate(parent, new_rate);
+out:
mutex_unlock(&voter_clk_lock);
}
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
new file mode 100644
index 0000000..4e95e4e
--- /dev/null
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/cpr-regulator.h>
+
+struct cpr_regulator {
+ struct regulator_desc rdesc;
+ struct regulator_dev *rdev;
+ bool enabled;
+ int corner;
+
+ /* Process voltage parameters */
+ phys_addr_t efuse_phys;
+ u32 num_efuse_bits;
+ u32 efuse_bit_pos[CPR_PVS_EFUSE_BITS_MAX];
+ u32 pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
+ u32 pvs_corner_ceiling[NUM_APC_PVS][CPR_CORNER_MAX];
+ /* Process voltage variables */
+ u32 pvs_bin;
+ u32 pvs_process;
+ u32 *process_vmax;
+
+ /* APC voltage regulator */
+ struct regulator *vdd_apc;
+};
+
+static int cpr_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+
+ return cpr_vreg->enabled;
+}
+
+static int cpr_regulator_enable(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = regulator_enable(cpr_vreg->vdd_apc);
+ if (!rc)
+ cpr_vreg->enabled = true;
+ return rc;
+}
+
+static int cpr_regulator_disable(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = regulator_disable(cpr_vreg->vdd_apc);
+ if (!rc)
+ cpr_vreg->enabled = false;
+ return rc;
+}
+
+static int cpr_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+ int rc;
+ int vdd_apc_min, vdd_apc_max;
+
+ vdd_apc_min = cpr_vreg->process_vmax[min_uV];
+ vdd_apc_max = cpr_vreg->process_vmax[CPR_CORNER_SUPER_TURBO];
+ rc = regulator_set_voltage(cpr_vreg->vdd_apc,
+ vdd_apc_min, vdd_apc_max);
+ if (!rc)
+ cpr_vreg->corner = min_uV;
+
+ pr_debug("set [corner:%d] = %d uV: rc=%d\n", min_uV, vdd_apc_min, rc);
+ return rc;
+}
+
+static int cpr_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
+
+ return cpr_vreg->corner;
+}
+
+static struct regulator_ops cpr_corner_ops = {
+ .enable = cpr_regulator_enable,
+ .disable = cpr_regulator_disable,
+ .is_enabled = cpr_regulator_is_enabled,
+ .set_voltage = cpr_regulator_set_voltage,
+ .get_voltage = cpr_regulator_get_voltage,
+};
+
+static int __init cpr_regulator_pvs_init(struct cpr_regulator *cpr_vreg)
+{
+ void __iomem *efuse_base;
+ u32 efuse_bits;
+ int i, bit_pos;
+ u32 vmax;
+
+ efuse_base = ioremap(cpr_vreg->efuse_phys, 4);
+ if (!efuse_base) {
+ pr_err("Unable to map efuse_phys 0x%x\n",
+ cpr_vreg->efuse_phys);
+ return -EINVAL;
+ }
+
+ efuse_bits = readl_relaxed(efuse_base);
+
+ /* Construct PVS process # from the efuse bits */
+ for (i = 0; i < cpr_vreg->num_efuse_bits; i++) {
+ bit_pos = cpr_vreg->efuse_bit_pos[i];
+ cpr_vreg->pvs_bin |= (efuse_bits & BIT(bit_pos)) ? BIT(i) : 0;
+ }
+
+ cpr_vreg->pvs_process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
+ if (cpr_vreg->pvs_process >= NUM_APC_PVS)
+ cpr_vreg->pvs_process = APC_PVS_NO;
+
+ /* Use ceiling voltage of Turbo@Slow for all corners of APC_PVS_NO
+ but use SuperTurbo@Slow for its SuperTurbo */
+ vmax = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_TURBO];
+ for (i = CPR_CORNER_SVS; i <= CPR_CORNER_TURBO; i++)
+ cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][i] = vmax;
+ cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][CPR_CORNER_SUPER_TURBO]
+ = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW]
+ [CPR_CORNER_SUPER_TURBO];
+
+ cpr_vreg->process_vmax =
+ cpr_vreg->pvs_corner_ceiling[cpr_vreg->pvs_process];
+
+ iounmap(efuse_base);
+
+ pr_info("PVS Info: efuse_phys=0x%08X, n_bits=%d\n",
+ cpr_vreg->efuse_phys, cpr_vreg->num_efuse_bits);
+ pr_info("PVS Info: efuse=0x%08X, bin=%d, process=%d\n",
+ efuse_bits, cpr_vreg->pvs_bin, cpr_vreg->pvs_process);
+
+ return 0;
+}
+
+static int __init cpr_regulator_apc_init(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ cpr_vreg->vdd_apc = devm_regulator_get(&pdev->dev, "vdd-apc");
+ if (IS_ERR_OR_NULL(cpr_vreg->vdd_apc)) {
+ pr_err("devm_regulator_get: rc=%d\n",
+ (int)PTR_ERR(cpr_vreg->vdd_apc));
+ }
+
+ return PTR_RET(cpr_vreg->vdd_apc);
+}
+
+static void cpr_regulator_apc_exit(struct cpr_regulator *cpr_vreg)
+{
+ if (cpr_vreg->enabled)
+ regulator_disable(cpr_vreg->vdd_apc);
+}
+
+static int __init cpr_regulator_parse_dt(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ struct resource *res;
+ int rc;
+ size_t pvs_bins;
+
+ /* Parse process voltage parameters */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "efuse_phys");
+ if (!res || !res->start) {
+ pr_err("efuse_phys missing: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->efuse_phys = res->start;
+
+ rc = of_property_read_u32(of_node, "qcom,num-efuse-bits",
+ &cpr_vreg->num_efuse_bits);
+ if (rc < 0) {
+ pr_err("num-efuse-bits missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ if (cpr_vreg->num_efuse_bits == 0 ||
+ cpr_vreg->num_efuse_bits > CPR_PVS_EFUSE_BITS_MAX) {
+ pr_err("invalid num-efuse-bits : %d\n",
+ cpr_vreg->num_efuse_bits);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(of_node, "qcom,efuse-bit-pos",
+ cpr_vreg->efuse_bit_pos,
+ cpr_vreg->num_efuse_bits);
+ if (rc < 0) {
+ pr_err("efuse-bit-pos missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ pvs_bins = 1 << cpr_vreg->num_efuse_bits;
+ rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
+ cpr_vreg->pvs_bin_process,
+ pvs_bins);
+ if (rc < 0) {
+ pr_err("pvs-bin-process missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-corner-ceiling-slow",
+ &cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-corner-ceiling-nom",
+ &cpr_vreg->pvs_corner_ceiling[APC_PVS_NOM][CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-corner-ceiling-fast",
+ &cpr_vreg->pvs_corner_ceiling[APC_PVS_FAST][CPR_CORNER_SVS],
+ CPR_CORNER_MAX - CPR_CORNER_SVS);
+ if (rc < 0) {
+ pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __devinit cpr_regulator_probe(struct platform_device *pdev)
+{
+ struct cpr_regulator *cpr_vreg;
+ struct regulator_desc *rdesc;
+ struct regulator_init_data *init_data = pdev->dev.platform_data;
+ int rc;
+
+ if (!pdev->dev.of_node) {
+ pr_err("Device tree node is missing\n");
+ return -EINVAL;
+ }
+
+ init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+ if (!init_data) {
+ pr_err("regulator init data is missing\n");
+ return -EINVAL;
+ } else {
+ init_data->constraints.input_uV
+ = init_data->constraints.max_uV;
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
+ }
+
+ cpr_vreg = devm_kzalloc(&pdev->dev, sizeof(struct cpr_regulator),
+ GFP_KERNEL);
+ if (!cpr_vreg) {
+ pr_err("Can't allocate cpr_regulator memory\n");
+ return -ENOMEM;
+ }
+
+ rc = cpr_regulator_parse_dt(pdev, cpr_vreg);
+ if (rc) {
+ pr_err("Wrong DT parameter specified: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr_regulator_pvs_init(cpr_vreg);
+ if (rc) {
+ pr_err("Initialize PVS wrong: rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = cpr_regulator_apc_init(pdev, cpr_vreg);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ pr_err("Initialize APC wrong: rc=%d\n", rc);
+ return rc;
+ }
+
+ rdesc = &cpr_vreg->rdesc;
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->ops = &cpr_corner_ops;
+ rdesc->name = init_data->constraints.name;
+
+ cpr_vreg->rdev = regulator_register(rdesc, &pdev->dev, init_data,
+ cpr_vreg, pdev->dev.of_node);
+ if (IS_ERR(cpr_vreg->rdev)) {
+ rc = PTR_ERR(cpr_vreg->rdev);
+ pr_err("regulator_register failed: rc=%d\n", rc);
+
+ cpr_regulator_apc_exit(cpr_vreg);
+ return rc;
+ }
+
+ platform_set_drvdata(pdev, cpr_vreg);
+
+ pr_info("PVS [%d %d %d %d] uV\n",
+ cpr_vreg->process_vmax[CPR_CORNER_SVS],
+ cpr_vreg->process_vmax[CPR_CORNER_NORMAL],
+ cpr_vreg->process_vmax[CPR_CORNER_TURBO],
+ cpr_vreg->process_vmax[CPR_CORNER_SUPER_TURBO]);
+
+ return 0;
+}
+
+static int __devexit cpr_regulator_remove(struct platform_device *pdev)
+{
+ struct cpr_regulator *cpr_vreg;
+
+ cpr_vreg = platform_get_drvdata(pdev);
+ if (cpr_vreg) {
+ cpr_regulator_apc_exit(cpr_vreg);
+ regulator_unregister(cpr_vreg->rdev);
+ }
+
+ return 0;
+}
+
+static struct of_device_id cpr_regulator_match_table[] = {
+ { .compatible = CPR_REGULATOR_DRIVER_NAME, },
+ {}
+};
+
+static struct platform_driver cpr_regulator_driver = {
+ .driver = {
+ .name = CPR_REGULATOR_DRIVER_NAME,
+ .of_match_table = cpr_regulator_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = cpr_regulator_probe,
+ .remove = __devexit_p(cpr_regulator_remove),
+};
+
+/**
+ * cpr_regulator_init() - register cpr-regulator driver
+ *
+ * This initialization function should be called in systems in which driver
+ * registration ordering must be controlled precisely.
+ */
+int __init cpr_regulator_init(void)
+{
+ static bool initialized;
+
+ if (initialized)
+ return 0;
+ else
+ initialized = true;
+
+ return platform_driver_register(&cpr_regulator_driver);
+}
+EXPORT_SYMBOL(cpr_regulator_init);
+
+static void __exit cpr_regulator_exit(void)
+{
+ platform_driver_unregister(&cpr_regulator_driver);
+}
+
+MODULE_DESCRIPTION("CPR regulator driver");
+MODULE_LICENSE("GPL v2");
+
+arch_initcall(cpr_regulator_init);
+module_exit(cpr_regulator_exit);
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 8fd3cfc..ef835b8 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -102,9 +102,8 @@
int msm_bus_board_rpm_get_il_ids(uint16_t *id);
int msm_bus_board_get_iid(int id);
-#ifdef CONFIG_ARCH_MSM8226
-#define NFAB 6
-#endif
+#define NFAB_MSM8226 6
+#define NFAB_MSM8610 5
/*
* These macros specify the convention followed for allocating
@@ -302,6 +301,7 @@
MSM_BUS_MASTER_V_OCMEM_GFX3D,
MSM_BUS_MASTER_IPA,
MSM_BUS_MASTER_QPIC,
+ MSM_BUS_MASTER_MDPE,
MSM_BUS_MASTER_LAST,
@@ -459,6 +459,7 @@
MSM_BUS_SLAVE_SERVICE_CNOC,
MSM_BUS_SLAVE_IPS_CFG,
MSM_BUS_SLAVE_QPIC,
+ MSM_BUS_SLAVE_DSI_CFG,
MSM_BUS_SLAVE_LAST,
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index a50a37d..cafcdd2 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -48,7 +48,7 @@
#define IPC_ROUTER_XPRT_EVENT_CLOSE 3
#define IPC_ROUTER_INFINITY -1
-#define DEFAULT_RCV_TIMEO IPC_ROUTER_INFINITY
+#define DEFAULT_RCV_TIMEO 0
#define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 16b60a1..f40bd5d 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -414,7 +414,7 @@
}
if (timeout == 0)
- return -ETIMEDOUT;
+ return 0;
lock_sock(sk);
mutex_lock(&port_ptr->port_rx_q_lock);
}
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 9f06cf6..c8d6d5a 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -161,9 +161,11 @@
*/
pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
msleep(1000);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
- }
+ } else
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
goto start_mdm_peripheral;
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 03d158e..de46be8 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -649,7 +649,7 @@
}
}
- gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index 2ee07f3..ebc0c3a 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -15,4 +15,5 @@
obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o
obj-$(CONFIG_ARCH_MSM9625) += msm_bus_board_9625.o
obj-$(CONFIG_ARCH_MSM8226) += msm_bus_id.o
+obj-$(CONFIG_ARCH_MSM8610) += msm_bus_id.o
obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 9201398..fd2dbb5 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -182,7 +182,7 @@
};
struct msm_bus_board_algorithm {
- const int board_nfab;
+ int board_nfab;
void (*assign_iids)(struct msm_bus_fabric_registration *fabreg,
int fabid);
int (*get_iid)(int id);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_id.c b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
index 693c51e..7e9883f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_id.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
@@ -19,6 +19,7 @@
#include <mach/msm_bus_board.h>
#include <mach/board.h>
#include <mach/rpm.h>
+#include <mach/socinfo.h>
#include "msm_bus_core.h"
#include "msm_bus_noc.h"
#include "msm_bus_bimc.h"
@@ -67,7 +68,6 @@
static struct msm_bus_board_algorithm msm_bus_id_algo = {
- .board_nfab = NFAB,
.get_iid = msm_bus_get_iid,
.assign_iids = msm_bus_assign_iids,
};
@@ -79,5 +79,10 @@
void msm_bus_board_init(struct msm_bus_fabric_registration *pdata)
{
+ if (machine_is_msm8226())
+ msm_bus_id_algo.board_nfab = NFAB_MSM8226;
+ else if (machine_is_msm8610())
+ msm_bus_id_algo.board_nfab = NFAB_MSM8610;
+
pdata->board_algo = &msm_bus_id_algo;
}
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index 1589623..f70022e 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -213,7 +213,9 @@
switch (val) {
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
+ case PM_POST_RESTORE:
rq_info.hotplug_disabled = 0;
+ break;
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
rq_info.hotplug_disabled = 1;
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index ef10cdc..4778d5b 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -568,6 +568,6 @@
return platform_driver_register(&msm_watchdog_driver);
}
-late_initcall(init_watchdog);
+pure_initcall(init_watchdog);
MODULE_DESCRIPTION("MSM Watchdog Driver");
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 599b24c..06de8cc 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -25,6 +25,7 @@
#include <linux/regulator/consumer.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
+#include <linux/dma-mapping.h>
#include <mach/subsystem_restart.h>
#include <mach/clk.h>
@@ -78,10 +79,8 @@
#define BHS_TIMEOUT_US 50
struct mba_data {
- void __iomem *metadata_base;
void __iomem *rmb_base;
void __iomem *io_clamp_reg;
- unsigned long metadata_phys;
struct pil_desc desc;
struct subsys_device *subsys;
struct subsys_desc subsys_desc;
@@ -364,18 +363,28 @@
const u8 *metadata, size_t size)
{
struct mba_data *drv = dev_get_drvdata(pil->dev);
+ void *mdata_virt;
+ dma_addr_t mdata_phys;
s32 status;
int ret;
- /* Copy metadata to assigned shared buffer location */
- memcpy(drv->metadata_base, metadata, size);
+ /* Make metadata physically contiguous and 4K aligned. */
+ mdata_virt = dma_alloc_coherent(pil->dev, size, &mdata_phys,
+ GFP_KERNEL);
+ if (!mdata_virt) {
+ dev_err(pil->dev, "MBA metadata buffer allocation failed\n");
+ return -ENOMEM;
+ }
+ memcpy(mdata_virt, metadata, size);
+ /* wmb() ensures copy completes prior to starting authentication. */
+ wmb();
/* Initialize length counter to 0 */
writel_relaxed(0, drv->rmb_base + RMB_PMI_CODE_LENGTH);
drv->img_length = 0;
/* Pass address of meta-data to the MBA and perform authentication */
- writel_relaxed(drv->metadata_phys, drv->rmb_base + RMB_PMI_META_DATA);
+ writel_relaxed(mdata_phys, drv->rmb_base + RMB_PMI_META_DATA);
writel_relaxed(CMD_META_DATA_READY, drv->rmb_base + RMB_MBA_COMMAND);
ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
@@ -388,6 +397,8 @@
ret = -EINVAL;
}
+ dma_free_coherent(pil->dev, size, mdata_virt, mdata_phys);
+
return ret;
}
@@ -716,15 +727,6 @@
drv->rmb_base = devm_request_and_ioremap(&pdev->dev, res);
if (!drv->rmb_base)
return -ENOMEM;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "metadata_base");
- if (res) {
- drv->metadata_base = devm_ioremap(&pdev->dev,
- res->start, resource_size(res));
- if (!drv->metadata_base)
- return -ENOMEM;
- drv->metadata_phys = res->start;
- }
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index 7472b46..e74fdf9 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -56,9 +56,6 @@
goto fail;
}
- /* Query the DSP to check if resources are available */
- msleep(Q6_PIL_GET_DELAY_MS);
-
/* Set the state of the ADSP in APR driver */
apr_set_q6_state(APR_SUBSYS_LOADED);
} else if (adsp_state == APR_SUBSYS_LOADED) {
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 5969a3c..8a2c23f 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -32,22 +32,36 @@
#include <mach/msm_smd.h>
#include <mach/subsystem_restart.h>
#include <mach/socinfo.h>
+#include <mach/msm_ipc_logging.h>
#include "smd_private.h"
#define MAX_SMD_TTYS 37
#define MAX_TTY_BUF_SIZE 2048
#define MAX_RA_WAKE_LOCK_NAME_LEN 32
+#define SMD_TTY_LOG_PAGES 2
+#define SMD_TTY_INFO(buf...) \
+do { \
+ if (smd_tty_log_ctx) { \
+ ipc_log_string(smd_tty_log_ctx, buf); \
+ } \
+} while (0)
+
+#define SMD_TTY_ERR(buf...) \
+do { \
+ if (smd_tty_log_ctx) \
+ ipc_log_string(smd_tty_log_ctx, buf); \
+ pr_err(buf); \
+} while (0)
+
+static void *smd_tty_log_ctx;
static DEFINE_MUTEX(smd_tty_lock);
-static uint smd_tty_modem_wait;
-module_param_named(modem_wait, smd_tty_modem_wait,
- uint, S_IRUGO | S_IWUSR | S_IWGRP);
-
struct smd_tty_info {
smd_channel_t *ch;
struct tty_port port;
+ struct device *device_ptr;
struct wake_lock wake_lock;
int open_count;
struct tasklet_struct tty_tsklt;
@@ -58,6 +72,7 @@
int in_reset;
int in_reset_updated;
int is_open;
+ unsigned int open_wait;
wait_queue_head_t ch_opened_wait_queue;
spinlock_t reset_lock;
spinlock_t ra_lock; /* Read Available Lock*/
@@ -120,6 +135,57 @@
spin_unlock_irqrestore(&info->reset_lock, flags);
}
+static ssize_t open_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned int num_dev;
+ unsigned long wait;
+ if (dev == NULL) {
+ SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+ return -EINVAL;
+ }
+ for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+ if (dev == smd_tty[num_dev].device_ptr)
+ break;
+ }
+ if (num_dev >= MAX_SMD_TTYS) {
+ SMD_TTY_ERR("[%s]: Device Not found", __func__);
+ return -EINVAL;
+ }
+ if (!kstrtoul(buf, 10, &wait)) {
+ smd_tty[num_dev].open_wait = wait;
+ return n;
+ } else {
+ SMD_TTY_INFO("[%s]: Unable to convert %s to an int",
+ __func__, buf);
+ return -EINVAL;
+ }
+}
+
+static ssize_t open_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int num_dev;
+
+ if (dev == NULL) {
+ SMD_TTY_INFO("%s: Invalid Device passed", __func__);
+ return -EINVAL;
+ }
+ for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
+ if (dev == smd_tty[num_dev].device_ptr)
+ break;
+ }
+ if (num_dev >= MAX_SMD_TTYS)
+ SMD_TTY_ERR("[%s]: Device Not Found", __func__);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ smd_tty[num_dev].open_wait);
+}
+
+static DEVICE_ATTR
+ (open_timeout, 0664, open_timeout_show, open_timeout_store);
+
static void smd_tty_read(unsigned long param)
{
unsigned char *ptr;
@@ -165,7 +231,9 @@
** context here and nobody else could 'steal' our
** characters.
*/
- printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
+ SMD_TTY_ERR(
+ "%s - Possible smd_tty_buffer mismatch for %s",
+ __func__, info->ch->name);
}
wake_lock_timeout(&info->wake_lock, HZ / 2);
@@ -270,6 +338,16 @@
if (peripheral) {
info->pil = subsystem_get(peripheral);
if (IS_ERR(info->pil)) {
+ SMD_TTY_INFO(
+ "%s failed on smd_tty device :%s subsystem_get failed for %s",
+ __func__, smd_tty[n].smd->port_name,
+ peripheral);
+ /*
+ * Sleep, inorder to reduce the frequency of
+ * retry by user-space modules and to avoid
+ * possible watchdog bite.
+ */
+ msleep((smd_tty[n].open_wait * 1000));
res = PTR_ERR(info->pil);
goto out;
}
@@ -292,21 +370,22 @@
* Wait for a channel to be allocated so we know
* the modem is ready enough.
*/
- if (smd_tty_modem_wait) {
+ if (smd_tty[n].open_wait) {
res = wait_for_completion_interruptible_timeout(
&info->ch_allocated,
- msecs_to_jiffies(smd_tty_modem_wait *
+ msecs_to_jiffies(smd_tty[n].open_wait *
1000));
if (res == 0) {
- pr_err("Timed out waiting for SMD"
- " channel\n");
+ SMD_TTY_INFO(
+ "Timed out waiting for SMD channel %s",
+ smd_tty[n].smd->port_name);
res = -ETIMEDOUT;
goto release_pil;
} else if (res < 0) {
- pr_err("Error waiting for SMD channel:"
- " %d\n",
- res);
+ SMD_TTY_INFO(
+ "Error waiting for SMD channel %s : %d\n",
+ smd_tty[n].smd->port_name, res);
goto release_pil;
}
@@ -329,8 +408,10 @@
&info->ch, info,
smd_tty_notify);
if (res < 0) {
- pr_err("%s: %s open failed %d\n", __func__,
- smd_tty[n].smd->port_name, res);
+ SMD_TTY_INFO(
+ "%s: %s open failed %d\n",
+ __func__, smd_tty[n].smd->port_name,
+ res);
goto release_pil;
}
@@ -340,12 +421,16 @@
if (res == 0)
res = -ETIMEDOUT;
if (res < 0) {
- pr_err("%s: wait for %s smd_open failed %d\n",
+ SMD_TTY_INFO(
+ "%s: wait for %s smd_open failed %d\n",
__func__, smd_tty[n].smd->port_name,
res);
goto release_pil;
}
res = 0;
+ SMD_TTY_INFO("%s with PID %u opened port %s",
+ current->comm, current->pid,
+ smd_tty[n].smd->port_name);
}
}
@@ -382,6 +467,9 @@
wake_lock_destroy(&info->wake_lock);
wake_lock_destroy(&info->ra_wake_lock);
}
+ SMD_TTY_INFO("%s with PID %u closed port %s",
+ current->comm, current->pid,
+ info->smd->port_name);
tty->driver_data = 0;
del_timer(&info->buf_req_timer);
if (info->ch) {
@@ -430,6 +518,8 @@
}
if (len > avail)
len = avail;
+ SMD_TTY_INFO("[WRITE]: PID %u -> port %s %x bytes",
+ current->pid, info->smd->port_name, len);
return smd_write(info->ch, buf, len);
}
@@ -480,6 +570,8 @@
tiocm |= TIOCM_OUT2;
info->in_reset_updated = 0;
}
+ SMD_TTY_INFO("PID %u --> %s TIOCM is %x ",
+ current->pid, __func__, tiocm);
spin_unlock_irqrestore(&info->reset_lock, flags);
return tiocm;
@@ -493,6 +585,8 @@
if (info->in_reset)
return -ENETRESET;
+ SMD_TTY_INFO("PID %u --> %s Set: %x Clear: %x",
+ current->pid, __func__, set, clear);
return smd_tiocmset(info->ch, set, clear);
}
@@ -540,11 +634,25 @@
return 0;
}
}
- pr_err("%s: unknown device '%s'\n", __func__, pdev->name);
+ SMD_TTY_ERR("[ERR]%s: unknown device '%s'\n", __func__, pdev->name);
return -ENODEV;
}
+/**
+ * smd_tty_log_init()- Init function for IPC logging
+ *
+ * Initialize the buffer that is used to provide the log information
+ * pertaining to the smd_tty module.
+ */
+static void smd_tty_log_init(void)
+{
+ smd_tty_log_ctx = ipc_log_context_create(SMD_TTY_LOG_PAGES,
+ "smd_tty");
+ if (!smd_tty_log_ctx)
+ pr_err("%s: Unable to create IPC log", __func__);
+}
+
static struct tty_driver *smd_tty_driver;
static int __init smd_tty_init(void)
@@ -554,9 +662,12 @@
int idx;
struct tty_port *port;
+ smd_tty_log_init();
smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
- if (smd_tty_driver == 0)
+ if (smd_tty_driver == 0) {
+ SMD_TTY_ERR("%s - Driver allocation failed", __func__);
return -ENOMEM;
+ }
smd_tty_driver->owner = THIS_MODULE;
smd_tty_driver->driver_name = "smd_tty_driver";
@@ -577,7 +688,7 @@
ret = tty_register_driver(smd_tty_driver);
if (ret) {
put_tty_driver(smd_tty_driver);
- pr_err("%s: driver registration failed %d\n", __func__, ret);
+ SMD_TTY_ERR("%s: driver registration failed %d", __func__, ret);
return ret;
}
@@ -612,7 +723,14 @@
tty_port_init(port);
port->ops = &smd_tty_port_ops;
/* TODO: For kernel >= 3.7 use tty_port_register_device */
- tty_register_device(smd_tty_driver, idx, 0);
+ smd_tty[idx].device_ptr =
+ tty_register_device(smd_tty_driver, idx, 0);
+ if (device_create_file(smd_tty[idx].device_ptr,
+ &dev_attr_open_timeout))
+ SMD_TTY_ERR(
+ "%s: Unable to create device attributes for %s",
+ __func__, smd_configs[n].port_name);
+
init_completion(&smd_tty[idx].ch_allocated);
/* register platform device */
@@ -628,7 +746,8 @@
ret = platform_driver_register(&smd_tty[idx].driver);
if (ret) {
- pr_err("%s: init failed %d (%d)\n", __func__, idx, ret);
+ SMD_TTY_ERR(
+ "%s: init failed %d (%d)", __func__, idx, ret);
smd_tty[idx].driver.probe = NULL;
goto out;
}
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index c8e2dd3..233c5a5 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -33,6 +33,7 @@
};
struct msm_spm_device {
+ bool initialized;
struct msm_spm_driver_data reg_data;
struct msm_spm_power_modes *modes;
uint32_t num_modes;
@@ -55,6 +56,8 @@
struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+ if (!dev->initialized)
+ return;
dev->cpu_vdd = info->vlevel;
info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
}
@@ -119,6 +122,9 @@
uint32_t start_addr = 0;
int ret = -EINVAL;
+ if (!dev->initialized)
+ return -ENXIO;
+
if (mode == MSM_SPM_MODE_DISABLED) {
ret = msm_spm_drv_set_spm_enable(&dev->reg_data, false);
} else if (!msm_spm_drv_set_spm_enable(&dev->reg_data, true)) {
@@ -170,6 +176,7 @@
dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
}
msm_spm_drv_flush_seq_entry(&dev->reg_data);
+ dev->initialized = true;
return 0;
spm_failed_init:
@@ -278,6 +285,8 @@
void msm_spm_l2_reinit(void)
{
+ if (!msm_spm_l2_device.initialized)
+ return;
msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
}
EXPORT_SYMBOL(msm_spm_l2_reinit);
@@ -288,6 +297,8 @@
*/
int msm_spm_apcs_set_vdd(unsigned int vlevel)
{
+ if (!msm_spm_l2_device.initialized)
+ return -ENXIO;
return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
}
EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
@@ -298,6 +309,8 @@
*/
int msm_spm_apcs_set_phase(unsigned int phase_cnt)
{
+ if (!msm_spm_l2_device.initialized)
+ return -ENXIO;
return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
MSM_SPM_PMIC_PHASE_PORT, phase_cnt);
}
@@ -309,6 +322,8 @@
*/
int msm_spm_enable_fts_lpm(uint32_t mode)
{
+ if (!msm_spm_l2_device.initialized)
+ return -ENXIO;
return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
MSM_SPM_PMIC_PFM_PORT, mode);
}
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 45c9023..ed91480 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -227,7 +227,7 @@
pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
(unsigned long)base, (unsigned long)size / SZ_1M);
- dma_contiguous_reserve_area(size, &base, MEMBLOCK_ALLOC_ANYWHERE, name);
+ dma_contiguous_reserve_area(size, &base, 0, name);
return 0;
}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 071dd69..9e36e1e 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -314,6 +314,9 @@
diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
diag_send_feature_mask_update(smd_info->ch, smd_info->peripheral);
+ if (smd_info->notify_context == SMD_EVENT_OPEN)
+ diag_send_diag_mode_update_by_smd(smd_info, MODE_REALTIME);
+
smd_info->notify_context = 0;
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9d9df2a..555ffa0 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -20,6 +20,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
+#include <linux/wakelock.h>
#include <mach/msm_smd.h>
#include <asm/atomic.h>
#include <asm/mach-types.h>
@@ -76,6 +77,9 @@
#define DIAG_STATUS_OPEN (0x00010000) /* DCI channel open status mask */
#define DIAG_STATUS_CLOSED (0x00020000) /* DCI channel closed status mask */
+#define MODE_REALTIME 1
+#define MODE_NONREALTIME 0
+
#define NUM_SMD_DATA_CHANNELS 3
#define NUM_SMD_CONTROL_CHANNELS 3
#define NUM_SMD_DCI_CHANNELS 1
@@ -143,6 +147,14 @@
int pid;
};
+struct diag_nrt_wake_lock {
+ int enabled;
+ int ref_count;
+ int copy_count;
+ struct wake_lock read_lock;
+ spinlock_t read_spinlock;
+};
+
/* This structure is defined in USB header file */
#ifndef CONFIG_DIAG_OVER_USB
struct diag_request {
@@ -173,6 +185,8 @@
struct diag_request *write_ptr_1;
struct diag_request *write_ptr_2;
+ struct diag_nrt_wake_lock nrt_lock;
+
struct work_struct diag_read_smd_work;
struct work_struct diag_notify_update_smd_work;
int notify_context;
@@ -239,6 +253,7 @@
struct diag_ctrl_msg_mask *msg_mask;
struct diag_ctrl_feature_mask *feature_mask;
/* State for diag forwarding */
+ int real_time_mode;
struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 65fc89f..fb8efe4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -20,6 +20,7 @@
#include <linux/diagchar.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
+#include <linux/ratelimit.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
#endif
@@ -278,10 +279,11 @@
/* If the SD logging process exits, change logging to USB mode */
if (driver->logging_process_id == current->tgid) {
driver->logging_mode = USB_MODE;
+ diag_send_diag_mode_update(MODE_REALTIME);
diagfwd_connect();
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diag_clear_hsic_tbl();
- diagfwd_cancel_hsic();
+ diagfwd_cancel_hsic(REOPEN_HSIC);
diagfwd_connect_bridge(0);
#endif
}
@@ -707,6 +709,11 @@
diag_clear_hsic_tbl();
} else if (old_mode == NO_LOGGING_MODE && new_mode
== MEMORY_DEVICE_MODE) {
+ int i;
+ for (i = 0; i < MAX_HSIC_CH; i++)
+ if (diag_hsic[i].hsic_inited)
+ diag_hsic[i].hsic_data_requested =
+ driver->real_time_mode ? 1 : 0;
diagfwd_connect_bridge(0);
} else if (old_mode == USB_MODE && new_mode
== NO_LOGGING_MODE) {
@@ -716,12 +723,15 @@
diagfwd_connect_bridge(0);
} else if (old_mode == USB_MODE && new_mode
== MEMORY_DEVICE_MODE) {
- diagfwd_cancel_hsic();
+ if (driver->real_time_mode)
+ diagfwd_cancel_hsic(REOPEN_HSIC);
+ else
+ diagfwd_cancel_hsic(DONT_REOPEN_HSIC);
diagfwd_connect_bridge(0);
} else if (old_mode == MEMORY_DEVICE_MODE && new_mode
== USB_MODE) {
diag_clear_hsic_tbl();
- diagfwd_cancel_hsic();
+ diagfwd_cancel_hsic(REOPEN_HSIC);
diagfwd_connect_bridge(0);
}
}
@@ -770,12 +780,25 @@
int diag_switch_logging(unsigned long ioarg)
{
int i, temp, success = -EINVAL, status;
+ int temp_realtime_mode = driver->real_time_mode;
+
mutex_lock(&driver->diagchar_mutex);
temp = driver->logging_mode;
driver->logging_mode = (int)ioarg;
+
+ if (driver->logging_mode == MEMORY_DEVICE_MODE_NRT) {
+ diag_send_diag_mode_update(MODE_NONREALTIME);
+ driver->logging_mode = MEMORY_DEVICE_MODE;
+ } else {
+ diag_send_diag_mode_update(MODE_REALTIME);
+ }
+
if (temp == driver->logging_mode) {
mutex_unlock(&driver->diagchar_mutex);
- pr_err("diag: forbidden logging change requested\n");
+ if (driver->logging_mode != MEMORY_DEVICE_MODE ||
+ temp_realtime_mode)
+ pr_info_ratelimited("diag: Already in logging mode change requested, mode: %d\n",
+ driver->logging_mode);
return 0;
}
@@ -1097,6 +1120,7 @@
int num_data = 0, data_type;
int remote_token;
int exit_stat;
+ int clear_read_wakelock;
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
@@ -1111,6 +1135,7 @@
driver->data_ready[index]);
mutex_lock(&driver->diagchar_mutex);
+ clear_read_wakelock = 0;
if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
logging_mode == MEMORY_DEVICE_MODE)) {
remote_token = 0;
@@ -1172,6 +1197,10 @@
COPY_USER_SPACE_OR_EXIT(buf+ret,
*(data->buf_in_1),
data->write_ptr_1->length);
+ if (!driver->real_time_mode) {
+ process_lock_on_copy(&data->nrt_lock);
+ clear_read_wakelock++;
+ }
data->in_busy_1 = 0;
}
if (data->in_busy_2 == 1) {
@@ -1183,6 +1212,10 @@
COPY_USER_SPACE_OR_EXIT(buf+ret,
*(data->buf_in_2),
data->write_ptr_2->length);
+ if (!driver->real_time_mode) {
+ process_lock_on_copy(&data->nrt_lock);
+ clear_read_wakelock++;
+ }
data->in_busy_2 = 0;
}
}
@@ -1308,6 +1341,11 @@
goto exit;
}
exit:
+ if (clear_read_wakelock) {
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
+ process_lock_on_copy_complete(
+ &driver->smd_data[i].nrt_lock);
+ }
mutex_unlock(&driver->diagchar_mutex);
return ret;
}
@@ -1405,9 +1443,19 @@
#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
/* send masks to All 9k */
- if ((remote_proc >= MDM) && (remote_proc <= MDM4)) {
+ if ((remote_proc >= MDM) && (remote_proc <= MDM4) &&
+ (payload_size > 0)) {
index = remote_proc - MDM;
- if (diag_hsic[index].hsic_ch && (payload_size > 0)) {
+ /*
+ * If hsic data is being requested for this remote
+ * processor and its hsic in not open
+ */
+ if (!diag_hsic[index].hsic_device_opened) {
+ diag_hsic[index].hsic_data_requested = 1;
+ connect_bridge(0, index);
+ }
+
+ if (diag_hsic[index].hsic_ch) {
/* wait sending mask updates
* if HSIC ch not ready */
if (diag_hsic[index].in_busy_hsic_write)
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 79a73f3..bb74370 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -227,6 +227,93 @@
}
}
+void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (real_time)
+ lock->enabled = 0;
+ else
+ lock->enabled = 1;
+ lock->ref_count = 0;
+ lock->copy_count = 0;
+ wake_unlock(&lock->read_lock);
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_notify(struct diag_nrt_wake_lock *lock)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ /*
+ * Do not work with ref_count here in case
+ * of spurious interrupt
+ */
+ if (lock->enabled)
+ wake_lock(&lock->read_lock);
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (lock->enabled) {
+ if (pkt_len > 0) {
+ /*
+ * We have an data that is read that
+ * needs to be processed, make sure the
+ * processor does not go to sleep
+ */
+ lock->ref_count++;
+ if (!wake_lock_active(&lock->read_lock))
+ wake_lock(&lock->read_lock);
+ } else {
+ /*
+ * There was no data associated with the
+ * read from the smd, unlock the wake lock
+ * if it is not needed.
+ */
+ if (lock->ref_count < 1) {
+ if (wake_lock_active(&lock->read_lock))
+ wake_unlock(&lock->read_lock);
+ lock->ref_count = 0;
+ lock->copy_count = 0;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_copy(struct diag_nrt_wake_lock *lock)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (lock->enabled)
+ lock->copy_count++;
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
+void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock)
+{
+ unsigned long read_lock_flags;
+
+ spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
+ if (lock->enabled) {
+ lock->ref_count -= lock->copy_count;
+ if (lock->ref_count < 1) {
+ wake_unlock(&lock->read_lock);
+ lock->ref_count = 0;
+ }
+ lock->copy_count = 0;
+ }
+ spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+}
+
/* Process the data read from the smd data channel */
int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd)
@@ -324,6 +411,8 @@
smd_read(smd_info->ch, temp_buf, r);
temp_buf += r;
}
+ if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
+ process_lock_on_read(&smd_info->nrt_lock, pkt_len);
if (total_recd > 0) {
if (!buf) {
@@ -1321,6 +1410,9 @@
diag_dci_notify_client(smd_info->peripheral_mask,
DIAG_STATUS_OPEN);
}
+ } else if (event == SMD_EVENT_DATA && !driver->real_time_mode &&
+ smd_info->type == SMD_DATA_TYPE) {
+ process_lock_on_notify(&smd_info->nrt_lock);
}
wake_up(&driver->smd_wait_q);
@@ -1413,6 +1505,9 @@
void diag_smd_destructor(struct diag_smd_info *smd_info)
{
+ if (smd_info->type == SMD_DATA_TYPE)
+ wake_lock_destroy(&smd_info->nrt_lock.read_lock);
+
if (smd_info->ch)
smd_close(smd_info->ch);
@@ -1524,6 +1619,30 @@
goto err;
}
+ smd_info->nrt_lock.enabled = 0;
+ smd_info->nrt_lock.ref_count = 0;
+ smd_info->nrt_lock.copy_count = 0;
+ if (type == SMD_DATA_TYPE) {
+ spin_lock_init(&smd_info->nrt_lock.read_spinlock);
+
+ switch (peripheral) {
+ case MODEM_DATA:
+ wake_lock_init(&smd_info->nrt_lock.read_lock,
+ WAKE_LOCK_SUSPEND, "diag_nrt_modem_read");
+ break;
+ case LPASS_DATA:
+ wake_lock_init(&smd_info->nrt_lock.read_lock,
+ WAKE_LOCK_SUSPEND, "diag_nrt_lpass_read");
+ break;
+ case WCNSS_DATA:
+ wake_lock_init(&smd_info->nrt_lock.read_lock,
+ WAKE_LOCK_SUSPEND, "diag_nrt_wcnss_read");
+ break;
+ default:
+ break;
+ }
+ }
+
return 1;
err:
kfree(smd_info->buf_in_1);
@@ -1544,6 +1663,7 @@
diag_debug_buf_idx = 0;
driver->read_len_legacy = 0;
driver->use_device_tree = has_device_tree();
+ driver->real_time_mode = 1;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index afbe4be..8cf15de 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -23,6 +23,11 @@
void diagfwd_exit(void);
void diag_process_hdlc(void *data, unsigned len);
void diag_smd_send_req(struct diag_smd_info *smd_info);
+void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time);
+void process_lock_on_notify(struct diag_nrt_wake_lock *lock);
+void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len);
+void process_lock_on_copy(struct diag_nrt_wake_lock *lock);
+void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock);
void diag_usb_legacy_notifier(void *, unsigned, struct diag_request *);
long diagchar_ioctl(struct file *, unsigned int, unsigned long);
int diag_device_write(void *, int, struct diag_request *);
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index b934805..475f5ba 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -65,7 +65,9 @@
driver->in_busy_smux = 0;
diagfwd_connect_smux();
} else {
- if (diag_hsic[index].hsic_device_enabled) {
+ if (diag_hsic[index].hsic_device_enabled &&
+ (driver->logging_mode != MEMORY_DEVICE_MODE ||
+ diag_hsic[index].hsic_data_requested)) {
diag_hsic[index].in_busy_hsic_read_on_device = 0;
diag_hsic[index].in_busy_hsic_write = 0;
/* If the HSIC (diag_bridge) platform
@@ -126,20 +128,24 @@
usb_diag_free_req(diag_bridge[i].ch);
}
- if (i == SMUX && driver->diag_smux_enabled &&
+ if (i == SMUX) {
+ if (driver->diag_smux_enabled &&
driver->logging_mode == USB_MODE) {
- driver->in_busy_smux = 1;
- driver->lcid = LCID_INVALID;
- driver->smux_connected = 0;
- /* Turn off communication over usb and smux */
- msm_smux_close(LCID_VALID);
+ driver->in_busy_smux = 1;
+ driver->lcid = LCID_INVALID;
+ driver->smux_connected = 0;
+ /*
+ * Turn off communication over usb
+ * and smux
+ */
+ msm_smux_close(LCID_VALID);
+ }
} else {
if (diag_hsic[i].hsic_device_enabled &&
- driver->logging_mode !=
- MEMORY_DEVICE_MODE) {
+ (driver->logging_mode != MEMORY_DEVICE_MODE
+ || !diag_hsic[i].hsic_data_requested)) {
diag_hsic[i].
- in_busy_hsic_read_on_device
- = 1;
+ in_busy_hsic_read_on_device = 1;
diag_hsic[i].in_busy_hsic_write = 1;
/* Turn off communication over usb
* and HSIC */
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 7e58249..4ddd78a 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
#include <linux/diagchar.h>
#include <linux/platform_device.h>
#include <linux/kmemleak.h>
+#include <linux/delay.h>
#include "diagchar.h"
#include "diagfwd.h"
#include "diagfwd_cntl.h"
@@ -131,6 +132,83 @@
return flag;
}
+void diag_send_diag_mode_update(int real_time)
+{
+ int i;
+
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ diag_send_diag_mode_update_by_smd(&driver->smd_cntl[i],
+ real_time);
+}
+
+void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info,
+ int real_time)
+{
+ struct diag_ctrl_msg_diagmode diagmode;
+ char buf[sizeof(struct diag_ctrl_msg_diagmode)];
+ int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
+ int wr_size = -ENOMEM, retry_count = 0, timer;
+
+ /* For now only allow the modem to receive the message */
+ if (!smd_info || smd_info->type != SMD_CNTL_TYPE ||
+ (smd_info->peripheral != MODEM_DATA))
+ return;
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
+ diagmode.ctrl_pkt_data_len = 36;
+ diagmode.version = 1;
+ diagmode.sleep_vote = real_time ? 1 : 0;
+ /*
+ * 0 - Disables real-time logging (to prevent
+ * frequent APPS wake-ups, etc.).
+ * 1 - Enable real-time logging
+ */
+ diagmode.real_time = real_time;
+ diagmode.use_nrt_values = 0;
+ diagmode.commit_threshold = 0;
+ diagmode.sleep_threshold = 0;
+ diagmode.sleep_time = 0;
+ diagmode.drain_timer_val = 0;
+ diagmode.event_stale_timer_val = 0;
+
+ memcpy(buf, &diagmode, msg_size);
+
+ if (smd_info->ch) {
+ while (retry_count < 3) {
+ wr_size = smd_write(smd_info->ch, buf, msg_size);
+ if (wr_size == -ENOMEM) {
+ /*
+ * The smd channel is full. Delay while
+ * smd processes existing data and smd
+ * has memory become available. The delay
+ * of 2000 was determined empirically as
+ * best value to use.
+ */
+ retry_count++;
+ for (timer = 0; timer < 5; timer++)
+ udelay(2000);
+ } else {
+ struct diag_smd_info *data =
+ &driver->smd_data[smd_info->peripheral];
+ driver->real_time_mode = real_time;
+ process_lock_enabling(&data->nrt_lock,
+ real_time);
+ break;
+ }
+ }
+ if (wr_size != msg_size)
+ pr_err("diag: proc %d fail feature update %d, tried %d",
+ smd_info->peripheral,
+ wr_size, msg_size);
+ } else {
+ pr_err("diag: ch invalid, feature update on proc %d\n",
+ smd_info->peripheral);
+ }
+
+ mutex_unlock(&driver->diag_cntl_mutex);
+}
+
static int diag_smd_cntl_probe(struct platform_device *pdev)
{
int r = 0;
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index c28b06d..7cd1866 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -84,11 +84,28 @@
/* Copy feature mask here */
} __packed;
+struct diag_ctrl_msg_diagmode {
+ uint32_t ctrl_pkt_id;
+ uint32_t ctrl_pkt_data_len;
+ uint32_t version;
+ uint32_t sleep_vote;
+ uint32_t real_time;
+ uint32_t use_nrt_values;
+ uint32_t commit_threshold;
+ uint32_t sleep_threshold;
+ uint32_t sleep_time;
+ uint32_t drain_timer_val;
+ uint32_t event_stale_timer_val;
+} __packed;
+
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
void diag_clean_reg_fn(struct work_struct *work);
int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd);
+void diag_send_diag_mode_update(int real_time);
+void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info,
+ int real_time);
#endif
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index 616c498..fa46aab 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -227,8 +227,12 @@
if (diag_hsic[index].in_busy_hsic_write)
return -EBUSY;
- /* Don't allow suspend if in MEMORY_DEVICE_MODE */
- if (driver->logging_mode == MEMORY_DEVICE_MODE)
+ /*
+ * Don't allow suspend if in MEMORY_DEVICE_MODE and if there
+ * has been hsic data requested
+ */
+ if (driver->logging_mode == MEMORY_DEVICE_MODE &&
+ diag_hsic[index].hsic_ch)
return -EBUSY;
diag_hsic[index].hsic_suspend = 1;
@@ -288,7 +292,7 @@
}
/* diagfwd_cancel_hsic is called to cancel outstanding read/writes */
-int diagfwd_cancel_hsic(void)
+int diagfwd_cancel_hsic(int reopen)
{
int err, i;
@@ -302,17 +306,24 @@
diag_hsic[i].hsic_ch = 0;
diag_hsic[i].hsic_device_opened = 0;
diag_bridge_close(i);
- hsic_diag_bridge_ops[i].ctxt = (void *)(i);
- err = diag_bridge_open(i,
- &hsic_diag_bridge_ops[i]);
- if (err) {
- pr_err("diag: HSIC %d channel open error: %d\n",
- i, err);
+ if (reopen) {
+ hsic_diag_bridge_ops[i].ctxt =
+ (void *)(i);
+ err = diag_bridge_open(i,
+ &hsic_diag_bridge_ops[i]);
+ if (err) {
+ pr_err("diag: HSIC %d channel open error: %d\n",
+ i, err);
+ } else {
+ pr_debug("diag: opened HSIC channel: %d\n",
+ i);
+ diag_hsic[i].
+ hsic_device_opened = 1;
+ diag_hsic[i].hsic_ch = 1;
+ }
+ diag_hsic[i].hsic_data_requested = 1;
} else {
- pr_debug("diag: opened HSIC channel: %d\n",
- i);
- diag_hsic[i].hsic_device_opened = 1;
- diag_hsic[i].hsic_ch = 1;
+ diag_hsic[i].hsic_data_requested = 0;
}
}
}
@@ -428,15 +439,20 @@
diagmem_hsic_init(pdev->id);
INIT_WORK(&(diag_hsic[pdev->id].diag_read_hsic_work),
diag_read_hsic_work_fn);
+ diag_hsic[pdev->id].hsic_data_requested =
+ (driver->logging_mode == MEMORY_DEVICE_MODE) ? 0 : 1;
diag_hsic[pdev->id].hsic_inited = 1;
}
/*
* The probe function was called after the usb was connected
- * on the legacy channel OR ODL is turned on. Communication over usb
- * mdm and HSIC needs to be turned on.
+ * on the legacy channel OR ODL is turned on and hsic data is
+ * requested. Communication over usb mdm and HSIC needs to be
+ * turned on.
*/
- if (diag_bridge[pdev->id].usb_connected || (driver->logging_mode ==
- MEMORY_DEVICE_MODE)) {
+ if ((diag_bridge[pdev->id].usb_connected &&
+ (driver->logging_mode != MEMORY_DEVICE_MODE)) ||
+ ((driver->logging_mode == MEMORY_DEVICE_MODE) &&
+ diag_hsic[pdev->id].hsic_data_requested)) {
if (diag_hsic[pdev->id].hsic_device_opened) {
/* should not happen. close it before re-opening */
pr_warn("diag: HSIC channel already opened in probe\n");
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index d171efa..64556f2 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -19,8 +19,10 @@
#define N_MDM_READ 1
#define NUM_HSIC_BUF_TBL_ENTRIES N_MDM_WRITE
#define MAX_HSIC_CH 4
+#define REOPEN_HSIC 1
+#define DONT_REOPEN_HSIC 0
int diagfwd_write_complete_hsic(struct diag_request *, int index);
-int diagfwd_cancel_hsic(void);
+int diagfwd_cancel_hsic(int reopen);
void diag_read_usb_hsic_work_fn(struct work_struct *work);
void diag_usb_read_complete_hsic_fn(struct work_struct *w);
extern struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH];
@@ -37,6 +39,7 @@
int hsic_device_enabled;
int hsic_device_opened;
int hsic_suspend;
+ int hsic_data_requested;
int in_busy_hsic_read_on_device;
int in_busy_hsic_write;
struct work_struct diag_read_hsic_work;
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 4774c76..988d1c9 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -158,7 +158,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
index e077edf..6a8d412 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -402,7 +402,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cti-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
index d52ab28..31f85dc 100644
--- a/drivers/coresight/coresight-etb.c
+++ b/drivers/coresight/coresight-etb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -375,7 +375,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "etb-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 1033233..2777769 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -2090,7 +2090,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "etm-base");
if (!res)
return -ENODEV;
reg_size = resource_size(res);
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index 7f39a3e..625f481 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -187,7 +187,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "funnel-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
index fe37e5e..d4afa42 100644
--- a/drivers/coresight/coresight-replicator.c
+++ b/drivers/coresight/coresight-replicator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -139,7 +139,8 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "replicator-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 1db499b..87cf63a 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -806,7 +806,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "stm-base");
if (!res)
return -ENODEV;
@@ -814,7 +814,8 @@
if (!drvdata->base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "stm-data-base");
if (!res)
return -ENODEV;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 86276b7..4a9a97a 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1090,7 +1090,7 @@
return -ENOMEM;
drvdata->bamdata = bamdata;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bam-base");
if (!res)
return -ENODEV;
@@ -1147,7 +1147,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tmc-base");
if (!res)
return -ENODEV;
reg_size = resource_size(res);
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 73800dd..7ea71d3 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -710,7 +710,7 @@
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tpiu-base");
if (!res)
return -ENODEV;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1134f90..8545a5c 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -2728,6 +2728,7 @@
rc = clk_set_rate(pce_dev->ce_core_src_clk, 100000000);
if (rc) {
clk_put(pce_dev->ce_core_src_clk);
+ pce_dev->ce_core_src_clk = NULL;
pr_err("Unable to set the core src clk @100Mhz.\n");
goto err_clk;
}
@@ -2735,7 +2736,6 @@
pr_warn("Unable to get CE core src clk, set to NULL\n");
pce_dev->ce_core_src_clk = NULL;
}
- pce_dev->ce_core_src_clk = ce_core_src_clk;
/* Get CE core clk */
ce_core_clk = clk_get(pce_dev->pdev, "core_clk");
@@ -2805,34 +2805,29 @@
int rc = 0;
/* Enable CE core clk */
- rc = clk_prepare_enable(pce_dev->ce_core_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE core clk\n");
- return rc;
+ if (pce_dev->ce_core_clk != NULL) {
+ rc = clk_prepare_enable(pce_dev->ce_core_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE core clk\n");
+ return rc;
+ }
}
/* Enable CE clk */
- rc = clk_prepare_enable(pce_dev->ce_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- clk_disable_unprepare(pce_dev->ce_core_clk);
- return rc;
+ if (pce_dev->ce_clk != NULL) {
+ rc = clk_prepare_enable(pce_dev->ce_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ clk_disable_unprepare(pce_dev->ce_core_clk);
+ return rc;
+ }
}
/* Enable AXI clk */
- rc = clk_prepare_enable(pce_dev->ce_bus_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE BUS clk\n");
- clk_disable_unprepare(pce_dev->ce_clk);
- clk_disable_unprepare(pce_dev->ce_core_clk);
- return rc;
- }
- /* Enable CORE SRC (INTERFACE) clk */
- if (pce_dev->ce_core_src_clk != NULL) {
- rc = clk_prepare_enable(pce_dev->ce_core_src_clk);
+ if (pce_dev->ce_bus_clk != NULL) {
+ rc = clk_prepare_enable(pce_dev->ce_bus_clk);
if (rc) {
pr_err("Unable to enable/prepare CE BUS clk\n");
clk_disable_unprepare(pce_dev->ce_clk);
clk_disable_unprepare(pce_dev->ce_core_clk);
- clk_disable_unprepare(pce_dev->ce_bus_clk);
return rc;
}
}
@@ -2846,8 +2841,6 @@
if (pce_dev->ce_clk != NULL)
clk_disable_unprepare(pce_dev->ce_clk);
- if (pce_dev->ce_core_src_clk != NULL)
- clk_disable_unprepare(pce_dev->ce_core_src_clk);
if (pce_dev->ce_core_clk != NULL)
clk_disable_unprepare(pce_dev->ce_core_clk);
if (pce_dev->ce_bus_clk != NULL)
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 9128177..85e2ec9 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -39,7 +39,6 @@
#include <mach/iommu_domains.h>
#include "ion_priv.h"
-#define DEBUG
/**
* struct ion_device - the metadata of the ion device node
@@ -107,6 +106,12 @@
unsigned int iommu_map_cnt;
};
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
+{
+ return ((buffer->flags & ION_FLAG_CACHED) &&
+ !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
+}
+
static void ion_iommu_release(struct kref *kref);
/* this function should only be called while dev->lock is held */
@@ -190,6 +195,8 @@
return NULL;
}
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
+
/* this function should only be called while dev->lock is held */
static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
struct ion_device *dev,
@@ -199,13 +206,15 @@
{
struct ion_buffer *buffer;
struct sg_table *table;
- int ret;
+ struct scatterlist *sg;
+ int i, ret;
buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
buffer->heap = heap;
+ buffer->flags = flags;
kref_init(&buffer->ref);
ret = heap->ops->allocate(heap, buffer, len, align, flags);
@@ -216,19 +225,52 @@
buffer->dev = dev;
buffer->size = len;
- buffer->flags = flags;
- table = buffer->heap->ops->map_dma(buffer->heap, buffer);
+ table = heap->ops->map_dma(heap, buffer);
if (IS_ERR_OR_NULL(table)) {
heap->ops->free(buffer);
kfree(buffer);
return ERR_PTR(PTR_ERR(table));
}
buffer->sg_table = table;
+ if (ion_buffer_fault_user_mappings(buffer)) {
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents,
+ i) {
+ if (sg_dma_len(sg) == PAGE_SIZE)
+ continue;
+ pr_err("%s: cached mappings that will be faulted in "
+ "must have pagewise sg_lists\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = ion_buffer_alloc_dirty(buffer);
+ if (ret)
+ goto err;
+ }
+
+ buffer->dev = dev;
+ buffer->size = len;
+ INIT_LIST_HEAD(&buffer->vmas);
mutex_init(&buffer->lock);
+ /* this will set up dma addresses for the sglist -- it is not
+ technically correct as per the dma api -- a specific
+ device isn't really taking ownership here. However, in practice on
+ our systems the only dma_address space is physical addresses.
+ Additionally, we can't afford the overhead of invalidating every
+ allocation via dma_map_sg. The implicit contract here is that
+ memory comming from the heaps is ready for dma, ie if it has a
+ cached mapping that mapping has been invalidated */
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
+ sg_dma_address(sg) = sg_phys(sg);
ion_buffer_add(dev, buffer);
return buffer;
+
+err:
+ heap->ops->unmap_dma(heap, buffer);
+ heap->ops->free(buffer);
+ kfree(buffer);
+ return ERR_PTR(ret);
}
/**
@@ -276,7 +318,6 @@
if (WARN_ON(buffer->kmap_cnt > 0))
buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
-
buffer->heap->ops->unmap_dma(buffer->heap, buffer);
ion_delayed_unsecure(buffer);
@@ -285,6 +326,8 @@
mutex_lock(&dev->lock);
rb_erase(&buffer->node, &dev->buffers);
mutex_unlock(&dev->lock);
+ if (buffer->flags & ION_FLAG_CACHED)
+ kfree(buffer->dirty);
kfree(buffer);
}
@@ -419,6 +462,16 @@
dbg_str[0] = '\0';
/*
+ * For now, we don't want to fault in pages individually since
+ * clients are already doing manual cache maintenance. In
+ * other words, the implicit caching infrastructure is in
+ * place (in code) but should not be used.
+ */
+ flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
+ pr_debug("%s: len %d align %d heap_mask %u flags %x\n", __func__, len,
+ align, heap_mask, flags);
+ /*
* traverse the list of heaps available in this system in priority
* order. If the heap type is supported by the client, and matches the
* request of the caller allocate from it. Repeat until allocate has
@@ -1205,12 +1258,46 @@
}
EXPORT_SYMBOL(ion_sg_table);
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+ size_t chunk_size, size_t total_size)
+{
+ struct sg_table *table;
+ int i, n_chunks, ret;
+ struct scatterlist *sg;
+
+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+
+ n_chunks = DIV_ROUND_UP(total_size, chunk_size);
+ pr_debug("creating sg_table with %d chunks\n", n_chunks);
+
+ ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
+ if (ret)
+ goto err0;
+
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ dma_addr_t addr = buffer_base + i * chunk_size;
+ sg_dma_address(sg) = addr;
+ }
+
+ return table;
+err0:
+ kfree(table);
+ return ERR_PTR(ret);
+}
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+ struct device *dev,
+ enum dma_data_direction direction);
+
static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
enum dma_data_direction direction)
{
struct dma_buf *dmabuf = attachment->dmabuf;
struct ion_buffer *buffer = dmabuf->priv;
+ ion_buffer_sync_for_device(buffer, attachment->dev, direction);
return buffer->sg_table;
}
@@ -1220,24 +1307,119 @@
{
}
-static void ion_vma_close(struct vm_area_struct *vma)
+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer)
+{
+ unsigned long pages = buffer->sg_table->nents;
+ unsigned long length = (pages + BITS_PER_LONG - 1)/BITS_PER_LONG;
+
+ buffer->dirty = kzalloc(length * sizeof(unsigned long), GFP_KERNEL);
+ if (!buffer->dirty)
+ return -ENOMEM;
+ return 0;
+}
+
+struct ion_vma_list {
+ struct list_head list;
+ struct vm_area_struct *vma;
+};
+
+static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
+ struct device *dev,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+ struct ion_vma_list *vma_list;
+
+ pr_debug("%s: syncing for device %s\n", __func__,
+ dev ? dev_name(dev) : "null");
+
+ if (!ion_buffer_fault_user_mappings(buffer))
+ return;
+
+ mutex_lock(&buffer->lock);
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+ if (!test_bit(i, buffer->dirty))
+ continue;
+ dma_sync_sg_for_device(dev, sg, 1, dir);
+ clear_bit(i, buffer->dirty);
+ }
+ list_for_each_entry(vma_list, &buffer->vmas, list) {
+ struct vm_area_struct *vma = vma_list->vma;
+
+ zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start,
+ NULL);
+ }
+ mutex_unlock(&buffer->lock);
+}
+
+int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct ion_buffer *buffer = vma->vm_private_data;
+ struct scatterlist *sg;
+ int i;
- pr_debug("%s: %d\n", __func__, __LINE__);
+ mutex_lock(&buffer->lock);
+ set_bit(vmf->pgoff, buffer->dirty);
+
+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
+ if (i != vmf->pgoff)
+ continue;
+ dma_sync_sg_for_cpu(NULL, sg, 1, DMA_BIDIRECTIONAL);
+ vm_insert_page(vma, (unsigned long)vmf->virtual_address,
+ sg_page(sg));
+ break;
+ }
+ mutex_unlock(&buffer->lock);
+ return VM_FAULT_NOPAGE;
+}
+
+static void ion_vm_open(struct vm_area_struct *vma)
+{
+ struct ion_buffer *buffer = vma->vm_private_data;
+ struct ion_vma_list *vma_list;
+
+ vma_list = kmalloc(sizeof(struct ion_vma_list), GFP_KERNEL);
+ if (!vma_list)
+ return;
+ vma_list->vma = vma;
+ mutex_lock(&buffer->lock);
+ list_add(&vma_list->list, &buffer->vmas);
+ mutex_unlock(&buffer->lock);
+ pr_debug("%s: adding %p\n", __func__, vma);
+}
+
+static void ion_vm_close(struct vm_area_struct *vma)
+{
+ struct ion_buffer *buffer = vma->vm_private_data;
+ struct ion_vma_list *vma_list, *tmp;
+
+ pr_debug("%s\n", __func__);
+ mutex_lock(&buffer->lock);
+ list_for_each_entry_safe(vma_list, tmp, &buffer->vmas, list) {
+ if (vma_list->vma != vma)
+ continue;
+ list_del(&vma_list->list);
+ kfree(vma_list);
+ pr_debug("%s: deleting %p\n", __func__, vma);
+ break;
+ }
+ mutex_unlock(&buffer->lock);
if (buffer->heap->ops->unmap_user)
buffer->heap->ops->unmap_user(buffer->heap, buffer);
}
-static struct vm_operations_struct ion_vm_ops = {
- .close = ion_vma_close,
+struct vm_operations_struct ion_vma_ops = {
+ .open = ion_vm_open,
+ .close = ion_vm_close,
+ .fault = ion_vm_fault,
};
static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
struct ion_buffer *buffer = dmabuf->priv;
- int ret;
+ int ret = 0;
if (!buffer->heap->ops->map_user) {
pr_err("%s: this heap does not define a method for mapping "
@@ -1245,22 +1427,26 @@
return -EINVAL;
}
+ if (ion_buffer_fault_user_mappings(buffer)) {
+ vma->vm_private_data = buffer;
+ vma->vm_ops = &ion_vma_ops;
+ vma->vm_flags |= VM_MIXEDMAP;
+ ion_vm_open(vma);
+ return 0;
+ }
+
+ if (!(buffer->flags & ION_FLAG_CACHED))
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
mutex_lock(&buffer->lock);
/* now map it to userspace */
ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma);
mutex_unlock(&buffer->lock);
- if (ret) {
+ if (ret)
pr_err("%s: failure mapping buffer to userspace\n",
__func__);
- } else {
- vma->vm_ops = &ion_vm_ops;
- /*
- * move the buffer into the vm_private_data so we can access it
- * from vma_open/close
- */
- vma->vm_private_data = buffer;
- }
+
return ret;
}
@@ -1396,6 +1582,30 @@
}
EXPORT_SYMBOL(ion_import_dma_buf);
+static int ion_sync_for_device(struct ion_client *client, int fd)
+{
+ struct dma_buf *dmabuf;
+ struct ion_buffer *buffer;
+
+ dmabuf = dma_buf_get(fd);
+ if (IS_ERR_OR_NULL(dmabuf))
+ return PTR_ERR(dmabuf);
+
+ /* if this memory came from ion */
+ if (dmabuf->ops != &dma_buf_ops) {
+ pr_err("%s: can not sync dmabuf from another exporter\n",
+ __func__);
+ dma_buf_put(dmabuf);
+ return -EINVAL;
+ }
+ buffer = dmabuf->priv;
+
+ dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
+ buffer->sg_table->nents, DMA_BIDIRECTIONAL);
+ dma_buf_put(dmabuf);
+ return 0;
+}
+
static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct ion_client *client = filp->private_data;
@@ -1468,6 +1678,15 @@
return ret;
break;
}
+ case ION_IOC_SYNC:
+ {
+ struct ion_fd_data data;
+ if (copy_from_user(&data, (void __user *)arg,
+ sizeof(struct ion_fd_data)))
+ return -EFAULT;
+ ion_sync_for_device(client, data.fd);
+ break;
+ }
case ION_IOC_CUSTOM:
{
struct ion_device *dev = client->dev;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 798c027..9610dfe 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -112,26 +112,13 @@
struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- struct sg_table *table;
- int ret;
+ size_t chunk_size = buffer->size;
- table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (!table)
- return ERR_PTR(-ENOMEM);
+ if (ION_IS_CACHED(buffer->flags))
+ chunk_size = PAGE_SIZE;
- ret = sg_alloc_table(table, 1, GFP_KERNEL);
- if (ret)
- goto err0;
-
- table->sgl->length = buffer->size;
- table->sgl->offset = 0;
- table->sgl->dma_address = buffer->priv_phys;
-
- return table;
-
-err0:
- kfree(table);
- return ERR_PTR(ret);
+ return ion_create_chunked_sg_table(buffer->priv_phys, chunk_size,
+ buffer->size);
}
void ion_carveout_heap_unmap_dma(struct ion_heap *heap,
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 3000252..2ef285b 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -457,6 +457,12 @@
struct ion_cp_buffer *buf;
phys_addr_t addr;
+ /*
+ * we never want Ion to fault pages in for us with this
+ * heap. We want to set up the mappings ourselves in .map_user
+ */
+ flags |= ION_FLAG_CACHED_NEEDS_SYNC;
+
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
return ION_CP_ALLOCATE_FAIL;
@@ -491,9 +497,6 @@
struct sg_table *ion_cp_heap_create_sg_table(struct ion_buffer *buffer)
{
size_t chunk_size = buffer->size;
- struct sg_table *table;
- int ret, i, n_chunks;
- struct scatterlist *sg;
struct ion_cp_buffer *buf = buffer->priv_virt;
if (ION_IS_CACHED(buffer->flags))
@@ -501,26 +504,8 @@
else if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M))
chunk_size = SZ_1M;
- table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (!table)
- return ERR_PTR(-ENOMEM);
-
- n_chunks = DIV_ROUND_UP(buffer->size, chunk_size);
-
- ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
- if (ret)
- goto err0;
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- sg_dma_address(sg) = buf->buffer + i * chunk_size;
- sg->length = chunk_size;
- sg->offset = 0;
- }
-
- return table;
-err0:
- kfree(table);
- return ERR_PTR(ret);
+ return ion_create_chunked_sg_table(buf->buffer, chunk_size,
+ buffer->size);
}
struct sg_table *ion_cp_heap_map_dma(struct ion_heap *heap,
@@ -614,6 +599,11 @@
int i;
pgprot_t pgprot;
+ if (!pages) {
+ mutex_unlock(&cp_heap->lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
if (ION_IS_CACHED(buffer->flags))
pgprot = PAGE_KERNEL;
else
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index ba48b50..9ab6b85 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -330,6 +330,14 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
+ /* Use the biggest alignment to allow bigger IOMMU mappings.
+ * Use the first entry since the first entry will always be the
+ * biggest entry. To take advantage of bigger mapping sizes both the
+ * VA and PA addresses have to be aligned to the biggest size.
+ */
+ if (buffer->sg_table->sgl->length > align)
+ align = buffer->sg_table->sgl->length;
+
ret = msm_allocate_iova_address(domain_num, partition_num,
data->mapped_size, align,
&data->iova_addr);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 2ab2ed6..28ef1a5 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -98,6 +98,8 @@
void *vaddr;
int dmap_cnt;
struct sg_table *sg_table;
+ unsigned long *dirty;
+ struct list_head vmas;
unsigned int iommu_map_cnt;
struct rb_root iommu_maps;
int marked;
@@ -179,6 +181,15 @@
};
/**
+ * ion_buffer_fault_user_mappings - fault in user mappings of this buffer
+ * @buffer: buffer
+ *
+ * indicates whether userspace mappings of this buffer will be faulted
+ * in, this can affect how buffers are allocated from the heap.
+ */
+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer);
+
+/**
* struct mem_map_data - represents information about the memory map for a heap
* @node: rb node used to store in the tree of mem_map_data
* @addr: start address of memory region.
@@ -330,4 +341,16 @@
int ion_heap_allow_heap_secure(enum ion_heap_type type);
int ion_heap_allow_handle_secure(enum ion_heap_type type);
+
+/**
+ * ion_create_chunked_sg_table - helper function to create sg table
+ * with specified chunk size
+ * @buffer_base: The starting address used for the sg dma address
+ * @chunk_size: The size of each entry in the sg table
+ * @total_size: The total size of the sg table (i.e. the sum of the
+ * entries). This will be rounded up to the nearest
+ * multiple of `chunk_size'
+ */
+struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base,
+ size_t chunk_size, size_t total_size);
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 7ca2cd2..ceb30a4 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -15,7 +15,10 @@
*
*/
+#include <asm/page.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
+#include <linux/highmem.h>
#include <linux/ion.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
@@ -35,6 +38,37 @@
static unsigned int system_heap_has_outer_cache;
static unsigned int system_heap_contig_has_outer_cache;
+struct page_info {
+ struct page *page;
+ unsigned long order;
+ struct list_head list;
+};
+
+static struct page_info *alloc_largest_available(unsigned long size,
+ bool split_pages)
+{
+ static unsigned int orders[] = {8, 4, 0};
+ struct page *page;
+ struct page_info *info;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(orders); i++) {
+ if (size < (1 << orders[i]) * PAGE_SIZE)
+ continue;
+ page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO |
+ __GFP_NOWARN | __GFP_NORETRY, orders[i]);
+ if (!page)
+ continue;
+ if (split_pages)
+ split_page(page, orders[i]);
+ info = kmap(page);
+ info->page = page;
+ info->order = orders[i];
+ return info;
+ }
+ return NULL;
+}
+
static int ion_system_heap_allocate(struct ion_heap *heap,
struct ion_buffer *buffer,
unsigned long size, unsigned long align,
@@ -42,31 +76,73 @@
{
struct sg_table *table;
struct scatterlist *sg;
- int i, j;
- int npages = PAGE_ALIGN(size) / PAGE_SIZE;
+ int ret;
+ struct list_head pages;
+ struct page_info *info, *tmp_info;
+ int i = 0;
+ long size_remaining = PAGE_ALIGN(size);
+ bool split_pages = ion_buffer_fault_user_mappings(buffer);
+
+
+ INIT_LIST_HEAD(&pages);
+ while (size_remaining > 0) {
+ info = alloc_largest_available(size_remaining, split_pages);
+ if (!info)
+ goto err;
+ list_add_tail(&info->list, &pages);
+ size_remaining -= (1 << info->order) * PAGE_SIZE;
+ i++;
+ }
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
- return -ENOMEM;
- i = sg_alloc_table(table, npages, GFP_KERNEL);
- if (i)
- goto err0;
- for_each_sg(table->sgl, sg, table->nents, i) {
- struct page *page;
- page = alloc_page(GFP_KERNEL|__GFP_ZERO);
- if (!page)
- goto err1;
- sg_set_page(sg, page, PAGE_SIZE, 0);
+ goto err;
+
+ if (split_pages)
+ ret = sg_alloc_table(table, PAGE_ALIGN(size) / PAGE_SIZE,
+ GFP_KERNEL);
+ else
+ ret = sg_alloc_table(table, i, GFP_KERNEL);
+
+ if (ret)
+ goto err1;
+
+ sg = table->sgl;
+ list_for_each_entry_safe(info, tmp_info, &pages, list) {
+ struct page *page = info->page;
+
+ if (split_pages) {
+ for (i = 0; i < (1 << info->order); i++) {
+ sg_set_page(sg, page + i, PAGE_SIZE, 0);
+ sg = sg_next(sg);
+ }
+ } else {
+ sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE,
+ 0);
+ sg = sg_next(sg);
+ }
+ list_del(&info->list);
+ kunmap(page);
}
+
+ dma_sync_sg_for_device(NULL, table->sgl, table->nents,
+ DMA_BIDIRECTIONAL);
+
buffer->priv_virt = table;
atomic_add(size, &system_heap_allocated);
return 0;
err1:
- for_each_sg(table->sgl, sg, i, j)
- __free_page(sg_page(sg));
- sg_free_table(table);
-err0:
kfree(table);
+err:
+ list_for_each_entry(info, &pages, list) {
+ if (split_pages)
+ for (i = 0; i < (1 << info->order); i++)
+ __free_page(info->page + i);
+ else
+ __free_pages(info->page, info->order);
+
+ kunmap(info->page);
+ }
return -ENOMEM;
}
@@ -77,7 +153,7 @@
struct sg_table *table = buffer->priv_virt;
for_each_sg(table->sgl, sg, table->nents, i)
- __free_page(sg_page(sg));
+ __free_pages(sg_page(sg), get_order(sg_dma_len(sg)));
if (buffer->sg_table)
sg_free_table(buffer->sg_table);
kfree(buffer->sg_table);
@@ -99,25 +175,33 @@
void *ion_system_heap_map_kernel(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- if (!ION_IS_CACHED(buffer->flags)) {
- pr_err("%s: cannot map system heap uncached\n", __func__);
- return ERR_PTR(-EINVAL);
- } else {
- struct scatterlist *sg;
- int i;
- void *vaddr;
- struct sg_table *table = buffer->priv_virt;
- struct page **pages = kmalloc(
- sizeof(struct page *) * table->nents,
- GFP_KERNEL);
+ struct scatterlist *sg;
+ int i, j;
+ void *vaddr;
+ pgprot_t pgprot;
+ struct sg_table *table = buffer->priv_virt;
+ int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+ struct page **pages = kzalloc(sizeof(struct page *) * npages,
+ GFP_KERNEL);
+ struct page **tmp = pages;
- for_each_sg(table->sgl, sg, table->nents, i)
- pages[i] = sg_page(sg);
- vaddr = vmap(pages, table->nents, VM_MAP, PAGE_KERNEL);
- kfree(pages);
+ if (buffer->flags & ION_FLAG_CACHED)
+ pgprot = PAGE_KERNEL;
+ else
+ pgprot = pgprot_writecombine(PAGE_KERNEL);
- return vaddr;
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE;
+ struct page *page = sg_page(sg);
+ BUG_ON(i >= npages);
+ for (j = 0; j < npages_this_entry; j++) {
+ *(tmp++) = page++;
+ }
}
+ vaddr = vmap(pages, npages, VM_MAP, pgprot);
+ kfree(pages);
+
+ return vaddr;
}
void ion_system_heap_unmap_kernel(struct ion_heap *heap,
@@ -155,26 +239,27 @@
int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
struct vm_area_struct *vma)
{
+ struct sg_table *table = buffer->priv_virt;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff;
+ struct scatterlist *sg;
+ int i;
+
if (!ION_IS_CACHED(buffer->flags)) {
pr_err("%s: cannot map system heap uncached\n", __func__);
return -EINVAL;
- } else {
- struct sg_table *table = buffer->priv_virt;
- unsigned long addr = vma->vm_start;
- unsigned long offset = vma->vm_pgoff;
- struct scatterlist *sg;
- int i;
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- if (offset) {
- offset--;
- continue;
- }
- vm_insert_page(vma, addr, sg_page(sg));
- addr += PAGE_SIZE;
- }
- return 0;
}
+
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ if (offset) {
+ offset--;
+ continue;
+ }
+ remap_pfn_range(vma, addr, page_to_pfn(sg_page(sg)),
+ sg_dma_len(sg), vma->vm_page_prot);
+ addr += sg_dma_len(sg);
+ }
+ return 0;
}
int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
@@ -271,6 +356,14 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
+ /* Use the biggest alignment to allow bigger IOMMU mappings.
+ * Use the first entry since the first entry will always be the
+ * biggest entry. To take advantage of bigger mapping sizes both the
+ * VA and PA addresses have to be aligned to the biggest size.
+ */
+ if (table->sgl->length > align)
+ align = table->sgl->length;
+
ret = msm_allocate_iova_address(domain_num, partition_num,
data->mapped_size, align,
&data->iova_addr);
@@ -374,7 +467,7 @@
}
struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap,
- struct ion_buffer *buffer)
+ struct ion_buffer *buffer)
{
struct sg_table *table;
int ret;
@@ -392,6 +485,13 @@
return table;
}
+void ion_system_contig_heap_unmap_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ sg_free_table(buffer->sg_table);
+ kfree(buffer->sg_table);
+}
+
int ion_system_contig_heap_map_user(struct ion_heap *heap,
struct ion_buffer *buffer,
struct vm_area_struct *vma)
@@ -553,7 +653,7 @@
.free = ion_system_contig_heap_free,
.phys = ion_system_contig_heap_phys,
.map_dma = ion_system_contig_heap_map_dma,
- .unmap_dma = ion_system_heap_unmap_dma,
+ .unmap_dma = ion_system_contig_heap_unmap_dma,
.map_kernel = ion_system_contig_heap_map_kernel,
.unmap_kernel = ion_system_contig_heap_unmap_kernel,
.map_user = ion_system_contig_heap_map_user,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 9f4d791..b9f00b5 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -310,8 +310,14 @@
struct kgsl_context *context;
struct adreno_context *adreno_ctx = NULL;
- if (!adreno_dev->drawctxt_active)
+ /*
+ * If we're idle and we don't need to use the GPU to save context
+ * state, use the CPU instead of the GPU to reprogram the
+ * iommu for simplicity's sake.
+ */
+ if (!adreno_dev->drawctxt_active || device->ftbl->isidle(device))
return kgsl_mmu_device_setstate(&device->mmu, flags);
+
num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
context = idr_find(&device->context_idr, context_id);
@@ -1225,10 +1231,10 @@
return 0;
}
-static int adreno_start(struct kgsl_device *device, unsigned int init_ram)
+static int adreno_init(struct kgsl_device *device)
{
- int status = -EINVAL;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
if (KGSL_STATE_DUMP_AND_FT != device->state)
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
@@ -1254,10 +1260,9 @@
if (adreno_dev->gpurev == ADRENO_REV_UNKNOWN) {
KGSL_DRV_ERR(device, "Unknown chip ID %x\n",
adreno_dev->chip_id);
- goto error_clk_off;
+ BUG_ON(1);
}
-
/*
* Check if firmware supports the sync lock PM4 packets needed
* for IOMMUv1
@@ -1269,19 +1274,7 @@
adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pfp_ver))
device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC;
- /* Set up the MMU */
- if (adreno_is_a2xx(adreno_dev)) {
- /*
- * the MH_CLNT_INTF_CTRL_CONFIG registers aren't present
- * on older gpus
- */
- if (adreno_is_a20x(adreno_dev)) {
- device->mh.mh_intf_cfg1 = 0;
- device->mh.mh_intf_cfg2 = 0;
- }
-
- kgsl_mh_start(device);
- }
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
/* Assign correct RBBM status register to hang detect regs
*/
@@ -1297,6 +1290,37 @@
ft_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
}
+ /* Power down the device */
+ kgsl_pwrctrl_disable(device);
+
+ return 0;
+}
+
+static int adreno_start(struct kgsl_device *device)
+{
+ int status = -EINVAL;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ if (KGSL_STATE_DUMP_AND_FT != device->state)
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+
+ /* Power up the device */
+ kgsl_pwrctrl_enable(device);
+
+ /* Set up a2xx special case */
+ if (adreno_is_a2xx(adreno_dev)) {
+ /*
+ * the MH_CLNT_INTF_CTRL_CONFIG registers aren't present
+ * on older gpus
+ */
+ if (adreno_is_a20x(adreno_dev)) {
+ device->mh.mh_intf_cfg1 = 0;
+ device->mh.mh_intf_cfg2 = 0;
+ }
+
+ kgsl_mh_start(device);
+ }
+
status = kgsl_mmu_start(device);
if (status)
goto error_clk_off;
@@ -1313,7 +1337,7 @@
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
device->ftbl->irqctrl(device, 1);
- status = adreno_ringbuffer_start(&adreno_dev->ringbuffer, init_ram);
+ status = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
if (status)
goto error_irq_off;
@@ -1712,7 +1736,12 @@
return 1;
}
- if (adreno_start(device, true)) {
+ if (adreno_init(device)) {
+ KGSL_FT_ERR(device, "Device init failed\n");
+ return 1;
+ }
+
+ if (adreno_start(device)) {
KGSL_FT_ERR(device, "Device start failed\n");
return 1;
}
@@ -3270,6 +3299,7 @@
.idle = adreno_idle,
.isidle = adreno_isidle,
.suspend_context = adreno_suspend_context,
+ .init = adreno_init,
.start = adreno_start,
.stop = adreno_stop,
.getproperty = adreno_getproperty,
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 29d689b..5396196 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -702,7 +702,7 @@
" %08X\n", r1, r2, r3);
KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ",
- kgsl_mmu_get_ptsize());
+ kgsl_mmu_get_ptsize(&device->mmu));
kgsl_regread(device, MH_MMU_TRAN_ERROR, &r1);
KGSL_LOG_DUMP(device, " TRAN_ERROR = %08X\n", r1);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 4333f2f..b746671 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -319,7 +319,7 @@
return 0;
}
-int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
+int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
{
int status;
/*cp_rb_cntl_u cp_rb_cntl; */
@@ -331,9 +331,6 @@
if (rb->flags & KGSL_FLAGS_STARTED)
return 0;
- if (init_ram)
- rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
-
kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
sizeof(struct kgsl_rbmemptrs));
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index fa03c05..e563ec7 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -97,8 +97,7 @@
int adreno_ringbuffer_init(struct kgsl_device *device);
-int adreno_ringbuffer_start(struct adreno_ringbuffer *rb,
- unsigned int init_ram);
+int adreno_ringbuffer_start(struct adreno_ringbuffer *rb);
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2b0d5d9..af25a3f 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -671,9 +671,10 @@
if (kgsl_mmu_enabled())
{
unsigned long pt_name;
+ struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
pt_name = task_tgid_nr(current);
- private->pagetable = kgsl_mmu_getpagetable(pt_name);
+ private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
if (private->pagetable == NULL) {
kfree(private);
private = NULL;
@@ -821,12 +822,14 @@
kgsl_sharedmem_set(&device->memstore, 0, 0,
device->memstore.size);
- result = device->ftbl->start(device, true);
-
- if (result) {
- mutex_unlock(&device->mutex);
+ result = device->ftbl->init(device);
+ if (result)
goto err_freedevpriv;
- }
+
+ result = device->ftbl->start(device);
+ if (result)
+ goto err_freedevpriv;
+
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
}
device->open_count++;
@@ -856,8 +859,8 @@
result = device->ftbl->stop(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
}
- mutex_unlock(&device->mutex);
err_freedevpriv:
+ mutex_unlock(&device->mutex);
filep->private_data = NULL;
kfree(dev_priv);
err_pmruntime:
@@ -872,7 +875,7 @@
{
struct rb_node *node = private->mem_rb.rb_node;
- if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
+ if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
return NULL;
while (node != NULL) {
@@ -925,7 +928,7 @@
struct rb_node *node = private->mem_rb.rb_node;
- if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
+ if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
return 0;
/* don't overflow */
@@ -1193,7 +1196,9 @@
}
for (i = 0; i < param->numibs; i++) {
- if (!kgsl_mmu_gpuaddr_in_range(ibdesc[i].gpuaddr)) {
+ struct kgsl_pagetable *pt = dev_priv->process_priv->pagetable;
+
+ if (!kgsl_mmu_gpuaddr_in_range(pt, ibdesc[i].gpuaddr)) {
result = -ERANGE;
KGSL_DRV_ERR(dev_priv->device,
"invalid ib base GPU virtual addr %x\n",
@@ -1767,13 +1772,6 @@
return -ENOMEM;
}
-static inline int
-can_use_cpu_map(void)
-{
- return (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
- && kgsl_mmu_is_perprocess());
-}
-
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -1805,7 +1803,7 @@
| KGSL_MEMFLAGS_USE_CPU_MAP;
entry->memdesc.flags = param->flags;
- if (!can_use_cpu_map())
+ if (!kgsl_mmu_use_cpu_map(private->pagetable->mmu))
entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
switch (memtype) {
@@ -2092,7 +2090,7 @@
struct kgsl_mem_entry *entry = NULL;
int result;
- if (!can_use_cpu_map())
+ if (!kgsl_mmu_use_cpu_map(private->pagetable->mmu))
param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index aca5660..37b5730 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -73,7 +73,8 @@
int (*idle) (struct kgsl_device *device);
unsigned int (*isidle) (struct kgsl_device *device);
int (*suspend_context) (struct kgsl_device *device);
- int (*start) (struct kgsl_device *device, unsigned int init_ram);
+ int (*init) (struct kgsl_device *device);
+ int (*start) (struct kgsl_device *device);
int (*stop) (struct kgsl_device *device);
int (*getproperty) (struct kgsl_device *device,
enum kgsl_property_type type, void *value,
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index cb206ac..5cc0dff 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -19,6 +19,7 @@
#include "kgsl.h"
#include "kgsl_mmu.h"
+#include "kgsl_gpummu.h"
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
#include "kgsl_trace.h"
@@ -364,10 +365,9 @@
return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
}
-void kgsl_gpummu_destroy_pagetable(void *mmu_specific_pt)
+void kgsl_gpummu_destroy_pagetable(struct kgsl_pagetable *pt)
{
- struct kgsl_gpummu_pt *gpummu_pt = (struct kgsl_gpummu_pt *)
- mmu_specific_pt;
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
kgsl_ptpool_free((struct kgsl_ptpool *)kgsl_driver.ptpool,
gpummu_pt->base.hostptr);
@@ -528,6 +528,11 @@
*/
int status = 0;
+ mmu->pt_base = KGSL_PAGETABLE_BASE;
+ mmu->pt_size = CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
+ mmu->pt_per_process = KGSL_MMU_USE_PER_PROCESS_PT;
+ mmu->use_cpu_map = false;
+
/* sub-client MMU lookups require address translation */
if ((mmu->config & ~0x1) > 0) {
/*make sure virtual address range is a multiple of 64Kb */
@@ -584,7 +589,7 @@
if (mmu->defaultpagetable == NULL)
mmu->defaultpagetable =
- kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+ kgsl_mmu_getpagetable(mmu, KGSL_MMU_GLOBAL_PT);
/* Return error if the default pagetable doesn't exist */
if (mmu->defaultpagetable == NULL)
@@ -604,14 +609,14 @@
}
static int
-kgsl_gpummu_unmap(void *mmu_specific_pt,
+kgsl_gpummu_unmap(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int *tlb_flags)
{
unsigned int numpages;
unsigned int pte, ptefirst, ptelast, superpte;
unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
- struct kgsl_gpummu_pt *gpummu_pt = mmu_specific_pt;
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
functions purturb the gpuaddr with an offset, so apply the
@@ -653,13 +658,13 @@
GSL_TLBFLUSH_FILTER_ISDIRTY((_p) / GSL_PT_SUPER_PTE))
static int
-kgsl_gpummu_map(void *mmu_specific_pt,
+kgsl_gpummu_map(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int protflags,
unsigned int *tlb_flags)
{
unsigned int pte;
- struct kgsl_gpummu_pt *gpummu_pt = mmu_specific_pt;
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
struct scatterlist *s;
int flushtlb = 0;
int i;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 0bd22d3..f327c04 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -604,9 +604,9 @@
*
* Return - void
*/
-static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
+static void kgsl_iommu_destroy_pagetable(struct kgsl_pagetable *pt)
{
- struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
if (iommu_pt->domain)
iommu_domain_free(iommu_pt->domain);
kfree(iommu_pt);
@@ -829,7 +829,7 @@
if (KGSL_DEVICE_3D0 != mmu->device->id ||
!msm_soc_version_supports_iommu_v0() ||
- !kgsl_mmu_is_perprocess() ||
+ !kgsl_mmu_is_perprocess(mmu) ||
iommu->sync_lock_vars)
return 0;
@@ -870,7 +870,7 @@
uint32_t page_offset = 0;
if (!msm_soc_version_supports_iommu_v0() ||
- !kgsl_mmu_is_perprocess())
+ !kgsl_mmu_is_perprocess(mmu))
return status;
/*
@@ -1268,6 +1268,32 @@
if (status)
goto done;
+ /* We presently do not support per-process for IOMMU-v1 */
+ mmu->pt_per_process = KGSL_MMU_USE_PER_PROCESS_PT &&
+ msm_soc_version_supports_iommu_v0();
+
+ /*
+ * For IOMMU per-process pagetables, the allocatable range
+ * and the kernel global range must both be outside
+ * the userspace address range. There is a 1Mb gap
+ * between these address ranges to make overrun
+ * detection easier.
+ * For the shared pagetable case use 2GB and because
+ * mirroring the CPU address space is not possible and
+ * we're better off with extra room.
+ */
+ if (mmu->pt_per_process) {
+ mmu->pt_base = PAGE_OFFSET;
+ mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE
+ - kgsl_mmu_get_base_addr(mmu) - SZ_1M;
+ mmu->use_cpu_map = true;
+ } else {
+ mmu->pt_base = KGSL_PAGETABLE_BASE;
+ mmu->pt_size = SZ_2G;
+ mmu->use_cpu_map = false;
+ }
+
+
iommu->iommu_reg_list = kgsl_iommuv0_reg;
iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V0;
@@ -1321,7 +1347,8 @@
* switching on the 3D side for which a separate table is allocated */
if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v0()) {
mmu->priv_bank_table =
- kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
+ kgsl_mmu_getpagetable(mmu,
+ KGSL_MMU_PRIV_BANK_TABLE_NAME);
if (mmu->priv_bank_table == NULL) {
status = -ENOMEM;
goto err;
@@ -1330,7 +1357,7 @@
if (status)
goto err;
}
- mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+ mmu->defaultpagetable = kgsl_mmu_getpagetable(mmu, KGSL_MMU_GLOBAL_PT);
/* Return error if the default pagetable doesn't exist */
if (mmu->defaultpagetable == NULL) {
status = -ENOMEM;
@@ -1534,13 +1561,13 @@
}
static int
-kgsl_iommu_unmap(void *mmu_specific_pt,
+kgsl_iommu_unmap(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int *tlb_flags)
{
int ret;
unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
- struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
functions purturb the gpuaddr with an offset, so apply the
@@ -1561,20 +1588,20 @@
* Flushing only required if per process pagetables are used. With
* global case, flushing will happen inside iommu_map function
*/
- if (!ret && kgsl_mmu_is_perprocess())
+ if (!ret && kgsl_mmu_is_perprocess(pt->mmu))
*tlb_flags = UINT_MAX;
return 0;
}
static int
-kgsl_iommu_map(void *mmu_specific_pt,
+kgsl_iommu_map(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int protflags,
unsigned int *tlb_flags)
{
int ret;
unsigned int iommu_virt_addr;
- struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
BUG_ON(NULL == iommu_pt);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index ccaceb3..4e95373 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -23,6 +23,7 @@
#include "kgsl.h"
#include "kgsl_mmu.h"
+#include "kgsl_gpummu.h"
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
#include "adreno.h"
@@ -103,7 +104,7 @@
if (pagetable->pool)
gen_pool_destroy(pagetable->pool);
- pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv);
+ pagetable->pt_ops->mmu_destroy_pagetable(pagetable);
kfree(pagetable);
}
@@ -193,7 +194,7 @@
if (pt) {
ret += snprintf(buf, PAGE_SIZE, "0x%x\n",
- kgsl_mmu_get_ptsize());
+ kgsl_mmu_get_ptsize(pt->mmu));
}
kgsl_put_pagetable(pt);
@@ -444,7 +445,8 @@
}
EXPORT_SYMBOL(kgsl_mh_intrcallback);
-static struct kgsl_pagetable *kgsl_mmu_createpagetableobject(
+static struct kgsl_pagetable *
+kgsl_mmu_createpagetableobject(struct kgsl_mmu *mmu,
unsigned int name)
{
int status = 0;
@@ -463,8 +465,8 @@
spin_lock_init(&pagetable->lock);
- ptsize = kgsl_mmu_get_ptsize();
-
+ ptsize = kgsl_mmu_get_ptsize(mmu);
+ pagetable->mmu = mmu;
pagetable->name = name;
pagetable->max_entries = KGSL_PAGETABLE_ENTRIES(ptsize);
pagetable->fault_addr = 0xFFFFFFFF;
@@ -497,7 +499,7 @@
goto err_kgsl_pool;
}
- if (gen_pool_add(pagetable->pool, kgsl_mmu_get_base_addr(),
+ if (gen_pool_add(pagetable->pool, kgsl_mmu_get_base_addr(mmu),
ptsize, -1)) {
KGSL_CORE_ERR("gen_pool_add failed\n");
goto err_pool;
@@ -526,7 +528,7 @@
return pagetable;
err_mmu_create:
- pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv);
+ pagetable->pt_ops->mmu_destroy_pagetable(pagetable);
err_pool:
gen_pool_destroy(pagetable->pool);
err_kgsl_pool:
@@ -538,20 +540,21 @@
return NULL;
}
-struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name)
+struct kgsl_pagetable *kgsl_mmu_getpagetable(struct kgsl_mmu *mmu,
+ unsigned long name)
{
struct kgsl_pagetable *pt;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return (void *)(-1);
- if (!kgsl_mmu_is_perprocess())
+ if (!kgsl_mmu_is_perprocess(mmu))
name = KGSL_MMU_GLOBAL_PT;
pt = kgsl_get_pagetable(name);
if (pt == NULL)
- pt = kgsl_mmu_createpagetableobject(name);
+ pt = kgsl_mmu_createpagetableobject(mmu, name);
return pt;
}
@@ -688,7 +691,7 @@
if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
- ret = pagetable->pt_ops->mmu_map(pagetable->priv, memdesc, protflags,
+ ret = pagetable->pt_ops->mmu_map(pagetable, memdesc, protflags,
&pagetable->tlb_flags);
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
@@ -741,7 +744,7 @@
if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
- pagetable->pt_ops->mmu_unmap(pagetable->priv, memdesc,
+ pagetable->pt_ops->mmu_unmap(pagetable, memdesc,
&pagetable->tlb_flags);
/* If buffer is unmapped 0 fault addr */
@@ -894,15 +897,16 @@
}
EXPORT_SYMBOL(kgsl_mmu_set_mmutype);
-int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+int kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pt, unsigned int gpuaddr)
{
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return 1;
- if (gpuaddr >= kgsl_mmu_get_base_addr() &&
- gpuaddr < kgsl_mmu_get_base_addr() + kgsl_mmu_get_ptsize())
+ if (gpuaddr >= kgsl_mmu_get_base_addr(pt->mmu) &&
+ gpuaddr < kgsl_mmu_get_base_addr(pt->mmu) +
+ kgsl_mmu_get_ptsize(pt->mmu))
return 1;
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
- && kgsl_mmu_is_perprocess())
+ && kgsl_mmu_is_perprocess(pt->mmu))
return (gpuaddr > 0 && gpuaddr < TASK_SIZE);
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 2d48e86..d7d9516 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -24,6 +24,13 @@
#define KGSL_MMU_ALIGN_MASK (~((1 << PAGE_SHIFT) - 1))
+/* defconfig option for disabling per process pagetables */
+#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
+#define KGSL_MMU_USE_PER_PROCESS_PT true
+#else
+#define KGSL_MMU_USE_PER_PROCESS_PT false
+#endif
+
/* Identifier for the global page table */
/* Per process page tables will probably pass in the thread group
as an identifier */
@@ -116,6 +123,7 @@
unsigned int tlb_flags;
unsigned int fault_addr;
void *priv;
+ struct kgsl_mmu *mmu;
};
struct kgsl_mmu;
@@ -160,15 +168,15 @@
};
struct kgsl_mmu_pt_ops {
- int (*mmu_map) (void *mmu_pt,
+ int (*mmu_map) (struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int protflags,
unsigned int *tlb_flags);
- int (*mmu_unmap) (void *mmu_pt,
+ int (*mmu_unmap) (struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc,
unsigned int *tlb_flags);
void *(*mmu_create_pagetable) (void);
- void (*mmu_destroy_pagetable) (void *pt);
+ void (*mmu_destroy_pagetable) (struct kgsl_pagetable *);
};
#define KGSL_MMU_FLAGS_IOMMU_SYNC BIT(31)
@@ -187,14 +195,19 @@
const struct kgsl_mmu_ops *mmu_ops;
void *priv;
int fault;
+ unsigned long pt_base;
+ unsigned long pt_size;
+ bool pt_per_process;
+ bool use_cpu_map;
};
-#include "kgsl_gpummu.h"
-
extern struct kgsl_mmu_ops iommu_ops;
extern struct kgsl_mmu_pt_ops iommu_pt_ops;
+extern struct kgsl_mmu_ops gpummu_ops;
+extern struct kgsl_mmu_pt_ops gpummu_pt_ops;
-struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name);
+struct kgsl_pagetable *kgsl_mmu_getpagetable(struct kgsl_mmu *,
+ unsigned long name);
void kgsl_mmu_putpagetable(struct kgsl_pagetable *pagetable);
void kgsl_mh_start(struct kgsl_device *device);
void kgsl_mh_intrcallback(struct kgsl_device *device);
@@ -221,7 +234,7 @@
int kgsl_mmu_enabled(void);
void kgsl_mmu_set_mmutype(char *mmutype);
enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
-int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr);
+int kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pt, unsigned int gpuaddr);
/*
* Static inline functions of MMU that simply call the SMMU specific
@@ -335,75 +348,51 @@
/*
* kgsl_mmu_is_perprocess() - Runtime check for per-process
* pagetables.
+ * @mmu: the mmu
*
- * Returns non-zero if per-process pagetables are enabled,
- * 0 if not.
+ * Returns true if per-process pagetables are enabled,
+ * false if not.
*/
-#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
-static inline int kgsl_mmu_is_perprocess(void)
+static inline int kgsl_mmu_is_perprocess(struct kgsl_mmu *mmu)
{
+ return mmu->pt_per_process;
+}
- /* We presently do not support per-process for IOMMU-v1 */
- return (kgsl_mmu_get_mmutype() != KGSL_MMU_TYPE_IOMMU)
- || msm_soc_version_supports_iommu_v0();
-}
-#else
-static inline int kgsl_mmu_is_perprocess(void)
+/*
+ * kgsl_mmu_use_cpu_map() - Runtime check for matching the CPU
+ * address space on the GPU.
+ * @mmu: the mmu
+ *
+ * Returns true if supported false if not.
+ */
+static inline int kgsl_mmu_use_cpu_map(struct kgsl_mmu *mmu)
{
- return 0;
+ return mmu->pt_per_process;
}
-#endif
/*
* kgsl_mmu_base_addr() - Get gpu virtual address base.
+ * @mmu: the mmu
*
* Returns the start address of the allocatable gpu
* virtual address space. Other mappings that mirror
* the CPU address space are possible outside this range.
*/
-static inline unsigned int kgsl_mmu_get_base_addr(void)
+static inline unsigned int kgsl_mmu_get_base_addr(struct kgsl_mmu *mmu)
{
- if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()
- || !kgsl_mmu_is_perprocess())
- return KGSL_PAGETABLE_BASE;
- /*
- * This is the start of the kernel address
- * space, so allocations from this range will
- * never conflict with userpace addresses
- */
- return PAGE_OFFSET;
+ return mmu->pt_base;
}
/*
* kgsl_mmu_get_ptsize() - Get gpu pagetable size
+ * @mmu: the mmu
*
* Returns the usable size of the gpu allocatable
* address space.
*/
-static inline unsigned int kgsl_mmu_get_ptsize(void)
+static inline unsigned int kgsl_mmu_get_ptsize(struct kgsl_mmu *mmu)
{
- /*
- * For IOMMU per-process pagetables, the allocatable range
- * and the kernel global range must both be outside
- * the userspace address range. There is a 1Mb gap
- * between these address ranges to make overrun
- * detection easier.
- * For the shared pagetable case use 2GB and because
- * mirroring the CPU address space is not possible and
- * we're better off with extra room.
- */
- enum kgsl_mmutype mmu_type = kgsl_mmu_get_mmutype();
-
- if (KGSL_MMU_TYPE_GPU == mmu_type)
- return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
- else if (KGSL_MMU_TYPE_IOMMU == mmu_type) {
- if (kgsl_mmu_is_perprocess())
- return KGSL_IOMMU_GLOBAL_MEM_BASE
- - kgsl_mmu_get_base_addr() - SZ_1M;
- else
- return SZ_2G;
- }
- return 0;
+ return mmu->pt_size;
}
static inline int kgsl_mmu_sync_lock(struct kgsl_mmu *mmu,
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index c716731..2f8d93e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1289,7 +1289,7 @@
kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
switch (device->state) {
case KGSL_STATE_SLUMBER:
- status = device->ftbl->start(device, 0);
+ status = device->ftbl->start(device);
if (status) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
KGSL_DRV_ERR(device, "start failed %d\n", status);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index f0410d6..b78c6fe 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -93,7 +93,8 @@
#define Z180_CMDWINDOW_TARGET_SHIFT 0
#define Z180_CMDWINDOW_ADDR_SHIFT 8
-static int z180_start(struct kgsl_device *device, unsigned int init_ram);
+static int z180_init(struct kgsl_device *device);
+static int z180_start(struct kgsl_device *device);
static int z180_stop(struct kgsl_device *device);
static int z180_wait(struct kgsl_device *device,
struct kgsl_context *context,
@@ -319,16 +320,11 @@
*p++ = ADDR_VGV3_LAST << 24;
}
-static void z180_cmdstream_start(struct kgsl_device *device, int init_ram)
+static void z180_cmdstream_start(struct kgsl_device *device)
{
struct z180_device *z180_dev = Z180_DEVICE(device);
unsigned int cmd = VGV3_NEXTCMD_JUMP << VGV3_NEXTCMD_NEXTCMD_FSHIFT;
- if (init_ram) {
- z180_dev->timestamp = 0;
- z180_dev->current_timestamp = 0;
- }
-
addmarker(&z180_dev->ringbuffer, 0);
z180_cmdwindow_write(device, ADDR_VGV3_MODE, 4);
@@ -552,7 +548,17 @@
return 0;
}
-static int z180_start(struct kgsl_device *device, unsigned int init_ram)
+static int z180_init(struct kgsl_device *device)
+{
+ struct z180_device *z180_dev = Z180_DEVICE(device);
+
+ z180_dev->timestamp = 0;
+ z180_dev->current_timestamp = 0;
+
+ return 0;
+}
+
+static int z180_start(struct kgsl_device *device)
{
int status = 0;
@@ -569,7 +575,7 @@
if (status)
goto error_clk_off;
- z180_cmdstream_start(device, init_ram);
+ z180_cmdstream_start(device);
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
@@ -919,6 +925,7 @@
.idle = z180_idle,
.isidle = z180_isidle,
.suspend_context = z180_suspend_context,
+ .init = z180_init,
.start = z180_start,
.stop = z180_stop,
.getproperty = z180_getproperty,
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 2fdf791..60c2da3 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -212,7 +212,7 @@
bool descending = 1;
uint32_t i = 0;
- if ((pts == NULL) || (output == NULL))
+ if (pts == NULL)
return -EINVAL;
/* Check if table is descending or ascending */
@@ -258,7 +258,7 @@
bool descending = 1;
uint32_t i = 0;
- if ((pts == NULL) || (output == NULL))
+ if (pts == NULL)
return -EINVAL;
/* Check if table is descending or ascending */
@@ -372,7 +372,7 @@
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph btm_param;
- int64_t *low_output = 0, *high_output = 0;
+ int64_t low_output = 0, high_output = 0;
int rc = 0;
rc = qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_ABSOLUTE);
@@ -382,21 +382,21 @@
}
/* Convert to Kelvin and account for voltage to be written as 2mV/K */
- *low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
+ low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
/* Convert to voltage threshold */
- *low_output *= btm_param.dy;
- do_div(*low_output, btm_param.adc_vref);
- *low_output += btm_param.adc_gnd;
+ low_output *= btm_param.dy;
+ do_div(low_output, btm_param.adc_vref);
+ low_output += btm_param.adc_gnd;
/* Convert to Kelvin and account for voltage to be written as 2mV/K */
- *high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
+ high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
/* Convert to voltage threshold */
- *high_output *= btm_param.dy;
- do_div(*high_output, btm_param.adc_vref);
- *high_output += btm_param.adc_gnd;
+ high_output *= btm_param.dy;
+ do_div(high_output, btm_param.adc_vref);
+ high_output += btm_param.adc_gnd;
- low_threshold = (uint32_t *) low_output;
- high_threshold = (uint32_t *) high_output;
+ *low_threshold = low_output;
+ *high_threshold = high_output;
return 0;
}
@@ -612,7 +612,6 @@
}
EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
-/* Converts millivolts to ADC high/low threshold code */
int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
@@ -655,45 +654,54 @@
}
EXPORT_SYMBOL_GPL(qpnp_adc_vbatt_rscaler);
-/* Converts decidegreesC to voltage based on the mapping table */
int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph btm_param;
- int64_t *low_output = 0, *high_output = 0;
+ int64_t low_output = 0, high_output = 0;
int rc = 0;
qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
- rc = qpnp_adc_map_temp_voltage(
+ pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
+ param->low_temp);
+ rc = qpnp_adc_map_voltage_temp(
adcmap_btm_threshold,
ARRAY_SIZE(adcmap_btm_threshold),
(param->low_temp),
- low_output);
- if (rc)
+ &low_output);
+ if (rc) {
+ pr_debug("low_temp mapping failed with %d\n", rc);
return rc;
+ }
- *low_output *= btm_param.dy;
- do_div(*low_output, btm_param.adc_vref);
- *low_output += btm_param.adc_gnd;
+ pr_debug("low_output:%lld\n", low_output);
+ low_output *= btm_param.dy;
+ do_div(low_output, btm_param.adc_vref);
+ low_output += btm_param.adc_gnd;
- rc = qpnp_adc_map_temp_voltage(
+ rc = qpnp_adc_map_voltage_temp(
adcmap_btm_threshold,
ARRAY_SIZE(adcmap_btm_threshold),
(param->high_temp),
- high_output);
- if (rc)
+ &high_output);
+ if (rc) {
+ pr_debug("high temp mapping failed with %d\n", rc);
return rc;
+ }
- pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
- param->low_temp);
- *high_output *= btm_param.dy;
- do_div(*high_output, btm_param.adc_vref);
- *high_output += btm_param.adc_gnd;
+ pr_debug("high_output:%lld\n", high_output);
+ high_output *= btm_param.dy;
+ do_div(high_output, btm_param.adc_vref);
+ high_output += btm_param.adc_gnd;
- low_threshold = (uint32_t *) low_output;
- high_threshold = (uint32_t *) high_output;
+ /* btm low temperature correspondes to high voltage threshold */
+ *low_threshold = high_output;
+ /* btm high temperature correspondes to low voltage threshold */
+ *high_threshold = low_output;
+ pr_debug("high_volt:%d, low_volt:%d\n", *high_threshold,
+ *low_threshold);
return 0;
}
EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 2017c8d..60dcada 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -404,6 +404,8 @@
iadc->adc->calib.gain_uv = (num * QPNP_ADC_GAIN_NV)/
(iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+ pr_debug("gain_uv:%d offset_uv:%d\n",
+ iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
return 0;
}
@@ -439,6 +441,9 @@
goto fail;
}
+ pr_debug("raw gain:0x%x, raw offset:0x%x\n",
+ iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
+
rc = qpnp_convert_raw_offset_voltage();
if (rc < 0) {
pr_err("qpnp raw_voltage conversion failed\n");
@@ -449,6 +454,8 @@
QPNP_BIT_SHIFT_8;
rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
+ pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
+
rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
QPNP_IADC_SEC_ACCESS_DATA);
if (rc < 0) {
@@ -545,6 +552,8 @@
return rc;
}
+ pr_debug("rsense:0%x\n", rslt_rsense);
+
if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
sign_bit = 1;
@@ -610,6 +619,8 @@
}
rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
+ pr_debug("current raw:0%x and rsense:%d\n",
+ raw_data, rsense_n_ohms);
num = raw_data - iadc->adc->calib.offset_raw;
if (num < 0) {
@@ -658,6 +669,10 @@
result->ideal_offset_uv =
QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
result->offset_uv = iadc->adc->calib.offset_uv;
+ pr_debug("raw gain:0%x, raw offset:0%x\n",
+ result->gain_raw, result->offset_raw);
+ pr_debug("gain_uv:%d offset_uv:%d\n",
+ result->gain_uv, result->offset_uv);
mutex_unlock(&iadc->adc->adc_lock);
return 0;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index edbde44..0470a62 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -491,6 +491,9 @@
goto calib_fail;
}
+ pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
+ calib_read_1, calib_read_2);
+
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
(calib_read_1 - calib_read_2);
@@ -555,6 +558,8 @@
goto calib_fail;
}
+ pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
+ calib_read_1, calib_read_2);
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
(calib_read_1 - calib_read_2);
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index 1472293..b62bb76 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -371,6 +371,55 @@
return pa;
}
+static int check_range(unsigned long *fl_table, unsigned int va,
+ unsigned int len)
+{
+ unsigned int offset = 0;
+ unsigned long *fl_pte;
+ unsigned long fl_offset;
+ unsigned long *sl_table;
+ unsigned long sl_start, sl_end;
+ int i;
+
+ fl_offset = FL_OFFSET(va); /* Upper 12 bits */
+ fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
+
+ while (offset < len) {
+ if (*fl_pte & FL_TYPE_TABLE) {
+ sl_start = SL_OFFSET(va);
+ sl_table = __va(((*fl_pte) & FL_BASE_MASK));
+ sl_end = ((len - offset) / SZ_4K) + sl_start;
+
+ if (sl_end > NUM_SL_PTE)
+ sl_end = NUM_SL_PTE;
+
+ for (i = sl_start; i < sl_end; i++) {
+ if (sl_table[i] != 0) {
+ pr_err("%08x - %08x already mapped\n",
+ va, va + SZ_4K);
+ return -EBUSY;
+ }
+ offset += SZ_4K;
+ va += SZ_4K;
+ }
+
+
+ sl_start = 0;
+ } else {
+ if (*fl_pte != 0) {
+ pr_err("%08x - %08x already mapped\n",
+ va, va + SZ_1M);
+ return -EBUSY;
+ }
+ va += SZ_1M;
+ offset += SZ_1M;
+ sl_start = 0;
+ }
+ fl_pte++;
+ }
+ return 0;
+}
+
static inline int is_fully_aligned(unsigned int va, phys_addr_t pa, size_t len,
int align)
{
@@ -406,6 +455,10 @@
fl_pte = pt->fl_table + fl_offset; /* int pointers, 4 bytes */
pa = get_phys_addr(sg);
+ ret = check_range(pt->fl_table, va, len);
+ if (ret)
+ goto fail;
+
while (offset < len) {
chunk_size = SZ_4K;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index a780526..f1bfd68 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -98,6 +98,8 @@
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
stream_info->num_planes = 2;
break;
/*TD: Add more image format*/
@@ -188,6 +190,11 @@
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width / 2;
break;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ size = plane_cfg[plane_idx].output_height *
+ plane_cfg[plane_idx].output_width;
+ break;
/*TD: Add more image format*/
default:
pr_err("%s: Invalid output format\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index f337e27..ae89500 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -418,6 +418,8 @@
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
val = CAL_WORD(pixel_per_line, 1, 8);
break;
/*TD: Add more image format*/
@@ -461,6 +463,9 @@
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
return 8;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ return 16;
/*TD: Add more image format*/
default:
pr_err("%s: Invalid output format\n", __func__);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 8f8e723..2ca5008 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -241,7 +241,7 @@
static u32 get_frame_size_compressed(int plane,
u32 height, u32 width)
{
- return (MAX_SUPPORTED_WIDTH * MAX_SUPPORTED_HEIGHT * 3/2)/2;
+ return (width * height * 3/2)/2;
}
struct msm_vidc_format vdec_formats[] = {
@@ -302,6 +302,14 @@
.type = OUTPUT_PORT,
},
{
+ .name = "HEVC",
+ .description = "HEVC compressed format",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
@@ -630,8 +638,8 @@
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
fmt->get_frame_size(i,
- f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
+ inst->capability.height.max,
+ inst->capability.width.max);
inst->bufq[OUTPUT_PORT].
vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
@@ -767,8 +775,8 @@
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
fmt->get_frame_size(i,
- f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
+ inst->capability.height.max,
+ inst->capability.width.max);
}
} else {
buff_req_buffer =
@@ -827,8 +835,8 @@
frame_sz.height = inst->prop.height;
msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
f->fmt.pix_mp.plane_fmt[0].sizeimage =
- fmt->get_frame_size(0, f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
+ fmt->get_frame_size(0, inst->capability.height.max,
+ inst->capability.width.max);
f->fmt.pix_mp.num_planes = fmt->num_planes;
for (i = 0; i < fmt->num_planes; ++i) {
inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
@@ -921,7 +929,8 @@
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
for (i = 0; i < *num_planes; i++) {
sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
- i, inst->prop.height, inst->prop.width);
+ i, inst->capability.height.max,
+ inst->capability.width.max);
}
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 4346a4e..30530d4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -142,9 +142,10 @@
}
mutex_lock(&vidc_driver->lock);
list_for_each_entry(core, &vidc_driver->cores, list) {
- if (core && core->id == core_id)
+ if (core && core->id == core_id) {
found = 1;
break;
+ }
}
mutex_unlock(&vidc_driver->lock);
if (found)
@@ -366,22 +367,27 @@
}
}
+static void queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
+{
+ struct v4l2_event event = {.id = 0, .type = event_type};
+ v4l2_event_queue_fh(&inst->event_handler, &event);
+ wake_up(&inst->kernel_event_queue);
+}
+
static void handle_event_change(enum command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct v4l2_event dqevent;
struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
+ int event = 0;
int rc = 0;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- dqevent.id = 0;
event_notify = (struct msm_vidc_cb_event *) response->data;
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
control.id =
V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
@@ -389,24 +395,24 @@
dprintk(VIDC_WARN,
"Failed to get Smooth streamng flag\n");
if (!rc && control.value == true)
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
break;
default:
break;
}
+
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
+
rc = msm_vidc_check_session_supported(inst);
if (!rc) {
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst, event);
}
+
return;
} else {
dprintk(VIDC_ERR,
@@ -496,13 +502,9 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct v4l2_event dqevent;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
} else {
dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
}
@@ -512,7 +514,6 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst = NULL;
- struct v4l2_event dqevent;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
if (inst) {
@@ -521,10 +522,7 @@
mutex_lock(&inst->sync_lock);
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->sync_lock);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
} else {
dprintk(VIDC_ERR,
@@ -536,7 +534,6 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst = NULL ;
struct msm_vidc_core *core = NULL;
- struct v4l2_event dqevent;
if (response) {
core = get_vidc_core(response->device_id);
dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
@@ -544,18 +541,14 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
list_for_each_entry(inst, &core->instances,
list) {
- v4l2_event_queue_fh(&inst->event_handler,
- &dqevent);
-
mutex_lock(&inst->lock);
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->lock);
- wake_up(&inst->kernel_event_queue);
+ queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
} else {
dprintk(VIDC_ERR,
@@ -572,7 +565,6 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
struct msm_vidc_core *core = NULL;
- struct v4l2_event dqevent;
dprintk(VIDC_ERR, "Venus Subsystem crashed\n");
core = get_vidc_core(response->device_id);
if (!core) {
@@ -583,11 +575,9 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
list_for_each_entry(inst, &core->instances, list) {
if (inst) {
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
mutex_lock(&inst->lock);
inst->state = MSM_VIDC_CORE_INVALID;
inst->session = NULL;
@@ -600,15 +590,11 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct v4l2_event dqevent;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
- dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
inst->session = NULL;
- wake_up(&inst->kernel_event_queue);
show_stats(inst);
} else {
dprintk(VIDC_ERR,
@@ -1212,6 +1198,10 @@
HAL_VIDEO_CODEC_SPARK
HAL_VIDEO_CODEC_VP6
HAL_VIDEO_CODEC_VP7*/
+ case V4L2_PIX_FMT_HEVC:
+ codec = HAL_VIDEO_CODEC_HEVC;
+ break;
+
default:
dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
codec = HAL_UNUSED_CODEC;
@@ -2144,7 +2134,6 @@
static void msm_comm_flush_in_invalid_state(struct msm_vidc_inst *inst)
{
- struct v4l2_event dqevent = {0};
struct list_head *ptr, *next;
struct vb2_buffer *vb;
if (!list_empty(&inst->bufq[CAPTURE_PORT].
@@ -2181,9 +2170,7 @@
}
}
}
- dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
return;
}
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 5948c7c..3208df9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -210,8 +210,7 @@
"Output" : "Capture");
for (j = 0; j < inst->fmts[i]->num_planes; j++)
write_str(&dbg_buf, "size for plane %d: %u\n", j,
- inst->fmts[i]->get_frame_size(j,
- inst->prop.height, inst->prop.width));
+ inst->bufq[i].vb2_bufq.plane_sizes[j]);
}
write_str(&dbg_buf, "-------------------------------\n");
for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 1bfbaa6..e5696be 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -37,7 +37,7 @@
#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
#define MAX_DEBUGFS_NAME 50
#define DEFAULT_TIMEOUT 3
-#define DEFAULT_HEIGHT 1080
+#define DEFAULT_HEIGHT 1088
#define DEFAULT_WIDTH 1920
#define MIN_SUPPORTED_WIDTH 32
#define MIN_SUPPORTED_HEIGHT 32
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index afe1431..123b654 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -12,6 +12,8 @@
*/
#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
#include <mach/qdsp6v2/apr.h>
#include <mach/subsystem_restart.h>
#include "hfi_packetization.h"
@@ -19,6 +21,7 @@
#include "q6_hfi.h"
#include "vidc_hfi_api.h"
+static struct hal_device_data hal_ctxt;
static int write_queue(void *info, u8 *packet)
{
@@ -190,17 +193,86 @@
static int q6_hfi_register_iommu_domains(struct q6_hfi_device *device)
{
- (void)device;
+ struct iommu_domain *domain;
+ int rc = 0, i = 0;
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
- dprintk(VIDC_ERR, "Not implemented: %s", __func__);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return -EINVAL;
+ }
- return 0;
+ iommu_group_set = &device->res->iommu_group_set;
+
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ iommu_map->group = iommu_group_find(iommu_map->name);
+ if (!iommu_map->group) {
+ dprintk(VIDC_ERR, "Failed to find group :%s\n",
+ iommu_map->name);
+ goto fail_group;
+ }
+ domain = iommu_group_get_iommudata(iommu_map->group);
+ if (IS_ERR_OR_NULL(domain)) {
+ dprintk(VIDC_ERR,
+ "Failed to get domain data for group %p",
+ iommu_map->group);
+ goto fail_group;
+ }
+ iommu_map->domain = msm_find_domain_no(domain);
+ if (iommu_map->domain < 0) {
+ dprintk(VIDC_ERR,
+ "Failed to get domain index for domain %p",
+ domain);
+ goto fail_group;
+ }
+ }
+ return rc;
+
+fail_group:
+ for (--i; i >= 0; i--) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if (iommu_map->group)
+ iommu_group_put(iommu_map->group);
+ iommu_map->group = NULL;
+ iommu_map->domain = -1;
+ }
+ return -EINVAL;
}
-static int q6_hfi_init_resources(struct q6_hfi_device *device)
+static void q6_hfi_deregister_iommu_domains(struct q6_hfi_device *device)
+{
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
+ int i = 0;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return;
+ }
+
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if (iommu_map->group)
+ iommu_group_put(iommu_map->group);
+ iommu_map->group = NULL;
+ iommu_map->domain = -1;
+ }
+}
+
+static int q6_hfi_init_resources(struct q6_hfi_device *device,
+ struct msm_vidc_platform_resources *res)
{
int rc = 0;
+ if (!device || !res) {
+ dprintk(VIDC_ERR, "Invalid device or resources");
+ return -EINVAL;
+ }
+
+ device->res = res;
rc = q6_hfi_register_iommu_domains(device);
if (rc)
dprintk(VIDC_ERR, "Failed to register iommu domains: %d\n", rc);
@@ -208,12 +280,17 @@
return rc;
}
+static void q6_hfi_deinit_resources(struct q6_hfi_device *device)
+{
+ q6_hfi_deregister_iommu_domains(device);
+}
+
static void *q6_hfi_add_device(u32 device_id,
hfi_cmd_response_callback callback)
{
struct q6_hfi_device *hdevice = NULL;
- if (device_id || !callback) {
+ if (!callback) {
dprintk(VIDC_ERR, "Invalid Paramters");
return NULL;
}
@@ -225,19 +302,23 @@
goto err_alloc;
}
- INIT_LIST_HEAD(&hal_ctxt.dev_head);
- INIT_LIST_HEAD(&hdevice->list);
hdevice->device_id = device_id;
hdevice->callback = callback;
+ dprintk(VIDC_DBG, "q6_hfi_add_device device_id %d\n", device_id);
+
INIT_WORK(&hdevice->vidc_worker, q6_hfi_core_work_handler);
hdevice->vidc_workq = create_singlethread_workqueue(
- "msm_vidc_workerq");
+ "msm_vidc_workerq_q6");
if (!hdevice->vidc_workq) {
dprintk(VIDC_ERR, ": create workq failed\n");
goto error_createq;
}
+ if (hal_ctxt.dev_count == 0)
+ INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+ INIT_LIST_HEAD(&hdevice->list);
list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
hal_ctxt.dev_count++;
@@ -249,6 +330,7 @@
}
static void *q6_hfi_get_device(u32 device_id,
+ struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
{
struct q6_hfi_device *device;
@@ -266,7 +348,7 @@
return NULL;
}
- rc = q6_hfi_init_resources(device);
+ rc = q6_hfi_init_resources(device, res);
if (rc) {
dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
goto err_fail_init_res;
@@ -283,12 +365,15 @@
struct q6_hfi_device *close, *dev;
if (device) {
+ q6_hfi_deinit_resources(device);
dev = (struct q6_hfi_device *) device;
list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+ if (close->device_id == dev->device_id) {
hal_ctxt.dev_count--;
list_del(&close->list);
destroy_workqueue(close->vidc_workq);
kfree(close);
+ }
}
}
@@ -394,7 +479,7 @@
q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
- rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_ARCH_OX_OFFSET);
+ rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
if (rc) {
dprintk(VIDC_ERR, "Failed to create sys init pkt");
goto err_core_init;
@@ -1115,13 +1200,74 @@
return -ENOTSUPP;
}
-static int q6_hfi_iommu_attach(void *dev)
+static int q6_hfi_iommu_attach(struct q6_hfi_device *device)
{
- (void)dev;
+ int rc = 0;
+ struct iommu_domain *domain;
+ int i;
+ struct iommu_set *iommu_group_set;
+ struct iommu_group *group;
+ struct iommu_info *iommu_map;
- dprintk(VIDC_ERR, "Not implemented: %s", __func__);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return -EINVAL;
+ }
- return 0;
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (IS_ERR_OR_NULL(domain)) {
+ dprintk(VIDC_ERR, "Failed to get domain: %s",
+ iommu_map->name);
+ rc = IS_ERR(domain) ? PTR_ERR(domain) : -EINVAL;
+ break;
+ }
+ dprintk(VIDC_DBG, "Attaching domain(id:%d) %p to group %p",
+ iommu_map->domain, domain, group);
+ rc = iommu_attach_group(domain, group);
+ if (rc) {
+ dprintk(VIDC_ERR, "IOMMU attach failed: %s",
+ iommu_map->name);
+ break;
+ }
+ }
+ if (i < iommu_group_set->count) {
+ i--;
+ for (; i >= 0; i--) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (group && domain)
+ iommu_detach_group(domain, group);
+ }
+ }
+ return rc;
+}
+
+static void q6_hfi_iommu_detach(struct q6_hfi_device *device)
+{
+ struct iommu_group *group;
+ struct iommu_domain *domain;
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
+ int i;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "Invalid parameter: %p", device);
+ return;
+ }
+
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (group && domain)
+ iommu_detach_group(domain, group);
+ }
}
static int q6_hfi_load_fw(void *dev)
@@ -1181,6 +1327,7 @@
return;
if (device->resources.fw.cookie) {
+ q6_hfi_iommu_detach(device);
subsystem_put(device->resources.fw.cookie);
device->resources.fw.cookie = NULL;
}
@@ -1246,16 +1393,18 @@
int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
{
int rc = 0;
- if (!hdev || !callback) {
- dprintk(VIDC_ERR, "Invalid params: %p %p\n", hdev, callback);
+ if (!hdev || !res || !callback) {
+ dprintk(VIDC_ERR, "Invalid params: %p %p %p",
+ hdev, res, callback);
rc = -EINVAL;
goto err_hfi_init;
}
- hdev->hfi_device_data = q6_hfi_get_device(device_id, callback);
+ hdev->hfi_device_data = q6_hfi_get_device(device_id, res, callback);
q6_init_hfi_callbacks(hdev);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
index 551eb04..3dc4607 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.h
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -13,9 +13,10 @@
#ifndef __Q6_HFI_H__
#define __Q6_HFI_H__
+#include <mach/qdsp6v2/apr.h>
#include "vidc_hfi.h"
#include "vidc_hfi_helper.h"
-#include <mach/qdsp6v2/apr.h>
+#include "msm_vidc_resources.h"
#define Q6_IFACEQ_QUEUE_SIZE (8 * 1024)
@@ -40,6 +41,7 @@
u32 device_id;
msm_vidc_callback callback;
struct q6_resources resources;
+ struct msm_vidc_platform_resources *res;
void *apr;
};
@@ -109,6 +111,7 @@
};
int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback);
void q6_hfi_delete_device(void *device);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 995c655..779b996 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -37,6 +37,8 @@
#define SHARED_QSIZE 0x1000000
+static struct hal_device_data hal_ctxt;
+
static const u32 venus_qdss_entries[][2] = {
{0xFC307000, 0x1000},
{0xFC322000, 0x1000},
@@ -988,7 +990,7 @@
goto err_core_init;
}
- rc = create_pkt_cmd_sys_init(&pkt, HFI_ARCH_OX_OFFSET);
+ rc = create_pkt_cmd_sys_init(&pkt, HFI_VIDEO_ARCH_OX);
if (rc) {
dprintk(VIDC_ERR, "Failed to create sys init pkt");
goto err_core_init;
@@ -2746,25 +2748,25 @@
if (rc)
goto err_init_regs;
- INIT_LIST_HEAD(&hal_ctxt.dev_head);
- INIT_LIST_HEAD(&hdevice->list);
- list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
- hal_ctxt.dev_count++;
hdevice->device_id = device_id;
-
hdevice->callback = callback;
hdevice->vidc_workq = create_singlethread_workqueue(
- "msm_vidc_workerq");
+ "msm_vidc_workerq_venus");
if (!hdevice->vidc_workq) {
dprintk(VIDC_ERR, ": create workq failed\n");
goto error_createq;
}
+ if (hal_ctxt.dev_count == 0)
+ INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+ INIT_LIST_HEAD(&hdevice->list);
+ list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
+ hal_ctxt.dev_count++;
+
return (void *) hdevice;
error_createq:
- hal_ctxt.dev_count--;
- list_del(&hal_ctxt.dev_head);
err_init_regs:
kfree(hdevice);
err_alloc:
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.c b/drivers/media/platform/msm/vidc/vidc_hfi.c
index e8131dd..46293a6 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.c
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.c
@@ -16,8 +16,6 @@
#include "venus_hfi.h"
#include "q6_hfi.h"
-struct hal_device_data hal_ctxt;
-
void *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, u32 device_id,
struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
@@ -37,7 +35,7 @@
break;
case VIDC_HFI_Q6:
- rc = q6_hfi_initialize(hdev, device_id, callback);
+ rc = q6_hfi_initialize(hdev, device_id, res, callback);
break;
default:
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 8b3e7cb..075b391 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -830,8 +830,6 @@
void *cookie;
};
-extern struct hal_device_data hal_ctxt;
-
u32 hfi_process_msg_packet(msm_vidc_callback callback,
u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr);
#endif
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 95e644b..e20348d 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -190,6 +190,7 @@
HAL_VIDEO_CODEC_VP6 = 0x00000400,
HAL_VIDEO_CODEC_VP7 = 0x00000800,
HAL_VIDEO_CODEC_VP8 = 0x00001000,
+ HAL_VIDEO_CODEC_HEVC = 0x00010000,
HAL_UNUSED_CODEC = 0x10000000,
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 01c5e0b..baf7bc4 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -76,9 +76,10 @@
#define HFI_VIDEO_CODEC_MPEG4 0x00000020
#define HFI_VIDEO_CODEC_DIVX_311 0x00000040
#define HFI_VIDEO_CODEC_DIVX 0x00000080
-#define HFI_VIDEO_CODEC_VC1 0x00000100
+#define HFI_VIDEO_CODEC_VC1 0x00000100
#define HFI_VIDEO_CODEC_SPARK 0x00000200
-#define HFI_VIDEO_CODEC_VP8 0x00001000
+#define HFI_VIDEO_CODEC_VP8 0x00001000
+#define HFI_VIDEO_CODEC_HEVC 0x00010000
#define HFI_H264_PROFILE_BASELINE 0x00000001
#define HFI_H264_PROFILE_MAIN 0x00000002
diff --git a/drivers/media/platform/msm/wfd/enc-subdev.h b/drivers/media/platform/msm/wfd/enc-subdev.h
index 8bfb884..a1469cd 100644
--- a/drivers/media/platform/msm/wfd/enc-subdev.h
+++ b/drivers/media/platform/msm/wfd/enc-subdev.h
@@ -25,6 +25,10 @@
VENC_MODE_VFR,
};
+enum venc_event {
+ VENC_EVENT_HARDWARE_ERROR,
+};
+
struct mem_region {
struct list_head list;
u8 *kvaddr;
@@ -64,6 +68,7 @@
struct vb2_buffer *buf);
void (*ip_buffer_done)(void *cookie, u32 status,
struct mem_region *mregion);
+ void (*on_event)(void *cookie, enum venc_event e);
};
static inline bool mem_region_equals(struct mem_region *a,
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 40362f0..9ebf763 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -48,6 +48,12 @@
bool secure;
};
+static const int subscribed_events[] = {
+ V4L2_EVENT_MSM_VIDC_CLOSE_DONE,
+ V4L2_EVENT_MSM_VIDC_FLUSH_DONE,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR,
+};
+
int venc_load_fw(struct v4l2_subdev *sd)
{
/*No need to explicitly load the fw */
@@ -134,13 +140,21 @@
bool bail_out = false;
msm_vidc_dqevent(inst->vidc_context, &event);
- if (event.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
+
+ switch (event.type) {
+ case V4L2_EVENT_MSM_VIDC_CLOSE_DONE:
WFD_MSG_DBG("enc callback thread shutting " \
"down normally\n");
bail_out = true;
- } else {
- WFD_MSG_ERR("Got unknown event %d, ignoring\n",
- event.id);
+ break;
+ case V4L2_EVENT_MSM_VIDC_SYS_ERROR:
+ inst->vmops.on_event(inst->vmops.cbdata,
+ VENC_EVENT_HARDWARE_ERROR);
+ bail_out = true;
+ break;
+ default:
+ WFD_MSG_INFO("Got unknown event %d, ignoring\n",
+ event.type);
}
complete_all(&inst->cmd_complete);
@@ -251,11 +265,43 @@
return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
}
+static int subscribe_events(struct venc_inst *inst)
+{
+ struct v4l2_event_subscription event = {0};
+ int c = 0, rc = 0;
+
+ for (c = 0; c < ARRAY_SIZE(subscribed_events); c++) {
+ event.type = subscribed_events[c];
+ rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ WFD_MSG_ERR("Failed to subscribe to event 0x%x\n",
+ subscribed_events[c]);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void unsubscribe_events(struct venc_inst *inst)
+{
+ struct v4l2_event_subscription event = {0};
+ int c = 0, rc = 0;
+ for (c = 0; c < ARRAY_SIZE(subscribed_events); c++) {
+ event.type = subscribed_events[c];
+ rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ /* Just log and ignore failiures */
+ WFD_MSG_WARN("Failed to unsubscribe to event 0x%x\n",
+ subscribed_events[c]);
+ }
+ }
+}
+
static long venc_open(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
struct venc_msg_ops *vmops = arg;
- struct v4l2_event_subscription event = {0};
int rc = 0;
if (!vmops) {
@@ -289,17 +335,9 @@
goto vidc_open_fail;
}
- event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ rc = subscribe_events(inst);
if (rc) {
- WFD_MSG_ERR("Failed to subscribe to CLOSE_DONE event\n");
- goto vidc_subscribe_fail;
- }
-
- event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
- if (rc) {
- WFD_MSG_ERR("Failed to subscribe to FLUSH_DONE event\n");
+ WFD_MSG_ERR("Failed to subscribe to events\n");
goto vidc_subscribe_fail;
}
@@ -317,11 +355,7 @@
vmops->cookie = inst;
return 0;
vidc_kthread_create_fail:
- event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- msm_vidc_unsubscribe_event(inst->vidc_context, &event);
-
- event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ unsubscribe_events(inst);
vidc_subscribe_fail:
msm_vidc_close(inst->vidc_context);
vidc_open_fail:
@@ -333,7 +367,6 @@
static long venc_close(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
- struct v4l2_event_subscription event = {0};
struct v4l2_encoder_cmd enc_cmd = {0};
int rc = 0;
@@ -352,15 +385,7 @@
if (inst->callback_thread && inst->callback_thread_running)
kthread_stop(inst->callback_thread);
- event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
- if (rc)
- WFD_MSG_WARN("Failed to unsubscribe close event\n");
-
- event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
- rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
- if (rc)
- WFD_MSG_WARN("Failed to unsubscribe flush event\n");
+ unsubscribe_events(inst);
rc = msm_vidc_close(inst->vidc_context);
if (rc)
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 102b9b9..72b02bb 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -25,8 +25,9 @@
#include <mach/board.h>
#include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-msm-mem.h>
@@ -42,6 +43,7 @@
#define DEFAULT_WFD_WIDTH 1280
#define DEFAULT_WFD_HEIGHT 720
#define VENC_INPUT_BUFFERS 4
+#define MAX_EVENTS 16
struct wfd_device {
struct mutex dev_lock;
@@ -92,12 +94,18 @@
struct list_head input_mem_list;
struct wfd_stats stats;
struct completion stop_mdp_thread;
+ struct v4l2_fh event_handler;
};
struct wfd_vid_buffer {
struct vb2_buffer vidbuf;
};
+static inline struct wfd_inst *file_to_inst(struct file *filp)
+{
+ return container_of(filp->private_data, struct wfd_inst, event_handler);
+}
+
static int wfd_vidbuf_queue_setup(struct vb2_queue *q,
const struct v4l2_format *fmt,
unsigned int *num_buffers,
@@ -105,7 +113,7 @@
unsigned int sizes[], void *alloc_ctxs[])
{
struct file *priv_data = (struct file *)(q->drv_priv);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
unsigned long flags;
int i;
@@ -124,10 +132,11 @@
return 0;
}
-void wfd_vidbuf_wait_prepare(struct vb2_queue *q)
+static void wfd_vidbuf_wait_prepare(struct vb2_queue *q)
{
}
-void wfd_vidbuf_wait_finish(struct vb2_queue *q)
+
+static void wfd_vidbuf_wait_finish(struct vb2_queue *q)
{
}
@@ -236,7 +245,8 @@
ION_IOC_INV_CACHES);
}
-int wfd_allocate_input_buffers(struct wfd_device *wfd_dev,
+
+static int wfd_allocate_input_buffers(struct wfd_device *wfd_dev,
struct wfd_inst *inst)
{
int i;
@@ -389,7 +399,8 @@
recon_alloc_fail:
return rc;
}
-void wfd_free_input_buffers(struct wfd_device *wfd_dev,
+
+static void wfd_free_input_buffers(struct wfd_device *wfd_dev,
struct wfd_inst *inst)
{
struct list_head *ptr, *next;
@@ -450,7 +461,7 @@
WFD_MSG_ERR("Failed to free recon buffers\n");
}
-struct mem_info *wfd_get_mem_info(struct wfd_inst *inst,
+static struct mem_info *wfd_get_mem_info(struct wfd_inst *inst,
unsigned long userptr)
{
struct mem_info_entry *temp;
@@ -468,7 +479,8 @@
spin_unlock_irqrestore(&inst->inst_lock, flags);
return ret;
}
-void wfd_put_mem_info(struct wfd_inst *inst,
+
+static void wfd_put_mem_info(struct wfd_inst *inst,
struct mem_info *minfo)
{
struct list_head *ptr, *next;
@@ -497,12 +509,13 @@
}
wfd_put_mem_info(inst, minfo);
}
-int wfd_vidbuf_buf_init(struct vb2_buffer *vb)
+
+static int wfd_vidbuf_buf_init(struct vb2_buffer *vb)
{
int rc = 0;
struct vb2_queue *q = vb->vb2_queue;
struct file *priv_data = (struct file *)(q->drv_priv);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
struct mem_info *minfo = vb2_plane_cookie(vb, 0);
@@ -532,24 +545,24 @@
return rc;
}
-int wfd_vidbuf_buf_prepare(struct vb2_buffer *vb)
+static int wfd_vidbuf_buf_prepare(struct vb2_buffer *vb)
{
return 0;
}
-int wfd_vidbuf_buf_finish(struct vb2_buffer *vb)
+static int wfd_vidbuf_buf_finish(struct vb2_buffer *vb)
{
return 0;
}
-void wfd_vidbuf_buf_cleanup(struct vb2_buffer *vb)
+static void wfd_vidbuf_buf_cleanup(struct vb2_buffer *vb)
{
int rc = 0;
struct vb2_queue *q = vb->vb2_queue;
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
struct mem_info *minfo = vb2_plane_cookie(vb, 0);
struct mem_region mregion;
@@ -574,7 +587,7 @@
{
int rc = 0, no_sig_wait = 0;
struct file *filp = (struct file *)data;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
struct mdp_buf_info obuf_mdp = {inst->mdp_inst, 0, 0, 0};
@@ -633,12 +646,12 @@
return rc;
}
-int wfd_vidbuf_start_streaming(struct vb2_queue *q, unsigned int count)
+static int wfd_vidbuf_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
int rc = 0;
WFD_MSG_ERR("Stream on called\n");
@@ -657,6 +670,7 @@
WFD_MSG_ERR("Failed to start vsg\n");
goto subdev_start_fail;
}
+
init_completion(&inst->stop_mdp_thread);
inst->mdp_task = kthread_run(mdp_output_thread, priv_data,
"mdp_output_thread");
@@ -673,12 +687,12 @@
return rc;
}
-int wfd_vidbuf_stop_streaming(struct vb2_queue *q)
+static int wfd_vidbuf_stop_streaming(struct vb2_queue *q)
{
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
int rc = 0;
WFD_MSG_DBG("mdp stop\n");
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
@@ -707,14 +721,14 @@
return rc;
}
-void wfd_vidbuf_buf_queue(struct vb2_buffer *vb)
+static void wfd_vidbuf_buf_queue(struct vb2_buffer *vb)
{
int rc = 0;
struct vb2_queue *q = vb->vb2_queue;
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(priv_data);
- struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+ struct wfd_inst *inst = file_to_inst(priv_data);
struct mem_region mregion;
struct mem_info *minfo = vb2_plane_cookie(vb, 0);
mregion.fd = minfo->fd;
@@ -787,7 +801,7 @@
static int wfdioc_g_fmt(struct file *filp, void *fh,
struct v4l2_format *fmt)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
unsigned long flags;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
@@ -811,7 +825,7 @@
struct v4l2_format *fmt)
{
int rc = 0;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
struct mdp_prop prop;
unsigned long flags;
@@ -862,7 +876,7 @@
static int wfdioc_reqbufs(struct file *filp, void *fh,
struct v4l2_requestbuffers *b)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
unsigned long flags;
int rc = 0;
@@ -918,7 +932,7 @@
struct v4l2_buffer *b)
{
int rc = 0;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
if (!inst || !b ||
(b->index < 0 || b->index >= inst->buf_count)) {
WFD_MSG_ERR("Invalid input parameters to QBUF IOCTL\n");
@@ -943,7 +957,7 @@
enum v4l2_buf_type i)
{
int rc = 0;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream on for buffer type = %d is not "
@@ -969,7 +983,7 @@
static int wfdioc_streamoff(struct file *filp, void *fh,
enum v4l2_buf_type i)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -993,7 +1007,7 @@
static int wfdioc_dqbuf(struct file *filp, void *fh,
struct v4l2_buffer *b)
{
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
int rc;
WFD_MSG_DBG("Waiting to dequeue buffer\n");
@@ -1057,7 +1071,7 @@
{
int rc = 0;
struct wfd_device *wfd_dev = video_drvdata(filp);
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
int64_t frame_interval = 0,
max_frame_interval = 0; /* both in nsecs*/
struct v4l2_qcom_frameskip frameskip, *usr_frameskip;
@@ -1112,7 +1126,7 @@
{
int rc = 0;
struct wfd_device *wfd_dev = video_drvdata(filp);
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct v4l2_qcom_frameskip frameskip;
int64_t frame_interval, max_frame_interval;
void *extendedmode = NULL;
@@ -1200,6 +1214,22 @@
return rc;
}
+static int wfdioc_subscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ struct wfd_inst *inst = container_of(fh, struct wfd_inst,
+ event_handler);
+ return v4l2_event_subscribe(&inst->event_handler, sub, MAX_EVENTS);
+}
+
+static int wfdioc_unsubscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ struct wfd_inst *inst = container_of(fh, struct wfd_inst,
+ event_handler);
+ return v4l2_event_unsubscribe(&inst->event_handler, sub);
+}
+
static const struct v4l2_ioctl_ops g_wfd_ioctl_ops = {
.vidioc_querycap = wfdioc_querycap,
.vidioc_s_fmt_vid_cap = wfdioc_s_fmt,
@@ -1213,13 +1243,16 @@
.vidioc_s_ctrl = wfdioc_s_ctrl,
.vidioc_g_parm = wfdioc_g_parm,
.vidioc_s_parm = wfdioc_s_parm,
+ .vidioc_subscribe_event = wfdioc_subscribe_event,
+ .vidioc_unsubscribe_event = wfdioc_unsubscribe_event,
+
};
static int wfd_set_default_properties(struct file *filp)
{
unsigned long flags;
struct v4l2_format fmt;
struct v4l2_control ctrl;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
if (!inst) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
@@ -1249,7 +1282,7 @@
struct mem_region *mregion)
{
struct file *filp = cookie;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct vsg_buf_info buf;
struct mdp_buf_info mdp_buf = {0};
struct wfd_device *wfd_dev =
@@ -1273,10 +1306,33 @@
}
+static void venc_on_event(void *cookie, enum venc_event e)
+{
+ struct file *filp = cookie;
+ struct wfd_inst *inst = file_to_inst(filp);
+ struct v4l2_event event;
+ int type = 0;
+
+ switch (e) {
+ case VENC_EVENT_HARDWARE_ERROR:
+ type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+ break;
+ default:
+ /* Whatever~~ */
+ break;
+ }
+
+ if (type) {
+ event.id = 0;
+ event.type = type;
+ v4l2_event_queue_fh(&inst->event_handler, &event);
+ }
+}
+
static int vsg_release_input_frame(void *cookie, struct vsg_buf_info *buf)
{
struct file *filp = cookie;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
int rc = 0;
@@ -1296,7 +1352,7 @@
static int vsg_encode_frame(void *cookie, struct vsg_buf_info *buf)
{
struct file *filp = cookie;
- struct wfd_inst *inst = filp->private_data;
+ struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
struct venc_buf_info venc_buf;
@@ -1389,11 +1445,15 @@
rc = -ENOMEM;
goto err_mdp_open;
}
- filp->private_data = inst;
+ filp->private_data = &inst->event_handler;
spin_lock_init(&inst->inst_lock);
INIT_LIST_HEAD(&inst->input_mem_list);
INIT_LIST_HEAD(&inst->minfo_list);
+ /* Set up userspace event handlers */
+ v4l2_fh_init(&inst->event_handler, wfd_dev->pvdev);
+ v4l2_fh_add(&inst->event_handler);
+
wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
mdp_mops.secure = wfd_dev->secure;
@@ -1411,8 +1471,10 @@
WFD_MSG_ERR("Failed to load video encoder firmware: %d\n", rc);
goto err_venc;
}
+
enc_mops.op_buffer_done = venc_op_buffer_done;
enc_mops.ip_buffer_done = venc_ip_buffer_done;
+ enc_mops.on_event = venc_on_event;
enc_mops.cbdata = filp;
enc_mops.secure = wfd_dev->secure;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
@@ -1444,9 +1506,12 @@
v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_CLOSE, (void *)inst->mdp_inst);
err_mdp_open:
+ v4l2_fh_del(&inst->event_handler);
+
mutex_lock(&wfd_dev->dev_lock);
wfd_dev->in_use = false;
mutex_unlock(&wfd_dev->dev_lock);
+
kfree(inst);
err_dev_busy:
return rc;
@@ -1459,7 +1524,7 @@
int rc = 0;
wfd_dev = video_drvdata(filp);
WFD_MSG_DBG("wfd_close: E\n");
- inst = filp->private_data;
+ inst = file_to_inst(filp);
if (inst) {
wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
vb2_queue_release(&inst->vid_bufq);
@@ -1484,6 +1549,8 @@
kfree(inst);
}
+ v4l2_fh_del(&inst->event_handler);
+
mutex_lock(&wfd_dev->dev_lock);
wfd_dev->in_use = false;
mutex_unlock(&wfd_dev->dev_lock);
@@ -1491,12 +1558,28 @@
WFD_MSG_DBG("wfd_close: X\n");
return 0;
}
+
+unsigned int wfd_poll(struct file *filp, struct poll_table_struct *pt)
+{
+ struct wfd_inst *inst = file_to_inst(filp);
+ unsigned int flags = 0;
+
+ poll_wait(filp, &inst->event_handler.wait, pt);
+
+ if (v4l2_event_pending(&inst->event_handler))
+ flags |= POLLPRI;
+
+ return flags;
+}
+
static const struct v4l2_file_operations g_wfd_fops = {
.owner = THIS_MODULE,
.open = wfd_open,
.release = wfd_close,
- .ioctl = video_ioctl2
+ .ioctl = video_ioctl2,
+ .poll = wfd_poll,
};
+
void release_video_device(struct video_device *pvdev)
{
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 9e22ffb..7d76b43 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -57,7 +57,6 @@
#define QSEOS_CHECK_VERSION_CMD 0x00001803
#define QSEE_CE_CLK_100MHZ 100000000
-#define QSEE_CE_CLK_50MHZ 50000000
#define QSEECOM_MAX_SG_ENTRY 512
@@ -78,10 +77,6 @@
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
-static int qsee_bw_count;
-static int qsee_sfpb_bw_count;
-static uint32_t qsee_perf_client;
-
struct qseecom_registered_listener_list {
struct list_head list;
struct qseecom_register_listener_req svc;
@@ -106,6 +101,13 @@
struct qseecom_handle *handle;
};
+struct qseecom_clk {
+ struct clk *ce_core_clk;
+ struct clk *ce_clk;
+ struct clk *ce_core_src_clk;
+ struct clk *ce_bus_clk;
+};
+
struct qseecom_control {
struct ion_client *ion_clnt; /* Ion client */
struct list_head registered_listener_list_head;
@@ -124,6 +126,12 @@
uint32_t qsee_version;
struct device *pdev;
bool commonlib_loaded;
+
+ int qsee_bw_count;
+ int qsee_sfpb_bw_count;
+
+ uint32_t qsee_perf_client;
+ struct qseecom_clk qsee;
};
struct qseecom_client_handle {
@@ -155,11 +163,6 @@
atomic_t ioctl_count;
};
-struct clk *ce_core_clk;
-struct clk *ce_clk;
-struct clk *ce_core_src_clk;
-struct clk *ce_bus_clk;
-
struct qseecom_sg_entry {
uint32_t phys_addr;
uint32_t len;
@@ -355,12 +358,14 @@
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
+ ret, data->listener.id);
return ret;
}
if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("SB deregistartion: result=%d\n", resp.result);
+ pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
+ resp.result, data->listener.id);
return -EPERM;
}
} else {
@@ -538,12 +543,13 @@
sizeof(send_data_rsp), resp,
sizeof(*resp));
if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ pr_err("scm_call() failed with err: %d (app_id = %d)\n",
+ ret, data->client.app_id);
return ret;
}
if (resp->result == QSEOS_RESULT_FAILURE) {
- pr_err("Response result %d not supported\n",
- resp->result);
+ pr_err("Response result %d FAIL (app_id = %d)\n",
+ resp->result, data->client.app_id);
return -EINVAL;
}
}
@@ -980,7 +986,8 @@
sizeof(send_data_req),
&resp, sizeof(resp));
if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ pr_err("scm_call() failed with err: %d (app_id = %d)\n",
+ ret, data->client.app_id);
return ret;
}
@@ -1161,13 +1168,15 @@
if (wait_event_freezable(this_lstnr->rcv_req_wq,
__qseecom_listener_has_rcvd_req(data,
this_lstnr))) {
- pr_warning("Interrupted: exiting wait_rcv_req loop\n");
+ pr_warning("Interrupted: exiting Listener Service = %d\n",
+ (uint32_t)data->listener.id);
/* woken up for different reason */
return -ERESTARTSYS;
}
if (data->abort) {
- pr_err("Aborting driver!\n");
+ pr_err("Aborting Listener Service = %d\n",
+ (uint32_t)data->listener.id);
return -ENODEV;
}
this_lstnr->rcv_req_flag = 0;
@@ -1387,6 +1396,14 @@
}
/* Populate the remaining parameters */
load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
+ /* Vote for the SFPB clock */
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret) {
+ pr_err("Unable to vote for SFPB clock: ret = %d", ret);
+ kzfree(img_data);
+ return -EIO;
+ }
+
/* SCM_CALL to load the image */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
sizeof(struct qseecom_load_lib_image_ireq),
@@ -1417,6 +1434,7 @@
}
}
kzfree(img_data);
+ qsee_disable_clock_vote(data, CLK_SFPB);
return ret;
}
@@ -1517,7 +1535,7 @@
}
if (ret) {
- pr_err("Failed to loadd commonlib image\n");
+ pr_err("Failed to load commonlib image\n");
kfree(data);
kfree(*handle);
*handle = NULL;
@@ -1746,64 +1764,123 @@
return 0;
}
+static int __qseecom_enable_clk(void)
+{
+ int rc = 0;
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
+ /* Enable CE core clk */
+ rc = clk_prepare_enable(qclk->ce_core_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE core clk\n");
+ goto err;
+ }
+ /* Enable CE clk */
+ rc = clk_prepare_enable(qclk->ce_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ goto ce_clk_err;
+ }
+ /* Enable AXI clk */
+ rc = clk_prepare_enable(qclk->ce_bus_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE bus clk\n");
+ goto ce_bus_clk_err;
+ }
+ return 0;
+
+ce_bus_clk_err:
+ clk_disable_unprepare(qclk->ce_clk);
+ce_clk_err:
+ clk_disable_unprepare(qclk->ce_core_clk);
+err:
+ return -EIO;
+}
+
+static void __qseecom_disable_clk(void)
+{
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
+ if (qclk->ce_clk != NULL)
+ clk_disable_unprepare(qclk->ce_clk);
+ if (qclk->ce_core_clk != NULL)
+ clk_disable_unprepare(qclk->ce_core_clk);
+ if (qclk->ce_bus_clk != NULL)
+ clk_disable_unprepare(qclk->ce_bus_clk);
+}
+
static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
int32_t clk_type)
{
int ret = 0;
+ struct qseecom_clk *qclk;
- if (!qsee_perf_client)
+ qclk = &qseecom.qsee;
+ if (!qseecom.qsee_perf_client)
return ret;
switch (clk_type) {
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
- if (!qsee_bw_count) {
- if (qsee_sfpb_bw_count > 0)
+ if (!qseecom.qsee_bw_count) {
+ if (qseecom.qsee_sfpb_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 3);
+ qseecom.qsee_perf_client, 3);
else {
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_100MHZ);
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 1);
+ if (qclk->ce_core_src_clk != NULL)
+ ret = __qseecom_enable_clk();
+ if (!ret) {
+ ret =
+ msm_bus_scale_client_update_request(
+ qseecom.qsee_perf_client, 1);
+ if ((ret) &&
+ (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
+ }
}
if (ret)
pr_err("DFAB Bandwidth req failed (%d)\n",
ret);
else {
- qsee_bw_count++;
+ qseecom.qsee_bw_count++;
data->client.perf_enabled = true;
}
} else {
- qsee_bw_count++;
+ qseecom.qsee_bw_count++;
data->client.perf_enabled = true;
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
mutex_lock(&qsee_bw_mutex);
- if (!qsee_sfpb_bw_count) {
- if (qsee_bw_count > 0)
+ if (!qseecom.qsee_sfpb_bw_count) {
+ if (qseecom.qsee_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 3);
+ qseecom.qsee_perf_client, 3);
else {
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_100MHZ);
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 2);
+ if (qclk->ce_core_src_clk != NULL)
+ ret = __qseecom_enable_clk();
+ if (!ret) {
+ ret =
+ msm_bus_scale_client_update_request(
+ qseecom.qsee_perf_client, 2);
+ if ((ret) &&
+ (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
+ }
}
if (ret)
pr_err("SFPB Bandwidth req failed (%d)\n",
ret);
else {
- qsee_sfpb_bw_count++;
+ qseecom.qsee_sfpb_bw_count++;
data->client.fast_load_enabled = true;
}
} else {
- qsee_sfpb_bw_count++;
+ qseecom.qsee_sfpb_bw_count++;
data->client.fast_load_enabled = true;
}
mutex_unlock(&qsee_bw_mutex);
@@ -1819,70 +1896,70 @@
int32_t clk_type)
{
int32_t ret = 0;
+ struct qseecom_clk *qclk;
- if (!qsee_perf_client)
+ qclk = &qseecom.qsee;
+ if (!qseecom.qsee_perf_client)
return;
switch (clk_type) {
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
- if (qsee_bw_count == 0) {
+ if (qseecom.qsee_bw_count == 0) {
pr_err("Client error.Extra call to disable DFAB clk\n");
mutex_unlock(&qsee_bw_mutex);
return;
}
- if (qsee_bw_count == 1) {
- if (qsee_sfpb_bw_count > 0)
+ if (qseecom.qsee_bw_count == 1) {
+ if (qseecom.qsee_sfpb_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 2);
+ qseecom.qsee_perf_client, 2);
else {
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 0);
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_50MHZ);
+ qseecom.qsee_perf_client, 0);
+ if ((!ret) && (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
}
if (ret)
pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
else {
- qsee_bw_count--;
+ qseecom.qsee_bw_count--;
data->client.perf_enabled = false;
}
} else {
- qsee_bw_count--;
+ qseecom.qsee_bw_count--;
data->client.perf_enabled = false;
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
mutex_lock(&qsee_bw_mutex);
- if (qsee_sfpb_bw_count == 0) {
+ if (qseecom.qsee_sfpb_bw_count == 0) {
pr_err("Client error.Extra call to disable SFPB clk\n");
mutex_unlock(&qsee_bw_mutex);
return;
}
- if (qsee_sfpb_bw_count == 1) {
- if (qsee_bw_count > 0)
+ if (qseecom.qsee_sfpb_bw_count == 1) {
+ if (qseecom.qsee_bw_count > 0)
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 1);
+ qseecom.qsee_perf_client, 1);
else {
ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 0);
- if (ce_core_src_clk != NULL)
- clk_set_rate(ce_core_src_clk,
- QSEE_CE_CLK_50MHZ);
+ qseecom.qsee_perf_client, 0);
+ if ((!ret) && (qclk->ce_core_src_clk != NULL))
+ __qseecom_disable_clk();
}
if (ret)
pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
else {
- qsee_sfpb_bw_count--;
+ qseecom.qsee_sfpb_bw_count--;
data->client.fast_load_enabled = false;
}
} else {
- qsee_sfpb_bw_count--;
+ qseecom.qsee_sfpb_bw_count--;
data->client.fast_load_enabled = false;
}
mutex_unlock(&qsee_bw_mutex);
@@ -1941,6 +2018,13 @@
ret = -EFAULT;
goto qseecom_load_external_elf_set_cpu_err;
}
+ /* Vote for the SFPB clock */
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret) {
+ pr_err("Unable to vote for SFPB clock: ret = %d", ret);
+ ret = -EIO;
+ goto qseecom_load_external_elf_set_cpu_err;
+ }
/* SCM_CALL to load the external elf */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
@@ -1980,7 +2064,7 @@
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
-
+ qsee_disable_clock_vote(data, CLK_SFPB);
return ret;
}
@@ -2350,97 +2434,61 @@
.release = qseecom_release
};
-static int __qseecom_enable_clk(void)
-{
- int rc = 0;
-
- /* Enable CE core clk */
- rc = clk_prepare_enable(ce_core_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE core clk\n");
- return -EIO;
- } else {
- /* Enable CE clk */
- rc = clk_prepare_enable(ce_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- clk_disable_unprepare(ce_core_clk);
- return -EIO;
- } else {
- /* Enable AXI clk */
- rc = clk_prepare_enable(ce_bus_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- clk_disable_unprepare(ce_core_clk);
- clk_disable_unprepare(ce_clk);
- return -EIO;
- }
- }
- }
- return rc;
-}
-
-static void __qseecom_disable_clk(void)
-{
- if (ce_clk != NULL)
- clk_disable_unprepare(ce_clk);
- if (ce_core_clk != NULL)
- clk_disable_unprepare(ce_core_clk);
- if (ce_bus_clk != NULL)
- clk_disable_unprepare(ce_bus_clk);
-}
-
static int __qseecom_init_clk(void)
{
int rc = 0;
struct device *pdev;
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
pdev = qseecom.pdev;
/* Get CE3 src core clk. */
- ce_core_src_clk = clk_get(pdev, "core_clk_src");
- if (!IS_ERR(ce_core_src_clk)) {
- /* Set the core src clk @50Mhz */
- rc = clk_set_rate(ce_core_src_clk, QSEE_CE_CLK_50MHZ);
+
+ qclk->ce_core_src_clk = clk_get(pdev, "core_clk_src");
+ if (!IS_ERR(qclk->ce_core_src_clk)) {
+ /* Set the core src clk @100Mhz */
+ rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
if (rc) {
- clk_put(ce_core_src_clk);
+ clk_put(qclk->ce_core_src_clk);
pr_err("Unable to set the core src clk @100Mhz.\n");
return -EIO;
}
} else {
pr_warn("Unable to get CE core src clk, set to NULL\n");
- ce_core_src_clk = NULL;
+ qclk->ce_core_src_clk = NULL;
}
/* Get CE core clk */
- ce_core_clk = clk_get(pdev, "core_clk");
- if (IS_ERR(ce_core_clk)) {
- rc = PTR_ERR(ce_core_clk);
+ qclk->ce_core_clk = clk_get(pdev, "core_clk");
+ if (IS_ERR(qclk->ce_core_clk)) {
+ rc = PTR_ERR(qclk->ce_core_clk);
pr_err("Unable to get CE core clk\n");
- if (ce_core_src_clk != NULL)
- clk_put(ce_core_src_clk);
+ if (qclk->ce_core_src_clk != NULL)
+ clk_put(qclk->ce_core_src_clk);
return -EIO;
}
/* Get CE Interface clk */
- ce_clk = clk_get(pdev, "iface_clk");
- if (IS_ERR(ce_clk)) {
- rc = PTR_ERR(ce_clk);
+ qclk->ce_clk = clk_get(pdev, "iface_clk");
+ if (IS_ERR(qclk->ce_clk)) {
+ rc = PTR_ERR(qclk->ce_clk);
pr_err("Unable to get CE interface clk\n");
- if (ce_core_src_clk != NULL)
- clk_put(ce_core_src_clk);
- clk_put(ce_core_clk);
+ if (qclk->ce_core_src_clk != NULL)
+ clk_put(qclk->ce_core_src_clk);
+ clk_put(qclk->ce_core_clk);
return -EIO;
}
/* Get CE AXI clk */
- ce_bus_clk = clk_get(pdev, "bus_clk");
- if (IS_ERR(ce_bus_clk)) {
- rc = PTR_ERR(ce_bus_clk);
+ qclk->ce_bus_clk = clk_get(pdev, "bus_clk");
+ if (IS_ERR(qclk->ce_bus_clk)) {
+ rc = PTR_ERR(qclk->ce_bus_clk);
pr_err("Unable to get CE BUS interface clk\n");
- if (ce_core_src_clk != NULL)
- clk_put(ce_core_src_clk);
- clk_put(ce_core_clk);
- clk_put(ce_clk);
+ if (qclk->ce_core_src_clk != NULL)
+ clk_put(qclk->ce_core_src_clk);
+ clk_put(qclk->ce_core_clk);
+ clk_put(qclk->ce_clk);
return -EIO;
}
return rc;
@@ -2448,21 +2496,25 @@
static void __qseecom_deinit_clk(void)
{
- if (ce_clk != NULL) {
- clk_put(ce_clk);
- ce_clk = NULL;
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
+
+ if (qclk->ce_clk != NULL) {
+ clk_put(qclk->ce_clk);
+ qclk->ce_clk = NULL;
}
- if (ce_core_clk != NULL) {
- clk_put(ce_core_clk);
- ce_clk = NULL;
+ if (qclk->ce_core_clk != NULL) {
+ clk_put(qclk->ce_core_clk);
+ qclk->ce_clk = NULL;
}
- if (ce_bus_clk != NULL) {
- clk_put(ce_bus_clk);
- ce_clk = NULL;
+ if (qclk->ce_bus_clk != NULL) {
+ clk_put(qclk->ce_bus_clk);
+ qclk->ce_clk = NULL;
}
- if (ce_core_src_clk != NULL) {
- clk_put(ce_core_src_clk);
- ce_core_src_clk = NULL;
+ if (qclk->ce_core_src_clk != NULL) {
+ clk_put(qclk->ce_core_src_clk);
+ qclk->ce_core_src_clk = NULL;
}
}
@@ -2475,14 +2527,14 @@
struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
- qsee_bw_count = 0;
- qsee_perf_client = 0;
- qsee_sfpb_bw_count = 0;
+ qseecom.qsee_bw_count = 0;
+ qseecom.qsee_perf_client = 0;
+ qseecom.qsee_sfpb_bw_count = 0;
- ce_core_clk = NULL;
- ce_clk = NULL;
- ce_core_src_clk = NULL;
- ce_bus_clk = NULL;
+ qseecom.qsee.ce_core_clk = NULL;
+ qseecom.qsee.ce_clk = NULL;
+ qseecom.qsee.ce_core_src_clk = NULL;
+ qseecom.qsee.ce_bus_clk = NULL;
rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
if (rc < 0) {
@@ -2561,11 +2613,7 @@
ret = __qseecom_init_clk();
if (ret)
goto err;
- ret = __qseecom_enable_clk();
- if (ret) {
- __qseecom_deinit_clk();
- goto err;
- }
+
qseecom_platform_support = (struct msm_bus_scale_pdata *)
msm_bus_cl_get_pdata(pdev);
if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
@@ -2599,10 +2647,10 @@
pdev->dev.platform_data;
}
- qsee_perf_client = msm_bus_scale_register_client(
+ qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
- if (!qsee_perf_client)
+ if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
return 0;
err:
@@ -2621,7 +2669,7 @@
int ret = 0;
if (pdev->dev.platform_data != NULL)
- msm_bus_scale_unregister_client(qsee_perf_client);
+ msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
@@ -2672,13 +2720,13 @@
if (qseecom.qseos_version > QSEEE_VERSION_00)
qseecom_unload_commonlib_image();
- if (qsee_perf_client)
- msm_bus_scale_client_update_request(qsee_perf_client, 0);
+ if (qseecom.qsee_perf_client)
+ msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
+ 0);
/* register client for bus scaling */
- if (pdev->dev.of_node) {
- __qseecom_disable_clk();
+ if (pdev->dev.of_node)
__qseecom_deinit_clk();
- }
+
return ret;
};
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index f3973ef..4a063fd 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1160,9 +1160,16 @@
data_cnt = SPS_MAX_DESC_SIZE;
} else {
data_cnt = len;
- if (i == data->sg_len - 1)
+ if ((i == data->sg_len - 1) &&
+ (sps_pipe_handle ==
+ host->sps.cons.pipe_handle)) {
+ /*
+ * set EOT only for consumer pipe, for
+ * producer pipe h/w will set it.
+ */
flags = SPS_IOVEC_FLAG_INT |
SPS_IOVEC_FLAG_EOT;
+ }
}
rc = sps_transfer_one(sps_pipe_handle, addr,
data_cnt, host, flags);
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 41dd6e7..ed67df4 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -22,7 +22,7 @@
#include <mach/ecm_ipa.h>
#define DRIVER_NAME "ecm_ipa"
-#define DRIVER_VERSION "12-Mar-2013"
+#define DRIVER_VERSION "20-Mar-2013"
#define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
#define ECM_IPA_IPV6_HDR_NAME "ecm_eth_ipv6"
#define IPA_TO_USB_CLIENT IPA_CLIENT_USB_CONS
@@ -30,13 +30,6 @@
#define ECM_IPA_ERROR(fmt, args...) \
pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
fmt, __func__, __LINE__, current->comm, ## args)
-#ifdef ECM_IPA_DEBUG_ON
-#define ECM_IPA_DEBUG(fmt, args...) \
- pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
- fmt, __func__, __LINE__, current->comm, ## args)
-#else /* ECM_IPA_DEBUG_ON */
-#define ECM_IPA_DEBUG(fmt, args...)
-#endif /* ECM_IPA_DEBUG_ON */
#define NULL_CHECK(ptr) \
do { \
@@ -47,8 +40,8 @@
} \
while (0)
-#define ECM_IPA_LOG_ENTRY() ECM_IPA_DEBUG("begin\n")
-#define ECM_IPA_LOG_EXIT() ECM_IPA_DEBUG("end\n")
+#define ECM_IPA_LOG_ENTRY() pr_debug("begin\n")
+#define ECM_IPA_LOG_EXIT() pr_debug("end\n")
/**
* struct ecm_ipa_dev - main driver context parameters
@@ -192,7 +185,7 @@
struct net_device *net;
struct ecm_ipa_dev *dev;
ECM_IPA_LOG_ENTRY();
- ECM_IPA_DEBUG("%s version %s\n", DRIVER_NAME, DRIVER_VERSION);
+ pr_debug("%s version %s\n", DRIVER_NAME, DRIVER_VERSION);
NULL_CHECK(ecm_ipa_rx_dp_notify);
NULL_CHECK(ecm_ipa_tx_dp_notify);
NULL_CHECK(priv);
@@ -202,7 +195,7 @@
ECM_IPA_ERROR("fail to allocate etherdev\n");
goto fail_alloc_etherdev;
}
- ECM_IPA_DEBUG("etherdev was successfully allocated\n");
+ pr_debug("etherdev was successfully allocated\n");
dev = netdev_priv(net);
memset(dev, 0, sizeof(*dev));
dev->tx_enable = true;
@@ -213,11 +206,11 @@
*priv = (void *)dev;
snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
net->netdev_ops = &ecm_ipa_netdev_ops;
- ECM_IPA_DEBUG("internal data structures were intialized\n");
+ pr_debug("internal data structures were intialized\n");
ret = ecm_ipa_debugfs_init(dev);
if (ret)
goto fail_debugfs;
- ECM_IPA_DEBUG("debugfs entries were created\n");
+ pr_debug("debugfs entries were created\n");
*ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
*ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
ECM_IPA_LOG_EXIT();
@@ -382,7 +375,7 @@
ECM_IPA_LOG_ENTRY();
result = ipa_deregister_intf("ecm0");
if (result)
- ECM_IPA_DEBUG("Fail on Tx prop deregister\n");
+ pr_debug("Fail on Tx prop deregister\n");
ECM_IPA_LOG_EXIT();
return;
}
@@ -415,14 +408,14 @@
NULL_CHECK(dev);
net = dev->net;
NULL_CHECK(net);
- ECM_IPA_DEBUG("host_ethaddr=%pM device_ethaddr=%pM\n",
+ pr_debug("host_ethaddr=%pM device_ethaddr=%pM\n",
host_ethaddr, device_ethaddr);
result = ecm_ipa_create_rm_resource(dev);
if (result) {
ECM_IPA_ERROR("fail on RM create\n");
return -EINVAL;
}
- ECM_IPA_DEBUG("RM resource was created\n");
+ pr_debug("RM resource was created\n");
netif_carrier_off(dev->net);
result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
device_ethaddr);
@@ -435,19 +428,19 @@
ECM_IPA_ERROR("fail on ipa rules set\n");
goto fail_set_device_ethernet;
}
- ECM_IPA_DEBUG("Ethernet header insertion was set\n");
+ pr_debug("Ethernet header insertion was set\n");
result = ecm_ipa_register_properties();
if (result) {
ECM_IPA_ERROR("fail on properties set\n");
goto fail_register_tx;
}
- ECM_IPA_DEBUG("ECM 2 Tx and 2 Rx properties were registered\n");
+ pr_debug("ECM 2 Tx and 2 Rx properties were registered\n");
result = register_netdev(net);
if (result) {
ECM_IPA_ERROR("register_netdev failed: %d\n", result);
goto fail_register_netdev;
}
- ECM_IPA_DEBUG("register_netdev succeeded\n");
+ pr_debug("register_netdev succeeded\n");
ECM_IPA_LOG_EXIT();
return 0;
fail_register_netdev:
@@ -467,7 +460,7 @@
struct ecm_ipa_dev *dev = priv;
ECM_IPA_LOG_ENTRY();
NULL_CHECK(priv);
- ECM_IPA_DEBUG("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
+ pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
usb_to_ipa_hdl, ipa_to_usb_hdl);
if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
@@ -511,10 +504,10 @@
ECM_IPA_LOG_ENTRY();
if (event == IPA_RM_RESOURCE_GRANTED &&
netif_queue_stopped(dev->net)) {
- ECM_IPA_DEBUG("Resource Granted - waking queue\n");
+ pr_debug("Resource Granted - waking queue\n");
netif_wake_queue(dev->net);
} else {
- ECM_IPA_DEBUG("Resource released\n");
+ pr_debug("Resource released\n");
}
ECM_IPA_LOG_EXIT();
}
@@ -532,7 +525,7 @@
ECM_IPA_ERROR("Fail on ipa_rm_create_resource\n");
goto fail_rm_create;
}
- ECM_IPA_DEBUG("rm client was created");
+ pr_debug("rm client was created");
result = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_STD_ECM_PROD,
INACTIVITY_MSEC_DELAY);
@@ -540,14 +533,14 @@
ECM_IPA_ERROR("Fail on ipa_rm_inactivity_timer_init\n");
goto fail_it;
}
- ECM_IPA_DEBUG("rm_it client was created");
+ pr_debug("rm_it client was created");
result = ipa_rm_add_dependency(IPA_RM_RESOURCE_STD_ECM_PROD,
IPA_RM_RESOURCE_USB_CONS);
if (result)
ECM_IPA_ERROR("unable to add dependency (%d)\n", result);
- ECM_IPA_DEBUG("rm dependency was set\n");
+ pr_debug("rm dependency was set\n");
ECM_IPA_LOG_EXIT();
return 0;
@@ -596,7 +589,7 @@
static int ecm_ipa_stop(struct net_device *net)
{
ECM_IPA_LOG_ENTRY();
- ECM_IPA_DEBUG("stopping net device\n");
+ pr_debug("stopping net device\n");
netif_stop_queue(net);
ECM_IPA_LOG_EXIT();
return 0;
@@ -624,7 +617,7 @@
unregister_netdev(dev->net);
free_netdev(dev->net);
}
- ECM_IPA_DEBUG("cleanup done\n");
+ pr_debug("cleanup done\n");
ecm_ipa_ctx = NULL;
ECM_IPA_LOG_EXIT();
return ;
@@ -678,20 +671,20 @@
if (unlikely(tx_filter(skb))) {
dev_kfree_skb_any(skb);
- ECM_IPA_DEBUG("packet got filtered out on Tx path\n");
+ pr_debug("packet got filtered out on Tx path\n");
status = NETDEV_TX_OK;
goto out;
}
ret = resource_request(dev);
if (ret) {
- ECM_IPA_DEBUG("Waiting to resource\n");
+ pr_debug("Waiting to resource\n");
netif_stop_queue(net);
goto resource_busy;
}
spin_lock_irqsave(&dev->ack_spinlock, flags);
if (dev->last_out_skb) {
- ECM_IPA_DEBUG("No Tx-ack received for previous packet\n");
+ pr_debug("No Tx-ack received for previous packet\n");
spin_unlock_irqrestore(&dev->ack_spinlock, flags);
netif_stop_queue(net);
status = -NETDEV_TX_BUSY;
@@ -743,7 +736,7 @@
skb->dev = dev->net;
skb->protocol = eth_type_trans(skb, dev->net);
if (rx_filter(skb)) {
- ECM_IPA_DEBUG("packet got filtered out on Rx path\n");
+ pr_debug("packet got filtered out on Rx path\n");
dev_kfree_skb_any(skb);
return;
}
@@ -789,7 +782,7 @@
dev->last_out_skb = NULL;
spin_unlock_irqrestore(&dev->ack_spinlock, flags);
if (netif_queue_stopped(dev->net)) {
- ECM_IPA_DEBUG("waking up queue\n");
+ pr_debug("waking up queue\n");
netif_wake_queue(dev->net);
}
dev_kfree_skb_any(skb);
@@ -866,9 +859,9 @@
missing = copy_from_user(&input, buf, 1);
if (missing)
return -EFAULT;
- ECM_IPA_DEBUG("input received %c\n", input);
+ pr_debug("input received %c\n", input);
*enable = input - '0';
- ECM_IPA_DEBUG("value was set to %d\n", *enable);
+ pr_debug("value was set to %d\n", *enable);
return count;
}
@@ -1001,7 +994,7 @@
ECM_IPA_ERROR("failed to configure IPA to USB end-point\n");
goto out;
}
- ECM_IPA_DEBUG("end-point registers successfully configured\n");
+ pr_debug("end-point registers successfully configured\n");
out:
ECM_IPA_LOG_EXIT();
return result;
@@ -1040,7 +1033,7 @@
ECM_IPA_ERROR("failed to configure USB to IPA\n");
goto out;
}
- ECM_IPA_DEBUG("end-point registers successfully configured\n");
+ pr_debug("end-point registers successfully configured\n");
out:
ECM_IPA_LOG_EXIT();
return result;
@@ -1057,7 +1050,7 @@
if (!is_valid_ether_addr(device_ethaddr))
return -EINVAL;
memcpy(dev_ethaddr, device_ethaddr, ETH_ALEN);
- ECM_IPA_DEBUG("device ethernet address: %pM\n", dev_ethaddr);
+ pr_debug("device ethernet address: %pM\n", dev_ethaddr);
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index cfbedfb..a4b7e22 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,6 +13,8 @@
#include <linux/delay.h>
#include "ipa_i.h"
+#define IPA_HOLB_TMR_VAL 0xff
+
static void ipa_enable_data_path(u32 clnt_hdl)
{
struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
@@ -248,6 +250,20 @@
memcpy(&sps->desc, &ep->connect.desc, sizeof(struct sps_mem_buffer));
memcpy(&sps->data, &ep->connect.data, sizeof(struct sps_mem_buffer));
+ if (in->client == IPA_CLIENT_HSIC1_CONS ||
+ in->client == IPA_CLIENT_HSIC2_CONS ||
+ in->client == IPA_CLIENT_HSIC3_CONS ||
+ in->client == IPA_CLIENT_HSIC4_CONS) {
+ IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
+ IPA_HOLB_TMR_VAL);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx),
+ 0x1);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx),
+ IPA_HOLB_TMR_VAL);
+ }
+
IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx);
return 0;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 16c47ba..a5fac9e 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -52,6 +52,28 @@
struct sps_connect *sps_connections;
};
+/**
+* struct usb_bam_ctx_type - represents the usb bam driver entity
+* @usb_bam_sps: holds the sps pipes the usb bam driver holds
+* against the sps driver.
+* @usb_bam_pdev: the platfrom device that represents the usb bam.
+* @usb_bam_wq: Worqueue used for managing states of reset against
+* a peer bam.
+* @qscratch_ram1_reg: The memory region mapped to the qscratch
+* registers.
+* @max_connections: The maximum number of pipes that are configured
+* in the platform data.
+* @mem_clk: Clock that controls the usb bam driver memory in
+* case the usb bam uses its private memory for the pipes.
+* @mem_iface_clk: Clock that controls the usb bam private memory in
+* case the usb bam uses its private memory for the pipes.
+* @qdss_core_name: Stores the name of the core ("ssusb", "hsusb" or "hsic")
+* that it used as a peer of the qdss in bam2bam mode.
+* @h_bam: This array stores for each BAM ("ssusb", "hsusb" or "hsic") the
+* handle/device of the sps driver.
+* @pipes_enabled_per_bam: This array stores for each BAM
+* ("ssusb", "hsusb" or "hsic") the number of pipes currently enabled.
+*/
struct usb_bam_ctx_type {
struct usb_bam_sps_type usb_bam_sps;
struct platform_device *usb_bam_pdev;
@@ -61,8 +83,8 @@
struct clk *mem_clk;
struct clk *mem_iface_clk;
char qdss_core_name[USB_BAM_MAX_STR_LEN];
- char bam_enabled_list[USB_BAM_MAX_STR_LEN];
u32 h_bam[MAX_BAMS];
+ u8 pipes_enabled_per_bam[MAX_BAMS];
};
static char *bam_enable_strings[3] = {
@@ -442,7 +464,6 @@
int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
int ret;
- enum usb_bam bam;
struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
struct msm_usb_bam_platform_data *pdata;
@@ -467,13 +488,11 @@
pr_err("idx is wrong %d", idx);
return -EINVAL;
}
- bam = pipe_connect->bam_type;
- if (bam < 0)
- return -EINVAL;
- /* Check if BAM requires RESET before connect */
- if (pdata->reset_on_connect[bam] == true)
- sps_device_reset(ctx.h_bam[bam]);
+ /* Check if BAM requires RESET before connect and reset of first pipe */
+ if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
+ (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
+ sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
ret = connect_pipe(idx, bam_pipe_idx);
if (ret) {
@@ -482,6 +501,7 @@
}
pipe_connect->enabled = 1;
+ ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
return 0;
}
@@ -548,6 +568,8 @@
u8 idx;
struct usb_bam_pipe_connect *pipe_connect;
int ret;
+ struct msm_usb_bam_platform_data *pdata =
+ ctx.usb_bam_pdev->dev.platform_data;
if (!ipa_params) {
pr_err("%s: Invalid ipa params\n",
@@ -573,6 +595,11 @@
return 0;
}
+ /* Check if BAM requires RESET before connect and reset of first pipe */
+ if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
+ (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
+ sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+
ret = connect_pipe_ipa(idx, ipa_params);
ipa_rm_request_resource(IPA_RM_RESOURCE_USB_PROD);
@@ -582,6 +609,7 @@
}
pipe_connect->enabled = 1;
+ ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
return 0;
}
@@ -799,6 +827,11 @@
}
pipe_connect->enabled = 0;
+ if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
+ pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
+ __func__, pipe_connect->bam_type);
+ else
+ ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
return 0;
}
@@ -993,6 +1026,7 @@
__func__);
goto err;
}
+ bam = usb_bam_connections[i].bam_type;
rc = of_property_read_u32(node, "qcom,peer-bam",
&usb_bam_connections[i].peer_bam);
@@ -1220,6 +1254,9 @@
usb_bam_work);
}
+ for (i = 0; i < MAX_BAMS; i++)
+ ctx.pipes_enabled_per_bam[i] = 0;
+
spin_lock_init(&usb_bam_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index a2701ce..91aaf3c 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -170,6 +170,9 @@
int disable_flat_portion_ocv;
int ocv_dis_high_soc;
int ocv_dis_low_soc;
+ int high_ocv_correction_limit_uv;
+ int low_ocv_correction_limit_uv;
+ int hold_soc_est;
int prev_vbat_batt_terminal_uv;
int vbatt_cutoff_count;
int low_voltage_detect;
@@ -1861,6 +1864,7 @@
int m = 0;
int rc = 0;
int delta_ocv_uv_limit = 0;
+ int correction_limit_uv = 0;
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
@@ -1905,17 +1909,13 @@
/*
* do not adjust
- * if soc is same as what bms calculated
- * if soc_est is between 45 and 25, this is the flat portion of the
- * curve where soc_est is not so accurate. We generally don't want to
- * adjust when soc_est is inaccurate except for the cases when soc is
- * way far off (higher than 50 or lesser than 20).
- * Also don't adjust soc if it is above 90 becuase we might pull it low
+ * if soc_est is same as what bms calculated
+ * OR if soc_est > 15
+ * OR if soc it is above 90 because we might pull it low
* and cause a bad user experience
*/
if (soc_est == soc
- || (is_between(45, chip->adjust_soc_low_threshold, soc_est)
- && is_between(50, chip->adjust_soc_low_threshold - 5, soc))
+ || soc_est > 15
|| soc >= 90)
goto out;
@@ -1964,6 +1964,22 @@
pr_debug("new delta ocv = %d\n", delta_ocv_uv);
}
+ if (chip->last_ocv_uv > 3800000)
+ correction_limit_uv = the_chip->high_ocv_correction_limit_uv;
+ else
+ correction_limit_uv = the_chip->low_ocv_correction_limit_uv;
+
+ if (abs(delta_ocv_uv) > correction_limit_uv) {
+ pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+ correction_limit_uv);
+
+ if (delta_ocv_uv > 0)
+ delta_ocv_uv = correction_limit_uv;
+ else
+ delta_ocv_uv = -1 * correction_limit_uv;
+ pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+ }
+
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1980,7 +1996,7 @@
* if soc_new is ZERO force it higher so that phone doesnt report soc=0
* soc = 0 should happen only when soc_est == 0
*/
- if (soc_new == 0 && soc_est != 0)
+ if (soc_new == 0 && soc_est >= the_chip->hold_soc_est)
soc_new = 1;
soc = soc_new;
@@ -2479,9 +2495,18 @@
/* last_soc < soc ... scale and catch up */
if (last_soc != -EINVAL && last_soc < soc && soc != 100)
- soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+ soc = scale_soc_while_chg(chip, delta_time_us,
+ soc, last_soc);
- last_soc = soc;
+ /* restrict soc to 1% change */
+ if (last_soc != -EINVAL) {
+ if (soc < last_soc && soc != 0)
+ soc = last_soc - 1;
+ if (soc > last_soc && soc != 100)
+ soc = last_soc + 1;
+ }
+
+ last_soc = bound_soc(soc);
backup_soc_and_iavg(chip, batt_temp, last_soc);
pr_debug("Reported SOC = %d\n", last_soc);
chip->t_soc_queried = now;
@@ -2986,6 +3011,7 @@
GET_VBAT_VSENSE_SIMULTANEOUS,
STOP_OCV,
START_OCV,
+ SET_OCV,
};
static int test_batt_temp = 5;
@@ -3227,6 +3253,8 @@
(void *)STOP_OCV, &calc_fops);
debugfs_create_file("start_ocv", 0644, chip->dent,
(void *)START_OCV, &calc_fops);
+ debugfs_create_file("set_ocv", 0644, chip->dent,
+ (void *)SET_OCV, &calc_fops);
debugfs_create_file("simultaneous", 0644, chip->dent,
(void *)GET_VBAT_VSENSE_SIMULTANEOUS, &calc_fops);
@@ -3372,6 +3400,11 @@
chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc;
chip->ocv_dis_low_soc = pdata->ocv_dis_low_soc;
+ chip->high_ocv_correction_limit_uv
+ = pdata->high_ocv_correction_limit_uv;
+ chip->low_ocv_correction_limit_uv = pdata->low_ocv_correction_limit_uv;
+ chip->hold_soc_est = pdata->hold_soc_est;
+
chip->alarm_low_mv = pdata->alarm_low_mv;
chip->alarm_high_mv = pdata->alarm_high_mv;
chip->low_voltage_detect = pdata->low_voltage_detect;
@@ -3463,6 +3496,18 @@
return 0;
}
+static int pm8921_bms_suspend(struct device *dev)
+{
+ /*
+ * set the last reported soc to invalid, so that
+ * next time we resume we don't want to restrict
+ * the decrease of soc by only 1%
+ */
+ last_soc = -EINVAL;
+
+ return 0;
+}
+
static int pm8921_bms_resume(struct device *dev)
{
int rc;
@@ -3490,6 +3535,7 @@
static const struct dev_pm_ops pm8921_bms_pm_ops = {
.resume = pm8921_bms_resume,
+ .suspend = pm8921_bms_suspend,
};
static struct platform_driver pm8921_bms_driver = {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index f8b06bf..35d8df9 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -190,8 +190,8 @@
* @safe_current: battery safety current setting
* @maxinput_usb_ma: Maximum Input current USB
* @maxinput_dc_ma: Maximum Input current DC
- * @warm_bat_degc Warm battery temperature in degree Celsius
- * @cool_bat_degc Cool battery temperature in degree Celsius
+ * @warm_bat_decidegc Warm battery temperature in degree Celsius
+ * @cool_bat_decidegc Cool battery temperature in degree Celsius
* @revision: PMIC revision
* @thermal_levels amount of thermal mitigation levels
* @thermal_mitigation thermal mitigation level values
@@ -242,8 +242,8 @@
unsigned int term_current;
unsigned int maxinput_usb_ma;
unsigned int maxinput_dc_ma;
- unsigned int warm_bat_degc;
- unsigned int cool_bat_degc;
+ unsigned int warm_bat_decidegc;
+ unsigned int cool_bat_decidegc;
unsigned int safe_current;
unsigned int revision;
unsigned int thermal_levels;
@@ -546,6 +546,12 @@
if (chip->batt_present ^ batt_present) {
chip->batt_present = batt_present;
power_supply_changed(&chip->batt_psy);
+
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ && batt_present) {
+ if (qpnp_adc_tm_channel_measure(&chip->adc_param))
+ pr_err("request ADC error\n");
+ }
}
if (chip->bms_psy)
@@ -1305,56 +1311,74 @@
}
}
-#define TEMP_HYSTERISIS_DEGC 2
+#define HYSTERISIS_DECIDEGC 20
static void
qpnp_chg_adc_notification(enum qpnp_tm_state state, void *ctx)
{
struct qpnp_chg_chip *chip = ctx;
bool bat_warm = 0, bat_cool = 0;
+ int temp;
if (state >= ADC_TM_STATE_NUM) {
pr_err("invalid notification %d\n", state);
return;
}
- pr_debug("state = %s\n", state == ADC_TM_HIGH_STATE ? "high" : "low");
+ temp = get_prop_batt_temp(chip);
- if (state == ADC_TM_HIGH_STATE) {
- if (!chip->bat_is_warm) {
+ pr_debug("temp = %d state = %s\n", temp,
+ state == ADC_TM_WARM_STATE ? "warm" : "cool");
+
+ if (state == ADC_TM_WARM_STATE) {
+ if (temp > chip->warm_bat_decidegc) {
bat_warm = true;
bat_cool = false;
chip->adc_param.low_temp =
- chip->warm_bat_degc - TEMP_HYSTERISIS_DEGC;
- } else if (chip->bat_is_cool) {
+ chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC;
+ chip->adc_param.state_request =
+ ADC_TM_COOL_THR_ENABLE;
+ } else if (temp >
+ chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC){
bat_warm = false;
bat_cool = false;
- chip->adc_param.high_temp = chip->warm_bat_degc;
+
+ chip->adc_param.low_temp = chip->cool_bat_decidegc;
+ chip->adc_param.high_temp = chip->warm_bat_decidegc;
+ chip->adc_param.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
}
} else {
- if (!chip->bat_is_cool) {
+ if (temp < chip->cool_bat_decidegc) {
+ bat_warm = false;
bat_cool = true;
- bat_warm = false;
chip->adc_param.high_temp =
- chip->cool_bat_degc + TEMP_HYSTERISIS_DEGC;
- } else if (chip->bat_is_warm) {
- bat_cool = false;
+ chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC;
+ chip->adc_param.state_request =
+ ADC_TM_WARM_THR_ENABLE;
+ } else if (temp >
+ chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC){
bat_warm = false;
- chip->adc_param.low_temp = chip->cool_bat_degc;
+ bat_cool = false;
+
+ chip->adc_param.low_temp = chip->cool_bat_decidegc;
+ chip->adc_param.high_temp = chip->warm_bat_decidegc;
+ chip->adc_param.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
}
}
if (chip->bat_is_cool ^ bat_cool || chip->bat_is_warm ^ bat_warm) {
+ chip->bat_is_cool = bat_cool;
+ chip->bat_is_warm = bat_warm;
+
/* set appropriate voltages and currents */
qpnp_chg_set_appropriate_vddmax(chip);
qpnp_chg_set_appropriate_battery_current(chip);
qpnp_chg_set_appropriate_vbatdet(chip);
-
- chip->bat_is_cool = bat_cool;
- chip->bat_is_warm = bat_warm;
}
- /* re-arm ADC interrupt */
- qpnp_adc_tm_channel_measure(&chip->adc_param);
+ if (qpnp_adc_tm_channel_measure(&chip->adc_param))
+ pr_err("request ADC error\n");
}
static int
@@ -1744,8 +1768,8 @@
/* Get the warm-bat-degc property */
rc = of_property_read_u32(spmi->dev.of_node,
- "qcom,chg-warm-bat-degc",
- &chip->warm_bat_degc);
+ "qcom,chg-warm-bat-decidegc",
+ &chip->warm_bat_decidegc);
if (rc && rc != -EINVAL) {
pr_err("Error reading warm-bat-degc property %d\n", rc);
goto fail_chg_enable;
@@ -1753,14 +1777,14 @@
/* Get the cool-bat-degc property */
rc = of_property_read_u32(spmi->dev.of_node,
- "qcom,chg-cool-bat-degc",
- &chip->cool_bat_degc);
+ "qcom,chg-cool-bat-decidegc",
+ &chip->cool_bat_decidegc);
if (rc && rc != -EINVAL) {
pr_err("Error reading cool-bat-degc property %d\n", rc);
goto fail_chg_enable;
}
- if (chip->cool_bat_degc && chip->warm_bat_degc) {
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
rc = qpnp_adc_tm_is_ready();
if (rc) {
pr_err("tm not ready %d\n", rc);
@@ -1998,19 +2022,22 @@
}
}
- if (chip->cool_bat_degc && chip->warm_bat_degc) {
- chip->adc_param.low_temp = chip->cool_bat_degc;
- chip->adc_param.high_temp = chip->warm_bat_degc;
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
+ chip->adc_param.low_temp = chip->cool_bat_decidegc;
+ chip->adc_param.high_temp = chip->warm_bat_decidegc;
chip->adc_param.timer_interval = ADC_MEAS2_INTERVAL_1S;
chip->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
chip->adc_param.btm_ctx = chip;
chip->adc_param.threshold_notification =
qpnp_chg_adc_notification;
chip->adc_param.channel = LR_MUX1_BATT_THERM;
- rc = qpnp_adc_tm_channel_measure(&chip->adc_param);
- if (rc) {
- pr_err("request ADC error %d\n", rc);
- goto fail_chg_enable;
+
+ if (get_prop_batt_present(chip)) {
+ rc = qpnp_adc_tm_channel_measure(&chip->adc_param);
+ if (rc) {
+ pr_err("request ADC error %d\n", rc);
+ goto fail_chg_enable;
+ }
}
}
@@ -2039,6 +2066,10 @@
qpnp_charger_remove(struct spmi_device *spmi)
{
struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
+ if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ && chip->batt_present) {
+ qpnp_adc_tm_disable_chan_meas(&chip->adc_param);
+ }
dev_set_drvdata(&spmi->dev, NULL);
kfree(chip);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 71554ed..9b2f554 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -64,60 +64,6 @@
printk(x); \
} while (0)
-
-static int can_use_cma_pages(struct zone *zone, gfp_t gfp_mask)
-{
- int can_use = 0;
- int mtype = allocflags_to_migratetype(gfp_mask);
- int i = 0;
- int *mtype_fallbacks = get_migratetype_fallbacks(mtype);
-
- if (is_migrate_cma(mtype)) {
- can_use = 1;
- } else {
- for (i = 0;; i++) {
- int fallbacktype = mtype_fallbacks[i];
-
- if (is_migrate_cma(fallbacktype)) {
- can_use = 1;
- break;
- }
-
- if (fallbacktype == MIGRATE_RESERVE)
- break;
- }
- }
- return can_use;
-}
-
-
-static int nr_free_zone_pages(struct zone *zone, gfp_t gfp_mask)
-{
- int sum = zone_page_state(zone, NR_FREE_PAGES);
-
- if (!can_use_cma_pages(zone, gfp_mask))
- sum -= zone_page_state(zone, NR_FREE_CMA_PAGES);
-
- return sum;
-}
-
-
-static int nr_free_pages(gfp_t gfp_mask)
-{
- struct zoneref *z;
- struct zone *zone;
- int sum = 0;
-
- struct zonelist *zonelist = node_zonelist(numa_node_id(), gfp_mask);
-
- for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
- sum += nr_free_zone_pages(zone, gfp_mask);
- }
-
- return sum;
-}
-
-
static int test_task_flag(struct task_struct *p, int flag)
{
struct task_struct *t = p;
@@ -160,15 +106,6 @@
other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM);
- if (nr_to_scan > 0 && other_free > other_file) {
- /*
- * If the number of free pages is going to affect the decision
- * of which process is selected then ensure only free pages
- * which can satisfy the request are considered.
- */
- other_free = nr_free_pages(sc->gfp_mask);
- }
-
if (lowmem_adj_size < array_size)
array_size = lowmem_adj_size;
if (lowmem_minfree_size < array_size)
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index e84220f..c02db14 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -182,6 +182,7 @@
bool thermal_node;
bool low_thr_notify;
bool high_thr_notify;
+ uint32_t scale_type;
};
struct qpnp_adc_tm_drv {
@@ -457,7 +458,7 @@
return rc;
}
-static int32_t qpnp_adc_tm_meas_int_update(uint16_t addr,
+static int32_t qpnp_adc_tm_reg_update(uint16_t addr,
u8 mask, bool state)
{
u8 reg_value = 0;
@@ -484,7 +485,7 @@
return rc;
}
-static int32_t qpnp_adc_tm_usbid_btm_thr_en(uint32_t btm_chan,
+static int32_t qpnp_adc_tm_thr_update(uint32_t btm_chan,
struct qpnp_vadc_chan_properties *chan_prop)
{
int rc = 0;
@@ -519,7 +520,7 @@
if (rc < 0)
pr_err("high threshold msb setting failed\n");
- pr_debug("client requested high:%d and low:%d\n",
+ pr_debug("client requested low:%d and high:%d\n",
chan_prop->low_thr, chan_prop->high_thr);
return rc;
@@ -551,7 +552,7 @@
sensor_mask = 1 << chan_idx;
if (!adc_tm->sensor[chan_idx].thermal_node) {
/* Update low and high notification thresholds */
- rc = qpnp_adc_tm_usbid_btm_thr_en(btm_chan,
+ rc = qpnp_adc_tm_thr_update(btm_chan,
chan_prop);
if (rc < 0) {
pr_err("setting chan:%d threshold failed\n", btm_chan);
@@ -565,7 +566,7 @@
pr_debug("low sensor mask:%x with state:%d\n",
sensor_mask, chan_prop->state_request);
/* Enable low threshold's interrupt */
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
if (rc < 0) {
pr_err("low thr enable err:%d\n", btm_chan);
@@ -579,7 +580,7 @@
ADC_TM_HIGH_LOW_THR_ENABLE)) {
/* Enable high threshold's interrupt */
pr_debug("high sensor mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
if (rc < 0) {
pr_err("high thr enable err:%d\n", btm_chan);
@@ -589,7 +590,7 @@
}
/* Enable corresponding BTM channel measurement */
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
if (rc < 0) {
pr_err("multi measurement en failed\n");
@@ -677,7 +678,7 @@
/* Recurring interval measurement enable */
rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
op_cntrl, true);
if (rc < 0) {
pr_err("adc-tm meas interval op configure failed\n");
@@ -766,7 +767,7 @@
return rc;
}
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("multi measurement update failed\n");
@@ -955,6 +956,47 @@
return 0;
}
+static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
+{
+ /* Battery therm's warm temperature translates to low voltage */
+ if (adc_tm->low_thr_notify) {
+ /* HIGH_STATE = WARM_TEMP for battery client */
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->low_thr_notify = false;
+ }
+
+ /* Battery therm's cool temperature translates to high voltage */
+ if (adc_tm->high_thr_notify) {
+ /* LOW_STATE = COOL_TEMP for battery client */
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->high_thr_notify = false;
+ }
+
+ return;
+}
+
+static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
+{
+ /* For non batt therm clients */
+ if (adc_tm->low_thr_notify) {
+ pr_debug("notify kernel with low state\n");
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->low_thr_notify = false;
+ }
+
+ if (adc_tm->high_thr_notify) {
+ pr_debug("notify kernel with high state\n");
+ adc_tm->btm_param->threshold_notification(
+ ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
+ adc_tm->high_thr_notify = false;
+ }
+
+ return;
+}
+
static void notify_adc_tm_fn(struct work_struct *work)
{
struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
@@ -966,19 +1008,10 @@
pr_debug("notifying uspace client\n");
} else {
if (adc_tm->btm_param->threshold_notification != NULL) {
- if (adc_tm->low_thr_notify) {
- pr_debug("notify kernel with low state\n");
- adc_tm->btm_param->threshold_notification(
- ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
- adc_tm->low_thr_notify = false;
- }
-
- if (adc_tm->high_thr_notify) {
- pr_debug("notify kernel with high state\n");
- adc_tm->btm_param->threshold_notification(
- ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
- adc_tm->high_thr_notify = false;
- }
+ if (adc_tm->scale_type == SCALE_RBATT_THERM)
+ notify_battery_therm(adc_tm);
+ else
+ notify_clients(adc_tm);
}
}
@@ -1008,7 +1041,7 @@
/* low_thr (lower voltage) for higher temp */
thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
low_thr_int_chan_en;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, state);
if (rc)
pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
@@ -1017,7 +1050,7 @@
/* high_thr (higher voltage) for cooler temp */
thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
high_thr_int_chan_en;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, state);
if (rc)
pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
@@ -1090,7 +1123,7 @@
such as usb_id, vbatt, pmic_therm */
sensor_mask = 1 << sensor_num;
pr_debug("non thermal node - mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
@@ -1133,7 +1166,7 @@
such as usb_id, vbatt, pmic_therm */
pr_debug("non thermal node - mask:%x\n", sensor_mask);
sensor_mask = 1 << sensor_num;
- rc = qpnp_adc_tm_meas_int_update(
+ rc = qpnp_adc_tm_reg_update(
QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
@@ -1157,6 +1190,13 @@
}
}
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi meas disable for channel failed\n");
+ goto fail;
+ }
+
rc = qpnp_adc_tm_enable_if_channel_meas();
if (rc < 0) {
pr_err("re-enabling measurement failed\n");
@@ -1315,6 +1355,7 @@
}
adc_tm->sensor[dt_index].btm_param = param;
+ adc_tm->sensor[dt_index].scale_type = scale_type;
fail_unlock:
mutex_unlock(&adc_tm->adc->adc_lock);
@@ -1363,21 +1404,21 @@
btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("low threshold int write failed\n");
goto fail;
}
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("high threshold int enable failed\n");
goto fail;
}
- rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("multi measurement en failed\n");
@@ -1534,6 +1575,8 @@
adc_tm->sensor[sen_idx].vadc_channel_num =
adc_tm->adc->adc_channels[sen_idx].channel_num;
adc_tm->sensor[sen_idx].sensor_num = sen_idx;
+ pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
+ adc_tm->adc->adc_channels[sen_idx].channel_num);
if (thermal_node) {
/* Register with the thermal zone */
pr_debug("thermal node%x\n", btm_channel_num);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 64ef2db..9fad90c 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2086,16 +2086,25 @@
static void dwc3_id_work(struct work_struct *w)
{
struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, id_work);
+ int ret;
/* Give external client a chance to handle */
- if (!mdwc->ext_inuse) {
- if (usb_ext) {
- int ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
- dwc3_ext_notify_online);
- dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
- __func__, ret);
- mdwc->ext_inuse = (ret == 0);
+ if (!mdwc->ext_inuse && usb_ext) {
+ if (mdwc->pmic_id_irq)
+ disable_irq(mdwc->pmic_id_irq);
+
+ ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
+ dwc3_ext_notify_online);
+ dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
+ __func__, ret);
+
+ if (mdwc->pmic_id_irq) {
+ /* ID may have changed while IRQ disabled; update it */
+ mdwc->id_state = !!irq_read_line(mdwc->pmic_id_irq);
+ enable_irq(mdwc->pmic_id_irq);
}
+
+ mdwc->ext_inuse = (ret == 0);
}
if (!mdwc->ext_inuse) { /* notify OTG */
@@ -2107,10 +2116,14 @@
static irqreturn_t dwc3_pmic_id_irq(int irq, void *data)
{
struct dwc3_msm *mdwc = data;
+ enum dwc3_id_state id;
/* If we can't read ID line state for some reason, treat it as float */
- mdwc->id_state = !!irq_read_line(irq);
- queue_work(system_nrt_wq, &mdwc->id_work);
+ id = !!irq_read_line(irq);
+ if (mdwc->id_state != id) {
+ mdwc->id_state = id;
+ queue_work(system_nrt_wq, &mdwc->id_work);
+ }
return IRQ_HANDLED;
}
@@ -2370,7 +2383,7 @@
goto free_hs_ldo_init;
}
- msm->ext_xceiv.id = DWC3_ID_FLOAT;
+ msm->id_state = msm->ext_xceiv.id = DWC3_ID_FLOAT;
msm->ext_xceiv.otg_capability = of_property_read_bool(node,
"qcom,otg-capability");
msm->charger.charging_disabled = of_property_read_bool(node,
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index daf9a26..ca1f817 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -426,6 +426,9 @@
if (!init) {
init = true;
+ if (!work_busy(&dotg->sm_work))
+ schedule_work(&dotg->sm_work);
+
complete(&dotg->dwc3_xcvr_vbus_init);
dev_dbg(phy->dev, "XCVR: BSV init complete\n");
return;
@@ -610,8 +613,11 @@
* driver initialization. Wait for it.
*/
ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5);
- if (!ret)
+ if (!ret) {
dev_err(phy->dev, "%s: completion timeout\n", __func__);
+ /* We can safely assume no cable connected */
+ set_bit(ID, &dotg->inputs);
+ }
ext_xceiv = dotg->ext_xceiv;
dwc3_otg_reset(dotg);
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 52e3126..5a3d753 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -345,6 +345,7 @@
/* MBIM control descriptors */
(struct usb_descriptor_header *) &mbim_control_intf,
(struct usb_descriptor_header *) &mbim_header_desc,
+ (struct usb_descriptor_header *) &mbim_union_desc,
(struct usb_descriptor_header *) &mbb_desc,
(struct usb_descriptor_header *) &ext_mbb_desc,
(struct usb_descriptor_header *) &hs_mbim_notify_desc,
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 4b9dfbf..2dccca8 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -387,7 +387,7 @@
unsigned port_num;
enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
- u8 src_connection_idx, dst_connection_idx;
+ int src_connection_idx = 0, dst_connection_idx = 0;
struct usb_gadget *gadget = dev->cdev->gadget;
pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
@@ -439,7 +439,6 @@
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
- case USB_GADGET_XPORT_BAM:
case USB_GADGET_XPORT_BAM2BAM:
src_connection_idx = usb_bam_get_connection_idx(gadget->name,
A2_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
@@ -451,6 +450,7 @@
gsmd_ctrl_disconnect(&dev->port, port_num);
return ret;
}
+ case USB_GADGET_XPORT_BAM:
ret = gbam_connect(&dev->port, port_num,
dxport, src_connection_idx, dst_connection_idx);
if (ret) {
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index dd41638..c847ee6 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -90,6 +90,8 @@
u32 smp_mb_cnt;
u32 smp_mb_size;
+ u32 rot_block_size;
+
struct mdss_hw_settings *hw_settings;
struct mdss_mdp_pipe *vig_pipes;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 98b99b2..d92422c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -127,6 +127,7 @@
static int mdss_mdp_parse_dt_prop_len(struct platform_device *pdev,
char *prop_name);
static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
+static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
u32 size, u32 *phys, void **virt)
@@ -1100,6 +1101,12 @@
return rc;
}
+ rc = mdss_mdp_parse_dt_misc(pdev);
+ if (rc) {
+ pr_err("Error in device tree : misc\n");
+ return rc;
+ }
+
return 0;
}
@@ -1405,6 +1412,19 @@
return rc;
}
+static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+ u32 data;
+ int rc;
+
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,mdss-rot-block-size",
+ &data);
+ mdata->rot_block_size = (!rc ? data : 128);
+
+ return 0;
+}
+
static int mdss_mdp_parse_dt_handler(struct platform_device *pdev,
char *prop_name, u32 *offsets, int len)
{
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index a89740a..bf78c61 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -164,6 +164,9 @@
#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C
#define MDSS_MDP_REG_SSPP_SRC_FORMAT 0x030
#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034
+#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0 0x050
+#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1 0x054
+#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2 0x058
#define MDSS_MDP_REG_SSPP_SRC_OP_MODE 0x038
#define MDSS_MDP_OP_DEINTERLACE BIT(22)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index c6b6e3f..b7b3c23 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -17,8 +17,6 @@
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
-#define ROT_BLK_SIZE 128
-
enum mdss_mdp_writeback_type {
MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
MDSS_MDP_WRITEBACK_TYPE_LINE,
@@ -251,7 +249,7 @@
pr_debug("rot setup wb_num=%d\n", ctx->wb_num);
ctx->opmode = BIT(6); /* ROT EN */
- if (ROT_BLK_SIZE == 128)
+ if (ctl->mdata->rot_block_size == 128)
ctx->opmode |= BIT(4); /* block size 128 */
ctx->opmode |= rot->bwc_mode;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 0a56ba4..0749f0c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1023,13 +1023,13 @@
if (offset > fbi->fix.smem_len) {
pr_err("invalid fb offset=%u total length=%u\n",
offset, fbi->fix.smem_len);
- return;
+ goto pan_display_error;
}
ret = mdss_mdp_overlay_start(mfd);
if (ret) {
pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
- return;
+ goto pan_display_error;
}
if (is_mdss_iommu_attached())
@@ -1044,18 +1044,18 @@
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
if (ret) {
pr_err("unable to allocate base pipe\n");
- return;
+ goto pan_display_error;
}
if (mdss_mdp_pipe_map(pipe)) {
pr_err("unable to map base pipe\n");
- return;
+ goto pan_display_error;
}
ret = mdss_mdp_pipe_queue_data(pipe, &data);
mdss_mdp_pipe_unmap(pipe);
if (ret) {
pr_err("unable to queue data\n");
- return;
+ goto pan_display_error;
}
if (fbi->var.xres > MAX_MIXER_WIDTH || mfd->split_display) {
@@ -1063,17 +1063,17 @@
MDSS_MDP_MIXER_MUX_RIGHT);
if (ret) {
pr_err("unable to allocate right base pipe\n");
- return;
+ goto pan_display_error;
}
if (mdss_mdp_pipe_map(pipe)) {
pr_err("unable to map right base pipe\n");
- return;
+ goto pan_display_error;
}
ret = mdss_mdp_pipe_queue_data(pipe, &data);
mdss_mdp_pipe_unmap(pipe);
if (ret) {
pr_err("unable to queue right data\n");
- return;
+ goto pan_display_error;
}
}
mutex_unlock(&mfd->ov_lock);
@@ -1081,6 +1081,10 @@
if ((fbi->var.activate & FB_ACTIVATE_VBL) ||
(fbi->var.activate & FB_ACTIVATE_FORCE))
mdss_mdp_overlay_kickoff(mfd->ctl);
+ return;
+
+pan_display_error:
+ mutex_unlock(&mfd->ov_lock);
}
/* function is called in irq context should have minimum processing */
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 7ff6414..ca741b1 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -19,7 +19,9 @@
#include "mdss_mdp.h"
-#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
+#define SMP_MB_SIZE (mdss_res->smp_mb_size)
+#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
+#define SMP_ENTRIES_PER_MB (SMP_MB_SIZE / 16)
static DEFINE_MUTEX(mdss_mdp_sspp_lock);
static DEFINE_MUTEX(mdss_mdp_smp_lock);
@@ -29,6 +31,17 @@
u32 ndx);
static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe);
+static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
+ u32 reg, u32 val)
+{
+ writel_relaxed(val, pipe->base + reg);
+}
+
+static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
+{
+ return readl_relaxed(pipe->base + reg);
+}
+
static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
{
u32 i, mmb;
@@ -45,9 +58,10 @@
return i;
}
-static void mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
+static int mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
{
u32 mmb, off, data, s;
+ int cnt = 0;
for_each_set_bit(mmb, smp, SMP_MB_CNT) {
off = (mmb / 3) * 4;
@@ -57,7 +71,9 @@
data |= client_id << s;
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_W0 + off, data);
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_R0 + off, data);
+ cnt++;
}
+ return cnt;
}
static void mdss_mdp_smp_mmb_free(unsigned long *smp)
@@ -70,6 +86,24 @@
}
}
+static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt)
+{
+ u32 entries, val, wm[3];
+
+ entries = mb_cnt * SMP_ENTRIES_PER_MB;
+ val = entries >> 2;
+
+ wm[0] = val;
+ wm[1] = wm[0] + val;
+ wm[2] = wm[1] + val;
+
+ pr_debug("pnum=%d watermarks %u,%u,%u\n", pipe->num,
+ wm[0], wm[1], wm[2]);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0, wm[0]);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1, wm[1]);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2, wm[2]);
+}
+
static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
{
mutex_lock(&mdss_mdp_smp_lock);
@@ -103,8 +137,7 @@
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < ps.num_planes; i++) {
- num_blks = DIV_ROUND_UP(2 * ps.ystride[i],
- mdss_res->smp_mb_size);
+ num_blks = DIV_ROUND_UP(2 * ps.ystride[i], SMP_MB_SIZE);
if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
num_blks = roundup_pow_of_two(num_blks);
@@ -131,9 +164,12 @@
static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
{
int i;
+ int cnt = 0;
+
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < MAX_PLANES; i++)
- mdss_mdp_smp_mmb_set(pipe->ftch_id + i, &pipe->smp[i]);
+ cnt += mdss_mdp_smp_mmb_set(pipe->ftch_id + i, &pipe->smp[i]);
+ mdss_mdp_smp_set_wm_levels(pipe, cnt);
mutex_unlock(&mdss_mdp_smp_lock);
return 0;
}
@@ -327,17 +363,6 @@
}
-static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
- u32 reg, u32 val)
-{
- writel_relaxed(val, pipe->base + reg);
-}
-
-static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
-{
- return readl_relaxed(pipe->base + reg);
-}
-
static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
{
u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index d208f1e..7939832 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -26,6 +26,7 @@
#define UART_MODE 4
#define SOCKET_MODE 5
#define CALLBACK_MODE 6
+#define MEMORY_DEVICE_MODE_NRT 7
/* different values that go in for diag_data_type */
#define DATA_TYPE_EVENT 0
#define DATA_TYPE_F3 1
diff --git a/include/linux/ion.h b/include/linux/ion.h
index fb1c5f6..7c54004 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -59,6 +59,9 @@
cached, ion will do cache
maintenance when the buffer is
mapped for dma */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created
+ at mmap time, if this is set
+ caches must be managed manually */
#ifdef __KERNEL__
#include <linux/err.h>
@@ -606,6 +609,16 @@
#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
/**
+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
+ *
+ * Deprecated in favor of using the dma_buf api's correctly (syncing
+ * will happend automatically when the buffer is mapped to a device).
+ * If necessary should be used after touching a cached buffer from the cpu,
+ * this will make the buffer in memory coherent.
+ */
+#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+
+/**
* DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
*
* Takes the argument of the architecture specific ioctl to call and
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 9461c76..5e6a8c3 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -46,6 +46,14 @@
* @ocv_dis_low_soc: the low soc percent when ocv should be enabled
* @low_voltage_detect: feature to enable 0 SOC reporting on low volatge
* @vbatt_cutoff_retries: number of tries before we report a 0 SOC
+ * @high_ocv_correction_limit_uv: the max amount of OCV corrections
+ * allowed when ocv is high
+ * (higher than 3.8V)
+ * @low_ocv_correction_limit_uv: the max amount of OCV corrections
+ * allowed when ocv is low
+ * (lower or equal to 3.8V)
+ * @hold_soc_est: the min est soc below which the calculated soc
+ * is allowed to go to 0%
*/
struct pm8921_bms_platform_data {
struct pm8xxx_bms_core_data bms_cdata;
@@ -69,6 +77,9 @@
int ocv_dis_low_soc;
int low_voltage_detect;
int vbatt_cutoff_retries;
+ int high_ocv_correction_limit_uv;
+ int low_ocv_correction_limit_uv;
+ int hold_soc_est;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca7a586..5dc65bd 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -61,14 +61,6 @@
MIGRATE_TYPES
};
-/*
- * Returns a list which contains the migrate types on to which
- * an allocation falls back when the free list for the migrate
- * type mtype is depleted.
- * The end of the list is delimited by the type MIGRATE_RESERVE.
- */
-extern int *get_migratetype_fallbacks(int mtype);
-
#ifdef CONFIG_CMA
bool is_cma_pageblock(struct page *page);
# define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 646c22e..3d159c4 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -57,7 +57,8 @@
struct msm_spk_prot_cfg)
#define AUDIO_GET_SPEAKER_PROT _IOR(AUDIO_IOCTL_MAGIC, 26, \
struct msm_spk_prot_status)
-
+#define AUDIO_SET_AANC_CAL _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+27), unsigned)
#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+30)
/* ACDB structures */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0ab5143..84e099d 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1704,9 +1704,14 @@
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -1715,6 +1720,11 @@
NL80211_RATE_INFO_MCS,
NL80211_RATE_INFO_40_MHZ_WIDTH,
NL80211_RATE_INFO_SHORT_GI,
+ NL80211_RATE_INFO_VHT_MCS,
+ NL80211_RATE_INFO_VHT_NSS,
+ NL80211_RATE_INFO_80_MHZ_WIDTH,
+ NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+ NL80211_RATE_INFO_160_MHZ_WIDTH,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index a853aff..fc6ab91 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -637,34 +637,48 @@
* enum qpnp_tm_state - This lets the client know whether the threshold
* that was crossed was high/low.
* %ADC_TM_HIGH_STATE: Client is notified of crossing the requested high
- * threshold.
+ * voltage threshold.
+ * %ADC_TM_COOL_STATE: Client is notified of crossing the requested cool
+ * temperature threshold.
* %ADC_TM_LOW_STATE: Client is notified of crossing the requested low
- * threshold.
+ * voltage threshold.
+ * %ADC_TM_WARM_STATE: Client is notified of crossing the requested high
+ * temperature threshold.
*/
enum qpnp_tm_state {
ADC_TM_HIGH_STATE = 0,
+ ADC_TM_COOL_STATE = ADC_TM_HIGH_STATE,
ADC_TM_LOW_STATE,
+ ADC_TM_WARM_STATE = ADC_TM_LOW_STATE,
ADC_TM_STATE_NUM,
};
/**
* enum qpnp_state_request - Request to enable/disable the corresponding
* high/low voltage/temperature thresholds.
- * %ADC_TM_HIGH_THR_ENABLE: Enable high voltage/temperature threshold.
+ * %ADC_TM_HIGH_THR_ENABLE: Enable high voltage threshold.
+ * %ADC_TM_COOL_THR_ENABLE = Enables cool temperature threshold.
* %ADC_TM_LOW_THR_ENABLE: Enable low voltage/temperature threshold.
+ * %ADC_TM_WARM_THR_ENABLE = Enables warm temperature threshold.
* %ADC_TM_HIGH_LOW_THR_ENABLE: Enable high and low voltage/temperature
* threshold.
* %ADC_TM_HIGH_THR_DISABLE: Disable high voltage/temperature threshold.
+ * %ADC_TM_COOL_THR_ENABLE = Disables cool temperature threshold.
* %ADC_TM_LOW_THR_DISABLE: Disable low voltage/temperature threshold.
+ * %ADC_TM_WARM_THR_ENABLE = Disables warm temperature threshold.
* %ADC_TM_HIGH_THR_DISABLE: Disable high and low voltage/temperature
* threshold.
*/
enum qpnp_state_request {
ADC_TM_HIGH_THR_ENABLE = 0,
+ ADC_TM_COOL_THR_ENABLE = ADC_TM_HIGH_THR_ENABLE,
ADC_TM_LOW_THR_ENABLE,
+ ADC_TM_WARM_THR_ENABLE = ADC_TM_LOW_THR_ENABLE,
ADC_TM_HIGH_LOW_THR_ENABLE,
ADC_TM_HIGH_THR_DISABLE,
+ ADC_TM_COOL_THR_DISABLE = ADC_TM_HIGH_THR_DISABLE,
ADC_TM_LOW_THR_DISABLE,
+ ADC_TM_WARM_THR_DISABLE = ADC_TM_LOW_THR_DISABLE,
ADC_TM_HIGH_LOW_THR_DISABLE,
ADC_TM_THR_NUM,
};
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
new file mode 100644
index 0000000..538ad15
--- /dev/null
+++ b/include/linux/regulator/cpr-regulator.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __REGULATOR_CPR_REGULATOR_H__
+#define __REGULATOR_CPR_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+#define CPR_REGULATOR_DRIVER_NAME "qcom,cpr-regulator"
+
+#define CPR_PVS_EFUSE_BITS_MAX 5
+#define CPR_PVS_EFUSE_BINS_MAX (1 << CPR_PVS_EFUSE_BITS_MAX)
+
+/**
+ * enum cpr_corner_enum - CPR corner enum values
+ * %CPR_CORNER_SVS: Lowest voltage for APC
+ * %CPR_CORNER_NORMAL: Normal mode voltage
+ * %CPR_CORNER_TURBO: Turbo mode voltage
+ * %CPR_CORNER_SUPER_TURBO: Super Turbo mode voltage
+ *
+ * These should be used in regulator_set_voltage() for CPR
+ * regulator as if they had units of uV.
+ */
+enum cpr_corner_enum {
+ CPR_CORNER_SVS = 1,
+ CPR_CORNER_NORMAL,
+ CPR_CORNER_TURBO,
+ CPR_CORNER_SUPER_TURBO,
+ CPR_CORNER_MAX,
+};
+
+/**
+ * enum pvs_process_enum - PVS process enum values
+ * %APC_PVS_NO: No PVS
+ * %APC_PVS_SLOW: Slow PVS process
+ * %APC_PVS_NOM: Nominal PVS process
+ * %APC_PVS_FAST: Fast PVS process
+ */
+enum apc_pvs_process_enum {
+ APC_PVS_NO,
+ APC_PVS_SLOW,
+ APC_PVS_NOM,
+ APC_PVS_FAST,
+ NUM_APC_PVS,
+};
+
+#ifdef CONFIG_MSM_CPR_REGULATOR
+
+int __init cpr_regulator_init(void);
+
+#else
+
+static inline int __init cpr_regulator_init(void)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_MSM_CPR_REGULATOR */
+
+#endif /* __REGULATOR_CPR_REGULATOR_H__ */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 52811ae..bfa0eca 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -578,14 +578,24 @@
* Used by the driver to indicate the specific rate transmission
* type for 802.11n transmissions.
*
- * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
- * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
+ * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
+ * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
+ * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
+ * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
+ * @RATE_INFO_FLAGS_60G: 60GHz MCS
*/
enum rate_info_flags {
- RATE_INFO_FLAGS_MCS = 1<<0,
- RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1,
- RATE_INFO_FLAGS_SHORT_GI = 1<<2,
+ RATE_INFO_FLAGS_MCS = BIT(0),
+ RATE_INFO_FLAGS_VHT_MCS = BIT(1),
+ RATE_INFO_FLAGS_40_MHZ_WIDTH = BIT(2),
+ RATE_INFO_FLAGS_80_MHZ_WIDTH = BIT(3),
+ RATE_INFO_FLAGS_80P80_MHZ_WIDTH = BIT(4),
+ RATE_INFO_FLAGS_160_MHZ_WIDTH = BIT(5),
+ RATE_INFO_FLAGS_SHORT_GI = BIT(6),
+ RATE_INFO_FLAGS_60G = BIT(7),
};
/**
@@ -596,11 +606,13 @@
* @flags: bitflag of flags from &enum rate_info_flags
* @mcs: mcs index if struct describes a 802.11n bitrate
* @legacy: bitrate in 100kbit/s for 802.11abg
+ * @nss: number of streams (VHT only)
*/
struct rate_info {
u8 flags;
u8 mcs;
u16 legacy;
+ u8 nss;
};
/**
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1484f16..04e683f 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6515,6 +6515,54 @@
#define AFE_MAX_CDC_REGISTERS_TO_CONFIG (20)
+/* AANC Port Config Specific */
+#define AFE_PARAM_ID_AANC_PORT_CONFIG (0x00010215)
+#define AFE_API_VERSION_AANC_PORT_CONFIG (0x1)
+#define AANC_TX_MIC_UNUSED (0)
+#define AANC_TX_VOICE_MIC (1)
+#define AANC_TX_ERROR_MIC (2)
+#define AANC_TX_NOISE_MIC (3)
+#define AFE_PORT_MAX_CHANNEL_CNT (8)
+#define AFE_MODULE_AANC (0x00010214)
+#define AFE_PARAM_ID_CDC_AANC_VERSION (0x0001023A)
+#define AFE_API_VERSION_CDC_AANC_VERSION (0x1)
+#define AANC_HW_BLOCK_VERSION_1 (1)
+#define AANC_HW_BLOCK_VERSION_2 (2)
+
+struct afe_param_aanc_port_cfg {
+ /* Minor version used for tracking the version of the module's
+ * source port configuration.
+ */
+ uint32_t aanc_port_cfg_minor_version;
+
+ /* Sampling rate of the source Tx port. 8k - 192k*/
+ uint32_t tx_port_sample_rate;
+
+ /* Channel mapping for the Tx port signal carrying Noise (X),
+ * Error (E), and Voice (V) signals.
+ */
+ uint8_t tx_port_channel_map[AFE_PORT_MAX_CHANNEL_CNT];
+
+ /* Number of channels on the source Tx port. */
+ uint16_t tx_port_num_channels;
+
+ /* Port ID of the Rx path reference signal. */
+ uint16_t rx_path_ref_port_id;
+
+ /* Sampling rate of the reference port. 8k - 192k*/
+ uint32_t ref_port_sample_rate;
+} __packed;
+
+struct afe_param_id_cdc_aanc_version {
+ /* Minor version used for tracking the version of the module's
+ * hw version
+ */
+ uint32_t cdc_aanc_minor_version;
+
+ /* HW version. */
+ uint32_t aanc_hw_version;
+} __packed;
+
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
@@ -6746,6 +6794,7 @@
AFE_SLIMBUS_SLAVE_PORT_CONFIG,
AFE_SLIMBUS_SLAVE_CONFIG,
AFE_CDC_REGISTERS_CONFIG,
+ AFE_AANC_VERSION,
AFE_MAX_CONFIG_TYPES,
};
@@ -6842,4 +6891,26 @@
struct afe_param_cdc_slimbus_slave_cfg sb_slave_cfg;
} __packed;
+struct afe_svc_cmd_cdc_aanc_version {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_cdc_aanc_version version;
+} __packed;
+
+struct afe_port_cmd_set_aanc_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ union {
+ struct afe_param_aanc_port_cfg aanc_port_cfg;
+ struct afe_mod_enable_param mod_enable;
+ } __packed data;
+} __packed;
+
+struct afe_port_cmd_set_aanc_acdb_table {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+} __packed;
+
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 22ddbbc..9c86e1d 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -127,6 +127,14 @@
uint32_t mem_map_handle;
};
+struct aanc_data {
+ bool aanc_active;
+ uint16_t aanc_rx_port;
+ uint16_t aanc_tx_port;
+ uint32_t aanc_rx_port_sample_rate;
+ uint32_t aanc_tx_port_sample_rate;
+};
+
int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
int afe_close(int port_id);
int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
@@ -188,4 +196,5 @@
int afe_set_config(enum afe_config_type config_type, void *config_data,
int arg);
+void afe_set_aanc_info(struct aanc_data *aanc_info);
#endif /* __Q6AFE_V2_H__ */
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d6dd07a..b179e71 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -926,11 +926,6 @@
[MIGRATE_ISOLATE] = { MIGRATE_RESERVE }, /* Never used */
};
-int *get_migratetype_fallbacks(int mtype)
-{
- return fallbacks[mtype];
-}
-
/*
* Move the free pages in a range to the free lists of the requested type.
* Note that start_page and end_pages are not aligned on a pageblock
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 5063fa3..8861f91 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -145,6 +145,12 @@
{
struct fib_info *fi = container_of(head, struct fib_info, rcu);
+ change_nexthops(fi) {
+ if (nexthop_nh->nh_dev)
+ dev_put(nexthop_nh->nh_dev);
+ } endfor_nexthops(fi);
+
+ release_net(fi->fib_net);
if (fi->fib_metrics != (u32 *) dst_default_metrics)
kfree(fi->fib_metrics);
kfree(fi);
@@ -156,13 +162,7 @@
pr_warn("Freeing alive fib_info %p\n", fi);
return;
}
- change_nexthops(fi) {
- if (nexthop_nh->nh_dev)
- dev_put(nexthop_nh->nh_dev);
- nexthop_nh->nh_dev = NULL;
- } endfor_nexthops(fi);
fib_info_cnt--;
- release_net(fi->fib_net);
call_rcu(&fi->rcu, free_fib_info_rcu);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 69318b0..5097036 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2384,25 +2384,46 @@
rate = nla_nest_start(msg, attr);
if (!rate)
- goto nla_put_failure;
+ return false;
/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
bitrate = cfg80211_calculate_bitrate(info);
if (bitrate > 0)
- NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
+ nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
- if (info->flags & RATE_INFO_FLAGS_MCS)
- NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
- if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
- if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
+ if (info->flags & RATE_INFO_FLAGS_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+ return false;
+ } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
+ return false;
+ if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
+ nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+ return false;
+ }
nla_nest_end(msg, rate);
return true;
-
-nla_put_failure:
- return false;
}
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 017d4fc..b89fb94 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -876,13 +876,86 @@
return err;
}
+static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
+{
+ static const u32 base[4][10] = {
+ { 6500000,
+ 13000000,
+ 19500000,
+ 26000000,
+ 39000000,
+ 52000000,
+ 58500000,
+ 65000000,
+ 78000000,
+ 0,
+ },
+ { 13500000,
+ 27000000,
+ 40500000,
+ 54000000,
+ 81000000,
+ 108000000,
+ 121500000,
+ 135000000,
+ 162000000,
+ 180000000,
+ },
+ { 29300000,
+ 58500000,
+ 87800000,
+ 117000000,
+ 175500000,
+ 234000000,
+ 263300000,
+ 292500000,
+ 351000000,
+ 390000000,
+ },
+ { 58500000,
+ 117000000,
+ 175500000,
+ 234000000,
+ 351000000,
+ 468000000,
+ 526500000,
+ 585000000,
+ 702000000,
+ 780000000,
+ },
+ };
+ u32 bitrate;
+ int idx;
+
+ if (WARN_ON_ONCE(rate->mcs > 9))
+ return 0;
+
+ idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
+ RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
+ rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
+ rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+
+ bitrate = base[idx][rate->mcs];
+ bitrate *= rate->nss;
+
+ if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+ bitrate = (bitrate / 9) * 10;
+
+ /* do NOT round down here */
+ return (bitrate + 50000) / 100000;
+}
+
u16 cfg80211_calculate_bitrate(struct rate_info *rate)
{
int modulation, streams, bitrate;
- if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+ if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+ !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
return rate->legacy;
+ if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
+ return cfg80211_calculate_bitrate_vht(rate);
+
/* the formula below does only work for MCS values smaller than 32 */
if (rate->mcs >= 32)
return 0;
diff --git a/scripts/build-all.py b/scripts/build-all.py
index 4789af7..3cecbe2 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -88,6 +88,7 @@
r'[fm]sm[0-9]*_defconfig',
r'apq*_defconfig',
r'qsd*_defconfig',
+ r'msmzinc*_defconfig',
)
for p in arch_pats:
for n in glob.glob('arch/arm/configs/' + p):
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 634493b..ca8cfaa 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -2135,12 +2135,12 @@
dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
if (w->shift == 5) {
- e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
- e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
- req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
- } else if (w->shift == 4) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
+ } else if (w->shift == 4) {
+ e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
+ e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
} else {
pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 80738ba..5f4490b 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -99,10 +99,17 @@
SB_PGD_PORT_TX_ENABLE_n,
SB_PGD_PORT_RX_WATERMARK_n,
SB_PGD_PORT_RX_ENABLE_n,
+ SB_PGD_TX_PORTn_MULTI_CHNL_0,
+ SB_PGD_TX_PORTn_MULTI_CHNL_1,
+ SB_PGD_RX_PORTn_MULTI_CHNL_0,
+ SB_PGD_RX_PORTn_MULTI_CHNL_1,
+ AANC_FF_GAIN_ADAPTIVE,
+ AANC_FFGAIN_ADAPTIVE_EN,
+ AANC_GAIN_CONTROL,
MAX_CFG_REGISTERS,
};
-static struct afe_param_cdc_reg_cfg mad_audio_reg_cfg[] = {
+static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_MAIN_CTL_1),
@@ -157,12 +164,30 @@
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
- }
+ },
+ { 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_IIR_B1_CTL),
+ AANC_FF_GAIN_ADAPTIVE, 0x4, 8, 0
+ },
+ { 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_IIR_B1_CTL),
+ AANC_FFGAIN_ADAPTIVE_EN, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_GAIN_CTL),
+ AANC_GAIN_CONTROL, 0xFF, 8, 0
+ },
};
-static struct afe_param_cdc_reg_cfg_data taiko_mad_audio_reg_cfg = {
- .num_registers = ARRAY_SIZE(mad_audio_reg_cfg),
- .reg_data = mad_audio_reg_cfg,
+static struct afe_param_cdc_reg_cfg_data taiko_audio_reg_cfg = {
+ .num_registers = ARRAY_SIZE(audio_reg_cfg),
+ .reg_data = audio_reg_cfg,
+};
+
+static struct afe_param_id_cdc_aanc_version taiko_cdc_aanc_version = {
+ .cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
+ .aanc_hw_version = AANC_HW_BLOCK_VERSION_2,
};
module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
@@ -556,55 +581,6 @@
return 0;
}
-static int taiko_pa_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 ear_pa_gain;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- ear_pa_gain = snd_soc_read(codec, TAIKO_A_RX_EAR_GAIN);
-
- ear_pa_gain = ear_pa_gain >> 5;
-
- if (ear_pa_gain == 0x00) {
- ucontrol->value.integer.value[0] = 0;
- } else if (ear_pa_gain == 0x04) {
- ucontrol->value.integer.value[0] = 1;
- } else {
- pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
- __func__, ear_pa_gain);
- return -EINVAL;
- }
-
- pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
-
- return 0;
-}
-
-static int taiko_pa_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 ear_pa_gain;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
- ucontrol->value.integer.value[0]);
-
- switch (ucontrol->value.integer.value[0]) {
- case 0:
- ear_pa_gain = 0x00;
- break;
- case 1:
- ear_pa_gain = 0x80;
- break;
- default:
- return -EINVAL;
- }
-
- snd_soc_update_bits(codec, TAIKO_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
- return 0;
-}
-
static int taiko_get_iir_enable_audio_mixer(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -961,10 +937,7 @@
return 0;
}
-static const char * const taiko_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
-static const struct soc_enum taiko_ear_pa_gain_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, taiko_ear_pa_gain_text),
-};
+
static const char *const taiko_anc_func_text[] = {"OFF", "ON"};
static const struct soc_enum taiko_anc_func_enum =
@@ -1044,26 +1017,6 @@
static const struct snd_kcontrol_new taiko_snd_controls[] = {
- SOC_ENUM_EXT("EAR PA Gain", taiko_ear_pa_gain_enum[0],
- taiko_pa_gain_get, taiko_pa_gain_put),
-
- SOC_SINGLE_TLV("LINEOUT1 Volume", TAIKO_A_RX_LINE_1_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("LINEOUT2 Volume", TAIKO_A_RX_LINE_2_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("LINEOUT3 Volume", TAIKO_A_RX_LINE_3_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("LINEOUT4 Volume", TAIKO_A_RX_LINE_4_GAIN, 0, 12, 1,
- line_gain),
-
- SOC_SINGLE_TLV("HPHL Volume", TAIKO_A_RX_HPH_L_GAIN, 0, 12, 1,
- line_gain),
- SOC_SINGLE_TLV("HPHR Volume", TAIKO_A_RX_HPH_R_GAIN, 0, 12, 1,
- line_gain),
-
- SOC_SINGLE_TLV("SPK DRV Volume", TAIKO_A_SPKR_DRV_GAIN, 3, 7, 1,
- line_gain),
-
SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL,
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -1099,6 +1052,7 @@
digital_gain),
SOC_SINGLE_S8_TLV("DEC10 Volume", TAIKO_A_CDC_TX10_VOL_CTL_GAIN, -84,
40, digital_gain),
+
SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAIKO_A_CDC_IIR1_GAIN_B1_CTL, -84,
40, digital_gain),
SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TAIKO_A_CDC_IIR1_GAIN_B2_CTL, -84,
@@ -1107,17 +1061,12 @@
40, digital_gain),
SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAIKO_A_CDC_IIR1_GAIN_B4_CTL, -84,
40, digital_gain),
- SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_TX_1_2_EN, 5, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_TX_1_2_EN, 1, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_TX_3_4_EN, 5, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_TX_3_4_EN, 1, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
- SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, taiko_get_anc_slot,
taiko_put_anc_slot),
SOC_ENUM_EXT("ANC Function", taiko_anc_func_enum, taiko_get_anc_func,
taiko_put_anc_func),
+
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -1207,6 +1156,122 @@
};
+static int taiko_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ ear_pa_gain = snd_soc_read(codec, TAIKO_A_RX_EAR_GAIN);
+
+ ear_pa_gain = ear_pa_gain >> 5;
+
+ ucontrol->value.integer.value[0] = ear_pa_gain;
+
+ pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+
+ return 0;
+}
+
+static int taiko_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ ear_pa_gain = ucontrol->value.integer.value[0] << 5;
+
+ snd_soc_update_bits(codec, TAIKO_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
+ return 0;
+}
+
+static const char * const taiko_1_x_ear_pa_gain_text[] = {
+ "POS_6_DB", "UNDEFINED_1", "UNDEFINED_2", "UNDEFINED_3", "POS_2_DB",
+ "NEG_2P5_DB", "UNDEFINED_4", "NEG_12_DB"
+};
+
+static const struct soc_enum taiko_1_x_ear_pa_gain_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(taiko_1_x_ear_pa_gain_text),
+ taiko_1_x_ear_pa_gain_text);
+
+static const struct snd_kcontrol_new taiko_1_x_analog_gain_controls[] = {
+
+ SOC_ENUM_EXT("EAR PA Gain", taiko_1_x_ear_pa_gain_enum,
+ taiko_pa_gain_get, taiko_pa_gain_put),
+
+ SOC_SINGLE_TLV("HPHL Volume", TAIKO_A_RX_HPH_L_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", TAIKO_A_RX_HPH_R_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAIKO_A_RX_LINE_1_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAIKO_A_RX_LINE_2_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT3 Volume", TAIKO_A_RX_LINE_3_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT4 Volume", TAIKO_A_RX_LINE_4_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("SPK DRV Volume", TAIKO_A_SPKR_DRV_GAIN, 3, 7, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_TX_1_2_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_TX_3_4_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_TX_3_4_EN, 1, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
+};
+
+static const char * const taiko_2_x_ear_pa_gain_text[] = {
+ "POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB",
+ "POS_0_DB", "NEG_2P5_DB", "UNDEFINED", "NEG_12_DB"
+};
+
+static const struct soc_enum taiko_2_x_ear_pa_gain_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(taiko_2_x_ear_pa_gain_text),
+ taiko_2_x_ear_pa_gain_text);
+
+static const struct snd_kcontrol_new taiko_2_x_analog_gain_controls[] = {
+
+ SOC_ENUM_EXT("EAR PA Gain", taiko_2_x_ear_pa_gain_enum,
+ taiko_pa_gain_get, taiko_pa_gain_put),
+
+ SOC_SINGLE_TLV("HPHL Volume", TAIKO_A_RX_HPH_L_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", TAIKO_A_RX_HPH_R_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAIKO_A_RX_LINE_1_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAIKO_A_RX_LINE_2_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT3 Volume", TAIKO_A_RX_LINE_3_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT4 Volume", TAIKO_A_RX_LINE_4_GAIN, 0, 20, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("SPK DRV Volume", TAIKO_A_SPKR_DRV_GAIN, 3, 8, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_CDC_TX_1_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_CDC_TX_2_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_CDC_TX_3_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_CDC_TX_4_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_CDC_TX_5_GAIN, 2, 19, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_CDC_TX_6_GAIN, 2, 19, 0,
+ analog_gain),
+};
+
static const char * const rx_mix1_text[] = {
"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
"RX5", "RX6", "RX7"
@@ -3581,8 +3646,8 @@
return 1;
}
- for (i = 0; i < ARRAY_SIZE(mad_audio_reg_cfg); i++)
- if (mad_audio_reg_cfg[i].reg_logical_addr -
+ for (i = 0; i < ARRAY_SIZE(audio_reg_cfg); i++)
+ if (audio_reg_cfg[i].reg_logical_addr -
TAIKO_REGISTER_START_OFFSET == reg)
return 1;
@@ -3869,7 +3934,7 @@
taiko->comp_fs[comp_rx_path[j]]
= compander_fs;
}
- if (j <= 2)
+ if (j < 2)
rx_mix_1_reg_1 += 3;
else
rx_mix_1_reg_1 += 2;
@@ -5420,6 +5485,12 @@
TAIKO_REG_VAL(TAIKO_A_CDC_TX9_MUX_CTL, 0x48),
TAIKO_REG_VAL(TAIKO_A_CDC_TX10_MUX_CTL, 0x48),
TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX3_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX4_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B4_CTL, 0x8),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B4_CTL, 0x8),
TAIKO_REG_VAL(TAIKO_A_CDC_VBAT_GAIN_UPD_MON, 0x0),
TAIKO_REG_VAL(TAIKO_A_CDC_PA_RAMP_B1_CTL, 0x0),
TAIKO_REG_VAL(TAIKO_A_CDC_PA_RAMP_B2_CTL, 0x0),
@@ -5632,9 +5703,11 @@
case AFE_SLIMBUS_SLAVE_CONFIG:
return &priv->slimbus_slave_cfg;
case AFE_CDC_REGISTERS_CONFIG:
- return &taiko_mad_audio_reg_cfg;
+ return &taiko_audio_reg_cfg;
case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
return &taiko_slimbus_slave_port_cfg;
+ case AFE_AANC_VERSION:
+ return &taiko_cdc_aanc_version;
default:
pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
return NULL;
@@ -5843,12 +5916,19 @@
taiko_init_slim_slave_cfg(codec);
}
- if (TAIKO_IS_1_0(control->version))
+ if (TAIKO_IS_1_0(control->version)) {
snd_soc_dapm_new_controls(dapm, taiko_1_dapm_widgets,
ARRAY_SIZE(taiko_1_dapm_widgets));
- else
+ snd_soc_add_codec_controls(codec,
+ taiko_1_x_analog_gain_controls,
+ ARRAY_SIZE(taiko_1_x_analog_gain_controls));
+ } else {
snd_soc_dapm_new_controls(dapm, taiko_2_dapm_widgets,
ARRAY_SIZE(taiko_2_dapm_widgets));
+ snd_soc_add_codec_controls(codec,
+ taiko_2_x_analog_gain_controls,
+ ARRAY_SIZE(taiko_2_x_analog_gain_controls));
+ }
control->num_rx_port = TAIKO_RX_MAX;
control->rx_chs = ptr;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 5b54e1b..764f4c6 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -3018,14 +3018,19 @@
switch (event) {
case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
ret = MBHC_MICBIAS1;
+ break;
case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
ret = MBHC_MICBIAS2;
+ break;
case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
ret = MBHC_MICBIAS3;
+ break;
case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
ret = MBHC_MICBIAS4;
+ break;
default:
ret = MBHC_MICBIAS_INVALID;
+ break;
}
return ret;
}
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 4dc6505..b97d9dc 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -772,20 +772,19 @@
.codec_name = "snd-soc-dummy",
},
{
- .name = "VoLTE",
- .stream_name = "VoLTE",
- .cpu_dai_name = "VoLTE",
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
- .be_id = MSM_FRONTEND_DAI_VOLTE,
},
{
.name = "MSM8226 LowLatency",
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 8c0d1a9..65b3a57 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -746,21 +746,21 @@
btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
btn_low[0] = -50;
- btn_high[0] = 10;
- btn_low[1] = 11;
- btn_high[1] = 52;
- btn_low[2] = 53;
- btn_high[2] = 94;
- btn_low[3] = 95;
- btn_high[3] = 133;
- btn_low[4] = 134;
- btn_high[4] = 171;
- btn_low[5] = 172;
- btn_high[5] = 208;
- btn_low[6] = 209;
- btn_high[6] = 244;
- btn_low[7] = 245;
- btn_high[7] = 330;
+ btn_high[0] = 21;
+ btn_low[1] = 22;
+ btn_high[1] = 67;
+ btn_low[2] = 68;
+ btn_high[2] = 111;
+ btn_low[3] = 112;
+ btn_high[3] = 153;
+ btn_low[4] = 154;
+ btn_high[4] = 191;
+ btn_low[5] = 192;
+ btn_high[5] = 233;
+ btn_low[6] = 234;
+ btn_high[6] = 272;
+ btn_low[7] = 273;
+ btn_high[7] = 400;
n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
n_ready[0] = 80;
n_ready[1] = 68;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 50a0113..30e9629 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -44,6 +44,7 @@
#define BTSCO_RATE_16KHZ 16000
static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
#define SAMPLING_RATE_48KHZ 48000
#define SAMPLING_RATE_96KHZ 96000
@@ -733,6 +734,46 @@
return 0;
}
+static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (hdmi_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -840,6 +881,8 @@
pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
channels->min, channels->max);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ hdmi_rx_bit_format);
if (channels->max < 2)
channels->min = channels->max = 2;
rate->min = rate->max = 48000;
@@ -1067,6 +1110,8 @@
slim0_rx_bit_format_get, slim0_rx_bit_format_put),
SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
+ hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
};
static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
@@ -1154,6 +1199,14 @@
return err;
}
+ config_data = taiko_get_afe_config(codec, AFE_AANC_VERSION);
+ err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, err);
+ return err;
+ }
+
/* start mbhc */
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration)
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 259f3ed..16d6e81 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -42,6 +42,9 @@
/* ANC Cal */
struct acdb_atomic_cal_block anc_cal;
+ /* AANC Cal */
+ struct acdb_atomic_cal_block aanc_cal;
+
/* LSM Cal */
struct acdb_atomic_cal_block lsm_cal;
@@ -252,6 +255,46 @@
atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
}
+void get_aanc_cal(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ cal_block->cal_size =
+ atomic_read(&acdb_data.aanc_cal.cal_size);
+ cal_block->cal_paddr =
+ atomic_read(&acdb_data.aanc_cal.cal_paddr);
+ cal_block->cal_kvaddr =
+ atomic_read(&acdb_data.aanc_cal.cal_kvaddr);
+done:
+ return;
+}
+
+void store_aanc_cal(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ (long)atomic64_read(&acdb_data.mem_len));
+ goto done;
+ }
+
+ atomic_set(&acdb_data.aanc_cal.cal_size,
+ cal_block->cal_size);
+ atomic_set(&acdb_data.aanc_cal.cal_paddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+ atomic_set(&acdb_data.aanc_cal.cal_kvaddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+done:
+ return;
+}
+
void get_lsm_cal(struct acdb_cal_block *cal_block)
{
pr_debug("%s\n", __func__);
@@ -1109,6 +1152,9 @@
case AUDIO_SET_ASM_CUSTOM_TOPOLOGY:
store_asm_custom_topology((struct cal_block *)data);
goto done;
+ case AUDIO_SET_AANC_CAL:
+ store_aanc_cal((struct cal_block *)data);
+ goto done;
default:
pr_err("ACDB=> ACDB ioctl not found!\n");
}
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 4834855..3c644ed 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -19,6 +19,7 @@
enum {
RX_CAL,
TX_CAL,
+ AANC_TX_CAL,
MAX_AUDPROC_TYPES
};
@@ -64,5 +65,6 @@
void get_vocvol_cal(struct acdb_cal_block *cal_block);
void get_sidetone_cal(struct sidetone_cal *cal_data);
void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
+void get_aanc_cal(struct acdb_cal_block *cal_block);
#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 329d293..16df886 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -23,6 +23,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/msm-dai-q6-v2.h>
+#include <sound/pcm_params.h>
#define HDMI_RX_CA_MAX 0x32
@@ -119,7 +120,14 @@
dai_data->port_config.hdmi_multi_ch.reserved = 0;
dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version = 1;
dai_data->port_config.hdmi_multi_ch.sample_rate = dai_data->rate;
- dai_data->port_config.hdmi_multi_ch.bit_width = 16;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->port_config.hdmi_multi_ch.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dai_data->port_config.hdmi_multi_ch.bit_width = 24;
+ break;
+ }
switch (dai_data->channels) {
case 2:
@@ -257,7 +265,7 @@
static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 2,
.channels_max = 8,
.rate_max = 48000,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 819512d..d8f2759 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -56,6 +56,7 @@
static int fm_pcmrx_switch_enable;
static int srs_alsa_ctrl_ever_called;
static int lsm_mux_slim_port;
+static int slim0_rx_aanc_fb_port;
enum {
MADNONE,
@@ -565,6 +566,8 @@
session_id = voc_get_session_id(VOICE_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOLTE)
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (val == MSM_FRONTEND_DAI_VOICE2)
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else
session_id = voc_get_session_id(VOIP_SESSION_NAME);
@@ -865,6 +868,42 @@
return afe_port_set_mad_type(port_id, mad_type);
}
+static int msm_routing_slim_0_rx_aanc_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] = slim0_rx_aanc_fb_port;
+ mutex_unlock(&routing_lock);
+ pr_debug("%s: AANC Mux Port %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+};
+
+static int msm_routing_slim_0_rx_aanc_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct aanc_data aanc_info;
+
+ mutex_lock(&routing_lock);
+ memset(&aanc_info, 0x00, sizeof(aanc_info));
+ pr_debug("%s: AANC Mux Port %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ slim0_rx_aanc_fb_port = ucontrol->value.integer.value[0];
+ if (ucontrol->value.integer.value[0] == 0) {
+ aanc_info.aanc_active = false;
+ aanc_info.aanc_tx_port = 0;
+ aanc_info.aanc_rx_port = 0;
+ } else {
+ aanc_info.aanc_active = true;
+ aanc_info.aanc_rx_port = SLIMBUS_0_RX;
+ aanc_info.aanc_tx_port =
+ (SLIMBUS_0_RX - 1 + (slim0_rx_aanc_fb_port * 2));
+ }
+ afe_set_aanc_info(&aanc_info);
+ mutex_unlock(&routing_lock);
+ return 0;
+};
static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1550,6 +1589,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1565,6 +1607,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1580,6 +1625,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1595,6 +1643,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1613,6 +1664,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1631,6 +1685,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1649,6 +1706,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1667,6 +1727,9 @@
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1720,6 +1783,27 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_Voice2", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_Voice2", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice2",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_Voice2", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new tx_volte_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX_VoLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
@@ -1895,6 +1979,21 @@
msm_routing_lsm_func_get, msm_routing_lsm_func_put),
};
+static const char * const aanc_slim_0_rx_text[] = {
+ "ZERO", "SLIMBUS_0_TX", "SLIMBUS_1_TX", "SLIMBUS_2_TX", "SLIMBUS_3_TX",
+ "SLIMBUS_4_TX", "SLIMBUS_5_TX", "SLIMBUS_6_TX"
+};
+
+static const struct soc_enum aanc_slim_0_rx_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aanc_slim_0_rx_text),
+ aanc_slim_0_rx_text);
+
+static const struct snd_kcontrol_new aanc_slim_0_rx_mux[] = {
+ SOC_DAPM_ENUM_EXT("AANC_SLIM_0_RX MUX", aanc_slim_0_rx_enum,
+ msm_routing_slim_0_rx_aanc_mux_get,
+ msm_routing_slim_0_rx_aanc_mux_put)
+};
+
static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
@@ -2235,6 +2334,8 @@
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_UL", "Voice2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
@@ -2348,6 +2449,8 @@
/* Mux Definitions */
SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+ SND_SOC_DAPM_MUX("SLIM_0_RX AANC MUX", SND_SOC_NOPM, 0, 0,
+ aanc_slim_0_rx_mux),
/* Mixer definitions */
SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2419,6 +2522,9 @@
SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
ARRAY_SIZE(tx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice2_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voice2_mixer_controls,
+ ARRAY_SIZE(tx_voice2_mixer_controls)),
SND_SOC_DAPM_MIXER("Voip_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_voip_mixer_controls,
ARRAY_SIZE(tx_voip_mixer_controls)),
@@ -2595,48 +2701,56 @@
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"PRI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"HDMI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
@@ -2644,6 +2758,7 @@
{"HDMI", NULL, "HDMI_DL_HL"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -2656,6 +2771,15 @@
{"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
{"Voice_Tx Mixer", "AUX_PCM_TX_Voice", "AUX_PCM_TX"},
{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
+
+ {"Voice2_Tx Mixer", "PRI_TX_Voice2", "PRI_I2S_TX"},
+ {"Voice2_Tx Mixer", "MI2S_TX_Voice2", "MI2S_TX"},
+ {"Voice2_Tx Mixer", "SLIM_0_TX_Voice2", "SLIMBUS_0_TX"},
+ {"Voice2_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice2", "INT_BT_SCO_TX"},
+ {"Voice2_Tx Mixer", "AFE_PCM_TX_Voice2", "PCM_TX"},
+ {"Voice2_Tx Mixer", "AUX_PCM_TX_Voice2", "AUX_PCM_TX"},
+ {"VOICE2_UL", NULL, "Voice2_Tx Mixer"},
+
{"VoLTE_Tx Mixer", "PRI_TX_VoLTE", "PRI_I2S_TX"},
{"VoLTE_Tx Mixer", "SLIM_0_TX_VoLTE", "SLIMBUS_0_TX"},
{"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
@@ -3002,6 +3126,10 @@
snd_soc_add_platform_controls(platform, lsm_function,
ARRAY_SIZE(lsm_function));
+
+ snd_soc_add_platform_controls(platform,
+ aanc_slim_0_rx_mux,
+ ARRAY_SIZE(aanc_slim_0_rx_mux));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 798f676..1c1029c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -73,6 +73,7 @@
MSM_FRONTEND_DAI_VOLTE,
MSM_FRONTEND_DAI_DTMF_RX,
MSM_FRONTEND_DAI_LSM1,
+ MSM_FRONTEND_DAI_VOICE2,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 333ee48..4df66d0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -59,6 +59,29 @@
return false;
}
+static int is_voice2(struct msm_voice *pvoice2)
+{
+ if (pvoice2 == &voice_info[VOICE2_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
+static uint16_t get_session_id(struct msm_voice *pvoc)
+{
+ uint16_t session_id = 0;
+
+ if (is_volte(pvoc))
+ session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (is_voice2(pvoc))
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ else
+ session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+ return session_id;
+}
+
+
static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -92,11 +115,15 @@
if (!strncmp("VoLTE", substream->pcm->id, 5)) {
voice = &voice_info[VOLTE_SESSION_INDEX];
pr_debug("%s: Open VoLTE Substream Id=%s\n",
- __func__, substream->pcm->id);
+ __func__, substream->pcm->id);
+ } else if (!strncmp("Voice2", substream->pcm->id, 6)) {
+ voice = &voice_info[VOICE2_SESSION_INDEX];
+ pr_debug("%s: Open Voice2 Substream Id=%s\n",
+ __func__, substream->pcm->id);
} else {
voice = &voice_info[VOICE_SESSION_INDEX];
pr_debug("%s: Open VOICE Substream Id=%s\n",
- __func__, substream->pcm->id);
+ __func__, substream->pcm->id);
}
mutex_lock(&voice->lock);
@@ -160,11 +187,10 @@
prtd->instance--;
if (!prtd->playback_start && !prtd->capture_start) {
pr_debug("end voice call\n");
- if (is_volte(prtd))
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
- voc_end_voice_call(session_id);
+
+ session_id = get_session_id(prtd);
+ if (session_id)
+ voc_end_voice_call(session_id);
}
mutex_unlock(&prtd->lock);
@@ -185,11 +211,9 @@
ret = msm_pcm_capture_prepare(substream);
if (prtd->playback_start && prtd->capture_start) {
- if (is_volte(prtd))
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
- voc_start_voice_call(session_id);
+ session_id = get_session_id(prtd);
+ if (session_id)
+ voc_start_voice_call(session_id);
}
mutex_unlock(&prtd->lock);
@@ -215,10 +239,8 @@
uint16_t session_id = 0;
pr_debug("%s: cmd = %d\n", __func__, cmd);
- if (is_volte(prtd))
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+ session_id = get_session_id(prtd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -233,8 +255,10 @@
ret = msm_pcm_playback_prepare(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ret = msm_pcm_capture_prepare(substream);
- if (prtd->playback_start && prtd->capture_start)
- voc_resume_voice_call(session_id);
+ if (prtd->playback_start && prtd->capture_start) {
+ if (session_id)
+ voc_resume_voice_call(session_id);
+ }
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -247,7 +271,8 @@
if (prtd->capture_start)
prtd->capture_start = 0;
}
- voc_standby_voice_call(session_id);
+ if (session_id)
+ voc_standby_voice_call(session_id);
break;
default:
ret = -EINVAL;
@@ -290,6 +315,24 @@
return 0;
}
+static int msm_voice2_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_voice2_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int volume = ucontrol->value.integer.value[0];
+ pr_debug("%s: volume: %d\n", __func__, volume);
+
+ voc_set_rx_vol_index(voc_get_session_id(VOICE2_SESSION_NAME),
+ RX_PATH, volume);
+ return 0;
+}
+
static int msm_voice_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -328,6 +371,25 @@
return 0;
}
+static int msm_voice2_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_voice2_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mute = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+
+ voc_set_tx_mute(voc_get_session_id(VOICE2_SESSION_NAME), TX_PATH, mute);
+
+ return 0;
+}
+
static int msm_voice_rx_device_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -368,6 +430,26 @@
return 0;
}
+static int msm_voice2_rx_device_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ voc_get_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME));
+ return 0;
+}
+
+static int msm_voice2_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mute = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+
+ voc_set_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME), mute);
+
+ return 0;
+}
+
static const char const *tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
static const struct soc_enum msm_tty_mode_enum[] = {
SOC_ENUM_SINGLE_EXT(4, tty_mode),
@@ -389,6 +471,7 @@
pr_debug("%s: tty_mode=%d\n", __func__, tty_mode);
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
return 0;
}
@@ -401,6 +484,8 @@
voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME),
wv_enable);
+ voc_set_widevoice_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ wv_enable);
return 0;
}
@@ -422,7 +507,9 @@
pr_debug("%s: st enable=%d\n", __func__, st_enable);
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_ST, st_enable);
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
+ voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
return 0;
}
@@ -444,7 +531,9 @@
pr_debug("%s: fens enable=%d\n", __func__, fens_enable);
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+ voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
return 0;
}
@@ -481,6 +570,13 @@
msm_volte_mute_get, msm_volte_mute_put),
SOC_SINGLE_EXT("VoLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
msm_volte_volume_get, msm_volte_volume_put),
+ SOC_SINGLE_EXT("Voice2 Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice2_rx_device_mute_get,
+ msm_voice2_rx_device_mute_put),
+ SOC_SINGLE_EXT("Voice2 Tx Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice2_mute_get, msm_voice2_mute_put),
+ SOC_SINGLE_EXT("Voice2 Rx Volume", SND_SOC_NOPM, 0, 5, 0,
+ msm_voice2_volume_get, msm_voice2_volume_put),
};
static struct snd_pcm_ops msm_pcm_ops = {
@@ -550,9 +646,12 @@
static int __init msm_soc_platform_init(void)
{
+ int i = 0;
+
memset(&voice_info, 0, sizeof(voice_info));
- mutex_init(&voice_info[VOICE_SESSION_INDEX].lock);
- mutex_init(&voice_info[VOLTE_SESSION_INDEX].lock);
+
+ for (i = 0; i < VOICE_SESSION_INDEX_MAX; i++)
+ mutex_init(&voice_info[i].lock);
return platform_driver_register(&msm_pcm_driver);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index a25fb2a..5425c46 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -16,6 +16,7 @@
enum {
VOICE_SESSION_INDEX,
VOLTE_SESSION_INDEX,
+ VOICE2_SESSION_INDEX,
VOICE_SESSION_INDEX_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 97cd3fc..fed0d81 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -45,6 +45,8 @@
u16 dtmf_gen_rx_portid;
struct afe_spkr_prot_calib_get_resp calib_data;
int vi_tx_port;
+ uint32_t afe_sample_rates[AFE_MAX_PORTS];
+ struct aanc_data aanc_info;
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -57,6 +59,21 @@
#define SIZEOF_CFG_CMD(y) \
(sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
+void afe_set_aanc_info(struct aanc_data *q6_aanc_info)
+{
+ pr_debug("%s\n", __func__);
+
+ this_afe.aanc_info.aanc_active = q6_aanc_info->aanc_active;
+ this_afe.aanc_info.aanc_rx_port = q6_aanc_info->aanc_rx_port;
+ this_afe.aanc_info.aanc_tx_port = q6_aanc_info->aanc_tx_port;
+
+ pr_debug("aanc active is %d rx port is %d, tx port is %d\n",
+ this_afe.aanc_info.aanc_active,
+ this_afe.aanc_info.aanc_rx_port,
+ this_afe.aanc_info.aanc_tx_port);
+}
+
+
static int32_t afe_callback(struct apr_client_data *data, void *priv)
{
if (!data) {
@@ -342,7 +359,12 @@
struct afe_audioif_config_command_no_payload afe_cal;
pr_debug("%s: path %d\n", __func__, path);
- get_afe_cal(path, &cal_block);
+ if (path == AANC_TX_CAL) {
+ get_aanc_cal(&cal_block);
+ } else {
+ get_afe_cal(path, &cal_block);
+ }
+
if (cal_block.cal_size <= 0) {
pr_debug("%s: No AFE cal to send!\n", __func__);
goto done;
@@ -403,6 +425,7 @@
int index = 0;
struct afe_spkr_prot_config_command config;
+ memset(&config, 0 , sizeof(config));
if (!prot_config) {
pr_err("%s Invalid params\n", __func__);
goto fail_cmd;
@@ -411,7 +434,6 @@
pr_err("%s invalid port %d", __func__, port);
goto fail_cmd;
}
- memset(&config, 0 , sizeof(config));
index = q6audio_get_port_index(port);
switch (param_id) {
case AFE_PARAM_ID_FBSP_MODE_RX_CFG:
@@ -464,7 +486,7 @@
}
ret = 0;
fail_cmd:
- pr_err("%s config.pdata.param_id %x status %d\n",
+ pr_debug("%s config.pdata.param_id %x status %d\n",
__func__, config.pdata.param_id, ret);
return ret;
}
@@ -738,13 +760,173 @@
pr_debug("%s: leave %d\n", __func__, ret);
return ret;
}
+static int afe_aanc_port_cfg(void *apr, uint16_t tx_port, uint16_t rx_port)
+{
+ struct afe_port_cmd_set_aanc_param cfg;
+ int ret = 0;
+ int index = 0;
+
+ pr_debug("%s: tx_port %d, rx_port %d\n",
+ __func__, tx_port, rx_port);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0)
+ return -EINVAL;
+
+ index = q6audio_get_port_index(tx_port);
+ if (q6audio_validate_port(tx_port) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, tx_port);
+ return -EINVAL;
+ }
+
+ cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cfg.hdr.pkt_size = sizeof(cfg);
+ cfg.hdr.src_port = 0;
+ cfg.hdr.dest_port = 0;
+ cfg.hdr.token = index;
+ cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+ cfg.param.port_id = tx_port;
+ cfg.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_aanc_port_cfg);
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.payload_address_msw = 0;
+ cfg.param.mem_map_handle = 0;
+
+ cfg.pdata.module_id = AFE_MODULE_AANC;
+ cfg.pdata.param_id = AFE_PARAM_ID_AANC_PORT_CONFIG;
+ cfg.pdata.param_size = sizeof(struct afe_param_aanc_port_cfg);
+ cfg.pdata.reserved = 0;
+
+ cfg.data.aanc_port_cfg.aanc_port_cfg_minor_version =
+ AFE_API_VERSION_AANC_PORT_CONFIG;
+ cfg.data.aanc_port_cfg.tx_port_sample_rate =
+ this_afe.aanc_info.aanc_tx_port_sample_rate;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[0] = AANC_TX_VOICE_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[1] = AANC_TX_NOISE_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[2] = AANC_TX_ERROR_MIC;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[3] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[4] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[5] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[6] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_channel_map[7] = AANC_TX_MIC_UNUSED;
+ cfg.data.aanc_port_cfg.tx_port_num_channels = 3;
+ cfg.data.aanc_port_cfg.rx_path_ref_port_id = rx_port;
+ cfg.data.aanc_port_cfg.ref_port_sample_rate =
+ this_afe.aanc_info.aanc_rx_port_sample_rate;
+
+ ret = afe_apr_send_pkt((uint32_t *) &cfg, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE AANC port config failed for tx_port %d, rx_port %d\n",
+ __func__, tx_port, rx_port);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_aanc_mod_enable(void *apr, uint16_t tx_port, uint16_t enable)
+{
+ struct afe_port_cmd_set_aanc_param cfg;
+ int ret = 0;
+ int index = 0;
+
+ pr_debug("%s: tx_port %d\n",
+ __func__, tx_port);
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0)
+ return -EINVAL;
+
+ index = q6audio_get_port_index(tx_port);
+ if (q6audio_validate_port(tx_port) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, tx_port);
+ return -EINVAL;
+ }
+
+ cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cfg.hdr.pkt_size = sizeof(cfg);
+ cfg.hdr.src_port = 0;
+ cfg.hdr.dest_port = 0;
+ cfg.hdr.token = index;
+ cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+
+ cfg.param.port_id = tx_port;
+ cfg.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_mod_enable_param);
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.payload_address_lsw = 0;
+ cfg.param.mem_map_handle = 0;
+
+ cfg.pdata.module_id = AFE_MODULE_AANC;
+ cfg.pdata.param_id = AFE_PARAM_ID_ENABLE;
+ cfg.pdata.param_size = sizeof(struct afe_mod_enable_param);
+ cfg.pdata.reserved = 0;
+
+ cfg.data.mod_enable.enable = enable;
+ cfg.data.mod_enable.reserved = 0;
+
+ ret = afe_apr_send_pkt((uint32_t *) &cfg, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE AANC enable failed for tx_port %d\n",
+ __func__, tx_port);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+int afe_send_aanc_version(
+ struct afe_param_id_cdc_aanc_version *version_cfg)
+{
+ int ret;
+ struct afe_svc_cmd_cdc_aanc_version config;
+
+ pr_debug("%s: enter\n", __func__);
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_id_cdc_aanc_version);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CDC_AANC_VERSION;
+ config.pdata.param_size =
+ sizeof(struct afe_param_id_cdc_aanc_version);
+ config.version = *version_cfg;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CDC_AANC_VERSION failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+ pr_debug("%s: leave ret %d\n", __func__, 0);
+ return ret;
+}
int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
{
int i;
i = port_id - SLIMBUS_0_RX;
- if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+ if (i < 0 || i >= ARRAY_SIZE(afe_ports_mad_type)) {
pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
return -EINVAL;
}
@@ -790,6 +972,9 @@
case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
ret = afe_send_slimbus_slave_port_cfg(config_data, arg);
break;
+ case AFE_AANC_VERSION:
+ ret = afe_send_aanc_version(config_data);
+ break;
default:
pr_err("%s: unknown configuration type", __func__);
ret = -EINVAL;
@@ -837,6 +1022,24 @@
return ret;
}
+static int afe_aanc_start(uint16_t tx_port_id, uint16_t rx_port_id)
+{
+ int ret;
+
+ pr_debug("%s Tx port is %d, Rx port is %d\n",
+ __func__, tx_port_id, rx_port_id);
+ ret = afe_aanc_port_cfg(this_afe.apr, tx_port_id, rx_port_id);
+ if (ret) {
+ pr_err("%s Send AANC Port Config failed %d\n",
+ __func__, ret);
+ goto fail_cmd;
+ }
+ afe_send_cal_block(AANC_TX_CAL, tx_port_id);
+
+fail_cmd:
+ return ret;
+}
+
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate) /* This function is no blocking */
{
@@ -845,6 +1048,7 @@
int cfg_type;
int index = 0;
enum afe_mad_type mad_type;
+ uint16_t port_index;
if (!afe_config) {
pr_err("%s: Error, no configuration data\n", __func__);
@@ -886,6 +1090,22 @@
}
}
+ if ((this_afe.aanc_info.aanc_active) &&
+ (this_afe.aanc_info.aanc_tx_port == port_id)) {
+ this_afe.aanc_info.aanc_tx_port_sample_rate = rate;
+ port_index =
+ afe_get_port_index(this_afe.aanc_info.aanc_rx_port);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.aanc_info.aanc_rx_port_sample_rate =
+ this_afe.afe_sample_rates[port_index];
+ } else {
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = afe_aanc_start(this_afe.aanc_info.aanc_tx_port,
+ this_afe.aanc_info.aanc_rx_port);
+ pr_debug("%s afe_aanc_start ret %d\n", __func__, ret);
+ }
config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
config.hdr.pkt_size = sizeof(config);
@@ -974,6 +1194,14 @@
ret = -EINVAL;
goto fail_cmd;
}
+
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = rate;
+ } else {
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
return afe_send_cmd_port_start(port_id);
fail_cmd:
@@ -2135,11 +2363,11 @@
static void config_debug_fs_init(void)
{
debugfs_afelb = debugfs_create_file("afe_loopback",
- S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+ S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback",
&afe_debug_fops);
debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
- S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
+ S_IRUGO | S_IWUSR | S_IWGRP, NULL, (void *) "afe_loopback_gain",
&afe_debug_fops);
}
static void config_debug_fs_exit(void)
@@ -2392,6 +2620,7 @@
enum afe_mad_type mad_type;
int ret = 0;
int index = 0;
+ uint16_t port_index;
if (this_afe.apr == NULL) {
pr_err("AFE is already closed\n");
@@ -2422,6 +2651,23 @@
pr_debug("%s: Not a MAD port\n", __func__);
}
+ port_index = afe_get_port_index(port_id);
+ if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[port_index] = 0;
+ } else {
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if ((port_id == this_afe.aanc_info.aanc_tx_port) &&
+ (this_afe.aanc_info.aanc_active)) {
+ memset(&this_afe.aanc_info, 0x00, sizeof(this_afe.aanc_info));
+ ret = afe_aanc_mod_enable(this_afe.apr, port_id, 0);
+ if (ret)
+ pr_err("%s: AFE mod disable failed %d\n",
+ __func__, ret);
+ }
+
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
stop.hdr.pkt_size = sizeof(stop);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index ea2b5c6..49b6d03 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -279,13 +279,13 @@
{
out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
- S_IFREG | S_IRUGO | S_IWUGO,\
+ S_IRUGO | S_IWUSR | S_IWGRP,\
NULL, NULL, &audio_output_latency_debug_fops);
if (IS_ERR(out_dentry))
pr_err("debugfs_create_file failed\n");
in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
- S_IFREG | S_IRUGO | S_IWUGO,\
+ S_IRUGO | S_IWUSR | S_IWGRP,\
NULL, NULL, &audio_input_latency_debug_fops);
if (IS_ERR(in_dentry))
pr_err("debugfs_create_file failed\n");
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 12e83b0..754a4fa 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -35,10 +35,6 @@
#define CMD_STATUS_SUCCESS 0
#define CMD_STATUS_FAIL 1
-#define VOC_PATH_PASSIVE 0
-#define VOC_PATH_FULL 1
-#define VOC_PATH_VOLTE_PASSIVE 2
-
/* CVP CAL Size: 245760 = 240 * 1024 */
#define CVP_CAL_SIZE 245760
/* CVS CAL Size: 49152 = 48 * 1024 */
@@ -180,6 +176,9 @@
if (name != NULL) {
if (!strncmp(name, "Voice session", 13))
session_id = common.voice[VOC_PATH_PASSIVE].session_id;
+ else if (!strncmp(name, "Voice2 session", 14))
+ session_id =
+ common.voice[VOC_PATH_VOICE2_PASSIVE].session_id;
else if (!strncmp(name, "VoLTE session", 13))
session_id =
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
@@ -223,6 +222,11 @@
return (session_id == common.voice[VOC_PATH_VOLTE_PASSIVE].session_id);
}
+static bool is_voice2_session(u16 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
+}
+
static int voice_apr_register(void)
{
void *modem_mvm, *modem_cvs, *modem_cvp;
@@ -347,7 +351,8 @@
}
pr_debug("%s: VoLTE command to MVM\n", __func__);
if (is_volte_session(v->session_id) ||
- is_voice_session(v->session_id)) {
+ is_voice_session(v->session_id) ||
+ is_voice2_session(v->session_id)) {
mvm_handle = voice_get_mvm_handle(v);
mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
@@ -421,7 +426,8 @@
if (!mvm_handle) {
if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id)) {
+ is_volte_session(v->session_id) ||
+ is_voice2_session(v->session_id)) {
mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -441,8 +447,12 @@
strlcpy(mvm_session_cmd.mvm_session.name,
"default volte voice",
sizeof(mvm_session_cmd.mvm_session.name));
+ } else if (is_voice2_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ VOICE2_SESSION_VSID,
+ sizeof(mvm_session_cmd.mvm_session.name));
} else {
- strlcpy(mvm_session_cmd.mvm_session.name,
+ strlcpy(mvm_session_cmd.mvm_session.name,
"default modem voice",
sizeof(mvm_session_cmd.mvm_session.name));
}
@@ -503,7 +513,8 @@
/* send cmd to create cvs session */
if (!cvs_handle) {
if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id)) {
+ is_volte_session(v->session_id) ||
+ is_voice2_session(v->session_id)) {
pr_debug("%s: creating CVS passive session\n",
__func__);
@@ -524,6 +535,10 @@
strlcpy(cvs_session_cmd.cvs_session.name,
"default volte voice",
sizeof(cvs_session_cmd.cvs_session.name));
+ } else if (is_voice2_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ VOICE2_SESSION_VSID,
+ sizeof(cvs_session_cmd.cvs_session.name));
} else {
strlcpy(cvs_session_cmd.cvs_session.name,
"default modem voice",
@@ -4167,6 +4182,7 @@
case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
case VSS_IMVM_CMD_SET_CAL_NETWORK:
case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
+ case VSS_IMEMORY_CMD_MAP_PHYSICAL:
case VSS_IMEMORY_CMD_UNMAP:
case VSS_IMVM_CMD_STANDBY_VOICE:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 98bd002..babfddc 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1275,7 +1275,7 @@
void *buf;
};
-#define MAX_VOC_SESSIONS 3
+#define MAX_VOC_SESSIONS 4
#define SESSION_ID_BASE 0xFFF0
struct common_data {
@@ -1327,6 +1327,20 @@
TX_PATH,
};
+
+#define VOC_PATH_PASSIVE 0
+#define VOC_PATH_FULL 1
+#define VOC_PATH_VOLTE_PASSIVE 2
+#define VOC_PATH_VOICE2_PASSIVE 3
+
+#define MAX_SESSION_NAME_LEN 32
+#define VOICE_SESSION_NAME "Voice session"
+#define VOIP_SESSION_NAME "VoIP session"
+#define VOLTE_SESSION_NAME "VoLTE session"
+#define VOICE2_SESSION_NAME "Voice2 session"
+
+#define VOICE2_SESSION_VSID "10dc1000"
+
/* called by alsa driver */
int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
uint32_t enable);
@@ -1353,10 +1367,6 @@
int voc_enable_dtmf_rx_detection(uint16_t session_id, uint32_t enable);
void voc_disable_dtmf_det_on_active_sessions(void);
-#define MAX_SESSION_NAME_LEN 32
-#define VOICE_SESSION_NAME "Voice session"
-#define VOIP_SESSION_NAME "VoIP session"
-#define VOLTE_SESSION_NAME "VoLTE session"
uint16_t voc_get_session_id(char *name);
int voc_start_playback(uint32_t set);