Merge "msm: kgsl: disable full cache flush if full_cache_threshold is 0"
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index ce797d3..8d1d46d 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -226,8 +226,9 @@
compatible = "qcom,coresight-hwevent";
reg = <0xfdf30018 0x80>,
<0xf9011080 0x80>,
- <0xfd4ab160 0x80>;
- reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+ <0xfd4ab160 0x80>,
+ <0xfc401600 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
coresight-id = <29>;
coresight-name = "coresight-hwevent";
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index c01193c..583fbfa 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -41,6 +41,7 @@
- "qcom,s5k3l1yx"
- "shinetech,gc0339"
- "shinetech,hi256"
+ - "shinetech,s5k4e1"
- reg : should contain i2c slave address of the device
- qcom,slave-id : should contain i2c slave address, device id address
and expected id read value
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
new file mode 100644
index 0000000..f70d90f
--- /dev/null
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -0,0 +1,28 @@
+Qualcomm QCA199x NFC NCI device
+
+Near Field Communication (NFC) device is based on NFC Controller Interface (NCI)
+
+Required properties:
+
+- compatible: "qcom,nfc-nci"
+- reg: NCI i2c slave address.
+- qcom,dis-gpio: specific gpio for hardware reset.
+- qcom,irq-gpio: specific gpio for read interrupt.
+- interrupt-parent: Should be phandle for the interrupt controller
+ that services interrupts for this device.
+- interrupts: should contain the NFC interrupt. NFC has one read interrupt.
+- qcom,clk-gpio: pmic gpio on which bbclk2 signal is coming.
+
+Example:
+
+ i2c@f9925000 { /* BLSP1 QUP3 */
+ nfc-nci@0e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 21 0x00>;
+ qcom,dis-gpio = <&msmgpio 20 0x00>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <21 0>;
+ qcom,clk-gpio = <&pm8226_gpios 3 0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 70bf993..e724c62 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -65,6 +65,14 @@
5 (2^5 = 32) 32 micro frame interrupt threshold aka 4ms interrupt threshold
6 (2^6 = 64) 64 micro frame interrupt threshold aka 8ms interrupt threshold
+- hsic,disable-cerr: CERR is 2bit down error counter that keeps track of number
+ of consecutive errors detected on single usb transaction. When set to non
+ zero value, hw decrements the count and updates qTD when transaction fails.
+ If counter reaches zero, hw marks the qTD inactive and triggers the interrupt.
+ When CERR is programmed to zero, hw ignores transaction failures. ECHI stack
+ programs the CERR to 3 by default. When this flag is true, CERR is set to
+ zero and transaction errors are ignored.
+
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
- qcom,msm_bus,name
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index ebb3134..ac314ea 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -50,7 +50,10 @@
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
- qcom,msm_bus,name
- - qcom,msm_bus,num_cases
+ - qcom,msm_bus,num_cases - There are three valid cases for this: NONE, MAX
+ and MIN bandwidth votes. Minimum two cases must be defined for
+ both NONE and MAX votes. If MIN vote is different from NONE VOTE
+ then specify third case for MIN VOTE.
- qcom,msm_bus,active_only
- qcom,msm_bus,num_paths
- qcom,msm_bus,vectors
@@ -76,6 +79,8 @@
HSPHY.
- qcom,hsusb-log2-itc: value of 2^(log2_itc-1) will be used as the
interrupt threshold (ITC), when log2_itc is between 1 to 7.
+- qcom,hsusb-l1-supported: If present, the device supports l1 (Link power
+ management).
Example HSUSB OTG controller device node :
usb@f9690000 {
diff --git a/arch/arm/boot/dts/apq8084-coresight.dtsi b/arch/arm/boot/dts/apq8084-coresight.dtsi
new file mode 100644
index 0000000..610d80b
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-coresight.dtsi
@@ -0,0 +1,145 @@
+/* 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.
+ */
+
+&soc {
+ tmc_etr: tmc@fc326000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc326000 0x1000>,
+ <0xfc37c000 0x3000>;
+ reg-names = "tmc-base", "bam-base";
+
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+ coresight-id = <0>;
+ coresight-name = "coresight-tmc-etr";
+ coresight-nr-inports = <1>;
+ };
+
+ replicator: replicator@fc324000 {
+ compatible = "qcom,coresight-replicator";
+ reg = <0xfc324000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-id = <2>;
+ coresight-name = "coresight-replicator";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etr>;
+ coresight-child-ports = <0>;
+ };
+
+ tmc_etf: tmc@fc325000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc325000 0x1000>;
+ reg-names = "tmc-base";
+
+ coresight-id = <3>;
+ coresight-name = "coresight-tmc-etf";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&replicator>;
+ coresight-child-ports = <0>;
+ coresight-default-sink;
+ };
+
+ funnel_merg: funnel@fc323000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc323000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <4>;
+ coresight-name = "coresight-funnel-merg";
+ coresight-nr-inports = <2>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etf>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in0: funnel@fc321000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc321000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <5>;
+ coresight-name = "coresight-funnel-in0";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in1: funnel@fc322000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc322000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <6>;
+ coresight-name = "coresight-funnel-in1";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <1>;
+ };
+
+ funnel_kpss: funnel@fc355000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc355000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <7>;
+ coresight-name = "coresight-funnel-kpss";
+ coresight-nr-inports = <4>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <5>;
+ };
+
+ funnel_mmss: funnel@fc36c000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc36c000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-id = <8>;
+ coresight-name = "coresight-funnel-mmss";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <1>;
+ };
+
+ stm: stm@fc302000 {
+ compatible = "arm,coresight-stm";
+ reg = <0xfc302000 0x1000>,
+ <0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-id = <9>;
+ coresight-name = "coresight-stm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <7>;
+ };
+
+ csr: csr@fc301000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0xfc301000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-id = <14>;
+ coresight-name = "coresight-csr";
+ coresight-nr-inports = <0>;
+
+ qcom,blk-size = <3>;
+ };
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index e5f083a..80b6ffa 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -21,6 +21,7 @@
/include/ "apq8084-ion.dtsi"
/include/ "apq8084-smp2p.dtsi"
+/include/ "apq8084-coresight.dtsi"
&soc {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index 7942567..2a6bbf9 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_nt35590_720p_cmd {
compatible = "qcom,mdss-dsi-panel";
label = "nt35590 720p command mode dsi panel";
@@ -58,473 +58,474 @@
00 00 00 00 0a 00 00 01 97 /* lane2 config */
00 00 00 00 0f 00 00 01 97 /* lane3 config */
00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
- 29 01 00 00 00 02 26 08
- 29 01 00 00 00 02 26 00
- 29 01 00 00 10 02 FF 00
- 29 01 00 00 00 02 BA 03
- 29 01 00 00 00 02 C2 08
- 29 01 00 00 00 02 FF 01
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 00 4A
- 29 01 00 00 00 02 01 33
- 29 01 00 00 00 02 02 53
- 29 01 00 00 00 02 03 55
- 29 01 00 00 00 02 04 55
- 29 01 00 00 00 02 05 33
- 29 01 00 00 00 02 06 22
- 29 01 00 00 00 02 08 56
- 29 01 00 00 00 02 09 8F
- 29 01 00 00 00 02 36 73
- 29 01 00 00 00 02 0B 9F
- 29 01 00 00 00 02 0C 9F
- 29 01 00 00 00 02 0D 2F
- 29 01 00 00 00 02 0E 24
- 29 01 00 00 00 02 11 83
- 29 01 00 00 00 02 12 03
- 29 01 00 00 00 02 71 2C
- 29 01 00 00 00 02 6F 03
- 29 01 00 00 00 02 0F 0A
- 29 01 00 00 00 02 FF 05
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 01 00
- 29 01 00 00 00 02 02 8B
- 29 01 00 00 00 02 03 82
- 29 01 00 00 00 02 04 82
- 29 01 00 00 00 02 05 30
- 29 01 00 00 00 02 06 33
- 29 01 00 00 00 02 07 01
- 29 01 00 00 00 02 08 00
- 29 01 00 00 00 02 09 46
- 29 01 00 00 00 02 0A 46
- 29 01 00 00 00 02 0D 0B
- 29 01 00 00 00 02 0E 1D
- 29 01 00 00 00 02 0F 08
- 29 01 00 00 00 02 10 53
- 29 01 00 00 00 02 11 00
- 29 01 00 00 00 02 12 00
- 29 01 00 00 00 02 14 01
- 29 01 00 00 00 02 15 00
- 29 01 00 00 00 02 16 05
- 29 01 00 00 00 02 17 00
- 29 01 00 00 00 02 19 7F
- 29 01 00 00 00 02 1A FF
- 29 01 00 00 00 02 1B 0F
- 29 01 00 00 00 02 1C 00
- 29 01 00 00 00 02 1D 00
- 29 01 00 00 00 02 1E 00
- 29 01 00 00 00 02 1F 07
- 29 01 00 00 00 02 20 00
- 29 01 00 00 00 02 21 06
- 29 01 00 00 00 02 22 55
- 29 01 00 00 00 02 23 4D
- 29 01 00 00 00 02 2D 02
- 29 01 00 00 00 02 28 01
- 29 01 00 00 00 02 2F 02
- 29 01 00 00 00 02 83 01
- 29 01 00 00 00 02 9E 58
- 29 01 00 00 00 02 9F 6A
- 29 01 00 00 00 02 A0 01
- 29 01 00 00 00 02 A2 10
- 29 01 00 00 00 02 BB 0A
- 29 01 00 00 00 02 BC 0A
- 29 01 00 00 00 02 32 08
- 29 01 00 00 00 02 33 B8
- 29 01 00 00 00 02 36 01
- 29 01 00 00 00 02 37 00
- 29 01 00 00 00 02 43 00
- 29 01 00 00 00 02 4B 21
- 29 01 00 00 00 02 4C 03
- 29 01 00 00 00 02 50 21
- 29 01 00 00 00 02 51 03
- 29 01 00 00 00 02 58 21
- 29 01 00 00 00 02 59 03
- 29 01 00 00 00 02 5D 21
- 29 01 00 00 00 02 5E 03
- 29 01 00 00 00 02 6C 00
- 29 01 00 00 00 02 6D 00
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 01
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 75 00
- 29 01 00 00 00 02 76 7D
- 29 01 00 00 00 02 77 00
- 29 01 00 00 00 02 78 8A
- 29 01 00 00 00 02 79 00
- 29 01 00 00 00 02 7A 9C
- 29 01 00 00 00 02 7B 00
- 29 01 00 00 00 02 7C B1
- 29 01 00 00 00 02 7D 00
- 29 01 00 00 00 02 7E BF
- 29 01 00 00 00 02 7F 00
- 29 01 00 00 00 02 80 CF
- 29 01 00 00 00 02 81 00
- 29 01 00 00 00 02 82 DD
- 29 01 00 00 00 02 83 00
- 29 01 00 00 00 02 84 E8
- 29 01 00 00 00 02 85 00
- 29 01 00 00 00 02 86 F2
- 29 01 00 00 00 02 87 01
- 29 01 00 00 00 02 88 1F
- 29 01 00 00 00 02 89 01
- 29 01 00 00 00 02 8A 41
- 29 01 00 00 00 02 8B 01
- 29 01 00 00 00 02 8C 78
- 29 01 00 00 00 02 8D 01
- 29 01 00 00 00 02 8E A5
- 29 01 00 00 00 02 8F 01
- 29 01 00 00 00 02 90 EE
- 29 01 00 00 00 02 91 02
- 29 01 00 00 00 02 92 29
- 29 01 00 00 00 02 93 02
- 29 01 00 00 00 02 94 2A
- 29 01 00 00 00 02 95 02
- 29 01 00 00 00 02 96 5D
- 29 01 00 00 00 02 97 02
- 29 01 00 00 00 02 98 93
- 29 01 00 00 00 02 99 02
- 29 01 00 00 00 02 9A B8
- 29 01 00 00 00 02 9B 02
- 29 01 00 00 00 02 9C E7
- 29 01 00 00 00 02 9D 03
- 29 01 00 00 00 02 9E 07
- 29 01 00 00 00 02 9F 03
- 29 01 00 00 00 02 A0 37
- 29 01 00 00 00 02 A2 03
- 29 01 00 00 00 02 A3 46
- 29 01 00 00 00 02 A4 03
- 29 01 00 00 00 02 A5 56
- 29 01 00 00 00 02 A6 03
- 29 01 00 00 00 02 A7 66
- 29 01 00 00 00 02 A9 03
- 29 01 00 00 00 02 AA 7A
- 29 01 00 00 00 02 AB 03
- 29 01 00 00 00 02 AC 93
- 29 01 00 00 00 02 AD 03
- 29 01 00 00 00 02 AE A3
- 29 01 00 00 00 02 AF 03
- 29 01 00 00 00 02 B0 B4
- 29 01 00 00 00 02 B1 03
- 29 01 00 00 00 02 B2 CB
- 29 01 00 00 00 02 B3 00
- 29 01 00 00 00 02 B4 7D
- 29 01 00 00 00 02 B5 00
- 29 01 00 00 00 02 B6 8A
- 29 01 00 00 00 02 B7 00
- 29 01 00 00 00 02 B8 9C
- 29 01 00 00 00 02 B9 00
- 29 01 00 00 00 02 BA B1
- 29 01 00 00 00 02 BB 00
- 29 01 00 00 00 02 BC BF
- 29 01 00 00 00 02 BD 00
- 29 01 00 00 00 02 BE CF
- 29 01 00 00 00 02 BF 00
- 29 01 00 00 00 02 C0 DD
- 29 01 00 00 00 02 C1 00
- 29 01 00 00 00 02 C2 E8
- 29 01 00 00 00 02 C3 00
- 29 01 00 00 00 02 C4 F2
- 29 01 00 00 00 02 C5 01
- 29 01 00 00 00 02 C6 1F
- 29 01 00 00 00 02 C7 01
- 29 01 00 00 00 02 C8 41
- 29 01 00 00 00 02 C9 01
- 29 01 00 00 00 02 CA 78
- 29 01 00 00 00 02 CB 01
- 29 01 00 00 00 02 CC A5
- 29 01 00 00 00 02 CD 01
- 29 01 00 00 00 02 CE EE
- 29 01 00 00 00 02 CF 02
- 29 01 00 00 00 02 D0 29
- 29 01 00 00 00 02 D1 02
- 29 01 00 00 00 02 D2 2A
- 29 01 00 00 00 02 D3 02
- 29 01 00 00 00 02 D4 5D
- 29 01 00 00 00 02 D5 02
- 29 01 00 00 00 02 D6 93
- 29 01 00 00 00 02 D7 02
- 29 01 00 00 00 02 D8 B8
- 29 01 00 00 00 02 D9 02
- 29 01 00 00 00 02 DA E7
- 29 01 00 00 00 02 DB 03
- 29 01 00 00 00 02 DC 07
- 29 01 00 00 00 02 DD 03
- 29 01 00 00 00 02 DE 37
- 29 01 00 00 00 02 DF 03
- 29 01 00 00 00 02 E0 46
- 29 01 00 00 00 02 E1 03
- 29 01 00 00 00 02 E2 56
- 29 01 00 00 00 02 E3 03
- 29 01 00 00 00 02 E4 66
- 29 01 00 00 00 02 E5 03
- 29 01 00 00 00 02 E6 7A
- 29 01 00 00 00 02 E7 03
- 29 01 00 00 00 02 E8 93
- 29 01 00 00 00 02 E9 03
- 29 01 00 00 00 02 EA A3
- 29 01 00 00 00 02 EB 03
- 29 01 00 00 00 02 EC B4
- 29 01 00 00 00 02 ED 03
- 29 01 00 00 00 02 EE CB
- 29 01 00 00 00 02 EF 00
- 29 01 00 00 00 02 F0 ED
- 29 01 00 00 00 02 F1 00
- 29 01 00 00 00 02 F2 F3
- 29 01 00 00 00 02 F3 00
- 29 01 00 00 00 02 F4 FE
- 29 01 00 00 00 02 F5 01
- 29 01 00 00 00 02 F6 09
- 29 01 00 00 00 02 F7 01
- 29 01 00 00 00 02 F8 13
- 29 01 00 00 00 02 F9 01
- 29 01 00 00 00 02 FA 1D
- 29 01 00 00 00 02 FF 02
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 00 01
- 29 01 00 00 00 02 01 26
- 29 01 00 00 00 02 02 01
- 29 01 00 00 00 02 03 2F
- 29 01 00 00 00 02 04 01
- 29 01 00 00 00 02 05 37
- 29 01 00 00 00 02 06 01
- 29 01 00 00 00 02 07 56
- 29 01 00 00 00 02 08 01
- 29 01 00 00 00 02 09 70
- 29 01 00 00 00 02 0A 01
- 29 01 00 00 00 02 0B 9D
- 29 01 00 00 00 02 0C 01
- 29 01 00 00 00 02 0D C2
- 29 01 00 00 00 02 0E 01
- 29 01 00 00 00 02 0F FF
- 29 01 00 00 00 02 10 02
- 29 01 00 00 00 02 11 31
- 29 01 00 00 00 02 12 02
- 29 01 00 00 00 02 13 32
- 29 01 00 00 00 02 14 02
- 29 01 00 00 00 02 15 60
- 29 01 00 00 00 02 16 02
- 29 01 00 00 00 02 17 94
- 29 01 00 00 00 02 18 02
- 29 01 00 00 00 02 19 B5
- 29 01 00 00 00 02 1A 02
- 29 01 00 00 00 02 1B E3
- 29 01 00 00 00 02 1C 03
- 29 01 00 00 00 02 1D 03
- 29 01 00 00 00 02 1E 03
- 29 01 00 00 00 02 1F 2D
- 29 01 00 00 00 02 20 03
- 29 01 00 00 00 02 21 3A
- 29 01 00 00 00 02 22 03
- 29 01 00 00 00 02 23 48
- 29 01 00 00 00 02 24 03
- 29 01 00 00 00 02 25 57
- 29 01 00 00 00 02 26 03
- 29 01 00 00 00 02 27 68
- 29 01 00 00 00 02 28 03
- 29 01 00 00 00 02 29 7B
- 29 01 00 00 00 02 2A 03
- 29 01 00 00 00 02 2B 90
- 29 01 00 00 00 02 2D 03
- 29 01 00 00 00 02 2F A0
- 29 01 00 00 00 02 30 03
- 29 01 00 00 00 02 31 CB
- 29 01 00 00 00 02 32 00
- 29 01 00 00 00 02 33 ED
- 29 01 00 00 00 02 34 00
- 29 01 00 00 00 02 35 F3
- 29 01 00 00 00 02 36 00
- 29 01 00 00 00 02 37 FE
- 29 01 00 00 00 02 38 01
- 29 01 00 00 00 02 39 09
- 29 01 00 00 00 02 3A 01
- 29 01 00 00 00 02 3B 13
- 29 01 00 00 00 02 3D 01
- 29 01 00 00 00 02 3F 1D
- 29 01 00 00 00 02 40 01
- 29 01 00 00 00 02 41 26
- 29 01 00 00 00 02 42 01
- 29 01 00 00 00 02 43 2F
- 29 01 00 00 00 02 44 01
- 29 01 00 00 00 02 45 37
- 29 01 00 00 00 02 46 01
- 29 01 00 00 00 02 47 56
- 29 01 00 00 00 02 48 01
- 29 01 00 00 00 02 49 70
- 29 01 00 00 00 02 4A 01
- 29 01 00 00 00 02 4B 9D
- 29 01 00 00 00 02 4C 01
- 29 01 00 00 00 02 4D C2
- 29 01 00 00 00 02 4E 01
- 29 01 00 00 00 02 4F FF
- 29 01 00 00 00 02 50 02
- 29 01 00 00 00 02 51 31
- 29 01 00 00 00 02 52 02
- 29 01 00 00 00 02 53 32
- 29 01 00 00 00 02 54 02
- 29 01 00 00 00 02 55 60
- 29 01 00 00 00 02 56 02
- 29 01 00 00 00 02 58 94
- 29 01 00 00 00 02 59 02
- 29 01 00 00 00 02 5A B5
- 29 01 00 00 00 02 5B 02
- 29 01 00 00 00 02 5C E3
- 29 01 00 00 00 02 5D 03
- 29 01 00 00 00 02 5E 03
- 29 01 00 00 00 02 5F 03
- 29 01 00 00 00 02 60 2D
- 29 01 00 00 00 02 61 03
- 29 01 00 00 00 02 62 3A
- 29 01 00 00 00 02 63 03
- 29 01 00 00 00 02 64 48
- 29 01 00 00 00 02 65 03
- 29 01 00 00 00 02 66 57
- 29 01 00 00 00 02 67 03
- 29 01 00 00 00 02 68 68
- 29 01 00 00 00 02 69 03
- 29 01 00 00 00 02 6A 7B
- 29 01 00 00 00 02 6B 03
- 29 01 00 00 00 02 6C 90
- 29 01 00 00 00 02 6D 03
- 29 01 00 00 00 02 6E A0
- 29 01 00 00 00 02 6F 03
- 29 01 00 00 00 02 70 CB
- 29 01 00 00 00 02 71 00
- 29 01 00 00 00 02 72 19
- 29 01 00 00 00 02 73 00
- 29 01 00 00 00 02 74 36
- 29 01 00 00 00 02 75 00
- 29 01 00 00 00 02 76 55
- 29 01 00 00 00 02 77 00
- 29 01 00 00 00 02 78 70
- 29 01 00 00 00 02 79 00
- 29 01 00 00 00 02 7A 83
- 29 01 00 00 00 02 7B 00
- 29 01 00 00 00 02 7C 99
- 29 01 00 00 00 02 7D 00
- 29 01 00 00 00 02 7E A8
- 29 01 00 00 00 02 7F 00
- 29 01 00 00 00 02 80 B7
- 29 01 00 00 00 02 81 00
- 29 01 00 00 00 02 82 C5
- 29 01 00 00 00 02 83 00
- 29 01 00 00 00 02 84 F7
- 29 01 00 00 00 02 85 01
- 29 01 00 00 00 02 86 1E
- 29 01 00 00 00 02 87 01
- 29 01 00 00 00 02 88 60
- 29 01 00 00 00 02 89 01
- 29 01 00 00 00 02 8A 95
- 29 01 00 00 00 02 8B 01
- 29 01 00 00 00 02 8C E1
- 29 01 00 00 00 02 8D 02
- 29 01 00 00 00 02 8E 20
- 29 01 00 00 00 02 8F 02
- 29 01 00 00 00 02 90 23
- 29 01 00 00 00 02 91 02
- 29 01 00 00 00 02 92 59
- 29 01 00 00 00 02 93 02
- 29 01 00 00 00 02 94 94
- 29 01 00 00 00 02 95 02
- 29 01 00 00 00 02 96 B4
- 29 01 00 00 00 02 97 02
- 29 01 00 00 00 02 98 E1
- 29 01 00 00 00 02 99 03
- 29 01 00 00 00 02 9A 01
- 29 01 00 00 00 02 9B 03
- 29 01 00 00 00 02 9C 28
- 29 01 00 00 00 02 9D 03
- 29 01 00 00 00 02 9E 30
- 29 01 00 00 00 02 9F 03
- 29 01 00 00 00 02 A0 37
- 29 01 00 00 00 02 A2 03
- 29 01 00 00 00 02 A3 3B
- 29 01 00 00 00 02 A4 03
- 29 01 00 00 00 02 A5 40
- 29 01 00 00 00 02 A6 03
- 29 01 00 00 00 02 A7 50
- 29 01 00 00 00 02 A9 03
- 29 01 00 00 00 02 AA 6D
- 29 01 00 00 00 02 AB 03
- 29 01 00 00 00 02 AC 80
- 29 01 00 00 00 02 AD 03
- 29 01 00 00 00 02 AE CB
- 29 01 00 00 00 02 AF 00
- 29 01 00 00 00 02 B0 19
- 29 01 00 00 00 02 B1 00
- 29 01 00 00 00 02 B2 36
- 29 01 00 00 00 02 B3 00
- 29 01 00 00 00 02 B4 55
- 29 01 00 00 00 02 B5 00
- 29 01 00 00 00 02 B6 70
- 29 01 00 00 00 02 B7 00
- 29 01 00 00 00 02 B8 83
- 29 01 00 00 00 02 B9 00
- 29 01 00 00 00 02 BA 99
- 29 01 00 00 00 02 BB 00
- 29 01 00 00 00 02 BC A8
- 29 01 00 00 00 02 BD 00
- 29 01 00 00 00 02 BE B7
- 29 01 00 00 00 02 BF 00
- 29 01 00 00 00 02 C0 C5
- 29 01 00 00 00 02 C1 00
- 29 01 00 00 00 02 C2 F7
- 29 01 00 00 00 02 C3 01
- 29 01 00 00 00 02 C4 1E
- 29 01 00 00 00 02 C5 01
- 29 01 00 00 00 02 C6 60
- 29 01 00 00 00 02 C7 01
- 29 01 00 00 00 02 C8 95
- 29 01 00 00 00 02 C9 01
- 29 01 00 00 00 02 CA E1
- 29 01 00 00 00 02 CB 02
- 29 01 00 00 00 02 CC 20
- 29 01 00 00 00 02 CD 02
- 29 01 00 00 00 02 CE 23
- 29 01 00 00 00 02 CF 02
- 29 01 00 00 00 02 D0 59
- 29 01 00 00 00 02 D1 02
- 29 01 00 00 00 02 D2 94
- 29 01 00 00 00 02 D3 02
- 29 01 00 00 00 02 D4 B4
- 29 01 00 00 00 02 D5 02
- 29 01 00 00 00 02 D6 E1
- 29 01 00 00 00 02 D7 03
- 29 01 00 00 00 02 D8 01
- 29 01 00 00 00 02 D9 03
- 29 01 00 00 00 02 DA 28
- 29 01 00 00 00 02 DB 03
- 29 01 00 00 00 02 DC 30
- 29 01 00 00 00 02 DD 03
- 29 01 00 00 00 02 DE 37
- 29 01 00 00 00 02 DF 03
- 29 01 00 00 00 02 E0 3B
- 29 01 00 00 00 02 E1 03
- 29 01 00 00 00 02 E2 40
- 29 01 00 00 00 02 E3 03
- 29 01 00 00 00 02 E4 50
- 29 01 00 00 00 02 E5 03
- 29 01 00 00 00 02 E6 6D
- 29 01 00 00 00 02 E7 03
- 29 01 00 00 00 02 E8 80
- 29 01 00 00 00 02 E9 03
- 29 01 00 00 00 02 EA CB
- 29 01 00 00 00 02 FF 01
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 02
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 04
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 00
- 29 01 00 00 64 02 11 00
- 29 01 00 00 00 02 FF EE
- 29 01 00 00 00 02 12 50
- 29 01 00 00 00 02 13 02
- 29 01 00 00 00 02 6A 60
- 29 01 00 00 00 02 FF 00
- 29 01 00 00 78 02 29 00];
+ qcom,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+ 29 01 00 00 00 00 02 26 08
+ 29 01 00 00 00 00 02 26 00
+ 29 01 00 00 10 00 02 FF 00
+ 29 01 00 00 00 00 02 BA 03
+ 29 01 00 00 00 00 02 C2 08
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 00 4A
+ 29 01 00 00 00 00 02 01 33
+ 29 01 00 00 00 00 02 02 53
+ 29 01 00 00 00 00 02 03 55
+ 29 01 00 00 00 00 02 04 55
+ 29 01 00 00 00 00 02 05 33
+ 29 01 00 00 00 00 02 06 22
+ 29 01 00 00 00 00 02 08 56
+ 29 01 00 00 00 00 02 09 8F
+ 29 01 00 00 00 00 02 36 73
+ 29 01 00 00 00 00 02 0B 9F
+ 29 01 00 00 00 00 02 0C 9F
+ 29 01 00 00 00 00 02 0D 2F
+ 29 01 00 00 00 00 02 0E 24
+ 29 01 00 00 00 00 02 11 83
+ 29 01 00 00 00 00 02 12 03
+ 29 01 00 00 00 00 02 71 2C
+ 29 01 00 00 00 00 02 6F 03
+ 29 01 00 00 00 00 02 0F 0A
+ 29 01 00 00 00 00 02 FF 05
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 01 00
+ 29 01 00 00 00 00 02 02 8B
+ 29 01 00 00 00 00 02 03 82
+ 29 01 00 00 00 00 02 04 82
+ 29 01 00 00 00 00 02 05 30
+ 29 01 00 00 00 00 02 06 33
+ 29 01 00 00 00 00 02 07 01
+ 29 01 00 00 00 00 02 08 00
+ 29 01 00 00 00 00 02 09 46
+ 29 01 00 00 00 00 02 0A 46
+ 29 01 00 00 00 00 02 0D 0B
+ 29 01 00 00 00 00 02 0E 1D
+ 29 01 00 00 00 00 02 0F 08
+ 29 01 00 00 00 00 02 10 53
+ 29 01 00 00 00 00 02 11 00
+ 29 01 00 00 00 00 02 12 00
+ 29 01 00 00 00 00 02 14 01
+ 29 01 00 00 00 00 02 15 00
+ 29 01 00 00 00 00 02 16 05
+ 29 01 00 00 00 00 02 17 00
+ 29 01 00 00 00 00 02 19 7F
+ 29 01 00 00 00 00 02 1A FF
+ 29 01 00 00 00 00 02 1B 0F
+ 29 01 00 00 00 00 02 1C 00
+ 29 01 00 00 00 00 02 1D 00
+ 29 01 00 00 00 00 02 1E 00
+ 29 01 00 00 00 00 02 1F 07
+ 29 01 00 00 00 00 02 20 00
+ 29 01 00 00 00 00 02 21 06
+ 29 01 00 00 00 00 02 22 55
+ 29 01 00 00 00 00 02 23 4D
+ 29 01 00 00 00 00 02 2D 02
+ 29 01 00 00 00 00 02 28 01
+ 29 01 00 00 00 00 02 2F 02
+ 29 01 00 00 00 00 02 83 01
+ 29 01 00 00 00 00 02 9E 58
+ 29 01 00 00 00 00 02 9F 6A
+ 29 01 00 00 00 00 02 A0 01
+ 29 01 00 00 00 00 02 A2 10
+ 29 01 00 00 00 00 02 BB 0A
+ 29 01 00 00 00 00 02 BC 0A
+ 29 01 00 00 00 00 02 32 08
+ 29 01 00 00 00 00 02 33 B8
+ 29 01 00 00 00 00 02 36 01
+ 29 01 00 00 00 00 02 37 00
+ 29 01 00 00 00 00 02 43 00
+ 29 01 00 00 00 00 02 4B 21
+ 29 01 00 00 00 00 02 4C 03
+ 29 01 00 00 00 00 02 50 21
+ 29 01 00 00 00 00 02 51 03
+ 29 01 00 00 00 00 02 58 21
+ 29 01 00 00 00 00 02 59 03
+ 29 01 00 00 00 00 02 5D 21
+ 29 01 00 00 00 00 02 5E 03
+ 29 01 00 00 00 00 02 6C 00
+ 29 01 00 00 00 00 02 6D 00
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 75 00
+ 29 01 00 00 00 00 02 76 7D
+ 29 01 00 00 00 00 02 77 00
+ 29 01 00 00 00 00 02 78 8A
+ 29 01 00 00 00 00 02 79 00
+ 29 01 00 00 00 00 02 7A 9C
+ 29 01 00 00 00 00 02 7B 00
+ 29 01 00 00 00 00 02 7C B1
+ 29 01 00 00 00 00 02 7D 00
+ 29 01 00 00 00 00 02 7E BF
+ 29 01 00 00 00 00 02 7F 00
+ 29 01 00 00 00 00 02 80 CF
+ 29 01 00 00 00 00 02 81 00
+ 29 01 00 00 00 00 02 82 DD
+ 29 01 00 00 00 00 02 83 00
+ 29 01 00 00 00 00 02 84 E8
+ 29 01 00 00 00 00 02 85 00
+ 29 01 00 00 00 00 02 86 F2
+ 29 01 00 00 00 00 02 87 01
+ 29 01 00 00 00 00 02 88 1F
+ 29 01 00 00 00 00 02 89 01
+ 29 01 00 00 00 00 02 8A 41
+ 29 01 00 00 00 00 02 8B 01
+ 29 01 00 00 00 00 02 8C 78
+ 29 01 00 00 00 00 02 8D 01
+ 29 01 00 00 00 00 02 8E A5
+ 29 01 00 00 00 00 02 8F 01
+ 29 01 00 00 00 00 02 90 EE
+ 29 01 00 00 00 00 02 91 02
+ 29 01 00 00 00 00 02 92 29
+ 29 01 00 00 00 00 02 93 02
+ 29 01 00 00 00 00 02 94 2A
+ 29 01 00 00 00 00 02 95 02
+ 29 01 00 00 00 00 02 96 5D
+ 29 01 00 00 00 00 02 97 02
+ 29 01 00 00 00 00 02 98 93
+ 29 01 00 00 00 00 02 99 02
+ 29 01 00 00 00 00 02 9A B8
+ 29 01 00 00 00 00 02 9B 02
+ 29 01 00 00 00 00 02 9C E7
+ 29 01 00 00 00 00 02 9D 03
+ 29 01 00 00 00 00 02 9E 07
+ 29 01 00 00 00 00 02 9F 03
+ 29 01 00 00 00 00 02 A0 37
+ 29 01 00 00 00 00 02 A2 03
+ 29 01 00 00 00 00 02 A3 46
+ 29 01 00 00 00 00 02 A4 03
+ 29 01 00 00 00 00 02 A5 56
+ 29 01 00 00 00 00 02 A6 03
+ 29 01 00 00 00 00 02 A7 66
+ 29 01 00 00 00 00 02 A9 03
+ 29 01 00 00 00 00 02 AA 7A
+ 29 01 00 00 00 00 02 AB 03
+ 29 01 00 00 00 00 02 AC 93
+ 29 01 00 00 00 00 02 AD 03
+ 29 01 00 00 00 00 02 AE A3
+ 29 01 00 00 00 00 02 AF 03
+ 29 01 00 00 00 00 02 B0 B4
+ 29 01 00 00 00 00 02 B1 03
+ 29 01 00 00 00 00 02 B2 CB
+ 29 01 00 00 00 00 02 B3 00
+ 29 01 00 00 00 00 02 B4 7D
+ 29 01 00 00 00 00 02 B5 00
+ 29 01 00 00 00 00 02 B6 8A
+ 29 01 00 00 00 00 02 B7 00
+ 29 01 00 00 00 00 02 B8 9C
+ 29 01 00 00 00 00 02 B9 00
+ 29 01 00 00 00 00 02 BA B1
+ 29 01 00 00 00 00 02 BB 00
+ 29 01 00 00 00 00 02 BC BF
+ 29 01 00 00 00 00 02 BD 00
+ 29 01 00 00 00 00 02 BE CF
+ 29 01 00 00 00 00 02 BF 00
+ 29 01 00 00 00 00 02 C0 DD
+ 29 01 00 00 00 00 02 C1 00
+ 29 01 00 00 00 00 02 C2 E8
+ 29 01 00 00 00 00 02 C3 00
+ 29 01 00 00 00 00 02 C4 F2
+ 29 01 00 00 00 00 02 C5 01
+ 29 01 00 00 00 00 02 C6 1F
+ 29 01 00 00 00 00 02 C7 01
+ 29 01 00 00 00 00 02 C8 41
+ 29 01 00 00 00 00 02 C9 01
+ 29 01 00 00 00 00 02 CA 78
+ 29 01 00 00 00 00 02 CB 01
+ 29 01 00 00 00 00 02 CC A5
+ 29 01 00 00 00 00 02 CD 01
+ 29 01 00 00 00 00 02 CE EE
+ 29 01 00 00 00 00 02 CF 02
+ 29 01 00 00 00 00 02 D0 29
+ 29 01 00 00 00 00 02 D1 02
+ 29 01 00 00 00 00 02 D2 2A
+ 29 01 00 00 00 00 02 D3 02
+ 29 01 00 00 00 00 02 D4 5D
+ 29 01 00 00 00 00 02 D5 02
+ 29 01 00 00 00 00 02 D6 93
+ 29 01 00 00 00 00 02 D7 02
+ 29 01 00 00 00 00 02 D8 B8
+ 29 01 00 00 00 00 02 D9 02
+ 29 01 00 00 00 00 02 DA E7
+ 29 01 00 00 00 00 02 DB 03
+ 29 01 00 00 00 00 02 DC 07
+ 29 01 00 00 00 00 02 DD 03
+ 29 01 00 00 00 00 02 DE 37
+ 29 01 00 00 00 00 02 DF 03
+ 29 01 00 00 00 00 02 E0 46
+ 29 01 00 00 00 00 02 E1 03
+ 29 01 00 00 00 00 02 E2 56
+ 29 01 00 00 00 00 02 E3 03
+ 29 01 00 00 00 00 02 E4 66
+ 29 01 00 00 00 00 02 E5 03
+ 29 01 00 00 00 00 02 E6 7A
+ 29 01 00 00 00 00 02 E7 03
+ 29 01 00 00 00 00 02 E8 93
+ 29 01 00 00 00 00 02 E9 03
+ 29 01 00 00 00 00 02 EA A3
+ 29 01 00 00 00 00 02 EB 03
+ 29 01 00 00 00 00 02 EC B4
+ 29 01 00 00 00 00 02 ED 03
+ 29 01 00 00 00 00 02 EE CB
+ 29 01 00 00 00 00 02 EF 00
+ 29 01 00 00 00 00 02 F0 ED
+ 29 01 00 00 00 00 02 F1 00
+ 29 01 00 00 00 00 02 F2 F3
+ 29 01 00 00 00 00 02 F3 00
+ 29 01 00 00 00 00 02 F4 FE
+ 29 01 00 00 00 00 02 F5 01
+ 29 01 00 00 00 00 02 F6 09
+ 29 01 00 00 00 00 02 F7 01
+ 29 01 00 00 00 00 02 F8 13
+ 29 01 00 00 00 00 02 F9 01
+ 29 01 00 00 00 00 02 FA 1D
+ 29 01 00 00 00 00 02 FF 02
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 00 01
+ 29 01 00 00 00 00 02 01 26
+ 29 01 00 00 00 00 02 02 01
+ 29 01 00 00 00 00 02 03 2F
+ 29 01 00 00 00 00 02 04 01
+ 29 01 00 00 00 00 02 05 37
+ 29 01 00 00 00 00 02 06 01
+ 29 01 00 00 00 00 02 07 56
+ 29 01 00 00 00 00 02 08 01
+ 29 01 00 00 00 00 02 09 70
+ 29 01 00 00 00 00 02 0A 01
+ 29 01 00 00 00 00 02 0B 9D
+ 29 01 00 00 00 00 02 0C 01
+ 29 01 00 00 00 00 02 0D C2
+ 29 01 00 00 00 00 02 0E 01
+ 29 01 00 00 00 00 02 0F FF
+ 29 01 00 00 00 00 02 10 02
+ 29 01 00 00 00 00 02 11 31
+ 29 01 00 00 00 00 02 12 02
+ 29 01 00 00 00 00 02 13 32
+ 29 01 00 00 00 00 02 14 02
+ 29 01 00 00 00 00 02 15 60
+ 29 01 00 00 00 00 02 16 02
+ 29 01 00 00 00 00 02 17 94
+ 29 01 00 00 00 00 02 18 02
+ 29 01 00 00 00 00 02 19 B5
+ 29 01 00 00 00 00 02 1A 02
+ 29 01 00 00 00 00 02 1B E3
+ 29 01 00 00 00 00 02 1C 03
+ 29 01 00 00 00 00 02 1D 03
+ 29 01 00 00 00 00 02 1E 03
+ 29 01 00 00 00 00 02 1F 2D
+ 29 01 00 00 00 00 02 20 03
+ 29 01 00 00 00 00 02 21 3A
+ 29 01 00 00 00 00 02 22 03
+ 29 01 00 00 00 00 02 23 48
+ 29 01 00 00 00 00 02 24 03
+ 29 01 00 00 00 00 02 25 57
+ 29 01 00 00 00 00 02 26 03
+ 29 01 00 00 00 00 02 27 68
+ 29 01 00 00 00 00 02 28 03
+ 29 01 00 00 00 00 02 29 7B
+ 29 01 00 00 00 00 02 2A 03
+ 29 01 00 00 00 00 02 2B 90
+ 29 01 00 00 00 00 02 2D 03
+ 29 01 00 00 00 00 02 2F A0
+ 29 01 00 00 00 00 02 30 03
+ 29 01 00 00 00 00 02 31 CB
+ 29 01 00 00 00 00 02 32 00
+ 29 01 00 00 00 00 02 33 ED
+ 29 01 00 00 00 00 02 34 00
+ 29 01 00 00 00 00 02 35 F3
+ 29 01 00 00 00 00 02 36 00
+ 29 01 00 00 00 00 02 37 FE
+ 29 01 00 00 00 00 02 38 01
+ 29 01 00 00 00 00 02 39 09
+ 29 01 00 00 00 00 02 3A 01
+ 29 01 00 00 00 00 02 3B 13
+ 29 01 00 00 00 00 02 3D 01
+ 29 01 00 00 00 00 02 3F 1D
+ 29 01 00 00 00 00 02 40 01
+ 29 01 00 00 00 00 02 41 26
+ 29 01 00 00 00 00 02 42 01
+ 29 01 00 00 00 00 02 43 2F
+ 29 01 00 00 00 00 02 44 01
+ 29 01 00 00 00 00 02 45 37
+ 29 01 00 00 00 00 02 46 01
+ 29 01 00 00 00 00 02 47 56
+ 29 01 00 00 00 00 02 48 01
+ 29 01 00 00 00 00 02 49 70
+ 29 01 00 00 00 00 02 4A 01
+ 29 01 00 00 00 00 02 4B 9D
+ 29 01 00 00 00 00 02 4C 01
+ 29 01 00 00 00 00 02 4D C2
+ 29 01 00 00 00 00 02 4E 01
+ 29 01 00 00 00 00 02 4F FF
+ 29 01 00 00 00 00 02 50 02
+ 29 01 00 00 00 00 02 51 31
+ 29 01 00 00 00 00 02 52 02
+ 29 01 00 00 00 00 02 53 32
+ 29 01 00 00 00 00 02 54 02
+ 29 01 00 00 00 00 02 55 60
+ 29 01 00 00 00 00 02 56 02
+ 29 01 00 00 00 00 02 58 94
+ 29 01 00 00 00 00 02 59 02
+ 29 01 00 00 00 00 02 5A B5
+ 29 01 00 00 00 00 02 5B 02
+ 29 01 00 00 00 00 02 5C E3
+ 29 01 00 00 00 00 02 5D 03
+ 29 01 00 00 00 00 02 5E 03
+ 29 01 00 00 00 00 02 5F 03
+ 29 01 00 00 00 00 02 60 2D
+ 29 01 00 00 00 00 02 61 03
+ 29 01 00 00 00 00 02 62 3A
+ 29 01 00 00 00 00 02 63 03
+ 29 01 00 00 00 00 02 64 48
+ 29 01 00 00 00 00 02 65 03
+ 29 01 00 00 00 00 02 66 57
+ 29 01 00 00 00 00 02 67 03
+ 29 01 00 00 00 00 02 68 68
+ 29 01 00 00 00 00 02 69 03
+ 29 01 00 00 00 00 02 6A 7B
+ 29 01 00 00 00 00 02 6B 03
+ 29 01 00 00 00 00 02 6C 90
+ 29 01 00 00 00 00 02 6D 03
+ 29 01 00 00 00 00 02 6E A0
+ 29 01 00 00 00 00 02 6F 03
+ 29 01 00 00 00 00 02 70 CB
+ 29 01 00 00 00 00 02 71 00
+ 29 01 00 00 00 00 02 72 19
+ 29 01 00 00 00 00 02 73 00
+ 29 01 00 00 00 00 02 74 36
+ 29 01 00 00 00 00 02 75 00
+ 29 01 00 00 00 00 02 76 55
+ 29 01 00 00 00 00 02 77 00
+ 29 01 00 00 00 00 02 78 70
+ 29 01 00 00 00 00 02 79 00
+ 29 01 00 00 00 00 02 7A 83
+ 29 01 00 00 00 00 02 7B 00
+ 29 01 00 00 00 00 02 7C 99
+ 29 01 00 00 00 00 02 7D 00
+ 29 01 00 00 00 00 02 7E A8
+ 29 01 00 00 00 00 02 7F 00
+ 29 01 00 00 00 00 02 80 B7
+ 29 01 00 00 00 00 02 81 00
+ 29 01 00 00 00 00 02 82 C5
+ 29 01 00 00 00 00 02 83 00
+ 29 01 00 00 00 00 02 84 F7
+ 29 01 00 00 00 00 02 85 01
+ 29 01 00 00 00 00 02 86 1E
+ 29 01 00 00 00 00 02 87 01
+ 29 01 00 00 00 00 02 88 60
+ 29 01 00 00 00 00 02 89 01
+ 29 01 00 00 00 00 02 8A 95
+ 29 01 00 00 00 00 02 8B 01
+ 29 01 00 00 00 00 02 8C E1
+ 29 01 00 00 00 00 02 8D 02
+ 29 01 00 00 00 00 02 8E 20
+ 29 01 00 00 00 00 02 8F 02
+ 29 01 00 00 00 00 02 90 23
+ 29 01 00 00 00 00 02 91 02
+ 29 01 00 00 00 00 02 92 59
+ 29 01 00 00 00 00 02 93 02
+ 29 01 00 00 00 00 02 94 94
+ 29 01 00 00 00 00 02 95 02
+ 29 01 00 00 00 00 02 96 B4
+ 29 01 00 00 00 00 02 97 02
+ 29 01 00 00 00 00 02 98 E1
+ 29 01 00 00 00 00 02 99 03
+ 29 01 00 00 00 00 02 9A 01
+ 29 01 00 00 00 00 02 9B 03
+ 29 01 00 00 00 00 02 9C 28
+ 29 01 00 00 00 00 02 9D 03
+ 29 01 00 00 00 00 02 9E 30
+ 29 01 00 00 00 00 02 9F 03
+ 29 01 00 00 00 00 02 A0 37
+ 29 01 00 00 00 00 02 A2 03
+ 29 01 00 00 00 00 02 A3 3B
+ 29 01 00 00 00 00 02 A4 03
+ 29 01 00 00 00 00 02 A5 40
+ 29 01 00 00 00 00 02 A6 03
+ 29 01 00 00 00 00 02 A7 50
+ 29 01 00 00 00 00 02 A9 03
+ 29 01 00 00 00 00 02 AA 6D
+ 29 01 00 00 00 00 02 AB 03
+ 29 01 00 00 00 00 02 AC 80
+ 29 01 00 00 00 00 02 AD 03
+ 29 01 00 00 00 00 02 AE CB
+ 29 01 00 00 00 00 02 AF 00
+ 29 01 00 00 00 00 02 B0 19
+ 29 01 00 00 00 00 02 B1 00
+ 29 01 00 00 00 00 02 B2 36
+ 29 01 00 00 00 00 02 B3 00
+ 29 01 00 00 00 00 02 B4 55
+ 29 01 00 00 00 00 02 B5 00
+ 29 01 00 00 00 00 02 B6 70
+ 29 01 00 00 00 00 02 B7 00
+ 29 01 00 00 00 00 02 B8 83
+ 29 01 00 00 00 00 02 B9 00
+ 29 01 00 00 00 00 02 BA 99
+ 29 01 00 00 00 00 02 BB 00
+ 29 01 00 00 00 00 02 BC A8
+ 29 01 00 00 00 00 02 BD 00
+ 29 01 00 00 00 00 02 BE B7
+ 29 01 00 00 00 00 02 BF 00
+ 29 01 00 00 00 00 02 C0 C5
+ 29 01 00 00 00 00 02 C1 00
+ 29 01 00 00 00 00 02 C2 F7
+ 29 01 00 00 00 00 02 C3 01
+ 29 01 00 00 00 00 02 C4 1E
+ 29 01 00 00 00 00 02 C5 01
+ 29 01 00 00 00 00 02 C6 60
+ 29 01 00 00 00 00 02 C7 01
+ 29 01 00 00 00 00 02 C8 95
+ 29 01 00 00 00 00 02 C9 01
+ 29 01 00 00 00 00 02 CA E1
+ 29 01 00 00 00 00 02 CB 02
+ 29 01 00 00 00 00 02 CC 20
+ 29 01 00 00 00 00 02 CD 02
+ 29 01 00 00 00 00 02 CE 23
+ 29 01 00 00 00 00 02 CF 02
+ 29 01 00 00 00 00 02 D0 59
+ 29 01 00 00 00 00 02 D1 02
+ 29 01 00 00 00 00 02 D2 94
+ 29 01 00 00 00 00 02 D3 02
+ 29 01 00 00 00 00 02 D4 B4
+ 29 01 00 00 00 00 02 D5 02
+ 29 01 00 00 00 00 02 D6 E1
+ 29 01 00 00 00 00 02 D7 03
+ 29 01 00 00 00 00 02 D8 01
+ 29 01 00 00 00 00 02 D9 03
+ 29 01 00 00 00 00 02 DA 28
+ 29 01 00 00 00 00 02 DB 03
+ 29 01 00 00 00 00 02 DC 30
+ 29 01 00 00 00 00 02 DD 03
+ 29 01 00 00 00 00 02 DE 37
+ 29 01 00 00 00 00 02 DF 03
+ 29 01 00 00 00 00 02 E0 3B
+ 29 01 00 00 00 00 02 E1 03
+ 29 01 00 00 00 00 02 E2 40
+ 29 01 00 00 00 00 02 E3 03
+ 29 01 00 00 00 00 02 E4 50
+ 29 01 00 00 00 00 02 E5 03
+ 29 01 00 00 00 00 02 E6 6D
+ 29 01 00 00 00 00 02 E7 03
+ 29 01 00 00 00 00 02 E8 80
+ 29 01 00 00 00 00 02 E9 03
+ 29 01 00 00 00 00 02 EA CB
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 02
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 04
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 00
+ 29 01 00 00 64 00 02 11 00
+ 29 01 00 00 00 00 02 FF EE
+ 29 01 00 00 00 00 02 12 50
+ 29 01 00 00 00 00 02 13 02
+ 29 01 00 00 00 00 02 6A 60
+ 29 01 00 00 00 00 02 FF 00
+ 29 01 00 00 78 00 02 29 00];
+
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
- 05 01 00 00 78 02 10 00];
+ qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index e8674a0..2eaa32f 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -210,6 +210,41 @@
qcom,pet-time = <10000>;
qcom,ipi-ping;
};
+
+ qcom,ocmem@fdd00000 {
+ compatible = "qcom,msm-ocmem";
+ reg = <0xfdd00000 0x2000>,
+ <0xfdd02000 0x2000>,
+ <0xfe070000 0x400>,
+ <0xfec00000 0x180000>;
+ reg-names = "ocmem_ctrl_physical", "dm_ctrl_physical", "br_ctrl_physical", "ocmem_physical";
+ interrupts = <0 76 0>, <0 77 0>;
+ interrupt-names = "ocmem_irq", "dm_irq";
+ qcom,ocmem-num-regions = <0x3>;
+ qcom,ocmem-num-macros = <0x18>;
+ qcom,resource-type = <0x706d636f>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfec00000 0x180000>;
+
+ partition@0 {
+ reg = <0x0 0x100000>;
+ qcom,ocmem-part-name = "graphics";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@80000 {
+ reg = <0x100000 0x80000>;
+ qcom,ocmem-part-name = "lp_audio";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@100000 {
+ reg = <0x100000 0x80000>;
+ qcom,ocmem-part-name = "video";
+ qcom,ocmem-part-min = <0x55000>;
+ };
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ce050a4..b801da8 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -148,14 +148,15 @@
<0x0 0x40 0x6>,
<0x0 0x40 0x7>;
- interrupt-names = "vsense_for_r",
- "vsense_avg",
- "sw_cc_thr",
- "ocv_thr",
- "charge_begin",
- "good_ocv",
+ interrupt-names = "cc_thr",
"ocv_for_r",
- "cc_thr";
+ "good_ocv",
+ "charge_begin",
+ "ocv_thr",
+ "sw_cc_thr",
+ "vsense_avg",
+ "vsense_for_r";
+
};
};
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index dee64e5..9574b7d 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -35,6 +35,13 @@
reg = <25>;
};
+ qcom,ion-heap@22 { /* adsp heap */
+ compatible = "qcom,msm-ion-reserve";
+ reg = <22>;
+ qcom,heap-align = <0x1000>;
+ linux,contiguous-region = <&adsp_mem>;
+ };
+
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index acab5e4..bd32138 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -37,6 +37,17 @@
};
};
+ i2c@f9925000 { /* BLSP1 QUP3 */
+ nfc-nci@0e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 21 0x00>;
+ qcom,dis-gpio = <&msmgpio 20 0x00>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <21 0>;
+ qcom,clk-gpio = <&pm8226_gpios 3 0>;
+ };
+ };
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
@@ -342,6 +353,11 @@
};
gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
};
gpio@c300 { /* GPIO 4 */
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 4e4b5db..d9bd5e8 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -18,7 +18,7 @@
reg = <0xf9089000 0x1000>;
qcom,core-id = <0>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -35,7 +35,7 @@
reg = <0xf9099000 0x1000>;
qcom,core-id = <1>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -52,7 +52,7 @@
reg = <0xf90a9000 0x1000>;
qcom,core-id = <2>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -69,7 +69,7 @@
reg = <0xf90b9000 0x1000>;
qcom,core-id = <3>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -367,6 +367,13 @@
qcom,pc-resets-timer;
};
+ qcom,cpu-sleep-status@f9088008{
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x100>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+
qcom,rpm-log@fc19dc00 {
compatible = "qcom,rpm-log";
reg = <0xfc19dc00 0x4000>;
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index db2f4e6..2148e1d 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -51,6 +51,11 @@
qcom,cpr-apc-volt-step = <10000>;
};
+&msm_gpu {
+ /* Updated chip ID */
+ qcom,chipid = <0x03000512>;
+};
+
&soc {
qcom,acpuclk@f9011050 {
reg = <0xf9011050 0x8>,
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b14a406..c151948 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -30,6 +30,12 @@
label = "secure_mem";
};
+ adsp_mem: adsp_region {
+ linux,contiguous-region;
+ reg = <0 0x2000000>;
+ label = "adsp_mem";
+ };
+
qsecom_mem: qsecom_region {
linux,contiguous-region;
reg = <0 0x780000>;
@@ -714,6 +720,18 @@
qcom,pmic-arb-channel = <0>;
};
+ i2c@f9925000 { /* BLSP-1 QUP-3 */
+ cell-index = <2>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9925000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 97 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <400000>;
+ qcom,i2c-src-freq = <19200000>;
+ };
i2c@f9926000 { /* BLSP-1 QUP-4 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index 0d34868..c48eaf7 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -18,7 +18,7 @@
reg = <0xf9089000 0x1000>;
qcom,core-id = <0>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -35,7 +35,7 @@
reg = <0xf9099000 0x1000>;
qcom,core-id = <1>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -52,7 +52,7 @@
reg = <0xf90a9000 0x1000>;
qcom,core-id = <2>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -69,7 +69,7 @@
reg = <0xf90b9000 0x1000>;
qcom,core-id = <3>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
+ qcom,saw2-cfg = <0x00>;
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
@@ -369,6 +369,13 @@
qcom,pc-resets-timer;
};
+ qcom,cpu-sleep-status@f9088008{
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x100>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+
qcom,rpm-log@fc19dc00 {
compatible = "qcom,rpm-log";
reg = <0xfc19dc00 0x4000>;
diff --git a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
index 2e18ed7..e73573a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
@@ -64,7 +64,7 @@
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 14 0>,
<&msmgpio 15 0>,
- <&msmgpio 8 0>;
+ <&msmgpio 88 0>;
qcom,gpio-reset = <1>;
qcom,gpio-standby = <2>;
qcom,gpio-req-tbl-num = <0 1 2>;
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dts
index 7b45194..4a2c57c 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -65,11 +65,11 @@
interrupts = <81 0x2>;
vdd-supply = <&pm8110_l19>;
vio-supply = <&pm8110_l14>;
- kionix,min_interval = <5>;
- kionix,init_interval = <200>;
- kionix,axis_map_x = <1>;
- kionix,axis_map_y = <0>;
- kionix,axis_map_z = <2>;
+ kionix,min-interval = <5>;
+ kionix,init-interval = <200>;
+ kionix,axis-map-x = <1>;
+ kionix,axis-map-y = <0>;
+ kionix,axis-map-z = <2>;
kionix,g-range = <2>;
kionix,negate-x;
kionix,negate-y;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 72d9317..ad0980c 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -769,6 +769,9 @@
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
qcom,freq-control-mask = <0xf>;
+ qcom,core-limit-temp = <80>;
+ qcom,core-temp-hysteresis = <10>;
+ qcom,core-control-mask = <0xe>;
};
qcom,ipc-spinlock@fd484000 {
@@ -819,12 +822,6 @@
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
};
- qcom,msm-contig-mem {
- compatible = "qcom,msm-contig-mem";
- qcom,memory-reservation-type = "EBI1";
- qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
- };
-
jtag_mm0: jtagmm@fc34c000 {
compatible = "qcom,jtag-mm";
reg = <0xfc34c000 0x1000>,
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
index 31f3a90..b9f2125 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -36,6 +36,8 @@
qcom,mount-angle = <0>;
qcom,actuator-src = <&actuator0>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -73,6 +75,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "imx135";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,actuator-src = <&actuator1>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -111,6 +115,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -146,6 +152,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 2a60df4..6937385 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -48,6 +48,7 @@
atmel,i2c-pull-up;
atmel,no-force-update;
atmel,cfg_1 {
+ atmel,fw-name = "atmel_8974_fluid_v1_0_AA.hex";
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
atmel,version = <0x10>;
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 1610f1f..9fee2e5 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -369,8 +369,9 @@
compatible = "qcom,coresight-hwevent";
reg = <0xfdf30018 0x80>,
<0xf9011080 0x80>,
- <0xfd4ab160 0x80>;
- reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+ <0xfd4ab160 0x80>,
+ <0xfc401600 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
coresight-id = <29>;
coresight-name = "coresight-hwevent";
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 3d2308d..638e6dd 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -43,6 +43,7 @@
atmel,i2c-pull-up;
atmel,no-force-update;
atmel,cfg_1 {
+ atmel,fw-name = "atmel_8974_fluid_v1_0_AA.hex";
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
atmel,version = <0x10>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 28111fa..4af48cc 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -43,6 +43,7 @@
atmel,i2c-pull-up;
atmel,no-force-update;
atmel,cfg_1 {
+ atmel,fw-name = "atmel_8974_fluid_v1_0_AA.hex";
atmel,family-id = <0x82>;
atmel,variant-id = <0x19>;
atmel,version = <0x10>;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 7c191fc..d9d5aaa 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -468,6 +468,7 @@
#size-cells = <1>;
ranges;
qcom,pfm-threshold = <73>;
+ qcom,use-phase-scaling-factor;
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index eed1aae..686cdd8 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -26,12 +26,11 @@
qcom,saw2-spm-dly= <0x3C102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
- 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
};
qcom,spm@f9099000 {
@@ -49,12 +48,11 @@
qcom,saw2-spm-dly= <0x3C102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
- 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
};
qcom,spm@f90a9000 {
@@ -72,12 +70,11 @@
qcom,saw2-spm-dly= <0x3C102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
- 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
};
qcom,spm@f90b9000 {
@@ -95,12 +92,11 @@
qcom,saw2-spm-dly= <0x3C102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
- 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
- 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 07 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
};
qcom,spm@f9012000 {
@@ -125,7 +121,7 @@
qcom,pfm-port = <0x2>;
qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
- qcom,saw2-spm-cmd-pc = [00 32 b0 11 42 07 01 b0 44
+ qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
50 02 32 50 0f];
};
@@ -453,4 +449,10 @@
reg-names = "phys_addr_base";
qcom,sleep-stats-version = <2>;
};
+
+ qcom,rpm-rbcpr-stats@fc000000 {
+ compatible = "qcom,rpmrbcpr-stats";
+ reg = <0xfc000000 0x1a0000>;
+ qcom,start-offset = <0x190010>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts b/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
new file mode 100644
index 0000000..74bd23d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974-cdp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974Pro CDP";
+ compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
+ qcom,msm-id = <209 1 0x10000>,
+ <211 1 0x10000>,
+ <212 1 0x10000>,
+ <214 1 0x10000>,
+ <215 1 0x10000>,
+ <217 1 0x10000>,
+ <218 1 0x10000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts b/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
new file mode 100644
index 0000000..9a31834
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974-fluid.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974Pro FLUID";
+ compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
+ qcom,msm-id = <209 3 0x10000>,
+ <211 3 0x10000>,
+ <212 3 0x10000>,
+ <214 3 0x10000>,
+ <215 3 0x10000>,
+ <217 3 0x10000>,
+ <218 3 0x10000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts b/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
new file mode 100644
index 0000000..0ec9d8a
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974-liquid.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974Pro LIQUID";
+ compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
+ qcom,msm-id = <209 9 0x10000>,
+ <211 9 0x10000>,
+ <212 9 0x10000>,
+ <214 9 0x10000>,
+ <215 9 0x10000>,
+ <217 9 0x10000>,
+ <218 9 0x10000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
new file mode 100644
index 0000000..002baf7
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974Pro MTP";
+ compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
+ qcom,msm-id = <209 8 0x10000>,
+ <211 8 0x10000>,
+ <212 8 0x10000>,
+ <214 8 0x10000>,
+ <215 8 0x10000>,
+ <217 8 0x10000>,
+ <218 8 0x10000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-ab.dtsi
new file mode 100644
index 0000000..9240514
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab.dtsi
@@ -0,0 +1,19 @@
+/* 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.
+ */
+
+/*
+ * As a general rule, only chipset-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi / msm8974pro.dtsi file(s).
+ */
+
+/include/ "msm8974pro.dtsi"
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
new file mode 100644
index 0000000..c5042b7
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
@@ -0,0 +1,25 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974pro-ac.dtsi"
+/include/ "msm8974-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974Pro-AC MTP";
+ compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
+ qcom,msm-id = <194 8 0x10000>,
+ <210 8 0x10000>,
+ <213 8 0x10000>,
+ <216 8 0x10000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-ac.dtsi
new file mode 100644
index 0000000..9240514
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac.dtsi
@@ -0,0 +1,19 @@
+/* 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.
+ */
+
+/*
+ * As a general rule, only chipset-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi / msm8974pro.dtsi file(s).
+ */
+
+/include/ "msm8974pro.dtsi"
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
new file mode 100644
index 0000000..96e78ac
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -0,0 +1,138 @@
+/* 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974.dtsi"
+/include/ "msm8974-v2-iommu.dtsi"
+/include/ "msm8974-v2-iommu-domains.dtsi"
+/include/ "msm8974-v2-pm.dtsi"
+
+&soc {
+ android_usb@fe8050c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfe8050c8 0xc8>;
+ qcom,android-usb-swfi-latency = <1>;
+ };
+
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+};
+
+/* GPU overrides */
+&msm_gpu {
+ /* Updated chip ID */
+ qcom,chipid = <0x03030001>;
+
+ /* Updated bus bandwidth requirements */
+ qcom,msm-bus,vectors-KBps =
+ /* Off */
+ <26 512 0 0>, <89 604 0 0>,
+ /* SVS */
+ <26 512 0 2400000>, <89 604 0 3000000>,
+ /* Nominal / SVS */
+ <26 512 0 4656000>, <89 604 0 3000000>,
+ /* Nominal */
+ <26 512 0 4656000>, <89 604 0 5120000>,
+ /* Turbo / Nominal */
+ <26 512 0 7464000>, <89 604 0 5120000>,
+ /* Turbo */
+ <26 512 0 7464000>, <89 604 0 6400000>;
+};
+
+&mdss_mdp {
+ qcom,vbif-settings = <0x0004 0x00000001>;
+
+ qcom,mdss-wb-off = <0x00011100 0x00011500
+ 0x00011900 0x00011D00 0x00012100>;
+ qcom,mdss-intf-off = <0x00012500 0x00012700
+ 0x00012900 0x00012b00>;
+ qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
+ qcom,mdss-has-bwc;
+ qcom,mdss-has-decimation;
+ qcom,mdss-ad-off = <0x0013100 0x00013300>;
+};
+
+&mdss_hdmi_tx {
+ reg = <0xfd922100 0x370>,
+ <0xfd922500 0x7C>,
+ <0xfc4b8000 0x60F0>;
+ reg-names = "core_physical", "phy_physical", "qfprom_physical";
+};
+
+&msm_vidc {
+ qcom,vidc-ns-map = <0x40000000 0x40000000>;
+ qcom,load-freq-tbl = <979200 465000000>,
+ <783360 465000000>,
+ <489600 266670000>,
+ <244800 133330000>;
+ qcom,reg-presets = <0x80004 0x1>,
+ <0x80070 0x11FFF>,
+ <0x80074 0xA4>,
+ <0x800A8 0x1FFF>,
+ <0x80124 0x3>,
+ <0xE0020 0x5555556>,
+ <0xE0024 0x0>;
+ qcom,bus-ports = <1>;
+ qcom,enc-ocmem-ab-ib = <0 0>,
+ <138000 1034000>,
+ <414000 1034000>,
+ <940000 1034000>,
+ <1880000 2068000>,
+ <3008000 3309000>,
+ <3760000 4136000>,
+ <4468000 2457000>;
+ qcom,dec-ocmem-ab-ib = <0 0>,
+ <176000 519000>,
+ <456000 519000>,
+ <864000 519000>,
+ <1728000 1038000>,
+ <2766000 1661000>,
+ <3456000 2076000>,
+ <3662000 2198000>;
+ qcom,enc-ddr-ab-ib = <0 0>,
+ <120000 302000>,
+ <364000 302000>,
+ <804000 302000>,
+ <1608000 604000>,
+ <2576000 967000>,
+ <4680000 1404000>,
+ <49880000 1496000>;
+ qcom,dec-ddr-ab-ib = <0 0>,
+ <208000 303000>,
+ <536000 303000>,
+ <1012000 303000>,
+ <2024000 606000>,
+ <3240000 970000>,
+ <4048000 1212000>,
+ <4264000 1279000>;
+ qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
+ &venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
+ qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
+ qcom,buffer-type-tz-usage-table = <0x91 0x1>,
+ <0x42 0x2>,
+ <0x120 0x3>;
+};
+
+&krait_pdn {
+ qcom,use-phase-switching;
+};
+
+&tspp {
+ vdd_cx-supply = <&pm8841_s2_corner>;
+};
diff --git a/arch/arm/boot/dts/msm9625-v2.1.dtsi b/arch/arm/boot/dts/msm9625-v2.1.dtsi
index 65ff96a..5720700 100644
--- a/arch/arm/boot/dts/msm9625-v2.1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.1.dtsi
@@ -34,3 +34,7 @@
&ipa_hw {
qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
};
+
+&hsusb_otg {
+ qcom,hsusb-l1-supported;
+};
diff --git a/arch/arm/boot/dts/msm9625-v2.dtsi b/arch/arm/boot/dts/msm9625-v2.dtsi
index b078309..14105cb 100644
--- a/arch/arm/boot/dts/msm9625-v2.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.dtsi
@@ -46,3 +46,7 @@
&ldrex_spinlock {
status = "ok";
};
+
+&hsusb_otg {
+ qcom,hsusb-l1-supported;
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 636c0f8..dda32ce 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -148,7 +148,7 @@
interrupts = <0 109 0>;
};
- usb@f9a55000 {
+ hsusb_otg: usb@f9a55000 {
compatible = "qcom,hsusb-otg";
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0 0 140 0>;
@@ -195,6 +195,7 @@
hsic,consider-ipa-handshake;
hsic,log2-itc = <3>;
qcom,ahb-async-bridge-bypass;
+ hsic,disable-cerr;
};
qcom,usbbam@f9a44000 {
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index 968daff..a9cca0b 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -96,4 +96,9 @@
qcom,pet-time = <10000>;
qcom,ipi-ping;
};
+
+ qcom,msm-mem-hole {
+ compatible = "qcom,msm-mem-hole";
+ qcom,memblock-remove = <0x07f00000 0x8000000>; /* Address and size of hole */
+ };
};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 9cd37d1..2965607 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -399,3 +399,8 @@
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index cb6161b..4a5c9a7 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -327,6 +327,18 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=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_SERIAL=y
CONFIG_USB_SERIAL_CSVT=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -403,10 +415,12 @@
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_NFC_QNCI=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index e6ab4a1..02d4873 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -352,6 +352,18 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=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_SERIAL=y
CONFIG_USB_SERIAL_CSVT=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -439,10 +451,12 @@
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_NFC_QNCI=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 2cfad74..010bc10 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -272,6 +272,7 @@
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_MSM_CAMERA is not set
CONFIG_OV8825=y
+CONFIG_s5k4e1=y
CONFIG_HI256=y
CONFIG_MSM_CAMERA_SENSOR=y
# CONFIG_MSM_CPP is not set
@@ -374,6 +375,7 @@
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
@@ -382,3 +384,4 @@
CONFIG_CRC_CCITT=y
CONFIG_INPUT_KXTJ9=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_SENSORS_STK3X1X=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index cf261d2..7225ec5 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -270,6 +270,7 @@
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_MSM_CAMERA is not set
CONFIG_OV8825=y
+CONFIG_s5k4e1=y
CONFIG_HI256=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_CCI=y
@@ -415,6 +416,7 @@
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
@@ -425,3 +427,4 @@
CONFIG_CRC_CCITT=y
CONFIG_INPUT_KXTJ9=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_SENSORS_STK3X1X=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index d770e3f..cdf4263 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -63,6 +63,7 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_MSM_BUS_SCALING=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
@@ -471,6 +472,7 @@
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_XCBC=y
@@ -480,3 +482,4 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8eecf79..19d428b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -62,6 +62,7 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_MSM_BUS_SCALING=y
CONFIG_MSM_BUSPM_DEV=m
CONFIG_MSM_WATCHDOG_V2=y
@@ -503,6 +504,7 @@
CONFIG_DEBUG_LL=y
CONFIG_EARLY_PRINTK=y
CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_XCBC=y
@@ -512,3 +514,4 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 6e94b32..0241da1 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -902,11 +902,13 @@
static int perf_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
void *v)
{
+ struct pmu *pmu;
switch (cmd) {
case CPU_PM_ENTER:
if (cpu_has_active_perf((int)v)) {
armpmu_update_counters();
- perf_pmu_disable(&cpu_pmu->pmu);
+ pmu = &cpu_pmu->pmu;
+ pmu->pmu_disable(pmu);
}
break;
@@ -919,7 +921,8 @@
*/
__get_cpu_var(from_idle) = 1;
cpu_pmu->reset(NULL);
- perf_pmu_enable(&cpu_pmu->pmu);
+ pmu = &cpu_pmu->pmu;
+ pmu->pmu_enable(pmu);
}
break;
}
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e9a236e..300b2da 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -87,7 +87,7 @@
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V4) += pil-q6v4.o pil-q6v4-lpass.o
obj-$(CONFIG_MSM_PIL_MODEM_QDSP6V4) += pil-q6v4.o pil-q6v4-mss.o
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
-obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
+obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
@@ -309,6 +309,7 @@
obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
+obj-$(CONFIG_ARCH_MSMKRYPTON) += clock-local2.o clock-pll.o clock-krypton.o clock-rpm.o clock-voter.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index c722304..2c120da 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -44,6 +44,8 @@
uint32_t acpuclk_get_switch_time(void)
{
+ if (!acpuclk_data)
+ return 0;
return acpuclk_data->switch_time_us;
}
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 7dc9a90..2a6bbb7 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -28,6 +28,7 @@
#include <mach/restart.h>
#include <mach/socinfo.h>
#include <mach/clk-provider.h>
+#include <mach/msm_smem.h>
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
@@ -84,6 +85,7 @@
*/
void __init apq8084_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_clock_init(&msm8084_clock_init_data);
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 378edc8..a32031d 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -136,8 +136,8 @@
static struct gpiomux_setting lcd_rst_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
- .dir = GPIOMUX_OUT_LOW,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_OUT_HIGH,
};
static struct gpiomux_setting lcd_rst_sus_cfg = {
@@ -211,6 +211,18 @@
[GPIOMUX_SUSPENDED] = &gpio_spi_cs_eth_config,
},
},
+ { /* NFC */
+ .gpio = 10, /* BLSP1 QUP3 I2C_DAT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ { /* NFC */
+ .gpio = 11, /* BLSP1 QUP3 I2C_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
};
static struct msm_gpiomux_config msm_synaptics_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 39efcd8..5ad6175 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -44,6 +44,7 @@
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
#include <mach/rpm-regulator-smd.h>
+#include <mach/msm_smem.h>
#include <linux/msm_thermal.h>
#include "board-dt.h"
#include "clock.h"
@@ -107,6 +108,7 @@
*/
void __init msm8226_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index b4d77f1..c6c9d14 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -45,6 +45,7 @@
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
#include <mach/rpm-regulator-smd.h>
+#include <mach/msm_smem.h>
#include <linux/msm_thermal.h>
#include "board-dt.h"
#include "clock.h"
@@ -102,6 +103,7 @@
void __init msm8610_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 771359c..68af757 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -40,6 +40,7 @@
#include <mach/rpm-smd.h>
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
+#include <mach/msm_smem.h>
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
@@ -91,6 +92,7 @@
*/
void __init msm8974_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 56246dd..fad2efc 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -39,6 +39,7 @@
#include <mach/rpm-regulator-smd.h>
#include "board-dt.h"
#include <mach/msm_bus_board.h>
+#include <mach/msm_smem.h>
#include "clock.h"
#include "modem_notifier.h"
#include "lpm_resources.h"
@@ -231,6 +232,7 @@
*/
void __init msm9625_add_drivers(void)
{
+ msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index b40fcfa..0d06b83 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -31,19 +31,6 @@
#include "clock.h"
#include "devices.h"
-static struct clk_lookup msm_clocks_dummy[] = {
- CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("core_clk", SPI_CLK, "f9928000.spi", OFF),
- CLK_DUMMY("iface_clk", SPI_P_CLK, "f9928000.spi", OFF),
-
-};
-
-static struct clock_init_data msm_dummy_clock_init_data __initdata = {
- .table = msm_clocks_dummy,
- .size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
static struct of_dev_auxdata msmkrypton_auxdata_lookup[] __initdata = {
{}
};
@@ -57,7 +44,7 @@
void __init msmkrypton_add_drivers(void)
{
msm_smd_init();
- msm_clock_init(&msm_dummy_clock_init_data);
+ msm_clock_init(&msmkrypton_clock_init_data);
}
static void __init msmkrypton_map_io(void)
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 574c979..cfdc074 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -26,6 +26,7 @@
#include <mach/restart.h>
#include <mach/socinfo.h>
#include <mach/clk-provider.h>
+#include <mach/msm_smem.h>
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
@@ -95,6 +96,7 @@
*/
void __init msmsamarium_add_drivers(void)
{
+ msm_smem_init();
msm_clock_init(&msm_dummy_clock_init_data);
}
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index bec9f1b4..940e24b 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -369,6 +369,27 @@
CLK_DUMMY("core_clk", NULL, "fe054000.qcom,iommu", OFF),
CLK_DUMMY("iface_clk", NULL, "fe064000.qcom,iommu", OFF),
CLK_DUMMY("core_clk", NULL, "fe064000.qcom,iommu", OFF),
+
+ /* CoreSight clocks */
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc326000.tmc", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc324000.replicator", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc325000.tmc", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc323000.funnel", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc321000.funnel", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc322000.funnel", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc345000.funnel", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc36c000.funnel", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fc302000.stm", OFF),
+
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc326000.tmc", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc324000.replicator", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc325000.tmc", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc323000.funnel", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc321000.funnel", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc322000.funnel", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc345000.funnel", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc36c000.funnel", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc302000.stm", OFF),
};
struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 7f0a394..d48fa4a 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2857,7 +2857,6 @@
static struct clk_freq_tbl ftbl_kpss_ahb_clk[] = {
F_GCC(19200000, xo_a_clk, 0, 0, 0),
F_GCC(37500000, gpll0, 16, 0, 0),
- F_GCC(75000000, gpll0, 8, 0, 0),
F_END
};
@@ -2870,7 +2869,6 @@
.c = {
.dbg_name = "kpss_ahb_clk_src",
.ops = &clk_ops_rcg,
- VDD_DIG_FMAX_MAP2(LOW, 37500000, NOMINAL, 75000000),
CLK_INIT(kpss_ahb_clk_src.c),
},
};
@@ -2901,6 +2899,7 @@
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);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &xo.c);
#ifdef CONFIG_DEBUG_FS
@@ -3113,6 +3112,9 @@
CLK_LOOKUP("apc3_m_clk", apc3_m_clk, ""),
CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
+ /* LPM Resources */
+ CLK_LOOKUP("xo", cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
+
/* PIL-LPASS */
CLK_LOOKUP("xo", cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "fe200000.qcom,lpass"),
@@ -3125,7 +3127,8 @@
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"),
-
+ /* NFC */
+ CLK_LOOKUP("ref_clk", cxo_d1_a_pin.c, "2-000e"),
/* PIL-PRONTO */
CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
@@ -3250,6 +3253,9 @@
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, "f9927000.i2c"),
+ /* I2C Clocks nfc */
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
/* lsuart-v14 Clocks */
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
@@ -3315,7 +3321,6 @@
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 75d8984..b1b9397 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -510,6 +510,15 @@
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpass_pil_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_mss_pil_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mba_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_wlan_clk, &gcc_xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_acpu_clk, &gcc_xo_clk_src.c);
+
static DEFINE_CLK_MEASURE(apc0_m_clk);
static DEFINE_CLK_MEASURE(apc1_m_clk);
static DEFINE_CLK_MEASURE(apc2_m_clk);
@@ -2740,17 +2749,18 @@
};
static struct clk_lookup msm_clocks_8610[] = {
- CLK_LOOKUP("xo", gcc_xo_clk_src.c, "msm_otg"),
- CLK_LOOKUP("xo", gcc_xo_clk_src.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("xo", cxo_otg_clk.c, "msm_otg"),
+ CLK_LOOKUP("xo", cxo_lpass_pil_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("xo", cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
- CLK_LOOKUP("xo", gcc_xo_clk_src.c, "fc880000.qcom,mss"),
+ CLK_LOOKUP("xo", cxo_mss_pil_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"),
- CLK_LOOKUP("xo", gcc_xo_clk_src.c, "pil-mba"),
- CLK_LOOKUP("xo", gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
- CLK_LOOKUP("xo", gcc_xo_clk_src.c, "fb21b000.qcom,pronto"),
+ CLK_LOOKUP("xo", cxo_pil_mba_clk.c, "pil-mba"),
+ CLK_LOOKUP("xo", cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
@@ -3003,10 +3013,12 @@
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-007d"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0020"),
CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"),
CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"),
+ CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0020"),
/* CSIPHY clocks */
@@ -3074,7 +3086,7 @@
CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("reg_clk", q6ss_ahbm_clk.c, "fe200000.qcom,lpass"),
- CLK_LOOKUP("xo", gcc_xo_a_clk_src.c, "f9011050.qcom,acpuclk"),
+ CLK_LOOKUP("xo", cxo_acpu_clk.c, "f9011050.qcom,acpuclk"),
CLK_LOOKUP("gpll0", gpll0_ao_clk_src.c, "f9011050.qcom,acpuclk"),
CLK_LOOKUP("a7sspll", a7sspll.c, "f9011050.qcom,acpuclk"),
@@ -3084,7 +3096,7 @@
CLK_LOOKUP("measure_clk", apc3_m_clk, ""),
CLK_LOOKUP("measure_clk", l2_m_clk, ""),
- CLK_LOOKUP("xo", gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("xo", cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
CLK_LOOKUP("rf_clk", cxo_a1.c, "fb000000.qcom,wcnss-wlan"),
CLK_LOOKUP("iface_clk", mdp_ahb_clk.c, "fd900000.qcom,mdss_mdp"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index ac34ed3..bd5a12e 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -831,6 +831,7 @@
static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &cxo_clk_src.c);
static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, &cxo_clk_src.c);
static DEFINE_CLK_BRANCH_VOTER(cxo_ehci_host_clk, &cxo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &cxo_clk_src.c);
static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
F(125000000, gpll0, 1, 5, 24),
@@ -4855,6 +4856,7 @@
CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
CLK_LOOKUP("xo", cxo_dwc3_clk.c, "msm_dwc3"),
CLK_LOOKUP("xo", cxo_ehci_host_clk.c, "msm_ehci_host"),
+ CLK_LOOKUP("xo", cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 14648ec..3b07069 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -430,9 +430,10 @@
static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, LONG_MAX);
-
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &cxo_clk_src.c);
+
static struct clk_freq_tbl ftbl_gcc_ipa_clk[] = {
F( 50000000, gpll0, 12, 0, 0),
F( 92310000, gpll0, 6.5, 0, 0),
@@ -1762,6 +1763,7 @@
static struct clk_lookup msm_clocks_9625[] = {
CLK_LOOKUP("xo", cxo_clk_src.c, ""),
+ CLK_LOOKUP("xo", cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
CLK_LOOKUP("pll0", gpll0_activeonly_clk_src.c, "f9010008.qcom,acpuclk"),
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index fe43b72..8ec87d1 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -22,6 +22,8 @@
#include <linux/list.h>
#include <linux/clkdev.h>
#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
#include <mach/clk-provider.h>
#include "clock.h"
@@ -351,49 +353,24 @@
debugfs_remove_recursive(clk_dir);
return -ENOMEM;
}
-
-/**
- * clock_debug_register() - Add additional clocks to clock debugfs hierarchy
- * @table: Table of clocks to create debugfs nodes for
- * @size: Size of @table
- *
- * Use this function to register additional clocks in debugfs. The clock debugfs
- * hierarchy must have already been initialized with clock_debug_init() prior to
- * calling this function. Unlike clock_debug_init(), this may be called multiple
- * times with different clock lists and can be used after the kernel has
- * finished booting.
- */
-int clock_debug_register(struct clk_lookup *table, size_t size)
-{
- struct clk_table *clk_table;
- unsigned long flags;
- int i;
-
- clk_table = kmalloc(sizeof(*clk_table), GFP_KERNEL);
- if (!clk_table)
- return -ENOMEM;
-
- clk_table->clocks = table;
- clk_table->num_clocks = size;
-
- spin_lock_irqsave(&clk_list_lock, flags);
- list_add_tail(&clk_table->node, &clk_list);
- spin_unlock_irqrestore(&clk_list_lock, flags);
-
- for (i = 0; i < size; i++)
- clock_debug_add(table[i].clk);
-
- return 0;
-}
+static DEFINE_MUTEX(clk_debug_lock);
+static int clk_debug_init_once;
/**
* clock_debug_init() - Initialize clock debugfs
+ * Lock clk_debug_lock before invoking this function.
*/
-int __init clock_debug_init(void)
+static int clock_debug_init(void)
{
+ if (clk_debug_init_once)
+ return 0;
+
+ clk_debug_init_once = 1;
+
debugfs_base = debugfs_create_dir("clk", NULL);
if (!debugfs_base)
return -ENOMEM;
+
if (!debugfs_create_u32("debug_suspend", S_IRUGO | S_IWUSR,
debugfs_base, &debug_suspend)) {
debugfs_remove_recursive(debugfs_base);
@@ -407,6 +384,45 @@
return 0;
}
+/**
+ * clock_debug_register() - Add additional clocks to clock debugfs hierarchy
+ * @table: Table of clocks to create debugfs nodes for
+ * @size: Size of @table
+ *
+ */
+int clock_debug_register(struct clk_lookup *table, size_t size)
+{
+ struct clk_table *clk_table;
+ unsigned long flags;
+ int i, ret;
+
+ mutex_lock(&clk_debug_lock);
+
+ ret = clock_debug_init();
+ if (ret)
+ goto out;
+
+ clk_table = kmalloc(sizeof(*clk_table), GFP_KERNEL);
+ if (!clk_table) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ clk_table->clocks = table;
+ clk_table->num_clocks = size;
+
+ spin_lock_irqsave(&clk_list_lock, flags);
+ list_add_tail(&clk_table->node, &clk_list);
+ spin_unlock_irqrestore(&clk_list_lock, flags);
+
+ for (i = 0; i < size; i++)
+ clock_debug_add(table[i].clk);
+
+out:
+ mutex_unlock(&clk_debug_lock);
+ return ret;
+}
+
static int clock_debug_print_clock(struct clk *c)
{
char *start = "";
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
index 4d74533..bea82d5 100644
--- a/arch/arm/mach-msm/clock-generic.c
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/err.h>
#include <linux/clk.h>
#include <mach/clk-provider.h>
@@ -67,10 +68,12 @@
{
struct mux_clk *mux = to_mux_clk(c);
int i;
- long prate, max_prate = 0, rrate = LONG_MAX;
+ unsigned long prate, max_prate = 0, rrate = ULONG_MAX;
for (i = 0; i < mux->num_parents; i++) {
prate = clk_round_rate(mux->parents[i].src, rate);
+ if (IS_ERR_VALUE(prate))
+ continue;
if (prate < rate) {
max_prate = max(prate, max_prate);
continue;
@@ -78,7 +81,7 @@
rrate = min(rrate, prate);
}
- if (rrate == LONG_MAX)
+ if (rrate == ULONG_MAX)
rrate = max_prate;
return rrate ? rrate : -EINVAL;
@@ -200,7 +203,7 @@
{
struct div_clk *d = to_div_clk(c);
unsigned int div, min_div, max_div;
- long p_rrate, rrate = LONG_MAX;
+ unsigned long p_rrate, rrate = ULONG_MAX;
rate = max(rate, 1UL);
@@ -208,12 +211,12 @@
min_div = max_div = d->div;
else {
min_div = max(d->min_div, 1U);
- max_div = min(d->max_div, (unsigned int) (LONG_MAX / rate));
+ max_div = min(d->max_div, (unsigned int) (ULONG_MAX / rate));
}
for (div = min_div; div <= max_div; div++) {
p_rrate = clk_round_rate(c->parent, rate * div);
- if (p_rrate < 0)
+ if (IS_ERR_VALUE(p_rrate))
break;
p_rrate /= div;
@@ -225,7 +228,7 @@
* for a higher divider. So, stop trying higher dividers.
*/
if (p_rrate < rate) {
- if (rrate == LONG_MAX) {
+ if (rrate == ULONG_MAX) {
rrate = p_rrate;
if (best_div)
*best_div = div;
@@ -242,7 +245,7 @@
break;
}
- if (rrate == LONG_MAX)
+ if (rrate == ULONG_MAX)
return -EINVAL;
return rrate;
@@ -263,6 +266,12 @@
if (rrate != rate)
return -EINVAL;
+ /*
+ * For fixed divider clock we don't want to return an error if the
+ * requested rate matches the achievable rate. So, don't check for
+ * !d->ops and return an error. __div_round_rate() ensures div ==
+ * d->div if !d->ops.
+ */
if (div > d->div)
rc = d->ops->set_div(d, div);
if (rc)
@@ -296,7 +305,7 @@
static int div_enable(struct clk *c)
{
struct div_clk *d = to_div_clk(c);
- if (d->ops->enable)
+ if (d->ops && d->ops->enable)
return d->ops->enable(d);
return 0;
}
@@ -304,7 +313,7 @@
static void div_disable(struct clk *c)
{
struct div_clk *d = to_div_clk(c);
- if (d->ops->disable)
+ if (d->ops && d->ops->disable)
return d->ops->disable(d);
}
@@ -312,7 +321,7 @@
{
struct div_clk *d = to_div_clk(c);
- if (d->ops->get_div)
+ if (d->ops && d->ops->get_div)
d->div = max(d->ops->get_div(d), 1);
d->div = max(d->div, 1U);
c->rate = clk_get_rate(c->parent) / d->div;
@@ -386,8 +395,13 @@
if (div == d->div)
return 0;
- if (d->ops->set_div)
- rc = d->ops->set_div(d, div);
+ /*
+ * For fixed divider clock we don't want to return an error if the
+ * requested rate matches the achievable rate. So, don't check for
+ * !d->ops and return an error. __slave_div_round_rate() ensures
+ * div == d->div if !d->ops.
+ */
+ rc = d->ops->set_div(d, div);
if (rc)
return rc;
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
new file mode 100644
index 0000000..aaee003
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -0,0 +1,125 @@
+/* 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+
+static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("core_clk", SPI_CLK, "f9928000.spi", OFF),
+ CLK_DUMMY("iface_clk", SPI_P_CLK, "f9928000.spi", OFF),
+
+ CLK_DUMMY("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc", OFF),
+ CLK_DUMMY("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc", OFF),
+ CLK_DUMMY("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc", OFF),
+ CLK_DUMMY("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc", OFF),
+ CLK_DUMMY("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc", OFF),
+ CLK_DUMMY("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc", OFF),
+ CLK_DUMMY("mem_clk", bimc_msmbus_clk.c, "msm_bimc", OFF),
+ CLK_DUMMY("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc", OFF),
+ CLK_DUMMY("mem_clk", bimc_acpu_a_clk.c, "", OFF),
+
+ CLK_DUMMY("clktype", gcc_imem_axi_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_imem_cfg_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_mss_cfg_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_mss_q6_bimc_axi_clk , "drivername", OFF),
+ CLK_DUMMY("mem_clk", gcc_usb30_master_clk , "drivername", OFF),
+ CLK_DUMMY("sleep_clk", gcc_usb30_sleep_clk , "drivername", OFF),
+ CLK_DUMMY("utmi_clk", gcc_usb30_mock_utmi_clk , "drivername", OFF),
+ CLK_DUMMY("iface_clk", gcc_usb_hsic_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_usb_hsic_system_clk , "drivername", OFF),
+ CLK_DUMMY("phyclk", gcc_usb_hsic_clk , "drivername", OFF),
+ CLK_DUMMY("cal_clk", gcc_usb_hsic_io_cal_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_usb_hs_system_clk , "drivername", OFF),
+ CLK_DUMMY("iface_clk", gcc_usb_hs_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("sleep_a_clk", gcc_usb2a_phy_sleep_clk , "drivername", OFF),
+ CLK_DUMMY("sleep_b_clk", gcc_usb2b_phy_sleep_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_sdcc2_apps_clk , "drivername", OFF),
+ CLK_DUMMY("iface_clk", gcc_sdcc2_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_sdcc3_apps_clk , "drivername", OFF),
+ CLK_DUMMY("iface_clk", gcc_sdcc3_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", sdcc3_apps_clk_src , "drivername", OFF),
+ CLK_DUMMY("iface_clk", gcc_blsp1_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup1_spi_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup1_i2c_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_uart1_apps_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup2_spi_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup2_i2c_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_uart2_apps_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup3_spi_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup3_i2c_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_uart3_apps_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup4_spi_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup4_i2c_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_uart4_apps_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup5_spi_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup5_i2c_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_uart5_apps_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup6_spi_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup6_i2c_apps_clk, "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_uart6_apps_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", blsp1_uart6_apps_clk_src , "drivername", OFF),
+ CLK_DUMMY("iface_clk", gcc_pdm_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_pdm2_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_prng_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("dma_bam_pclk", gcc_bam_dma_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("mem_clk", gcc_boot_rom_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_ce1_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_ce1_axi_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_ce1_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk_src", ce1_clk_src , "drivername", OFF),
+ CLK_DUMMY("bus_clk", gcc_lpass_q6_axi_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", pcie_pipe_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_gp1_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gp1_clk_src , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_gp2_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gp2_clk_src , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_gp3_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gp3_clk_src , "drivername", OFF),
+ CLK_DUMMY("core_clk", gcc_ipa_clk , "drivername", OFF),
+ CLK_DUMMY("iface_clk", gcc_ipa_cnoc_clk , "drivername", OFF),
+ CLK_DUMMY("inactivity_clk", gcc_ipa_sleep_clk , "drivername", OFF),
+ CLK_DUMMY("core_clk_src", ipa_clk_src , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_dcs_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", dcs_clk_src , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_pcie_cfg_ahb_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_pcie_pipe_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_pcie_axi_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_pcie_sleep_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", gcc_pcie_axi_mstr_clk , "drivername", OFF),
+ CLK_DUMMY("clktype", pcie_pipe_clk_src , "drivername", OFF),
+ CLK_DUMMY("clktype", pcie_aux_clk_src , "drivername", OFF),
+};
+
+struct clock_init_data msmkrypton_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 582bccf..3c43223 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -23,6 +23,7 @@
#include <linux/clkdev.h>
#include <linux/list.h>
#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
#include <trace/events/power.h>
#include <mach/clk-provider.h>
#include "clock.h"
@@ -39,6 +40,8 @@
};
static LIST_HEAD(handoff_vdd_list);
+static DEFINE_MUTEX(msm_clock_init_lock);
+
/* Find the voltage level required for a given rate. */
int find_vdd_level(struct clk *clk, unsigned long rate)
{
@@ -573,7 +576,7 @@
}
EXPORT_SYMBOL(clk_set_flags);
-static struct clock_init_data *clk_init_data;
+static LIST_HEAD(initdata_list);
static void init_sibling_lists(struct clk_lookup *clock_tbl, size_t num_clocks)
{
@@ -588,33 +591,6 @@
}
}
-/**
- * msm_clock_register() - Register additional clock tables
- * @table: Table of clocks
- * @size: Size of @table
- *
- * Upon return, clock APIs may be used to control clocks registered using this
- * function. This API may only be used after msm_clock_init() has completed.
- * Unlike msm_clock_init(), this function may be called multiple times with
- * different clock lists and used after the kernel has finished booting.
- */
-int msm_clock_register(struct clk_lookup *table, size_t size)
-{
- if (!clk_init_data)
- return -ENODEV;
-
- if (!table)
- return -EINVAL;
-
- init_sibling_lists(table, size);
- clkdev_add_table(table, size);
- clock_debug_register(table, size);
-
- return 0;
-}
-EXPORT_SYMBOL(msm_clock_register);
-
-
static void vdd_class_init(struct clk_vdd_class *vdd)
{
struct handoff_vdd *v;
@@ -646,7 +622,7 @@
list_add_tail(&v->list, &handoff_vdd_list);
}
-static int __init __handoff_clk(struct clk *clk)
+static int __handoff_clk(struct clk *clk)
{
enum handoff state = HANDOFF_DISABLED_CLK;
struct handoff_clk *h = NULL;
@@ -726,29 +702,20 @@
}
/**
- * msm_clock_init() - Register and initialize a clock driver
- * @data: Driver-specific clock initialization data
+ * msm_clock_register() - Register additional clock tables
+ * @table: Table of clocks
+ * @size: Size of @table
*
- * Upon return from this call, clock APIs may be used to control
- * clocks registered with this API.
+ * Upon return, clock APIs may be used to control clocks registered using this
+ * function.
*/
-int __init msm_clock_init(struct clock_init_data *data)
+int msm_clock_register(struct clk_lookup *table, size_t size)
{
- unsigned n;
- struct clk_lookup *clock_tbl;
- size_t num_clocks;
+ int n = 0;
- if (!data)
- return -EINVAL;
+ mutex_lock(&msm_clock_init_lock);
- clk_init_data = data;
- if (clk_init_data->pre_init)
- clk_init_data->pre_init();
-
- clock_tbl = data->table;
- num_clocks = data->size;
-
- init_sibling_lists(clock_tbl, num_clocks);
+ init_sibling_lists(table, size);
/*
* Enable regulators and temporarily set them up at maximum voltage.
@@ -757,23 +724,50 @@
* late_init, by which time we assume all the clocks would have been
* handed off.
*/
- for (n = 0; n < num_clocks; n++)
- vdd_class_init(clock_tbl[n].clk->vdd_class);
+ for (n = 0; n < size; n++)
+ vdd_class_init(table[n].clk->vdd_class);
/*
* Detect and preserve initial clock state until clock_late_init() or
* a driver explicitly changes it, whichever is first.
*/
- for (n = 0; n < num_clocks; n++)
- __handoff_clk(clock_tbl[n].clk);
+ for (n = 0; n < size; n++)
+ __handoff_clk(table[n].clk);
- clkdev_add_table(clock_tbl, num_clocks);
+ clkdev_add_table(table, size);
- if (clk_init_data->post_init)
- clk_init_data->post_init();
+ clock_debug_register(table, size);
- clock_debug_init();
- clock_debug_register(clock_tbl, num_clocks);
+ mutex_unlock(&msm_clock_init_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_clock_register);
+
+/**
+ * msm_clock_init() - Register and initialize a clock driver
+ * @data: Driver-specific clock initialization data
+ *
+ * Upon return from this call, clock APIs may be used to control
+ * clocks registered with this API.
+ */
+int __init msm_clock_init(struct clock_init_data *data)
+{
+ if (!data)
+ return -EINVAL;
+
+ if (data->pre_init)
+ data->pre_init();
+
+ mutex_lock(&msm_clock_init_lock);
+ if (data->late_init)
+ list_add(&data->list, &initdata_list);
+ mutex_unlock(&msm_clock_init_lock);
+
+ msm_clock_register(data->table, data->size);
+
+ if (data->post_init)
+ data->post_init();
return 0;
}
@@ -782,12 +776,21 @@
{
struct handoff_clk *h, *h_temp;
struct handoff_vdd *v, *v_temp;
+ struct clock_init_data *initdata, *initdata_temp;
int ret = 0;
- if (clk_init_data->late_init)
- ret = clk_init_data->late_init();
-
pr_info("%s: Removing enables held for handed-off clocks\n", __func__);
+
+ mutex_lock(&msm_clock_init_lock);
+
+ list_for_each_entry_safe(initdata, initdata_temp,
+ &initdata_list, list) {
+ ret = initdata->late_init();
+ if (ret)
+ pr_err("%s: %pS failed late_init.\n", __func__,
+ initdata);
+ }
+
list_for_each_entry_safe(h, h_temp, &handoff_list, list) {
clk_disable_unprepare(h->clk);
list_del(&h->list);
@@ -800,6 +803,11 @@
kfree(v);
}
+ mutex_unlock(&msm_clock_init_lock);
+
return ret;
}
-late_initcall(clock_late_init);
+/* clock_late_init should run only after all deferred probing
+ * (excluding DLKM probes) has completed.
+ */
+late_initcall_sync(clock_late_init);
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 2a65d2f..e294f4c 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -26,6 +26,7 @@
* @late_init: called during late init
*/
struct clock_init_data {
+ struct list_head list;
struct clk_lookup *table;
size_t size;
void (*pre_init)(void);
@@ -55,16 +56,15 @@
extern struct clock_init_data msm8226_rumi_clock_init_data;
extern struct clock_init_data msm8084_clock_init_data;
extern struct clock_init_data mpq8092_clock_init_data;
+extern struct clock_init_data msmkrypton_clock_init_data;
int msm_clock_init(struct clock_init_data *data);
int find_vdd_level(struct clk *clk, unsigned long rate);
#ifdef CONFIG_DEBUG_FS
-int clock_debug_init(void);
int clock_debug_register(struct clk_lookup *t, size_t s);
void clock_debug_print_enabled(void);
#else
-static inline int clock_debug_init(void) { return 0; }
static inline int clock_debug_register(struct clk_lookup *t, size_t s)
{
return 0;
diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
index 8270197..79fb1a3 100644
--- a/arch/arm/mach-msm/hsic_sysmon.c
+++ b/arch/arm/mach-msm/hsic_sysmon.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
@@ -239,7 +239,7 @@
if (!hs)
continue;
- ret += scnprintf(buf, DEBUG_BUF_SIZE,
+ ret += scnprintf(buf + ret, DEBUG_BUF_SIZE - ret,
"---HSIC Sysmon #%d---\n"
"epin:%d, epout:%d\n"
"bytes to host: %d\n"
@@ -324,15 +324,6 @@
struct usb_endpoint_descriptor *ep_desc;
int i;
int ret = -ENOMEM;
- __u8 ifc_num;
-
- pr_debug("id:%lu", id->driver_info);
-
- ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
-
- /* is this the interface we're looking for? */
- if (ifc_num != id->driver_info)
- return -ENODEV;
hs = kzalloc(sizeof(*hs), GFP_KERNEL);
if (!hs) {
@@ -367,12 +358,17 @@
goto error;
}
- hs->id = HSIC_SYSMON_DEV_EXT_MODEM;
- hsic_sysmon_devices[HSIC_SYSMON_DEV_EXT_MODEM] = hs;
+ hs->id = HSIC_SYSMON_DEV_EXT_MODEM + id->driver_info;
+ if (hs->id >= NUM_HSIC_SYSMON_DEVS) {
+ pr_warn("invalid dev id(%d)", hs->id);
+ hs->id = 0;
+ }
+
+ hsic_sysmon_devices[hs->id] = hs;
usb_set_intfdata(ifc, hs);
hs->pdev.name = "sys_mon";
- hs->pdev.id = SYSMON_SS_EXT_MODEM;
+ hs->pdev.id = SYSMON_SS_EXT_MODEM + hs->id;
hs->pdev.dev.release = hsic_sysmon_pdev_release;
platform_device_register(&hs->pdev);
@@ -406,11 +402,12 @@
return 0;
}
-/* driver_info maps to the interface number corresponding to sysmon */
+/* driver_info is the instance number when multiple devices are present */
static const struct usb_device_id hsic_sysmon_ids[] = {
- { USB_DEVICE(0x5c6, 0x9048), .driver_info = 1, },
- { USB_DEVICE(0x5c6, 0x904C), .driver_info = 1, },
- { USB_DEVICE(0x5c6, 0x9075), .driver_info = 1, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 1), .driver_info = 0, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x904C, 1), .driver_info = 0, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9075, 1), .driver_info = 0, },
+ { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9079, 1), .driver_info = 1, },
{} /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, hsic_sysmon_ids);
diff --git a/arch/arm/mach-msm/hsic_sysmon.h b/arch/arm/mach-msm/hsic_sysmon.h
index 983f464..9655dc0 100644
--- a/arch/arm/mach-msm/hsic_sysmon.h
+++ b/arch/arm/mach-msm/hsic_sysmon.h
@@ -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
@@ -18,6 +18,7 @@
*/
enum hsic_sysmon_device_id {
HSIC_SYSMON_DEV_EXT_MODEM,
+ HSIC_SYSMON_DEV_EXT_MODEM_2,
NUM_HSIC_SYSMON_DEVS
};
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
index bc60c6e..fac6575 100644
--- a/arch/arm/mach-msm/hsic_sysmon_test.c
+++ b/arch/arm/mach-msm/hsic_sysmon_test.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
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
@@ -36,13 +37,14 @@
size_t count, loff_t *ppos)
{
struct sysmon_test_dev *dev = sysmon_dev;
+ enum hsic_sysmon_device_id id =
+ (enum hsic_sysmon_device_id)file->private_data;
int ret;
if (!dev)
return -ENODEV;
- ret = hsic_sysmon_read(HSIC_SYSMON_DEV_EXT_MODEM, dev->buf, RD_BUF_SIZE,
- &dev->buflen, 3000);
+ ret = hsic_sysmon_read(id, dev->buf, RD_BUF_SIZE, &dev->buflen, 3000);
if (!ret)
return simple_read_from_buffer(ubuf, count, ppos,
dev->buf, dev->buflen);
@@ -53,7 +55,9 @@
static ssize_t sysmon_test_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
- struct sysmon_test_dev *dev = sysmon_dev;
+ struct sysmon_test_dev *dev = sysmon_dev;
+ enum hsic_sysmon_device_id id =
+ (enum hsic_sysmon_device_id)file->private_data;
int ret;
if (!dev)
@@ -64,8 +68,7 @@
return 0;
}
- ret = hsic_sysmon_write(HSIC_SYSMON_DEV_EXT_MODEM,
- dev->buf, count, 1000);
+ ret = hsic_sysmon_write(id, dev->buf, count, 1000);
if (ret < 0) {
pr_err("error writing to hsic_sysmon");
return ret;
@@ -76,38 +79,44 @@
static int sysmon_test_open(struct inode *inode, struct file *file)
{
- return hsic_sysmon_open(HSIC_SYSMON_DEV_EXT_MODEM);
+ file->private_data = inode->i_private;
+ return hsic_sysmon_open((enum hsic_sysmon_device_id)inode->i_private);
}
static int sysmon_test_release(struct inode *inode, struct file *file)
{
- hsic_sysmon_close(HSIC_SYSMON_DEV_EXT_MODEM);
+ hsic_sysmon_close((enum hsic_sysmon_device_id)inode->i_private);
return 0;
}
-static struct dentry *dfile;
-const struct file_operations sysmon_test_ops = {
+static const struct file_operations sysmon_test_ops = {
.read = sysmon_test_read,
.write = sysmon_test_write,
.open = sysmon_test_open,
.release = sysmon_test_release
};
+static struct dentry *dfile0, *dfile1;
+
static int __init sysmon_test_init(void)
{
sysmon_dev = kzalloc(sizeof(*sysmon_dev), GFP_KERNEL);
if (!sysmon_dev)
return -ENOMEM;
- dfile = debugfs_create_file("hsic_sysmon_test", 0666, NULL,
- 0, &sysmon_test_ops);
+ dfile0 = debugfs_create_file("hsic_sysmon_test.0", 0666, NULL,
+ (void *)HSIC_SYSMON_DEV_EXT_MODEM, &sysmon_test_ops);
+ dfile1 = debugfs_create_file("hsic_sysmon_test.1", 0666, NULL,
+ (void *)HSIC_SYSMON_DEV_EXT_MODEM_2, &sysmon_test_ops);
return 0;
}
static void __exit sysmon_test_exit(void)
{
- if (dfile)
- debugfs_remove(dfile);
+ if (dfile0)
+ debugfs_remove(dfile0);
+ if (dfile1)
+ debugfs_remove(dfile1);
kfree(sysmon_dev);
}
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
index 0f689f1..f6feda0 100644
--- a/arch/arm/mach-msm/include/mach/clock-generic.h
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -72,8 +72,6 @@
struct clk_div_ops {
int (*set_div)(struct div_clk *clk, int div);
int (*get_div)(struct div_clk *clk);
-
- /* Optional */
bool (*is_enabled)(struct div_clk *clk);
int (*enable)(struct div_clk *clk);
void (*disable)(struct div_clk *clk);
@@ -84,6 +82,7 @@
unsigned int min_div;
unsigned int max_div;
unsigned long rate_margin;
+ /* Optional */
struct clk_div_ops *ops;
/* Fields not used by helper function. */
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index eeda7ce..541ca44 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -189,7 +189,8 @@
};
enum dump_reg {
- DUMP_REG_FAR0,
+ DUMP_REG_FIRST,
+ DUMP_REG_FAR0 = DUMP_REG_FIRST,
DUMP_REG_FAR1,
DUMP_REG_PAR0,
DUMP_REG_PAR1,
@@ -201,10 +202,23 @@
DUMP_REG_SCTLR,
DUMP_REG_ACTLR,
DUMP_REG_PRRR,
+ DUMP_REG_MAIR0 = DUMP_REG_PRRR,
DUMP_REG_NMRR,
+ DUMP_REG_MAIR1 = DUMP_REG_NMRR,
MAX_DUMP_REGS,
};
+struct dump_regs_tbl {
+ /*
+ * To keep things context-bank-agnostic, we only store the CB
+ * register offset in `key'
+ */
+ unsigned long key;
+ const char *name;
+ int offset;
+};
+extern struct dump_regs_tbl dump_regs_tbl[MAX_DUMP_REGS];
+
#define COMBINE_DUMP_REG(upper, lower) (((u64) upper << 32) | lower)
struct msm_iommu_context_reg {
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
index 1c20d04..04cd441 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
@@ -19,6 +19,8 @@
#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
#define GET_CTX_REG(reg, base, ctx) \
(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+#define GET_CTX_REG_L(reg, base, ctx) \
+ (readll_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
#define SET_GLOBAL_REG(reg, base, val) writel_relaxed((val), ((base) + (reg)))
@@ -196,7 +198,7 @@
#define GET_CONTEXTIDR(b, c) GET_CTX_REG(CB_CONTEXTIDR, (b), (c))
#define GET_PRRR(b, c) GET_CTX_REG(CB_PRRR, (b), (c))
#define GET_NMRR(b, c) GET_CTX_REG(CB_NMRR, (b), (c))
-#define GET_PAR(b, c) GET_CTX_REG(CB_PAR, (b), (c))
+#define GET_PAR(b, c) GET_CTX_REG_L(CB_PAR, (b), (c))
#define GET_FSR(b, c) GET_CTX_REG(CB_FSR, (b), (c))
#define GET_FSRRESTORE(b, c) GET_CTX_REG(CB_FSRRESTORE, (b), (c))
#define GET_FAR(b, c) GET_CTX_REG(CB_FAR, (b), (c))
@@ -1307,6 +1309,7 @@
#define CB_PAR_TF (CB_PAR_TF_MASK << CB_PAR_TF_SHIFT)
#define CB_PAR_AFF (CB_PAR_AFF_MASK << CB_PAR_AFF_SHIFT)
#define CB_PAR_PF (CB_PAR_PF_MASK << CB_PAR_PF_SHIFT)
+#define CB_PAR_EF (CB_PAR_EF_MASK << CB_PAR_EF_SHIFT)
#define CB_PAR_TLBMCF (CB_PAR_TLBMCF_MASK << CB_PAR_TLBMCF_SHIFT)
#define CB_PAR_TLBLKF (CB_PAR_TLBLKF_MASK << CB_PAR_TLBLKF_SHIFT)
#define CB_PAR_ATOT (CB_PAR_ATOT_MASK << CB_PAR_ATOT_SHIFT)
@@ -1682,11 +1685,12 @@
#define CB_PAR_TF_MASK 0x01
#define CB_PAR_AFF_MASK 0x01
#define CB_PAR_PF_MASK 0x01
+#define CB_PAR_EF_MASK 0x01
#define CB_PAR_TLBMCF_MASK 0x01
#define CB_PAR_TLBLKF_MASK 0x01
-#define CB_PAR_ATOT_MASK 0x01
-#define CB_PAR_PLVL_MASK 0x03
-#define CB_PAR_STAGE_MASK 0x01
+#define CB_PAR_ATOT_MASK 0x01ULL
+#define CB_PAR_PLVL_MASK 0x03ULL
+#define CB_PAR_STAGE_MASK 0x01ULL
/* Primary Region Remap Register: CB_PRRR */
#define CB_PRRR_TR0_MASK 0x03
@@ -2052,11 +2056,12 @@
#define CB_PAR_TF_SHIFT 1
#define CB_PAR_AFF_SHIFT 2
#define CB_PAR_PF_SHIFT 3
+#define CB_PAR_EF_SHIFT 4
#define CB_PAR_TLBMCF_SHIFT 5
#define CB_PAR_TLBLKF_SHIFT 6
#define CB_PAR_ATOT_SHIFT 31
-#define CB_PAR_PLVL_SHIFT 0
-#define CB_PAR_STAGE_SHIFT 3
+#define CB_PAR_PLVL_SHIFT 32
+#define CB_PAR_STAGE_SHIFT 35
/* Primary Region Remap Register: CB_PRRR */
#define CB_PRRR_TR0_SHIFT 0
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 697de5e..b6acef2 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -648,6 +648,8 @@
int a2_mux_write(enum a2_mux_logical_channel_id lcid, struct sk_buff *skb);
+int a2_mux_is_ch_empty(enum a2_mux_logical_channel_id lcid);
+
int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid);
int a2_mux_is_ch_full(enum a2_mux_logical_channel_id lcid);
@@ -667,6 +669,8 @@
int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params);
+void ipa_bam_reg_dump(void);
+
#else /* CONFIG_IPA */
static inline int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
@@ -686,6 +690,11 @@
return -EPERM;
}
+static inline int a2_mux_is_ch_empty(enum a2_mux_logical_channel_id lcid)
+{
+ return -EPERM;
+}
+
static inline int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid)
{
return -EPERM;
@@ -1099,6 +1108,11 @@
return -EPERM;
}
+static inline void ipa_bam_reg_dump(void)
+{
+ return;
+}
+
#endif /* CONFIG_IPA*/
#endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index a87380c..f5f1954 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -29,6 +29,7 @@
enum msm_ipc_router_event {
MSM_IPC_ROUTER_READ_CB = 0,
MSM_IPC_ROUTER_WRITE_DONE,
+ MSM_IPC_ROUTER_RESUME_TX,
};
struct comm_mode_info {
diff --git a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
index 11867f3..1641e8c 100644
--- a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
+++ b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
@@ -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
@@ -20,6 +20,7 @@
#include <linux/socket.h>
#include <linux/gfp.h>
#include <linux/qmi_encdec.h>
+#include <linux/workqueue.h>
#define QMI_COMMON_TLV_TYPE 0
@@ -45,6 +46,8 @@
void *ind_cb_priv;
int handle_reset;
wait_queue_head_t reset_waitq;
+ struct list_head pending_txn_list;
+ struct delayed_work resume_tx_work;
};
enum qmi_result_type_v01 {
@@ -153,7 +156,8 @@
void *resp, unsigned int resp_len,
void (*resp_cb)(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
- void *resp_cb_data),
+ void *resp_cb_data,
+ int stat),
void *resp_cb_data);
/**
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2cc7b10..62fada1 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -134,25 +134,10 @@
int disable_smsm_reset_handshake;
};
-/*
- * Shared Memory Regions
- *
- * the array of these regions is expected to be in ascending order by phys_addr
- *
- * @phys_addr: physical base address of the region
- * @size: size of the region in bytes
- */
-struct smd_smem_regions {
- phys_addr_t phys_addr;
- resource_size_t size;
-};
-
struct smd_platform {
uint32_t num_ss_configs;
struct smd_subsystem_config *smd_ss_configs;
struct smd_subsystem_restart_config *smd_ssr_config;
- uint32_t num_smem_areas;
- struct smd_smem_regions *smd_smem_areas;
};
#ifdef CONFIG_MSM_SMD
@@ -322,24 +307,6 @@
*/
int smd_is_pkt_avail(smd_channel_t *ch);
-/**
- * smd_module_init_notifier_register() - Register a smd module
- * init notifier block
- * @nb: Notifier block to be registered
- *
- * In order to mark the dependency on SMD Driver module initialization
- * register a notifier using this API. Once the smd module_init is
- * done, notification will be passed to the registered module.
- */
-int smd_module_init_notifier_register(struct notifier_block *nb);
-
-/**
- * smd_module_init_notifier_register() - Unregister a smd module
- * init notifier block
- * @nb: Notifier block to be registered
- */
-int smd_module_init_notifier_unregister(struct notifier_block *nb);
-
/*
* SMD initialization function that registers for a SMD platform driver.
*
@@ -474,16 +441,6 @@
return -ENODEV;
}
-static inline int smd_module_init_notifier_register(struct notifier_block *nb)
-{
- return -ENODEV;
-}
-
-static inline int smd_module_init_notifier_unregister(struct notifier_block *nb)
-{
- return -ENODEV;
-}
-
static inline int __init msm_smd_init(void)
{
return 0;
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index 57f22cc..64ab6bf 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -144,6 +144,20 @@
void *smem_alloc2(unsigned id, unsigned size_in);
void *smem_get_entry(unsigned id, unsigned *size);
void *smem_find(unsigned id, unsigned size);
+
+/**
+ * smem_get_entry_no_rlock - Get existing item without using remote spinlock
+ *
+ * @id: ID of SMEM item
+ * @size_out: Pointer to size variable for storing the result
+ * @returns: Pointer to SMEM item or NULL if it doesn't exist
+ *
+ * This function does not lock the remote spinlock and should only be used in
+ * failure-recover cases such as retrieving the subsystem failure reason during
+ * subsystem restart.
+ */
+void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out);
+
/**
* smem_virt_to_phys() - Convert SMEM address to physical address.
*
@@ -155,6 +169,13 @@
*/
phys_addr_t smem_virt_to_phys(void *smem_address);
+/**
+ * SMEM initialization function that registers for a SMEM platform driver.
+ *
+ * @returns: success on successful driver registration.
+ */
+int __init msm_smem_init(void);
+
#else
static inline void *smem_alloc(unsigned id, unsigned size)
{
@@ -172,9 +193,17 @@
{
return NULL;
}
+void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out)
+{
+ return NULL;
+}
static inline phys_addr_t smem_virt_to_phys(void *smem_address)
{
return (phys_addr_t) NULL;
}
+static int __init msm_smem_init(void)
+{
+ return 0;
+}
#endif /* CONFIG_MSM_SMD */
#endif /* _ARCH_ARM_MACH_MSM_SMEM_H_ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
index 2cfb5ac..661d496 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.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
@@ -53,6 +53,12 @@
/* Encoder/decoder configuration block */
#define USM_PARAM_ID_ENCDEC_ENC_CFG_BLK 0x0001230D
+/* Max number of static located ports (bytes) */
+#define USM_MAX_PORT_NUMBER 8
+
+/* Max number of static located transparent data (bytes) */
+#define USM_MAX_CFG_DATA_SIZE 100
+
/* Parameter structures used in USM_STREAM_CMD_SET_ENCDEC_PARAM command */
/* common declarations */
struct usm_cfg_common {
@@ -60,26 +66,7 @@
u16 bits_per_sample;
u32 sample_rate;
u32 dev_id;
- u32 data_map;
-} __packed;
-
-/* Max number of static located transparent data (bytes) */
-#define USM_MAX_CFG_DATA_SIZE 100
-struct usm_encode_cfg_blk {
- u32 frames_per_buf;
- u32 format_id;
- /* <cfg_size> = sizeof(usm_cfg_common)+|tarnsp_data| */
- u32 cfg_size;
- struct usm_cfg_common cfg_common;
- /* Transparent configuration data for specific encoder */
- u8 transp_data[USM_MAX_CFG_DATA_SIZE];
-} __packed;
-
-struct usm_stream_cmd_encdec_cfg_blk {
- struct apr_hdr hdr;
- u32 param_id;
- u32 param_size;
- struct usm_encode_cfg_blk enc_blk;
+ u8 data_map[USM_MAX_PORT_NUMBER];
} __packed;
struct us_encdec_cfg {
@@ -89,16 +76,6 @@
u8 *params;
} __packed;
-struct usm_stream_media_format_update {
- struct apr_hdr hdr;
- u32 format_id;
- /* <cfg_size> = sizeof(usm_cfg_common)+|tarnsp_data| */
- u32 cfg_size;
- struct usm_cfg_common cfg_common;
- /* Transparent configuration data for specific encoder */
- u8 transp_data[USM_MAX_CFG_DATA_SIZE];
-} __packed;
-
/* Start/stop US signal detection */
#define USM_SESSION_CMD_SIGNAL_DETECT_MODE 0x00012719
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h
index 4008698..782f3ae 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_a.h
@@ -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
@@ -56,4 +56,43 @@
#define USM_DATA_EVENT_WRITE_DONE 0x00011274
+/* Max number of static located ports (bytes) */
+#define USM_MAX_PORT_NUMBER_A 4
+
+/* Parameter structures used in USM_STREAM_CMD_SET_ENCDEC_PARAM command */
+/* common declarations */
+struct usm_cfg_common_a {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+ u32 dev_id;
+ u8 data_map[USM_MAX_PORT_NUMBER_A];
+} __packed;
+
+struct usm_stream_media_format_update {
+ struct apr_hdr hdr;
+ u32 format_id;
+ /* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+ u32 cfg_size;
+ struct usm_cfg_common_a cfg_common;
+ /* Transparent configuration data for specific encoder */
+ u8 transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_encode_cfg_blk {
+ u32 frames_per_buf;
+ u32 format_id;
+ /* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+ u32 cfg_size;
+ struct usm_cfg_common_a cfg_common;
+ /* Transparent configuration data for specific encoder */
+ u8 transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_stream_cmd_encdec_cfg_blk {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct usm_encode_cfg_blk enc_blk;
+} __packed;
#endif /* __APR_US_A_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
index 11de6ef..26e8369 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
@@ -67,4 +67,30 @@
#define USM_DATA_EVENT_WRITE_DONE 0x00012727
+struct usm_stream_media_format_update {
+ struct apr_hdr hdr;
+ u32 format_id;
+ /* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+ u32 cfg_size;
+ struct usm_cfg_common cfg_common;
+ /* Transparent configuration data for specific encoder */
+ u8 transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_encode_cfg_blk {
+ u32 frames_per_buf;
+ u32 format_id;
+ /* <cfg_size> = sizeof(usm_cfg_common)+|transp_data| */
+ u32 cfg_size;
+ struct usm_cfg_common cfg_common;
+ /* Transparent configuration data for specific encoder */
+ u8 transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_stream_cmd_encdec_cfg_blk {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct usm_encode_cfg_blk enc_blk;
+} __packed;
#endif /* __APR_US_B_H__ */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index d52686c..52102e3 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -115,6 +115,9 @@
MSM_CPU_7X27AA,
MSM_CPU_9615,
MSM_CPU_8974,
+ MSM_CPU_8974PRO_AA,
+ MSM_CPU_8974PRO_AB,
+ MSM_CPU_8974PRO_AC,
MSM_CPU_8627,
MSM_CPU_8625,
MSM_CPU_9625,
@@ -434,6 +437,42 @@
#endif
}
+static inline int cpu_is_msm8974pro_aa(void)
+{
+#ifdef CONFIG_ARCH_MSM8974
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8974PRO_AA;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_msm8974pro_ab(void)
+{
+#ifdef CONFIG_ARCH_MSM8974
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8974PRO_AB;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_msm8974pro_ac(void)
+{
+#ifdef CONFIG_ARCH_MSM8974
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8974PRO_AC;
+#else
+ return 0;
+#endif
+}
+
static inline int cpu_is_mpq8092(void)
{
#ifdef CONFIG_ARCH_MPQ8092
@@ -499,4 +538,10 @@
cpu_is_msm8627();
}
+static inline int soc_class_is_msm8974(void)
+{
+ return cpu_is_msm8974() || cpu_is_msm8974pro_aa() ||
+ cpu_is_msm8974pro_ab() || cpu_is_msm8974pro_ac();
+}
+
#endif
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 9ec8395..5a69ea3 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -735,8 +735,14 @@
&rport_ptr->resume_tx_port_list, list) {
local_port =
msm_ipc_router_lookup_local_port(rtx_port->port_id);
- if (local_port)
+ if (local_port && local_port->notify)
+ local_port->notify(MSM_IPC_ROUTER_RESUME_TX,
+ local_port->priv);
+ else if (local_port)
post_pkt_to_port(local_port, pkt, 1);
+ else
+ pr_err("%s: Local Port %d not Found",
+ __func__, rtx_port->port_id);
list_del(&rtx_port->list);
kfree(rtx_port);
}
@@ -2216,10 +2222,13 @@
}
ret = msm_ipc_router_send_to(src, out_skb_head, dest);
+ if (ret == -EAGAIN)
+ return ret;
if (ret < 0) {
pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
__func__, ret);
msm_ipc_router_free_skb(out_skb_head);
+ return ret;
}
return 0;
}
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 7c1b8d6..b30cba4 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -131,6 +131,15 @@
#define VREF_LDO_BIT_POS 0
#define VREF_LDO_MASK KRAIT_MASK(6, 0)
+#define PWR_GATE_SWITCH_MODE_POS 4
+#define PWR_GATE_SWITCH_MODE_MASK KRAIT_MASK(6, 4)
+
+#define PWR_GATE_SWITCH_MODE_PC 0
+#define PWR_GATE_SWITCH_MODE_LDO 1
+#define PWR_GATE_SWITCH_MODE_BHS 2
+#define PWR_GATE_SWITCH_MODE_DT 3
+#define PWR_GATE_SWITCH_MODE_RET 4
+
#define LDO_HDROOM_MIN 50000
#define LDO_HDROOM_MAX 250000
@@ -144,6 +153,10 @@
#define LDO_DELTA_MAX 100000
#define MSM_L2_SAW_PHYS 0xf9012000
+#define MSM_MDD_BASE_PHYS 0xf908a800
+
+#define KPSS_VERSION_2P0 0x20000000
+
/**
* struct pmic_gang_vreg -
* @name: the string used to represent the gang
@@ -580,35 +593,55 @@
if (kvreg->mode == HS_MODE)
return 0;
/* enable bhs */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_EN_MASK, BHS_EN_MASK);
- /* complete the above write before the delay */
- mb();
- /* wait for the bhs to settle */
- udelay(BHS_SETTLING_DELAY_US);
+ if (version > KPSS_VERSION_2P0) {
+ krait_masked_write(kvreg, APC_PWR_GATE_MODE,
+ PWR_GATE_SWITCH_MODE_MASK,
+ PWR_GATE_SWITCH_MODE_BHS << PWR_GATE_SWITCH_MODE_POS);
- /* Turn on BHS segments */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL,
- BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
+ /* complete the writes before the delay */
+ mb();
- /* complete the above write before the delay */
- mb();
+ /* wait for the bhs to settle */
+ udelay(BHS_SETTLING_DELAY_US);
+ } else {
+ /* enable bhs */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+ BHS_EN_MASK, BHS_EN_MASK);
- /*
- * wait for the bhs to settle - note that
- * after the voltage has settled both BHS and LDO are supplying power
- * to the krait. This avoids glitches during switching
- */
- udelay(BHS_SETTLING_DELAY_US);
+ /* complete the above write before the delay */
+ mb();
- /*
- * enable ldo bypass - the krait is powered still by LDO since
- * LDO is enabled
- */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_BYP_MASK, LDO_BYP_MASK);
+ /* wait for the bhs to settle */
+ udelay(BHS_SETTLING_DELAY_US);
- /* disable ldo - only the BHS provides voltage to the cpu after this */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+ /* Turn on BHS segments */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK,
+ BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
+
+ /* complete the above write before the delay */
+ mb();
+
+ /*
+ * wait for the bhs to settle - note that
+ * after the voltage has settled both BHS and LDO are supplying
+ * power to the krait. This avoids glitches during switching
+ */
+ udelay(BHS_SETTLING_DELAY_US);
+
+ /*
+ * enable ldo bypass - the krait is powered still by LDO since
+ * LDO is enabled
+ */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+ LDO_BYP_MASK, LDO_BYP_MASK);
+
+ /*
+ * disable ldo - only the BHS provides voltage to
+ * the cpu after this
+ */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL,
LDO_PWR_DWN_MASK, LDO_PWR_DWN_MASK);
+ }
kvreg->mode = HS_MODE;
pr_debug("%s using BHS\n", kvreg->name);
@@ -629,27 +662,39 @@
switch_to_using_hs(kvreg);
set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
+ if (version > KPSS_VERSION_2P0) {
+ krait_masked_write(kvreg, APC_PWR_GATE_MODE,
+ PWR_GATE_SWITCH_MODE_MASK,
+ PWR_GATE_SWITCH_MODE_LDO << PWR_GATE_SWITCH_MODE_POS);
- /*
- * enable ldo - note that both LDO and BHS are are supplying voltage to
- * the cpu after this. This avoids glitches during switching from BHS
- * to LDO.
- */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_PWR_DWN_MASK, 0);
+ /* complete the writes before the delay */
+ mb();
- /* complete the writes before the delay */
- mb();
+ /* wait for the ldo to settle */
+ udelay(LDO_SETTLING_DELAY_US);
+ } else {
+ /*
+ * enable ldo - note that both LDO and BHS are are supplying
+ * voltage to the cpu after this. This avoids glitches during
+ * switching from BHS to LDO.
+ */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+ LDO_PWR_DWN_MASK, 0);
- /* wait for the ldo to settle */
- udelay(LDO_SETTLING_DELAY_US);
+ /* complete the writes before the delay */
+ mb();
- /*
- * disable BHS and disable LDO bypass seperate from enabling
- * the LDO above.
- */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL,
- BHS_EN_MASK | LDO_BYP_MASK, 0);
- krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK, 0);
+ /* wait for the ldo to settle */
+ udelay(LDO_SETTLING_DELAY_US);
+
+ /*
+ * disable BHS and disable LDO bypass seperate from enabling
+ * the LDO above.
+ */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+ BHS_EN_MASK | LDO_BYP_MASK, 0);
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK, 0);
+ }
kvreg->mode = LDO_MODE;
pr_debug("%s using LDO\n", kvreg->name);
@@ -993,22 +1038,34 @@
DEFINE_SIMPLE_ATTRIBUTE(retention_fops,
get_retention_dbg_uV, set_retention_dbg_uV, "%llu\n");
+static void kvreg_ldo_voltage_init(struct krait_power_vreg *kvreg)
+{
+ set_krait_retention_uv(kvreg, kvreg->retention_uV);
+ set_krait_ldo_uv(kvreg, kvreg->ldo_default_uV);
+}
+
#define CPU_PWR_CTL_ONLINE_MASK 0x80
static void kvreg_hw_init(struct krait_power_vreg *kvreg)
{
- int online;
- /*
- * bhs_cnt value sets the ramp-up time from power collapse,
- * initialize the ramp up time
- */
- set_krait_retention_uv(kvreg, kvreg->retention_uV);
- set_krait_ldo_uv(kvreg, kvreg->ldo_default_uV);
-
/* setup the bandgap that configures the reference to the LDO */
writel_relaxed(0x00000190, kvreg->mdd_base + MDD_CONFIG_CTL);
/* Enable MDD */
writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
mb();
+
+ if (version > KPSS_VERSION_2P0) {
+ /* Configure hardware sequencer delays. */
+ writel_relaxed(0x30430600, kvreg->reg_base + APC_PWR_GATE_DLY);
+
+ /* Enable the hardware sequencer in BHS mode. */
+ writel_relaxed(0x00000021, kvreg->reg_base + APC_PWR_GATE_MODE);
+ }
+}
+
+static void online_at_probe(struct krait_power_vreg *kvreg)
+{
+ int online;
+
online = CPU_PWR_CTL_ONLINE_MASK
& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
kvreg->online_at_probe
@@ -1017,11 +1074,15 @@
static void glb_init(void __iomem *apcs_gcc_base)
{
- /* configure bi-modal switch */
- writel_relaxed(0x0008736E, apcs_gcc_base + PWR_GATE_CONFIG);
/* read kpss version */
version = readl_relaxed(apcs_gcc_base + VERSION);
pr_debug("version= 0x%x\n", version);
+
+ /* configure bi-modal switch */
+ if (version > KPSS_VERSION_2P0)
+ writel_relaxed(0x0308736E, apcs_gcc_base + PWR_GATE_CONFIG);
+ else
+ writel_relaxed(0x0008736E, apcs_gcc_base + PWR_GATE_CONFIG);
}
static int __devinit krait_power_probe(struct platform_device *pdev)
@@ -1179,6 +1240,14 @@
list_add_tail(&kvreg->link, &the_gang->krait_power_vregs);
mutex_unlock(&the_gang->krait_power_vregs_lock);
+ online_at_probe(kvreg);
+ kvreg_ldo_voltage_init(kvreg);
+
+ if (kvreg->cpu_num == 0)
+ kvreg_hw_init(kvreg);
+
+ per_cpu(krait_vregs, cpu_num) = kvreg;
+
kvreg->rdev = regulator_register(&kvreg->desc, &pdev->dev, init_data,
kvreg, pdev->dev.of_node);
if (IS_ERR(kvreg->rdev)) {
@@ -1187,8 +1256,6 @@
goto out;
}
- kvreg_hw_init(kvreg);
- per_cpu(krait_vregs, cpu_num) = kvreg;
dev_dbg(&pdev->dev, "id=%d, name=%s\n", pdev->id, kvreg->name);
return 0;
@@ -1426,10 +1493,29 @@
}
module_exit(krait_power_exit);
-void secondary_cpu_hs_init(void *base_ptr)
+#define GCC_BASE 0xF9011000
+
+/**
+ * secondary_cpu_hs_init - Initialize BHS and LDO registers
+ * for nonboot cpu
+ *
+ * @base_ptr: address pointer to APC registers of a cpu
+ * @cpu: the cpu being brought out of reset
+ *
+ * seconday_cpu_hs_init() is called when a secondary cpu
+ * is being brought online for the first time. It is not
+ * called for boot cpu. It initializes power related
+ * registers and makes the core run from BHS.
+ * It also ends up turning on MDD which is required when the
+ * core switches to LDO mode
+ */
+void secondary_cpu_hs_init(void *base_ptr, int cpu)
{
uint32_t reg_val;
void *l2_saw_base;
+ void *gcc_base_ptr;
+ void *mdd_base;
+ struct krait_power_vreg *kvreg;
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
reg_val = BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
@@ -1438,14 +1524,23 @@
| BHS_EN_MASK;
writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
- /* complete the above write before the delay */
- mb();
- /* wait for the bhs to settle */
- udelay(BHS_SETTLING_DELAY_US);
+ if (version == 0) {
+ gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
+ version = readl_relaxed(gcc_base_ptr + VERSION);
+ iounmap(gcc_base_ptr);
+ }
- /* Turn on BHS segments */
- reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
- writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+ /* Turn on the BHS segments only for version < 2 */
+ if (version <= KPSS_VERSION_2P0) {
+ /* complete the above write before the delay */
+ mb();
+ /* wait for the bhs to settle */
+ udelay(BHS_SETTLING_DELAY_US);
+
+ /* Turn on BHS segments */
+ reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
+ writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+ }
/* complete the above write before the delay */
mb();
@@ -1456,23 +1551,48 @@
reg_val |= LDO_BYP_MASK;
writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
- if (the_gang && the_gang->manage_phases)
- return;
+ kvreg = per_cpu(krait_vregs, cpu);
+ if (kvreg != NULL) {
+ kvreg_hw_init(kvreg);
+ } else {
+ /*
+ * This nonboot cpu has not been probed yet. This cpu was
+ * brought out of reset as a part of maxcpus >= 2. Initialize
+ * its MDD and APC_PWR_GATE_MODE register here
+ */
+ mdd_base = ioremap_nocache(MSM_MDD_BASE_PHYS + cpu * 0x10000,
+ SZ_4K);
+ /* setup the bandgap that configures the reference to the LDO */
+ writel_relaxed(0x00000190, mdd_base + MDD_CONFIG_CTL);
+ /* Enable MDD */
+ writel_relaxed(0x00000002, mdd_base + MDD_MODE);
+ mb();
+ iounmap(mdd_base);
- /*
- * If the driver has not yet started to manage phases then enable
- * max phases.
- */
- l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
- if (!l2_saw_base) {
- __WARN();
- return;
+ if (version > KPSS_VERSION_2P0) {
+ writel_relaxed(0x30430600, base_ptr + APC_PWR_GATE_DLY);
+ writel_relaxed(0x00000021,
+ base_ptr + APC_PWR_GATE_MODE);
+ }
+ mb();
}
- writel_relaxed(0x10003, l2_saw_base + 0x1c);
- mb();
- udelay(PHASE_SETTLING_TIME_US);
- iounmap(l2_saw_base);
+ if (!the_gang || !the_gang->manage_phases) {
+ /*
+ * If the driver has not yet started to manage phases then
+ * enable max phases.
+ */
+ l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
+ if (l2_saw_base) {
+ writel_relaxed(0x10003, l2_saw_base + 0x1c);
+ mb();
+ udelay(PHASE_SETTLING_TIME_US);
+
+ iounmap(l2_saw_base);
+ } else {
+ __WARN();
+ }
+ }
}
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c
index 78d62ac..e03ac64 100644
--- a/arch/arm/mach-msm/msm_dcvs_scm.c
+++ b/arch/arm/mach-msm/msm_dcvs_scm.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
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/memory_alloc.h>
+#include <asm/cacheflush.h>
#include <mach/memory.h>
#include <mach/scm.h>
#include <mach/msm_dcvs_scm.h>
@@ -83,6 +84,12 @@
}
EXPORT_SYMBOL(msm_dcvs_scm_init);
+static void __msm_dcvs_flush_cache(void *v, size_t size)
+{
+ __cpuc_flush_dcache_area(v, size);
+ outer_flush_range(virt_to_phys(v), virt_to_phys(v) + size);
+}
+
int msm_dcvs_scm_register_core(uint32_t core_id,
struct msm_dcvs_core_param *param)
{
@@ -99,6 +106,8 @@
reg_data.core_id = core_id;
reg_data.core_param_phy = virt_to_phys(p);
+ __msm_dcvs_flush_cache(p, sizeof(struct msm_dcvs_core_param));
+
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_REGISTER_CORE,
®_data, sizeof(reg_data), NULL, 0);
@@ -125,6 +134,8 @@
algo.core_id = core_id;
algo.algo_phy = virt_to_phys(p);
+ __msm_dcvs_flush_cache(p, sizeof(struct msm_algo_param));
+
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
&algo, sizeof(algo), NULL, 0);
@@ -150,6 +161,8 @@
algo.core_id = 0;
algo.algo_phy = virt_to_phys(p);
+ __msm_dcvs_flush_cache(p, sizeof(struct msm_algo_param));
+
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
&algo, sizeof(algo), NULL, 0);
@@ -197,6 +210,12 @@
sizeof(struct msm_dcvs_freq_entry)*pwr_param->num_freq);
memcpy(coefft, coeffs, sizeof(struct msm_dcvs_energy_curve_coeffs));
+ __msm_dcvs_flush_cache(pwrt, sizeof(struct msm_dcvs_power_params));
+ __msm_dcvs_flush_cache(freqt,
+ sizeof(struct msm_dcvs_freq_entry) * pwr_param->num_freq);
+ __msm_dcvs_flush_cache(coefft,
+ sizeof(struct msm_dcvs_energy_curve_coeffs));
+
pwr.core_id = core_id;
pwr.pwr_param_phy = virt_to_phys(pwrt);
pwr.freq_phy = virt_to_phys(freqt);
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index 9b3e500..a8fed52 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -25,6 +25,8 @@
#include <linux/socket.h>
#include <linux/gfp.h>
#include <linux/qmi_encdec.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
#include <mach/msm_qmi_interface.h>
#include <mach/msm_ipc_router.h>
@@ -33,6 +35,8 @@
static LIST_HEAD(svc_event_nb_list);
static DEFINE_MUTEX(svc_event_nb_list_lock);
+static DEFINE_MUTEX(msm_qmi_init_lock);
+static struct workqueue_struct *msm_qmi_pending_workqueue;
struct elem_info qmi_response_type_v01_ei[] = {
{
@@ -87,12 +91,98 @@
spin_unlock_irqrestore(&handle->notify_lock, flags);
break;
+ case MSM_IPC_ROUTER_RESUME_TX:
+ queue_delayed_work(msm_qmi_pending_workqueue,
+ &handle->resume_tx_work,
+ msecs_to_jiffies(0));
+ break;
default:
break;
}
mutex_unlock(&handle->handle_lock);
}
+/**
+ * init_msm_qmi() - Init function for kernel space QMI
+ *
+ * This function is implemented to initialize the QMI resources that are common
+ * across kernel space QMI users. As it is not necessary for this init function
+ * to be module_init function it is called when the first handle of kernel space
+ * QMI gets created.
+ */
+static void init_msm_qmi(void)
+{
+ static bool msm_qmi_inited;
+
+ if (likely(msm_qmi_inited))
+ return;
+
+ mutex_lock(&msm_qmi_init_lock);
+ if (likely(msm_qmi_inited && msm_qmi_pending_workqueue)) {
+ mutex_unlock(&msm_qmi_init_lock);
+ return;
+ }
+ msm_qmi_inited = 1;
+ msm_qmi_pending_workqueue =
+ create_singlethread_workqueue("msm_qmi_rtx_q");
+ mutex_unlock(&msm_qmi_init_lock);
+}
+
+/**
+ * handle_resume_tx() - Handle the Resume_Tx event
+ * @work : Pointer to the work strcuture.
+ *
+ * This function handles the resume_tx event for any QMI client that
+ * exists in the kernel space. This function parses the pending_txn_list of
+ * the handle and attempts a send for each transaction in that list.
+ */
+static void handle_resume_tx(struct work_struct *work)
+{
+ struct delayed_work *rtx_work = to_delayed_work(work);
+ struct qmi_handle *handle =
+ container_of(rtx_work, struct qmi_handle, resume_tx_work);
+ struct qmi_txn *pend_txn, *temp_txn;
+ int ret;
+ uint16_t msg_id;
+
+ mutex_lock(&handle->handle_lock);
+ list_for_each_entry_safe(pend_txn, temp_txn,
+ &handle->pending_txn_list, list) {
+ ret = msm_ipc_router_send_msg(
+ (struct msm_ipc_port *)handle->src_port,
+ (struct msm_ipc_addr *)handle->dest_info,
+ pend_txn->enc_data, pend_txn->enc_data_len);
+
+ if (ret == -EAGAIN) {
+ mutex_unlock(&handle->handle_lock);
+ return;
+ }
+ msg_id = ((struct qmi_header *)pend_txn->enc_data)->msg_id;
+ kfree(pend_txn->enc_data);
+ if (ret < 0) {
+ if (pend_txn->type == QMI_ASYNC_TXN) {
+ pend_txn->resp_cb(pend_txn->handle,
+ msg_id, pend_txn->resp,
+ pend_txn->resp_cb_data,
+ ret);
+ list_del(&pend_txn->list);
+ kfree(pend_txn);
+ } else if (pend_txn->type == QMI_SYNC_TXN) {
+ pend_txn->send_stat = ret;
+ wake_up(&pend_txn->wait_q);
+ }
+ pr_err("%s: Sending transaction %d from port %d failed",
+ __func__, pend_txn->txn_id,
+ ((struct msm_ipc_port *)handle->src_port)->
+ this_port.port_id);
+ } else {
+ list_del(&pend_txn->list);
+ list_add_tail(&pend_txn->list, &handle->txn_list);
+ }
+ }
+ mutex_unlock(&handle->handle_lock);
+}
+
struct qmi_handle *qmi_handle_create(
void (*notify)(struct qmi_handle *handle,
enum qmi_event_type event, void *notify_priv),
@@ -118,20 +208,39 @@
temp_handle->src_port = port_ptr;
temp_handle->next_txn_id = 1;
INIT_LIST_HEAD(&temp_handle->txn_list);
+ INIT_LIST_HEAD(&temp_handle->pending_txn_list);
mutex_init(&temp_handle->handle_lock);
spin_lock_init(&temp_handle->notify_lock);
temp_handle->notify = notify;
temp_handle->notify_priv = notify_priv;
temp_handle->handle_reset = 0;
init_waitqueue_head(&temp_handle->reset_waitq);
+ INIT_DELAYED_WORK(&temp_handle->resume_tx_work, handle_resume_tx);
+ init_msm_qmi();
return temp_handle;
}
EXPORT_SYMBOL(qmi_handle_create);
static void clean_txn_info(struct qmi_handle *handle)
{
- struct qmi_txn *txn_handle, *temp_txn_handle;
+ struct qmi_txn *txn_handle, *temp_txn_handle, *pend_txn;
+ list_for_each_entry_safe(pend_txn, temp_txn_handle,
+ &handle->pending_txn_list, list) {
+ if (pend_txn->type == QMI_ASYNC_TXN) {
+ list_del(&pend_txn->list);
+ pend_txn->resp_cb(pend_txn->handle,
+ ((struct qmi_header *)
+ pend_txn->enc_data)->msg_id,
+ pend_txn->resp, pend_txn->resp_cb_data,
+ -ENETRESET);
+ kfree(pend_txn->enc_data);
+ kfree(pend_txn);
+ } else if (pend_txn->type == QMI_SYNC_TXN) {
+ kfree(pend_txn->enc_data);
+ wake_up(&pend_txn->wait_q);
+ }
+ }
list_for_each_entry_safe(txn_handle, temp_txn_handle,
&handle->txn_list, list) {
if (txn_handle->type == QMI_ASYNC_TXN) {
@@ -154,7 +263,7 @@
handle->handle_reset = 1;
clean_txn_info(handle);
mutex_unlock(&handle->handle_lock);
-
+ flush_delayed_work(&handle->resume_tx_work);
rc = wait_event_interruptible(handle->reset_waitq,
list_empty(&handle->txn_list));
@@ -194,7 +303,7 @@
struct msg_desc *resp_desc, void *resp, unsigned int resp_len,
void (*resp_cb)(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
- void *resp_cb_data),
+ void *resp_cb_data, int stat),
void *resp_cb_data)
{
struct qmi_txn *txn_handle;
@@ -230,6 +339,8 @@
txn_handle->resp_received = 0;
txn_handle->resp_cb = resp_cb;
txn_handle->resp_cb_data = resp_cb_data;
+ txn_handle->enc_data = NULL;
+ txn_handle->enc_data_len = 0;
/* Encode the request msg */
encoded_req_len = req_desc->max_msg_len + QMI_HEADER_SIZE;
@@ -256,12 +367,35 @@
txn_handle->txn_id, req_desc->msg_id,
encoded_req_len);
encoded_req_len += QMI_HEADER_SIZE;
- list_add_tail(&txn_handle->list, &handle->txn_list);
+ /*
+ * Check if this port has transactions queued to its pending list
+ * and if there are any pending transactions then add the current
+ * transaction to the pending list rather than sending it. This avoids
+ * out-of-order message transfers.
+ */
+ if (!list_empty(&handle->pending_txn_list)) {
+ rc = -EAGAIN;
+ goto append_pend_txn;
+ }
+
+ list_add_tail(&txn_handle->list, &handle->txn_list);
/* Send the request */
rc = msm_ipc_router_send_msg((struct msm_ipc_port *)(handle->src_port),
(struct msm_ipc_addr *)handle->dest_info,
encoded_req, encoded_req_len);
+append_pend_txn:
+ if (rc == -EAGAIN) {
+ txn_handle->enc_data = encoded_req;
+ txn_handle->enc_data_len = encoded_req_len;
+ if (list_empty(&handle->pending_txn_list))
+ list_del(&txn_handle->list);
+ list_add_tail(&txn_handle->list, &handle->pending_txn_list);
+ if (ret_txn_handle)
+ *ret_txn_handle = txn_handle;
+ mutex_unlock(&handle->handle_lock);
+ return 0;
+ }
if (rc < 0) {
pr_err("%s: send_msg failed %d\n", __func__, rc);
goto encode_and_send_req_err3;
@@ -305,14 +439,16 @@
/* Wait for the response */
if (!timeout_ms) {
- rc = wait_event_interruptible(txn_handle->wait_q,
- (txn_handle->resp_received ||
- handle->handle_reset));
+ wait_event(txn_handle->wait_q,
+ (txn_handle->resp_received ||
+ handle->handle_reset ||
+ (txn_handle->send_stat < 0)));
} else {
- rc = wait_event_interruptible_timeout(txn_handle->wait_q,
- (txn_handle->resp_received ||
- handle->handle_reset),
- msecs_to_jiffies(timeout_ms));
+ rc = wait_event_timeout(txn_handle->wait_q,
+ (txn_handle->resp_received ||
+ handle->handle_reset ||
+ (txn_handle->send_stat < 0)),
+ msecs_to_jiffies(timeout_ms));
if (rc == 0)
rc = -ETIMEDOUT;
}
@@ -324,6 +460,8 @@
rc = -ENETRESET;
if (rc >= 0)
rc = -EFAULT;
+ if (txn_handle->send_stat < 0)
+ rc = txn_handle->send_stat;
goto send_req_wait_err;
}
rc = 0;
@@ -344,7 +482,7 @@
void *resp, unsigned int resp_len,
void (*resp_cb)(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
- void *resp_cb_data),
+ void *resp_cb_data, int stat),
void *resp_cb_data)
{
return qmi_encode_and_send_req(NULL, handle, QMI_ASYNC_TXN,
@@ -407,7 +545,7 @@
if (txn_handle->resp_cb)
txn_handle->resp_cb(txn_handle->handle, msg_id,
txn_handle->resp,
- txn_handle->resp_cb_data);
+ txn_handle->resp_cb_data, 0);
list_del(&txn_handle->list);
kfree(txn_handle);
rc = 0;
diff --git a/arch/arm/mach-msm/msm_qmi_interface_priv.h b/arch/arm/mach-msm/msm_qmi_interface_priv.h
index 58f1ce3..8eba0db 100644
--- a/arch/arm/mach-msm/msm_qmi_interface_priv.h
+++ b/arch/arm/mach-msm/msm_qmi_interface_priv.h
@@ -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
@@ -34,12 +34,15 @@
uint16_t txn_id;
enum txn_type type;
struct qmi_handle *handle;
+ void *enc_data;
+ unsigned int enc_data_len;
struct msg_desc *resp_desc;
void *resp;
unsigned int resp_len;
int resp_received;
+ int send_stat;
void (*resp_cb)(struct qmi_handle *handle, unsigned int msg_id,
- void *msg, void *resp_cb_data);
+ void *msg, void *resp_cb_data, int stat);
void *resp_cb_data;
wait_queue_head_t wait_q;
};
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 70420db..643d945 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -32,6 +32,7 @@
"7 Perf: Add L1 counters to tracepoints\n"
"8 Perf: Add cortex A7 perf support\n"
"9 ARM: dts: msm: add perf-events support for msm8226\n"
+ "10 Perf: Fix counts across power collapse\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/pil-msa.c b/arch/arm/mach-msm/pil-msa.c
new file mode 100644
index 0000000..a8f5b0e
--- /dev/null
+++ b/arch/arm/mach-msm/pil-msa.c
@@ -0,0 +1,407 @@
+/* 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
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/dma-mapping.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+#include "pil-msa.h"
+
+/* Q6 Register Offsets */
+#define QDSP6SS_RST_EVB 0x010
+
+/* AXI Halting Registers */
+#define MSS_Q6_HALT_BASE 0x180
+#define MSS_MODEM_HALT_BASE 0x200
+#define MSS_NC_HALT_BASE 0x280
+
+/* RMB Status Register Values */
+#define STATUS_PBL_SUCCESS 0x1
+#define STATUS_XPU_UNLOCKED 0x1
+#define STATUS_XPU_UNLOCKED_SCRIBBLED 0x2
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE 0x00
+#define RMB_PBL_STATUS 0x04
+#define RMB_MBA_COMMAND 0x08
+#define RMB_MBA_STATUS 0x0C
+#define RMB_PMI_META_DATA 0x10
+#define RMB_PMI_CODE_START 0x14
+#define RMB_PMI_CODE_LENGTH 0x18
+
+#define MAX_VDD_MX_UV 1150000
+
+#define POLL_INTERVAL_US 50
+
+#define CMD_META_DATA_READY 0x1
+#define CMD_LOAD_READY 0x2
+
+#define STATUS_META_DATA_AUTH_SUCCESS 0x3
+#define STATUS_AUTH_COMPLETE 0x4
+
+/* External BHS */
+#define EXTERNAL_BHS_ON BIT(0)
+#define EXTERNAL_BHS_STATUS BIT(4)
+#define BHS_TIMEOUT_US 50
+
+static int pbl_mba_boot_timeout_ms = 1000;
+module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
+
+static int modem_auth_timeout_ms = 10000;
+module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
+
+static int pil_msa_pbl_power_up(struct q6v5_data *drv)
+{
+ int ret = 0;
+ struct device *dev = drv->desc.dev;
+ u32 regval;
+
+ if (drv->vreg) {
+ ret = regulator_enable(drv->vreg);
+ if (ret)
+ dev_err(dev, "Failed to enable modem regulator.\n");
+ }
+
+ if (drv->cxrail_bhs) {
+ regval = readl_relaxed(drv->cxrail_bhs);
+ regval |= EXTERNAL_BHS_ON;
+ writel_relaxed(regval, drv->cxrail_bhs);
+
+ ret = readl_poll_timeout(drv->cxrail_bhs, regval,
+ regval & EXTERNAL_BHS_STATUS, 1, BHS_TIMEOUT_US);
+ }
+
+ return ret;
+}
+
+static int pil_msa_pbl_power_down(struct q6v5_data *drv)
+{
+ u32 regval;
+
+ if (drv->cxrail_bhs) {
+ regval = readl_relaxed(drv->cxrail_bhs);
+ regval &= ~EXTERNAL_BHS_ON;
+ writel_relaxed(regval, drv->cxrail_bhs);
+ }
+
+ if (drv->vreg)
+ return regulator_disable(drv->vreg);
+
+ return 0;
+}
+
+static int pil_msa_pbl_enable_clks(struct q6v5_data *drv)
+{
+ int ret;
+
+ ret = clk_prepare_enable(drv->ahb_clk);
+ if (ret)
+ goto err_ahb_clk;
+ ret = clk_prepare_enable(drv->axi_clk);
+ if (ret)
+ goto err_axi_clk;
+ ret = clk_prepare_enable(drv->rom_clk);
+ if (ret)
+ goto err_rom_clk;
+
+ return 0;
+
+err_rom_clk:
+ clk_disable_unprepare(drv->axi_clk);
+err_axi_clk:
+ clk_disable_unprepare(drv->ahb_clk);
+err_ahb_clk:
+ return ret;
+}
+
+static void pil_msa_pbl_disable_clks(struct q6v5_data *drv)
+{
+ clk_disable_unprepare(drv->rom_clk);
+ clk_disable_unprepare(drv->axi_clk);
+ clk_disable_unprepare(drv->ahb_clk);
+}
+
+static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
+{
+ struct device *dev = drv->desc.dev;
+ int ret;
+ u32 status;
+
+ /* Wait for PBL completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
+ status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
+ if (ret) {
+ dev_err(dev, "PBL boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_PBL_SUCCESS) {
+ dev_err(dev, "PBL returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ /* Wait for MBA completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+ status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
+ if (ret) {
+ dev_err(dev, "MBA boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_XPU_UNLOCKED &&
+ status != STATUS_XPU_UNLOCKED_SCRIBBLED) {
+ dev_err(dev, "MBA returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pil_msa_pbl_shutdown(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
+
+ writel_relaxed(1, drv->restart_reg);
+
+ if (drv->is_booted) {
+ pil_msa_pbl_disable_clks(drv);
+ pil_msa_pbl_power_down(drv);
+ drv->is_booted = false;
+ }
+
+ return 0;
+}
+
+static int pil_msa_pbl_reset(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ phys_addr_t start_addr = pil_get_entry_addr(pil);
+ int ret;
+
+ /*
+ * Bring subsystem out of reset and enable required
+ * regulators and clocks.
+ */
+ ret = pil_msa_pbl_power_up(drv);
+ if (ret)
+ goto err_power;
+
+ /* Deassert reset to subsystem and wait for propagation */
+ writel_relaxed(0, drv->restart_reg);
+ mb();
+ udelay(2);
+
+ ret = pil_msa_pbl_enable_clks(drv);
+ if (ret)
+ goto err_clks;
+
+ /* Program Image Address */
+ if (drv->self_auth) {
+ writel_relaxed(start_addr, drv->rmb_base + RMB_MBA_IMAGE);
+ /* Ensure write to RMB base occurs before reset is released. */
+ mb();
+ } else {
+ writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
+ drv->reg_base + QDSP6SS_RST_EVB);
+ }
+
+ ret = pil_q6v5_reset(pil);
+ if (ret)
+ goto err_q6v5_reset;
+
+ /* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
+ if (drv->self_auth) {
+ ret = pil_msa_wait_for_mba_ready(drv);
+ if (ret)
+ goto err_auth;
+ }
+
+ drv->is_booted = true;
+
+ return 0;
+
+err_auth:
+ pil_q6v5_shutdown(pil);
+err_q6v5_reset:
+ pil_msa_pbl_disable_clks(drv);
+err_clks:
+ pil_msa_pbl_power_down(drv);
+err_power:
+ return ret;
+}
+
+static int pil_msa_pbl_make_proxy_votes(struct pil_desc *pil)
+{
+ int ret;
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+
+ ret = regulator_set_voltage(drv->vreg_mx, VDD_MSS_UV, MAX_VDD_MX_UV);
+ if (ret) {
+ dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
+ return ret;
+ }
+
+ ret = regulator_enable(drv->vreg_mx);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable vreg_mx\n");
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+ return ret;
+ }
+
+ ret = pil_q6v5_make_proxy_votes(pil);
+ if (ret) {
+ regulator_disable(drv->vreg_mx);
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+ }
+
+ return ret;
+}
+
+static void pil_msa_pbl_remove_proxy_votes(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ pil_q6v5_remove_proxy_votes(pil);
+ regulator_disable(drv->vreg_mx);
+ regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+}
+
+struct pil_reset_ops pil_msa_pbl_ops = {
+ .proxy_vote = pil_msa_pbl_make_proxy_votes,
+ .proxy_unvote = pil_msa_pbl_remove_proxy_votes,
+ .auth_and_reset = pil_msa_pbl_reset,
+ .shutdown = pil_msa_pbl_shutdown,
+};
+
+static int pil_msa_mba_make_proxy_votes(struct pil_desc *pil)
+{
+ int ret;
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+
+ ret = clk_prepare_enable(drv->xo);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable XO\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void pil_msa_mba_remove_proxy_votes(struct pil_desc *pil)
+{
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+ clk_disable_unprepare(drv->xo);
+}
+
+static int pil_msa_mba_init_image(struct pil_desc *pil,
+ const u8 *metadata, size_t size)
+{
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+ void *mdata_virt;
+ dma_addr_t mdata_phys;
+ s32 status;
+ int ret;
+
+ /* 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);
+
+ /* Pass address of meta-data to the MBA and perform authentication */
+ 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,
+ POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
+ if (ret) {
+ dev_err(pil->dev, "MBA authentication of headers timed out\n");
+ } else if (status < 0) {
+ dev_err(pil->dev, "MBA returned error %d for headers\n",
+ status);
+ ret = -EINVAL;
+ }
+
+ dma_free_coherent(pil->dev, size, mdata_virt, mdata_phys);
+
+ return ret;
+}
+
+static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
+ size_t size)
+{
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+ s32 status;
+ u32 img_length = readl_relaxed(drv->rmb_base + RMB_PMI_CODE_LENGTH);
+
+ /* Begin image authentication */
+ if (img_length == 0) {
+ writel_relaxed(phy_addr, drv->rmb_base + RMB_PMI_CODE_START);
+ writel_relaxed(CMD_LOAD_READY, drv->rmb_base + RMB_MBA_COMMAND);
+ }
+ /* Increment length counter */
+ img_length += size;
+ writel_relaxed(img_length, drv->rmb_base + RMB_PMI_CODE_LENGTH);
+
+ status = readl_relaxed(drv->rmb_base + RMB_MBA_STATUS);
+ if (status < 0) {
+ dev_err(pil->dev, "MBA returned error %d\n", status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pil_msa_mba_auth(struct pil_desc *pil)
+{
+ struct mba_data *drv = container_of(pil, struct mba_data, desc);
+ int ret;
+ s32 status;
+
+ /* Wait for all segments to be authenticated or an error to occur */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+ status == STATUS_AUTH_COMPLETE || status < 0,
+ 50, modem_auth_timeout_ms * 1000);
+ if (ret) {
+ dev_err(pil->dev, "MBA authentication of image timed out\n");
+ } else if (status < 0) {
+ dev_err(pil->dev, "MBA returned error %d for image\n", status);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+struct pil_reset_ops pil_msa_mba_ops = {
+ .init_image = pil_msa_mba_init_image,
+ .proxy_vote = pil_msa_mba_make_proxy_votes,
+ .proxy_unvote = pil_msa_mba_remove_proxy_votes,
+ .verify_blob = pil_msa_mba_verify_blob,
+ .auth_and_reset = pil_msa_mba_auth,
+};
diff --git a/arch/arm/mach-msm/pil-msa.h b/arch/arm/mach-msm/pil-msa.h
new file mode 100644
index 0000000..9a7b56e
--- /dev/null
+++ b/arch/arm/mach-msm/pil-msa.h
@@ -0,0 +1,29 @@
+/* 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
+ * 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 __MSM_PIL_MSA_H
+#define __MSM_PIL_MSA_H
+
+#include "peripheral-loader.h"
+
+#define VDD_MSS_UV 1050000
+
+struct mba_data {
+ void __iomem *rmb_base;
+ struct clk *xo;
+ struct pil_desc desc;
+};
+
+extern struct pil_reset_ops pil_msa_pbl_ops;
+extern struct pil_reset_ops pil_msa_mba_ops;
+
+#endif
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index b83202b..3a21e39 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -35,62 +35,20 @@
#include "peripheral-loader.h"
#include "pil-q6v5.h"
+#include "pil-msa.h"
#include "sysmon.h"
-/* Q6 Register Offsets */
-#define QDSP6SS_RST_EVB 0x010
+#define MAX_VDD_MSS_UV 1150000
+#define PROXY_TIMEOUT_MS 10000
+#define MAX_SSR_REASON_LEN 81U
+#define STOP_ACK_TIMEOUT_MS 1000
-/* AXI Halting Registers */
-#define MSS_Q6_HALT_BASE 0x180
-#define MSS_MODEM_HALT_BASE 0x200
-#define MSS_NC_HALT_BASE 0x280
-
-/* RMB Status Register Values */
-#define STATUS_PBL_SUCCESS 0x1
-#define STATUS_XPU_UNLOCKED 0x1
-#define STATUS_XPU_UNLOCKED_SCRIBBLED 0x2
-
-/* PBL/MBA interface registers */
-#define RMB_MBA_IMAGE 0x00
-#define RMB_PBL_STATUS 0x04
-#define RMB_MBA_COMMAND 0x08
-#define RMB_MBA_STATUS 0x0C
-#define RMB_PMI_META_DATA 0x10
-#define RMB_PMI_CODE_START 0x14
-#define RMB_PMI_CODE_LENGTH 0x18
-
-#define VDD_MSS_UV 1050000
-#define MAX_VDD_MSS_UV 1150000
-#define MAX_VDD_MX_UV 1150000
-
-#define PROXY_TIMEOUT_MS 10000
-#define POLL_INTERVAL_US 50
-
-#define CMD_META_DATA_READY 0x1
-#define CMD_LOAD_READY 0x2
-
-#define STATUS_META_DATA_AUTH_SUCCESS 0x3
-#define STATUS_AUTH_COMPLETE 0x4
-
-#define MAX_SSR_REASON_LEN 81U
-
-/* External BHS */
-#define EXTERNAL_BHS_ON BIT(0)
-#define EXTERNAL_BHS_STATUS BIT(4)
-#define BHS_TIMEOUT_US 50
-
-#define STOP_ACK_TIMEOUT_MS 1000
-
-struct mba_data {
- void __iomem *rmb_base;
- void __iomem *io_clamp_reg;
- struct pil_desc desc;
+struct modem_data {
+ struct mba_data *mba;
+ struct q6v5_data *q6;
struct subsys_device *subsys;
struct subsys_desc subsys_desc;
void *adsp_state_notifier;
- u32 img_length;
- struct q6v5_data *q6;
- bool self_auth;
void *ramdump_dev;
void *smem_ramdump_dev;
bool crash_shutdown;
@@ -101,354 +59,7 @@
struct completion stop_ack;
};
-static int pbl_mba_boot_timeout_ms = 1000;
-module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
-
-static int modem_auth_timeout_ms = 10000;
-module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
-
-static int pil_mss_power_up(struct q6v5_data *drv)
-{
- int ret = 0;
- struct device *dev = drv->desc.dev;
- u32 regval;
-
- if (drv->vreg) {
- ret = regulator_enable(drv->vreg);
- if (ret)
- dev_err(dev, "Failed to enable modem regulator.\n");
- }
-
- if (drv->cxrail_bhs) {
- regval = readl_relaxed(drv->cxrail_bhs);
- regval |= EXTERNAL_BHS_ON;
- writel_relaxed(regval, drv->cxrail_bhs);
-
- ret = readl_poll_timeout(drv->cxrail_bhs, regval,
- regval & EXTERNAL_BHS_STATUS, 1, BHS_TIMEOUT_US);
- }
-
- return ret;
-}
-
-static int pil_mss_power_down(struct q6v5_data *drv)
-{
- u32 regval;
-
- if (drv->cxrail_bhs) {
- regval = readl_relaxed(drv->cxrail_bhs);
- regval &= ~EXTERNAL_BHS_ON;
- writel_relaxed(regval, drv->cxrail_bhs);
- }
-
- if (drv->vreg)
- return regulator_disable(drv->vreg);
-
- return 0;
-}
-
-static int pil_mss_enable_clks(struct q6v5_data *drv)
-{
- int ret;
-
- ret = clk_prepare_enable(drv->ahb_clk);
- if (ret)
- goto err_ahb_clk;
- ret = clk_prepare_enable(drv->axi_clk);
- if (ret)
- goto err_axi_clk;
- ret = clk_prepare_enable(drv->rom_clk);
- if (ret)
- goto err_rom_clk;
-
- return 0;
-
-err_rom_clk:
- clk_disable_unprepare(drv->axi_clk);
-err_axi_clk:
- clk_disable_unprepare(drv->ahb_clk);
-err_ahb_clk:
- return ret;
-}
-
-static void pil_mss_disable_clks(struct q6v5_data *drv)
-{
- clk_disable_unprepare(drv->rom_clk);
- clk_disable_unprepare(drv->axi_clk);
- clk_disable_unprepare(drv->ahb_clk);
-}
-
-static int wait_for_mba_ready(struct q6v5_data *drv)
-{
- struct device *dev = drv->desc.dev;
- struct mba_data *mba = platform_get_drvdata(to_platform_device(dev));
- int ret;
- u32 status;
-
- /* Wait for PBL completion. */
- ret = readl_poll_timeout(mba->rmb_base + RMB_PBL_STATUS, status,
- status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
- if (ret) {
- dev_err(dev, "PBL boot timed out\n");
- return ret;
- }
- if (status != STATUS_PBL_SUCCESS) {
- dev_err(dev, "PBL returned unexpected status %d\n", status);
- return -EINVAL;
- }
-
- /* Wait for MBA completion. */
- ret = readl_poll_timeout(mba->rmb_base + RMB_MBA_STATUS, status,
- status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
- if (ret) {
- dev_err(dev, "MBA boot timed out\n");
- return ret;
- }
- if (status != STATUS_XPU_UNLOCKED &&
- status != STATUS_XPU_UNLOCKED_SCRIBBLED) {
- dev_err(dev, "MBA returned unexpected status %d\n", status);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int pil_mss_shutdown(struct pil_desc *pil)
-{
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
-
- pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
- pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
- pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
-
- writel_relaxed(1, drv->restart_reg);
-
- if (drv->is_booted) {
- pil_mss_disable_clks(drv);
- pil_mss_power_down(drv);
- drv->is_booted = false;
- }
-
- return 0;
-}
-
-static int pil_mss_reset(struct pil_desc *pil)
-{
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
- struct platform_device *pdev = to_platform_device(pil->dev);
- struct mba_data *mba = platform_get_drvdata(pdev);
- phys_addr_t start_addr = pil_get_entry_addr(pil);
- int ret;
-
- /*
- * Bring subsystem out of reset and enable required
- * regulators and clocks.
- */
- ret = pil_mss_power_up(drv);
- if (ret)
- goto err_power;
-
- /* Deassert reset to subsystem and wait for propagation */
- writel_relaxed(0, drv->restart_reg);
- mb();
- udelay(2);
-
- ret = pil_mss_enable_clks(drv);
- if (ret)
- goto err_clks;
-
- /* Program Image Address */
- if (mba->self_auth) {
- writel_relaxed(start_addr, mba->rmb_base + RMB_MBA_IMAGE);
- /* Ensure write to RMB base occurs before reset is released. */
- mb();
- } else {
- writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
- drv->reg_base + QDSP6SS_RST_EVB);
- }
-
- ret = pil_q6v5_reset(pil);
- if (ret)
- goto err_q6v5_reset;
-
- /* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
- if (mba->self_auth) {
- ret = wait_for_mba_ready(drv);
- if (ret)
- goto err_auth;
- }
-
- drv->is_booted = true;
-
- return 0;
-
-err_auth:
- pil_q6v5_shutdown(pil);
-err_q6v5_reset:
- pil_mss_disable_clks(drv);
-err_clks:
- pil_mss_power_down(drv);
-err_power:
- return ret;
-}
-
-static int pil_q6v5_mss_make_proxy_votes(struct pil_desc *pil)
-{
- int ret;
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
-
- ret = regulator_set_voltage(drv->vreg_mx, VDD_MSS_UV, MAX_VDD_MX_UV);
- if (ret) {
- dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
- return ret;
- }
-
- ret = regulator_enable(drv->vreg_mx);
- if (ret) {
- dev_err(pil->dev, "Failed to enable vreg_mx\n");
- regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
- return ret;
- }
-
- ret = pil_q6v5_make_proxy_votes(pil);
- if (ret) {
- regulator_disable(drv->vreg_mx);
- regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
- }
-
- return ret;
-}
-
-static void pil_q6v5_mss_remove_proxy_votes(struct pil_desc *pil)
-{
- struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
- pil_q6v5_remove_proxy_votes(pil);
- regulator_disable(drv->vreg_mx);
- regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
-}
-
-static struct pil_reset_ops pil_mss_ops = {
- .proxy_vote = pil_q6v5_mss_make_proxy_votes,
- .proxy_unvote = pil_q6v5_mss_remove_proxy_votes,
- .auth_and_reset = pil_mss_reset,
- .shutdown = pil_mss_shutdown,
-};
-
-static int pil_mba_make_proxy_votes(struct pil_desc *pil)
-{
- int ret;
- struct mba_data *drv = dev_get_drvdata(pil->dev);
-
- ret = clk_prepare_enable(drv->q6->xo);
- if (ret) {
- dev_err(pil->dev, "Failed to enable XO\n");
- return ret;
- }
- return 0;
-}
-
-static void pil_mba_remove_proxy_votes(struct pil_desc *pil)
-{
- struct mba_data *drv = dev_get_drvdata(pil->dev);
- clk_disable_unprepare(drv->q6->xo);
-}
-
-static int pil_mba_init_image(struct pil_desc *pil,
- 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;
-
- /* 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(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,
- POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
- if (ret) {
- dev_err(pil->dev, "MBA authentication of headers timed out\n");
- } else if (status < 0) {
- dev_err(pil->dev, "MBA returned error %d for headers\n",
- status);
- ret = -EINVAL;
- }
-
- dma_free_coherent(pil->dev, size, mdata_virt, mdata_phys);
-
- return ret;
-}
-
-static int pil_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
- size_t size)
-{
- struct mba_data *drv = dev_get_drvdata(pil->dev);
- s32 status;
-
- /* Begin image authentication */
- if (drv->img_length == 0) {
- writel_relaxed(phy_addr, drv->rmb_base + RMB_PMI_CODE_START);
- writel_relaxed(CMD_LOAD_READY, drv->rmb_base + RMB_MBA_COMMAND);
- }
- /* Increment length counter */
- drv->img_length += size;
- writel_relaxed(drv->img_length, drv->rmb_base + RMB_PMI_CODE_LENGTH);
-
- status = readl_relaxed(drv->rmb_base + RMB_MBA_STATUS);
- if (status < 0) {
- dev_err(pil->dev, "MBA returned error %d\n", status);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int pil_mba_auth(struct pil_desc *pil)
-{
- struct mba_data *drv = dev_get_drvdata(pil->dev);
- int ret;
- s32 status;
-
- /* Wait for all segments to be authenticated or an error to occur */
- ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
- status == STATUS_AUTH_COMPLETE || status < 0,
- 50, modem_auth_timeout_ms * 1000);
- if (ret) {
- dev_err(pil->dev, "MBA authentication of image timed out\n");
- } else if (status < 0) {
- dev_err(pil->dev, "MBA returned error %d for image\n", status);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static struct pil_reset_ops pil_mba_ops = {
- .init_image = pil_mba_init_image,
- .proxy_vote = pil_mba_make_proxy_votes,
- .proxy_unvote = pil_mba_remove_proxy_votes,
- .verify_blob = pil_mba_verify_blob,
- .auth_and_reset = pil_mba_auth,
-};
-
-#define subsys_to_drv(d) container_of(d, struct mba_data, subsys_desc)
+#define subsys_to_drv(d) container_of(d, struct modem_data, subsys_desc)
static void log_modem_sfr(void)
{
@@ -472,7 +83,7 @@
wmb();
}
-static void restart_modem(struct mba_data *drv)
+static void restart_modem(struct modem_data *drv)
{
log_modem_sfr();
drv->ignore_errors = true;
@@ -481,7 +92,7 @@
static irqreturn_t modem_err_fatal_intr_handler(int irq, void *dev_id)
{
- struct mba_data *drv = dev_id;
+ struct modem_data *drv = dev_id;
/* Ignore if we're the one that set the force stop GPIO */
if (drv->crash_shutdown)
@@ -495,7 +106,7 @@
static irqreturn_t modem_stop_ack_intr_handler(int irq, void *dev_id)
{
- struct mba_data *drv = dev_id;
+ struct modem_data *drv = dev_id;
pr_info("Received stop ack interrupt from modem\n");
complete(&drv->stop_ack);
return IRQ_HANDLED;
@@ -503,7 +114,7 @@
static int modem_shutdown(const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ struct modem_data *drv = subsys_to_drv(subsys);
unsigned long ret;
if (subsys->is_not_loadable)
@@ -518,14 +129,14 @@
gpio_set_value(drv->force_stop_gpio, 0);
}
- pil_shutdown(&drv->desc);
+ pil_shutdown(&drv->mba->desc);
pil_shutdown(&drv->q6->desc);
return 0;
}
static int modem_powerup(const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ struct modem_data *drv = subsys_to_drv(subsys);
int ret;
if (subsys->is_not_loadable)
@@ -540,7 +151,7 @@
ret = pil_boot(&drv->q6->desc);
if (ret)
return ret;
- ret = pil_boot(&drv->desc);
+ ret = pil_boot(&drv->mba->desc);
if (ret)
pil_shutdown(&drv->q6->desc);
return ret;
@@ -548,7 +159,7 @@
static void modem_crash_shutdown(const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ struct modem_data *drv = subsys_to_drv(subsys);
drv->crash_shutdown = true;
if (!subsys_get_crash_status(drv->subsys)) {
gpio_set_value(drv->force_stop_gpio, 1);
@@ -562,7 +173,7 @@
static int modem_ramdump(int enable, const struct subsys_desc *subsys)
{
- struct mba_data *drv = subsys_to_drv(subsys);
+ struct modem_data *drv = subsys_to_drv(subsys);
int ret;
if (!enable)
@@ -572,7 +183,7 @@
if (ret)
return ret;
- ret = pil_do_ramdump(&drv->desc, drv->ramdump_dev);
+ ret = pil_do_ramdump(&drv->mba->desc, drv->ramdump_dev);
if (ret < 0) {
pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);
goto out;
@@ -606,7 +217,7 @@
static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
{
- struct mba_data *drv = dev_id;
+ struct modem_data *drv = dev_id;
if (drv->ignore_errors)
return IRQ_HANDLED;
pr_err("Watchdog bite received from modem software!\n");
@@ -618,7 +229,7 @@
static int mss_start(const struct subsys_desc *desc)
{
int ret;
- struct mba_data *drv = subsys_to_drv(desc);
+ struct modem_data *drv = subsys_to_drv(desc);
if (desc->is_not_loadable)
return 0;
@@ -627,7 +238,7 @@
ret = pil_boot(&drv->q6->desc);
if (ret)
return ret;
- ret = pil_boot(&drv->desc);
+ ret = pil_boot(&drv->mba->desc);
if (ret)
pil_shutdown(&drv->q6->desc);
return ret;
@@ -635,16 +246,16 @@
static void mss_stop(const struct subsys_desc *desc)
{
- struct mba_data *drv = subsys_to_drv(desc);
+ struct modem_data *drv = subsys_to_drv(desc);
if (desc->is_not_loadable)
return;
- pil_shutdown(&drv->desc);
+ pil_shutdown(&drv->mba->desc);
pil_shutdown(&drv->q6->desc);
}
-static int __devinit pil_subsys_init(struct mba_data *drv,
+static int __devinit pil_subsys_init(struct modem_data *drv,
struct platform_device *pdev)
{
int irq, ret;
@@ -740,10 +351,11 @@
return ret;
}
-static int __devinit pil_mss_loadable_init(struct mba_data *drv,
+static int __devinit pil_mss_loadable_init(struct modem_data *drv,
struct platform_device *pdev)
{
struct q6v5_data *q6;
+ struct mba_data *mba;
struct pil_desc *q6_desc, *mba_desc;
struct resource *res;
struct property *prop;
@@ -758,25 +370,32 @@
if (clk_ready < 0)
return clk_ready;
+ mba = devm_kzalloc(&pdev->dev, sizeof(*mba), GFP_KERNEL);
+ if (IS_ERR(mba))
+ return PTR_ERR(mba);
+ drv->mba = mba;
+
q6 = pil_q6v5_init(pdev);
if (IS_ERR(q6))
return PTR_ERR(q6);
drv->q6 = q6;
+ drv->mba->xo = q6->xo;
q6_desc = &q6->desc;
- q6_desc->ops = &pil_mss_ops;
+ q6_desc->ops = &pil_msa_pbl_ops;
q6_desc->owner = THIS_MODULE;
q6_desc->proxy_timeout = PROXY_TIMEOUT_MS;
q6_desc->proxy_unvote_irq = clk_ready;
- drv->self_auth = of_property_read_bool(pdev->dev.of_node,
+ q6->self_auth = of_property_read_bool(pdev->dev.of_node,
"qcom,pil-self-auth");
- if (drv->self_auth) {
+ if (q6->self_auth) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"rmb_base");
- drv->rmb_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!drv->rmb_base)
+ q6->rmb_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!q6->rmb_base)
return -ENOMEM;
+ mba->rmb_base = q6->rmb_base;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
@@ -830,10 +449,10 @@
if (ret)
return ret;
- mba_desc = &drv->desc;
+ mba_desc = &mba->desc;
mba_desc->name = "modem";
mba_desc->dev = &pdev->dev;
- mba_desc->ops = &pil_mba_ops;
+ mba_desc->ops = &pil_msa_mba_ops;
mba_desc->owner = THIS_MODULE;
mba_desc->proxy_timeout = PROXY_TIMEOUT_MS;
mba_desc->proxy_unvote_irq = clk_ready;
@@ -852,7 +471,7 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
- struct mba_data *drv;
+ struct modem_data *drv;
int ret, err_fatal_gpio, is_not_loadable, stop_ack_gpio;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -901,14 +520,14 @@
static int __devexit pil_mss_driver_exit(struct platform_device *pdev)
{
- struct mba_data *drv = platform_get_drvdata(pdev);
+ struct modem_data *drv = platform_get_drvdata(pdev);
subsys_notif_unregister_notifier(drv->adsp_state_notifier,
&adsp_state_notifier_block);
subsys_unregister(drv->subsys);
destroy_ramdump_device(drv->smem_ramdump_dev);
destroy_ramdump_device(drv->ramdump_dev);
- pil_desc_release(&drv->desc);
+ pil_desc_release(&drv->mba->desc);
pil_desc_release(&drv->q6->desc);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index 48d10df..b2fb7f7 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -22,6 +22,7 @@
struct q6v5_data {
void __iomem *reg_base;
+ void __iomem *rmb_base;
void __iomem *cxrail_bhs; /* External BHS register */
struct clk *xo; /* XO clock source */
struct clk *ahb_clk; /* PIL access to registers */
@@ -37,6 +38,7 @@
struct regulator *vreg_pll;
bool is_booted;
struct pil_desc desc;
+ bool self_auth;
};
int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index f4ca4e3..796fba1 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -147,10 +147,11 @@
unsigned int cpu)
{
void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
+
if (!base_ptr)
return -ENODEV;
- secondary_cpu_hs_init(base_ptr);
+ secondary_cpu_hs_init(base_ptr, cpu);
writel_relaxed(0x021, base_ptr+0x04);
mb();
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 6799cbf..be32e82 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -967,7 +967,7 @@
if (acc_sts & msm_pm_slp_sts[cpu].mask)
return 0;
udelay(100);
- WARN(++timeout == 10, "CPU%u didn't collape within 1ms\n",
+ WARN(++timeout == 20, "CPU%u didn't collape within 2ms\n",
cpu);
}
@@ -1285,14 +1285,90 @@
},
};
+#ifdef CONFIG_ARM_LPAE
+static int msm_pm_idmap_add_pmd(pud_t *pud, unsigned long addr,
+ unsigned long end, unsigned long prot)
+{
+ pmd_t *pmd;
+ unsigned long next;
-static int __init msm_pm_setup_saved_state(void)
+ if (pud_none_or_clear_bad(pud) || (pud_val(*pud) & L_PGD_SWAPPER)) {
+ pmd = pmd_alloc_one(&init_mm, addr);
+ if (!pmd)
+ return -ENOMEM;
+
+ pud_populate(&init_mm, pud, pmd);
+ pmd += pmd_index(addr);
+ } else {
+ pmd = pmd_offset(pud, addr);
+ }
+
+ do {
+ next = pmd_addr_end(addr, end);
+ *pmd = __pmd((addr & PMD_MASK) | prot);
+ flush_pmd_entry(pmd);
+ } while (pmd++, addr = next, addr != end);
+
+ return 0;
+}
+#else /* !CONFIG_ARM_LPAE */
+static int msm_pm_idmap_add_pmd(pud_t *pud, unsigned long addr,
+ unsigned long end, unsigned long prot)
+{
+ pmd_t *pmd = pmd_offset(pud, addr);
+
+ addr = (addr & PMD_MASK) | prot;
+ pmd[0] = __pmd(addr);
+ addr += SECTION_SIZE;
+ pmd[1] = __pmd(addr);
+ flush_pmd_entry(pmd);
+
+ return 0;
+}
+#endif /* CONFIG_ARM_LPAE */
+
+static int msm_pm_idmap_add_pud(pgd_t *pgd, unsigned long addr,
+ unsigned long end,
+ unsigned long prot)
+{
+ pud_t *pud = pud_offset(pgd, addr);
+ unsigned long next;
+ int ret;
+
+ do {
+ next = pud_addr_end(addr, end);
+ ret = msm_pm_idmap_add_pmd(pud, addr, next, prot);
+ if (ret)
+ return ret;
+ } while (pud++, addr = next, addr != end);
+
+ return 0;
+}
+
+static int msm_pm_add_idmap(pgd_t *pgd, unsigned long addr,
+ unsigned long end,
+ unsigned long prot)
+{
+ unsigned long next;
+ int ret;
+
+ pgd += pgd_index(addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ ret = msm_pm_idmap_add_pud(pgd, addr, next, prot);
+ if (ret)
+ return ret;
+ } while (pgd++, addr = next, addr != end);
+
+ return 0;
+}
+
+static int msm_pm_setup_pagetable(void)
{
pgd_t *pc_pgd;
- pmd_t *pmd;
- unsigned long pmdval;
unsigned long exit_phys;
- dma_addr_t temp_phys;
+ unsigned long end;
+ int ret;
/* Page table for cores to come back up safely. */
pc_pgd = pgd_alloc(&init_mm);
@@ -1301,12 +1377,33 @@
exit_phys = virt_to_phys(msm_pm_collapse_exit);
- pmd = pmd_offset(pud_offset(pc_pgd + pgd_index(exit_phys),exit_phys),
- exit_phys);
- pmdval = (exit_phys & PGDIR_MASK) |
- PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
- pmd[0] = __pmd(pmdval);
- pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+ /*
+ * Make the (hopefully) reasonable assumption that the code size of
+ * msm_pm_collapse_exit won't be more than a section in size
+ */
+ end = exit_phys + SECTION_SIZE;
+
+ ret = msm_pm_add_idmap(pc_pgd, exit_phys, end,
+ PMD_TYPE_SECT | PMD_SECT_AP_WRITE);
+
+ if (ret)
+ return ret;
+
+ msm_pm_pc_pgd = virt_to_phys(pc_pgd);
+ clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
+ virt_to_phys(&msm_pm_pc_pgd));
+
+ return 0;
+}
+
+static int __init msm_pm_setup_saved_state(void)
+{
+ int ret;
+ dma_addr_t temp_phys;
+
+ ret = msm_pm_setup_pagetable();
+ if (ret)
+ return ret;
msm_saved_state = dma_zalloc_coherent(NULL, CPU_SAVED_STATE_SIZE *
num_possible_cpus(),
@@ -1322,19 +1419,6 @@
*/
msm_saved_state_phys = (unsigned long)temp_phys;
-
- /* It is remotely possible that the code in msm_pm_collapse_exit()
- * which turns on the MMU with this mapping is in the
- * next even-numbered megabyte beyond the
- * start of msm_pm_collapse_exit().
- * Map this megabyte in as well.
- */
- pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
- flush_pmd_entry(pmd);
- msm_pm_pc_pgd = virt_to_phys(pc_pgd);
- clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
- virt_to_phys(&msm_pm_pc_pgd));
-
return 0;
}
arch_initcall(msm_pm_setup_saved_state);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index d37a325..1ea213a 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -456,7 +456,7 @@
__func__, config->buf_num, config->stream_format,
config->port_cnt, config->params_data_size);
- pr_debug("%s: id[0]=%d, id[1]=%d, id[2]=%d, id[3]=%d, id[4]=%d\n",
+ pr_debug("%s: id[0]=%d, id[1]=%d, id[2]=%d, id[3]=%d, id[4]=%d,\n",
__func__,
config->port_id[0],
config->port_id[1],
@@ -464,6 +464,11 @@
config->port_id[3],
config->port_id[4]);
+ pr_debug("id[5]=%d, id[6]=%d, id[7]=%d\n",
+ config->port_id[5],
+ config->port_id[6],
+ config->port_id[7]);
+
/* q6usm allocation & configuration */
usf_xx->buffer_size = config->buf_size;
usf_xx->buffer_count = config->buf_num;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.c
index 5d30eb1..80b1aaa 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_a/q6usm_a.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
@@ -652,7 +652,7 @@
sizeof(struct usm_stream_cmd_encdec_cfg_blk);
uint32_t round_params_size = 0;
uint8_t is_allocated = 0;
-
+ size_t min_common_size;
if ((usc == NULL) || (us_cfg == NULL)) {
pr_err("%s: wrong input", __func__);
@@ -692,12 +692,13 @@
round_params_size;
enc_cfg->enc_blk.frames_per_buf = 1;
enc_cfg->enc_blk.format_id = int_format;
- enc_cfg->enc_blk.cfg_size = sizeof(struct usm_cfg_common)+
+ min_common_size = min(sizeof(struct usm_cfg_common),
+ sizeof(struct usm_cfg_common_a));
+ enc_cfg->enc_blk.cfg_size = min_common_size +
USM_MAX_CFG_DATA_SIZE +
round_params_size;
memcpy(&(enc_cfg->enc_blk.cfg_common), &(us_cfg->cfg_common),
- sizeof(struct usm_cfg_common));
-
+ min_common_size);
/* Transparent data copy */
memcpy(enc_cfg->enc_blk.transp_data, us_cfg->params,
us_cfg->params_size);
@@ -716,11 +717,15 @@
enc_cfg->enc_blk.transp_data[6],
enc_cfg->enc_blk.transp_data[7]
);
- pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:0x%x; dev_id=0x%x\n",
+ pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:[0x%x,0x%x,0x%x,0x%x];\n",
__func__, enc_cfg->enc_blk.cfg_common.sample_rate,
enc_cfg->enc_blk.cfg_common.ch_cfg,
enc_cfg->enc_blk.cfg_common.bits_per_sample,
- enc_cfg->enc_blk.cfg_common.data_map,
+ enc_cfg->enc_blk.cfg_common.data_map[0],
+ enc_cfg->enc_blk.cfg_common.data_map[1],
+ enc_cfg->enc_blk.cfg_common.data_map[2],
+ enc_cfg->enc_blk.cfg_common.data_map[3]);
+ pr_debug("dev_id=0x%x\n",
enc_cfg->enc_blk.cfg_common.dev_id);
rc = apr_send_pkt(usc->apr, (uint32_t *) enc_cfg);
@@ -757,7 +762,7 @@
uint32_t total_cfg_size = sizeof(struct usm_stream_media_format_update);
uint32_t round_params_size = 0;
uint8_t is_allocated = 0;
-
+ size_t min_common_size;
if ((usc == NULL) || (us_cfg == NULL)) {
pr_err("%s: wrong input", __func__);
@@ -794,11 +799,13 @@
dec_cfg->hdr.opcode = USM_DATA_CMD_MEDIA_FORMAT_UPDATE;
dec_cfg->format_id = int_format;
- dec_cfg->cfg_size = sizeof(struct usm_cfg_common) +
+ min_common_size = min(sizeof(struct usm_cfg_common),
+ sizeof(struct usm_cfg_common_a));
+ dec_cfg->cfg_size = min_common_size +
USM_MAX_CFG_DATA_SIZE +
round_params_size;
memcpy(&(dec_cfg->cfg_common), &(us_cfg->cfg_common),
- sizeof(struct usm_cfg_common));
+ min_common_size);
/* Transparent data copy */
memcpy(dec_cfg->transp_data, us_cfg->params, us_cfg->params_size);
pr_debug("%s: cfg_size[%d], params_size[%d]; parambytes[%d,%d,%d,%d]\n",
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index a3af3e78..fe7c8c2 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -620,13 +620,13 @@
uint32_t int_format = INVALID_FORMAT;
switch (ext_format) {
case FORMAT_USPS_EPOS:
- int_format = US_POINT_EPOS_FORMAT;
+ int_format = US_POINT_EPOS_FORMAT_V2;
break;
case FORMAT_USRAW:
- int_format = US_RAW_FORMAT;
+ int_format = US_RAW_FORMAT_V2;
break;
case FORMAT_USPROX:
- int_format = US_PROX_FORMAT;
+ int_format = US_PROX_FORMAT_V2;
break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
@@ -757,11 +757,19 @@
enc_cfg->enc_blk.transp_data[6],
enc_cfg->enc_blk.transp_data[7]
);
- pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:0x%x; dev_id=0x%x\n",
+ pr_debug("%s: srate:%d, ch=%d, bps= %d;\n",
__func__, enc_cfg->enc_blk.cfg_common.sample_rate,
enc_cfg->enc_blk.cfg_common.ch_cfg,
- enc_cfg->enc_blk.cfg_common.bits_per_sample,
- enc_cfg->enc_blk.cfg_common.data_map,
+ enc_cfg->enc_blk.cfg_common.bits_per_sample);
+ pr_debug("dmap:[0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x]; dev_id=0x%x\n",
+ enc_cfg->enc_blk.cfg_common.data_map[0],
+ enc_cfg->enc_blk.cfg_common.data_map[1],
+ enc_cfg->enc_blk.cfg_common.data_map[2],
+ enc_cfg->enc_blk.cfg_common.data_map[3],
+ enc_cfg->enc_blk.cfg_common.data_map[4],
+ enc_cfg->enc_blk.cfg_common.data_map[5],
+ enc_cfg->enc_blk.cfg_common.data_map[6],
+ enc_cfg->enc_blk.cfg_common.data_map[7],
enc_cfg->enc_blk.cfg_common.dev_id);
rc = apr_send_pkt(usc->apr, (uint32_t *) enc_cfg);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 38ed867..2bae37a 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -60,12 +60,13 @@
spinlock_t smd_lock_write;
spinlock_t smd_lock_read;
struct completion smd_open;
+ struct completion remote_open;
};
#define DEFAULT_BUFFER_SIZE 256
#define DEBUG_PRINT_BUFFER_SIZE 512
#define MAX_SLEEP_BUFFER 128
-
+#define SMD_CHANNEL_NOTIF_TIMEOUT 5000
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
#define INV_RSC "resource does not exist"
#define ERR "err\0"
@@ -1303,6 +1304,20 @@
}
EXPORT_SYMBOL(msm_rpm_exit_sleep);
+static int __devinit msm_rpm_smd_remote_probe(struct platform_device *pdev)
+{
+ if (pdev && pdev->id == msm_rpm_data.ch_type)
+ complete(&msm_rpm_data.remote_open);
+ return 0;
+}
+
+static struct platform_driver msm_rpm_smd_remote_driver = {
+ .probe = msm_rpm_smd_remote_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+};
+
static int __devinit msm_rpm_dev_probe(struct platform_device *pdev)
{
char *key = NULL;
@@ -1323,13 +1338,21 @@
key = "rpm-standalone";
standalone = of_property_read_bool(pdev->dev.of_node, key);
+ msm_rpm_smd_remote_driver.driver.name = msm_rpm_data.ch_name;
+ init_completion(&msm_rpm_data.remote_open);
init_completion(&msm_rpm_data.smd_open);
spin_lock_init(&msm_rpm_data.smd_lock_write);
spin_lock_init(&msm_rpm_data.smd_lock_read);
INIT_WORK(&msm_rpm_data.work, msm_rpm_smd_work);
- if (smd_named_open_on_edge(msm_rpm_data.ch_name, msm_rpm_data.ch_type,
- &msm_rpm_data.ch_info, &msm_rpm_data,
+ platform_driver_register(&msm_rpm_smd_remote_driver);
+ ret = wait_for_completion_timeout(&msm_rpm_data.remote_open,
+ msecs_to_jiffies(SMD_CHANNEL_NOTIF_TIMEOUT));
+
+ if (!ret || smd_named_open_on_edge(msm_rpm_data.ch_name,
+ msm_rpm_data.ch_type,
+ &msm_rpm_data.ch_info,
+ &msm_rpm_data,
msm_rpm_notify)) {
pr_info("Cannot open RPM channel %s %d\n", msm_rpm_data.ch_name,
msm_rpm_data.ch_type);
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 4cb43b1..b244c6f 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -268,7 +268,7 @@
rate = clk_round_rate(scm_clocks[CORE_CLK_SRC], 1);
clk_set_rate(scm_clocks[CORE_CLK_SRC], rate);
- if (cpu_is_msm8974() || cpu_is_msm8226() || cpu_is_msm8610()) {
+ if (soc_class_is_msm8974() || cpu_is_msm8226() || cpu_is_msm8610()) {
scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
} else {
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index 6e05177..e9f44e3 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -191,12 +191,12 @@
u32 cmd_addr = virt_to_phys(cmd);
/*
- * Flush the entire cache here so callers don't have to remember
- * to flush the cache when passing physical addresses to the secure
- * side in the buffer.
+ * Flush the command buffer so that the secure world sees
+ * the correct data.
*/
- flush_cache_all();
- outer_flush_all();
+ __cpuc_flush_dcache_area((void *)cmd, cmd->len);
+ outer_flush_range(cmd_addr, cmd_addr + cmd->len);
+
ret = smc(cmd_addr);
if (ret < 0)
ret = scm_remap_error(ret);
@@ -233,6 +233,13 @@
* @resp_len: length of the response buffer
*
* Sends a command to the SCM and waits for the command to finish processing.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking scm_call and invalidated in the cache
+ * immediately after scm_call returns. Cache maintenance on the command and
+ * response buffers is taken care of by scm_call; however, callers are
+ * responsible for any other cached buffers passed over to the secure world.
*/
int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
void *resp_buf, size_t resp_len)
diff --git a/arch/arm/mach-msm/smcmod.c b/arch/arm/mach-msm/smcmod.c
index 705bab5..fc7ffd5 100644
--- a/arch/arm/mach-msm/smcmod.c
+++ b/arch/arm/mach-msm/smcmod.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
@@ -28,6 +28,7 @@
#include <linux/printk.h>
#include <linux/msm_ion.h>
#include <asm/smcmod.h>
+#include <asm/cacheflush.h>
#include <mach/scm.h>
static DEFINE_MUTEX(ioctl_lock);
@@ -113,6 +114,20 @@
isb();
}
+/*
+ * FIXME:
+ * scm_call will no longer flush the entire cache before calling into the secure
+ * world. Until individual buffers in this driver can be flushed, flush the
+ * entire cache before calling into scm_call.
+ */
+int smcmod_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
+ void *resp_buf, size_t resp_len)
+{
+ flush_cache_all();
+ outer_flush_all();
+ return scm_call(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf, resp_len);
+}
+
static int smcmod_ion_fd_to_phys(int32_t fd, struct ion_client *ion_clientp,
struct ion_handle **ion_handlep, uint32_t *phys_addrp, size_t *sizep)
{
@@ -235,7 +250,7 @@
}
/* call scm function to switch to secure world */
- reqp->return_val = scm_call(reqp->service_id, reqp->command_id,
+ reqp->return_val = smcmod_scm_call(reqp->service_id, reqp->command_id,
cmd_vaddrp, reqp->cmd_len, resp_vaddrp, reqp->resp_len);
buf_cleanup:
@@ -356,7 +371,7 @@
}
/* call scm function to switch to secure world */
- reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
+ reqp->return_val = smcmod_scm_call(SMCMOD_SVC_CRYPTO,
SMCMOD_CRYPTO_CMD_CIPHER, &scm_req,
sizeof(scm_req), NULL, 0);
@@ -494,13 +509,13 @@
/* call scm function to switch to secure world */
if (reqp->fixed_block)
- reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
+ reqp->return_val = smcmod_scm_call(SMCMOD_SVC_CRYPTO,
SMCMOD_CRYPTO_CMD_MSG_DIGEST_FIXED,
&scm_req,
sizeof(scm_req),
NULL, 0);
else
- reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
+ reqp->return_val = smcmod_scm_call(SMCMOD_SVC_CRYPTO,
SMCMOD_CRYPTO_CMD_MSG_DIGEST,
&scm_req,
sizeof(scm_req),
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 4649390..c97ba68 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -176,8 +176,6 @@
},
};
-static void *smd_dev;
-
struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
#define SMSM_STATE_ADDR(entry) (smsm_info.state + entry)
@@ -381,14 +379,6 @@
static DEFINE_MUTEX(smsm_lock);
static struct smsm_state_info *smsm_states;
-/**
- * Variables to indicate smd module initialization.
- * Dependents to register for smd module init notifier.
- */
-static int smd_module_inited;
-static RAW_NOTIFIER_HEAD(smd_module_init_notifier_list);
-static DEFINE_MUTEX(smd_module_init_notifier_lock);
-static void smd_module_init_notify(uint32_t state, void *data);
static int smd_stream_write_avail(struct smd_channel *ch);
static int smd_stream_read_avail(struct smd_channel *ch);
@@ -708,6 +698,7 @@
uint32_t local_pid;
uint32_t remote_pid;
char subsys_name[SMD_MAX_CH_NAME_LEN];
+ bool initialized;
};
/**
@@ -762,6 +753,11 @@
static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm);
+static bool smd_edge_inited(int edge)
+{
+ return edge_to_pids[edge].initialized;
+}
+
/* on smp systems, the probe might get called from multiple cores,
hence use a lock */
static DEFINE_MUTEX(smd_probe_lock);
@@ -795,6 +791,11 @@
if (!shared[n].name[0])
continue;
+ if (!smd_initialized && !smd_edge_inited(type)) {
+ SMD_INFO("Probe skipping ch %d, edge not inited\n", n);
+ continue;
+ }
+
if (!smd_alloc_channel(&shared[n]))
smd_ch_allocated[n] = 1;
else
@@ -1913,7 +1914,7 @@
struct smd_channel *ch;
unsigned long flags;
- if (smd_initialized == 0) {
+ if (smd_initialized == 0 && !smd_edge_inited(edge)) {
SMD_INFO("smd_open() before smd_init()\n");
return -ENODEV;
}
@@ -2436,16 +2437,23 @@
struct smsm_size_info_type *smsm_size_info;
unsigned long flags;
unsigned long j_start;
+ static int first = 1;
+ remote_spinlock_t *remote_spinlock;
+
+ if (!first)
+ return 0;
+ first = 0;
/* Verify that remote spinlock is not deadlocked */
+ remote_spinlock = smem_get_remote_spinlock();
j_start = jiffies;
- while (!remote_spin_trylock_irqsave(&remote_spinlock, flags)) {
+ while (!remote_spin_trylock_irqsave(remote_spinlock, flags)) {
if (jiffies_to_msecs(jiffies - j_start) > RSPIN_INIT_WAIT_MS) {
panic("%s: Remote processor %d will not release spinlock\n",
- __func__, remote_spin_owner(&remote_spinlock));
+ __func__, remote_spin_owner(remote_spinlock));
}
}
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+ remote_spin_unlock_irqrestore(remote_spinlock, flags);
smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
sizeof(struct smsm_size_info_type));
@@ -2860,9 +2868,6 @@
int ret;
unsigned long flags;
- if (!smd_initialized)
- return;
-
while (kfifo_len(&smsm_snapshot_fifo) >= SMSM_SNAPSHOT_SIZE) {
mutex_lock(&smsm_lock);
for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
@@ -3084,42 +3089,6 @@
}
EXPORT_SYMBOL(smsm_state_cb_deregister);
-int smd_module_init_notifier_register(struct notifier_block *nb)
-{
- int ret;
- if (!nb)
- return -EINVAL;
- mutex_lock(&smd_module_init_notifier_lock);
- ret = raw_notifier_chain_register(&smd_module_init_notifier_list, nb);
- if (smd_module_inited)
- nb->notifier_call(nb, 0, NULL);
- mutex_unlock(&smd_module_init_notifier_lock);
- return ret;
-}
-EXPORT_SYMBOL(smd_module_init_notifier_register);
-
-int smd_module_init_notifier_unregister(struct notifier_block *nb)
-{
- int ret;
- if (!nb)
- return -EINVAL;
- mutex_lock(&smd_module_init_notifier_lock);
- ret = raw_notifier_chain_unregister(&smd_module_init_notifier_list,
- nb);
- mutex_unlock(&smd_module_init_notifier_lock);
- return ret;
-}
-EXPORT_SYMBOL(smd_module_init_notifier_unregister);
-
-static void smd_module_init_notify(uint32_t state, void *data)
-{
- mutex_lock(&smd_module_init_notifier_lock);
- smd_module_inited = 1;
- raw_notifier_call_chain(&smd_module_init_notifier_list,
- state, data);
- mutex_unlock(&smd_module_init_notifier_lock);
-}
-
int smd_core_init(void)
{
int r;
@@ -3315,9 +3284,6 @@
struct smd_subsystem_config *smd_ss_config_list;
struct smd_subsystem_config *cfg;
int err_ret = 0;
- struct smd_smem_regions *smd_smem_areas;
- struct smem_area *smem_areas_tmp = NULL;
- int smem_idx;
smd_platform_data = pdev->dev.platform_data;
num_ss = smd_platform_data->num_ss_configs;
@@ -3327,57 +3293,6 @@
disable_smsm_reset_handshake = smd_platform_data->
smd_ssr_config->disable_smsm_reset_handshake;
- smd_smem_areas = smd_platform_data->smd_smem_areas;
- num_smem_areas = smd_platform_data->num_smem_areas + 1;
-
- /* Initialize main SMEM region */
- smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
- GFP_KERNEL);
- if (!smem_areas_tmp) {
- pr_err("%s: smem_areas kmalloc failed\n", __func__);
- err_ret = -ENOMEM;
- goto smem_areas_alloc_fail;
- }
-
- smem_areas_tmp[0].phys_addr = msm_shared_ram_phys;
- smem_areas_tmp[0].size = MSM_SHARED_RAM_SIZE;
- smem_areas_tmp[0].virt_addr = MSM_SHARED_RAM_BASE;
-
- /* Configure auxiliary SMEM regions */
- for (smem_idx = 1; smem_idx < num_smem_areas; ++smem_idx) {
- smem_areas_tmp[smem_idx].phys_addr =
- smd_smem_areas[smem_idx].phys_addr;
- smem_areas_tmp[smem_idx].size =
- smd_smem_areas[smem_idx].size;
- smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
- (unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
- smem_areas_tmp[smem_idx].size);
- if (!smem_areas_tmp[smem_idx].virt_addr) {
- pr_err("%s: ioremap_nocache() of addr: %pa size: %pa\n",
- __func__,
- &smem_areas_tmp[smem_idx].phys_addr,
- &smem_areas_tmp[smem_idx].size);
- err_ret = -ENOMEM;
- goto smem_failed;
- }
-
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
- smem_areas_tmp[smem_idx].size)) {
- pr_err("%s: invalid virtual address block %i: %p:%pa\n",
- __func__, smem_idx,
- smem_areas_tmp[smem_idx].virt_addr,
- &smem_areas_tmp[smem_idx].size);
- ++smem_idx;
- err_ret = -EINVAL;
- goto smem_failed;
- }
-
- SMD_DBG("%s: %d = %pa %pa", __func__, smem_idx,
- &smd_smem_areas[smem_idx].phys_addr,
- &smd_smem_areas[smem_idx].size);
- }
-
for (i = 0; i < num_ss; i++) {
cfg = &smd_ss_config_list[i];
@@ -3421,7 +3336,6 @@
SMD_INFO("smd_core_platform_init() done\n");
- smem_areas = smem_areas_tmp;
return 0;
intr_failed:
@@ -3438,19 +3352,105 @@
(void *)cfg->smsm_int.dev_id
);
}
-smem_failed:
- for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
- iounmap(smem_areas_tmp[smem_idx].virt_addr);
-
- num_smem_areas = 0;
- kfree(smem_areas_tmp);
-
-smem_areas_alloc_fail:
return err_ret;
}
-static int __devinit parse_smd_devicetree(struct device_node *node,
- void *irq_out_base)
+static int msm_smsm_probe(struct platform_device *pdev)
+{
+ uint32_t edge;
+ char *key;
+ int ret;
+ uint32_t irq_offset;
+ uint32_t irq_bitmask;
+ uint32_t irq_line;
+ struct interrupt_config_item *private_irq;
+ struct device_node *node;
+ void *irq_out_base;
+ resource_size_t irq_out_size;
+ struct platform_device *parent_pdev;
+ struct resource *r;
+
+ disable_smsm_reset_handshake = 1;
+
+ node = pdev->dev.of_node;
+
+ if (!pdev->dev.parent) {
+ pr_err("%s: missing link to parent device\n", __func__);
+ return -ENODEV;
+ }
+
+ parent_pdev = to_platform_device(pdev->dev.parent);
+
+ key = "irq-reg-base";
+ /* existance check verified in smem driver */
+ r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+ irq_out_size = resource_size(r);
+ irq_out_base = ioremap_nocache(r->start, irq_out_size);
+ if (!irq_out_base) {
+ pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+ __func__, &r->start, &irq_out_size);
+ return -ENOMEM;
+ }
+ SMSM_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+ key = "qcom,smsm-edge";
+ ret = of_property_read_u32(node, key, &edge);
+ if (ret)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %d", __func__, key, edge);
+
+ key = "qcom,smsm-irq-offset";
+ ret = of_property_read_u32(node, key, &irq_offset);
+ if (ret)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+ key = "qcom,smsm-irq-bitmask";
+ ret = of_property_read_u32(node, key, &irq_bitmask);
+ if (ret)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+ key = "interrupts";
+ irq_line = irq_of_parse_and_map(node, 0);
+ if (!irq_line)
+ goto missing_key;
+ SMSM_DBG("%s: %s = %d", __func__, key, irq_line);
+
+ private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
+ private_irq->out_bit_pos = irq_bitmask;
+ private_irq->out_offset = irq_offset;
+ private_irq->out_base = irq_out_base;
+ private_irq->irq_id = irq_line;
+
+ ret = request_irq(irq_line,
+ private_irq->irq_handler,
+ IRQF_TRIGGER_RISING,
+ "smsm_dev",
+ NULL);
+ if (ret < 0) {
+ pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+ return ret;
+ } else {
+ ret = enable_irq_wake(irq_line);
+ if (ret < 0)
+ pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+ irq_line);
+ }
+
+ if (smsm_init())
+ pr_err("smsm_init() failed\n");
+
+ smsm_irq_handler(0, 0);
+
+ return 0;
+
+missing_key:
+ pr_err("%s: missing key: %s", __func__, key);
+ return -ENODEV;
+}
+
+static int msm_smd_probe(struct platform_device *pdev)
{
uint32_t edge;
char *key;
@@ -3461,6 +3461,32 @@
unsigned long irq_flags = IRQF_TRIGGER_RISING;
const char *pilstr;
struct interrupt_config_item *private_irq;
+ struct device_node *node;
+ void *irq_out_base;
+ resource_size_t irq_out_size;
+ struct platform_device *parent_pdev;
+ struct resource *r;
+
+ node = pdev->dev.of_node;
+
+ if (!pdev->dev.parent) {
+ pr_err("%s: missing link to parent device\n", __func__);
+ return -ENODEV;
+ }
+
+ parent_pdev = to_platform_device(pdev->dev.parent);
+
+ key = "irq-reg-base";
+ /* existance check verified in smem driver */
+ r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+ irq_out_size = resource_size(r);
+ irq_out_base = ioremap_nocache(r->start, irq_out_size);
+ if (!irq_out_base) {
+ pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+ __func__, &r->start, &irq_out_size);
+ return -ENOMEM;
+ }
+ SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
key = "qcom,smd-edge";
ret = of_property_read_u32(node, key, &edge);
@@ -3521,68 +3547,9 @@
strlcpy(edge_to_pids[edge].subsys_name, pilstr,
SMD_MAX_CH_NAME_LEN);
- return 0;
+ edge_to_pids[edge].initialized = true;
-missing_key:
- pr_err("%s: missing key: %s", __func__, key);
- return -ENODEV;
-}
-
-static int __devinit parse_smsm_devicetree(struct device_node *node,
- void *irq_out_base)
-{
- uint32_t edge;
- char *key;
- int ret;
- uint32_t irq_offset;
- uint32_t irq_bitmask;
- uint32_t irq_line;
- struct interrupt_config_item *private_irq;
-
- key = "qcom,smsm-edge";
- ret = of_property_read_u32(node, key, &edge);
- if (ret)
- goto missing_key;
- SMD_DBG("%s: %s = %d", __func__, key, edge);
-
- key = "qcom,smsm-irq-offset";
- ret = of_property_read_u32(node, key, &irq_offset);
- if (ret)
- goto missing_key;
- SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
-
- key = "qcom,smsm-irq-bitmask";
- ret = of_property_read_u32(node, key, &irq_bitmask);
- if (ret)
- goto missing_key;
- SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
-
- key = "interrupts";
- irq_line = irq_of_parse_and_map(node, 0);
- if (!irq_line)
- goto missing_key;
- SMD_DBG("%s: %s = %d", __func__, key, irq_line);
-
- private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
- private_irq->out_bit_pos = irq_bitmask;
- private_irq->out_offset = irq_offset;
- private_irq->out_base = irq_out_base;
- private_irq->irq_id = irq_line;
-
- ret = request_irq(irq_line,
- private_irq->irq_handler,
- IRQF_TRIGGER_RISING,
- "smsm_dev",
- NULL);
- if (ret < 0) {
- pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
- return ret;
- } else {
- ret = enable_irq_wake(irq_line);
- if (ret < 0)
- pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
- irq_line);
- }
+ schedule_work(&probe_work);
return 0;
@@ -3591,213 +3558,7 @@
return -ENODEV;
}
-static void __devinit unparse_smd_devicetree(struct device_node *node)
-{
- uint32_t irq_line;
-
- irq_line = irq_of_parse_and_map(node, 0);
-
- free_irq(irq_line, NULL);
-}
-
-static void __devinit unparse_smsm_devicetree(struct device_node *node)
-{
- uint32_t irq_line;
-
- irq_line = irq_of_parse_and_map(node, 0);
-
- free_irq(irq_line, NULL);
-}
-
-static int __devinit smd_core_devicetree_init(struct platform_device *pdev)
-{
- char *key;
- struct resource *r;
- void *irq_out_base;
- phys_addr_t aux_mem_base;
- resource_size_t aux_mem_size;
- int temp_string_size = 11; /* max 3 digit count */
- char temp_string[temp_string_size];
- struct device_node *node;
- int ret;
- const char *compatible;
- struct ramdump_segment *ramdump_segments_tmp = NULL;
- struct smem_area *smem_areas_tmp = NULL;
- int smem_idx = 0;
- int subnode_num = 0;
- int i;
- resource_size_t irq_out_size;
-
- disable_smsm_reset_handshake = 1;
-
- key = "irq-reg-base";
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
- if (!r) {
- pr_err("%s: missing '%s'\n", __func__, key);
- return -ENODEV;
- }
- irq_out_size = resource_size(r);
- irq_out_base = ioremap_nocache(r->start, irq_out_size);
- if (!irq_out_base) {
- pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
- __func__, &r->start, &irq_out_size);
- return -ENOMEM;
- }
- SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
-
- num_smem_areas = 1;
- while (1) {
- scnprintf(temp_string, temp_string_size, "aux-mem%d",
- num_smem_areas);
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- temp_string);
- if (!r)
- break;
-
- ++num_smem_areas;
- if (num_smem_areas > 999) {
- pr_err("%s: max num aux mem regions reached\n",
- __func__);
- break;
- }
- }
-
- /* Initialize main SMEM region and SSR ramdump region */
- key = "smem";
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
- if (!r) {
- pr_err("%s: missing '%s'\n", __func__, key);
- return -ENODEV;
- }
-
- smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
- GFP_KERNEL);
- if (!smem_areas_tmp) {
- pr_err("%s: smem areas kmalloc failed\n", __func__);
- ret = -ENOMEM;
- goto free_smem_areas;
- }
-
- ramdump_segments_tmp = kmalloc_array(num_smem_areas,
- sizeof(struct ramdump_segment), GFP_KERNEL);
- if (!ramdump_segments_tmp) {
- pr_err("%s: ramdump segment kmalloc failed\n", __func__);
- ret = -ENOMEM;
- goto free_smem_areas;
- }
-
- smem_areas_tmp[smem_idx].phys_addr = r->start;
- smem_areas_tmp[smem_idx].size = resource_size(r);
- smem_areas_tmp[smem_idx].virt_addr = MSM_SHARED_RAM_BASE;
-
- ramdump_segments_tmp[smem_idx].address = r->start;
- ramdump_segments_tmp[smem_idx].size = resource_size(r);
- ++smem_idx;
-
- /* Configure auxiliary SMEM regions */
- while (1) {
- scnprintf(temp_string, temp_string_size, "aux-mem%d",
- smem_idx);
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- temp_string);
- if (!r)
- break;
- aux_mem_base = r->start;
- aux_mem_size = resource_size(r);
-
- ramdump_segments_tmp[smem_idx].address = aux_mem_base;
- ramdump_segments_tmp[smem_idx].size = aux_mem_size;
-
- smem_areas_tmp[smem_idx].phys_addr = aux_mem_base;
- smem_areas_tmp[smem_idx].size = aux_mem_size;
- smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
- (unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
- smem_areas_tmp[smem_idx].size);
- SMD_DBG("%s: %s = %pa %pa -> %p", __func__, temp_string,
- &aux_mem_base, &aux_mem_size,
- smem_areas_tmp[smem_idx].virt_addr);
-
- if (!smem_areas_tmp[smem_idx].virt_addr) {
- pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
- __func__,
- &smem_areas_tmp[smem_idx].phys_addr,
- &smem_areas_tmp[smem_idx].size);
- ret = -ENOMEM;
- goto free_smem_areas;
- }
-
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
- smem_areas_tmp[smem_idx].size)) {
- pr_err("%s: invalid virtual address block %i: %p:%pa\n",
- __func__, smem_idx,
- smem_areas_tmp[smem_idx].virt_addr,
- &smem_areas_tmp[smem_idx].size);
- ++smem_idx;
- ret = -EINVAL;
- goto free_smem_areas;
- }
-
- ++smem_idx;
- if (smem_idx > 999) {
- pr_err("%s: max num aux mem regions reached\n",
- __func__);
- break;
- }
- }
-
- for_each_child_of_node(pdev->dev.of_node, node) {
- compatible = of_get_property(node, "compatible", NULL);
- if (!compatible) {
- pr_err("%s: invalid child node: compatible null\n",
- __func__);
- ret = -ENODEV;
- goto rollback_subnodes;
- }
- if (!strcmp(compatible, "qcom,smd")) {
- ret = parse_smd_devicetree(node, irq_out_base);
- if (ret)
- goto rollback_subnodes;
- } else if (!strcmp(compatible, "qcom,smsm")) {
- ret = parse_smsm_devicetree(node, irq_out_base);
- if (ret)
- goto rollback_subnodes;
- } else {
- pr_err("%s: invalid child node named: %s\n", __func__,
- compatible);
- ret = -ENODEV;
- goto rollback_subnodes;
- }
- ++subnode_num;
- }
-
- smem_areas = smem_areas_tmp;
- smem_ramdump_segments = ramdump_segments_tmp;
- return 0;
-
-rollback_subnodes:
- i = 0;
- for_each_child_of_node(pdev->dev.of_node, node) {
- if (i >= subnode_num)
- break;
- ++i;
- compatible = of_get_property(node, "compatible", NULL);
- if (!strcmp(compatible, "qcom,smd"))
- unparse_smd_devicetree(node);
- else
- unparse_smsm_devicetree(node);
- }
-free_smem_areas:
- for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
- iounmap(smem_areas_tmp[smem_idx].virt_addr);
-
- num_smem_areas = 0;
- kfree(ramdump_segments_tmp);
- kfree(smem_areas_tmp);
- return ret;
-}
-
-static int __devinit msm_smd_probe(struct platform_device *pdev)
+static int msm_smd_probe_legacy(struct platform_device *pdev)
{
int ret;
@@ -3805,13 +3566,6 @@
return -ENODEV;
SMD_INFO("smd probe\n");
- INIT_WORK(&probe_work, smd_channel_probe_worker);
-
- channel_close_wq = create_singlethread_workqueue("smd_channel_close");
- if (IS_ERR(channel_close_wq)) {
- pr_err("%s: create_singlethread_workqueue ENOMEM\n", __func__);
- return -ENOMEM;
- }
if (smsm_init()) {
pr_err("smsm_init() failed\n");
@@ -3820,13 +3574,8 @@
if (pdev) {
if (pdev->dev.of_node) {
- ret = smd_core_devicetree_init(pdev);
- if (ret) {
- pr_err("%s: device tree init failed\n",
- __func__);
- return ret;
- }
- smd_dev = &pdev->dev;
+ pr_err("%s: invalid device tree init\n", __func__);
+ return -ENODEV;
} else if (pdev->dev.platform_data) {
ret = smd_core_platform_init(pdev);
if (ret) {
@@ -3872,6 +3621,8 @@
unsigned long code,
void *data)
{
+ remote_spinlock_t *remote_spinlock;
+
/*
* Some SMD or SMSM clients assume SMD/SMSM SSR handling will be
* done in the AFTER_SHUTDOWN level. If this ever changes, extra
@@ -3886,7 +3637,8 @@
__func__, notifier->processor,
notifier->name);
- remote_spin_release(&remote_spinlock, notifier->processor);
+ remote_spinlock = smem_get_remote_spinlock();
+ remote_spin_release(remote_spinlock, notifier->processor);
remote_spin_release_all(notifier->processor);
smd_channel_reset(notifier->processor);
@@ -3912,17 +3664,39 @@
}
late_initcall(modem_restart_late_init);
-static struct of_device_id msm_smem_match_table[] = {
- { .compatible = "qcom,smem" },
+static struct of_device_id msm_smd_match_table[] = {
+ { .compatible = "qcom,smd" },
{},
};
static struct platform_driver msm_smd_driver = {
.probe = msm_smd_probe,
.driver = {
+ .name = "msm_smd_dt",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_smd_match_table,
+ },
+};
+
+static struct of_device_id msm_smsm_match_table[] = {
+ { .compatible = "qcom,smsm" },
+ {},
+};
+
+static struct platform_driver msm_smsm_driver = {
+ .probe = msm_smsm_probe,
+ .driver = {
+ .name = "msm_smsm",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_smsm_match_table,
+ },
+};
+
+static struct platform_driver msm_smd_driver_legacy = {
+ .probe = msm_smd_probe_legacy,
+ .driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
- .of_match_table = msm_smem_match_table,
},
};
@@ -3941,9 +3715,19 @@
}
registered = true;
- rc = init_smem_remote_spinlock();
+
+ INIT_WORK(&probe_work, smd_channel_probe_worker);
+
+ channel_close_wq = create_singlethread_workqueue("smd_channel_close");
+ if (IS_ERR(channel_close_wq)) {
+ pr_err("%s: create_singlethread_workqueue ENOMEM\n", __func__);
+ return -ENOMEM;
+ }
+
+ rc = platform_driver_register(&msm_smd_driver_legacy);
if (rc) {
- pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+ pr_err("%s: msm_smd_driver_legacy register failed %d\n",
+ __func__, rc);
return rc;
}
@@ -3954,7 +3738,12 @@
return rc;
}
- smd_module_init_notify(0, NULL);
+ rc = platform_driver_register(&msm_smsm_driver);
+ if (rc) {
+ pr_err("%s: msm_smsm_driver register failed %d\n",
+ __func__, rc);
+ return rc;
+ }
return 0;
}
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 0b270b7..3461e49 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -175,8 +175,10 @@
if (dev == smd_tty[num_dev].device_ptr)
break;
}
- if (num_dev >= MAX_SMD_TTYS)
+ if (num_dev >= MAX_SMD_TTYS) {
SMD_TTY_ERR("[%s]: Device Not Found", __func__);
+ return -EINVAL;
+ }
return snprintf(buf, PAGE_SIZE, "%d\n",
smd_tty[num_dev].open_wait);
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index bbb6ce0..1ec2a78 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/printk.h>
+#include <linux/notifier.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
@@ -53,15 +54,20 @@
pr_debug(x); \
} while (0)
-remote_spinlock_t remote_spinlock;
-int spinlocks_initialized;
-uint32_t num_smem_areas;
-struct smem_area *smem_areas;
-struct ramdump_segment *smem_ramdump_segments;
+#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
+static remote_spinlock_t remote_spinlock;
+static uint32_t num_smem_areas;
+static struct smem_area *smem_areas;
+static struct ramdump_segment *smem_ramdump_segments;
+static int spinlocks_initialized;
static void *smem_ramdump_dev;
static DEFINE_MUTEX(spinlock_init_lock);
static DEFINE_SPINLOCK(smem_init_check_lock);
+static int smem_module_inited;
+static RAW_NOTIFIER_HEAD(smem_module_init_notifier_list);
+static DEFINE_MUTEX(smem_module_init_notifier_lock);
+
struct restart_notifier_block {
unsigned processor;
@@ -82,6 +88,8 @@
{SMEM_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
};
+static int init_smem_remote_spinlock(void);
+
/**
* smem_phys_to_virt() - Convert a physical base and offset to virtual address
*
@@ -192,11 +200,21 @@
}
EXPORT_SYMBOL(smem_alloc);
-static void *__smem_get_entry(unsigned id, unsigned *size, bool skip_init_check)
+/**
+ * __smem_get_entry - Get pointer and size of existing SMEM item
+ *
+ * @id: ID of SMEM item
+ * @size: Pointer to size variable for storing the result
+ * @skip_init_check: True means do not verify that SMEM has been initialized
+ * @use_rspinlock: True to use the remote spinlock
+ * @returns: Pointer to SMEM item or NULL if it doesn't exist
+ */
+static void *__smem_get_entry(unsigned id, unsigned *size,
+ bool skip_init_check, bool use_rspinlock)
{
struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
struct smem_heap_entry *toc = shared->heap_toc;
- int use_spinlocks = spinlocks_initialized;
+ int use_spinlocks = spinlocks_initialized && use_rspinlock;
void *ret = 0;
unsigned long flags = 0;
@@ -233,7 +251,7 @@
unsigned size;
void *ptr;
- ptr = __smem_get_entry(id, &size, skip_init_check);
+ ptr = __smem_get_entry(id, &size, skip_init_check, true);
if (!ptr)
return 0;
@@ -312,10 +330,26 @@
void *smem_get_entry(unsigned id, unsigned *size)
{
- return __smem_get_entry(id, size, false);
+ return __smem_get_entry(id, size, false, true);
}
EXPORT_SYMBOL(smem_get_entry);
+/**
+ * smem_get_entry_no_rlock - Get existing item without using remote spinlock
+ *
+ * @id: ID of SMEM item
+ * @size_out: Pointer to size variable for storing the result
+ * @returns: Pointer to SMEM item or NULL if it doesn't exist
+ *
+ * This function does not lock the remote spinlock and should only be used in
+ * failure-recover cases such as retrieving the subsystem failure reason during
+ * subsystem restart.
+ */
+void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out)
+{
+ return __smem_get_entry(id, size_out, false, false);
+}
+EXPORT_SYMBOL(smem_get_entry_no_rlock);
/**
* smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
@@ -324,6 +358,8 @@
*/
remote_spinlock_t *smem_get_remote_spinlock(void)
{
+ if (unlikely(!spinlocks_initialized))
+ init_smem_remote_spinlock();
return &remote_spinlock;
}
EXPORT_SYMBOL(smem_get_remote_spinlock);
@@ -333,7 +369,7 @@
*
* @returns: sucess or error code for failure
*/
-int init_smem_remote_spinlock(void)
+static int init_smem_remote_spinlock(void)
{
int rc = 0;
@@ -473,3 +509,223 @@
return 0;
}
late_initcall(modem_restart_late_init);
+
+int smem_module_init_notifier_register(struct notifier_block *nb)
+{
+ int ret;
+ if (!nb)
+ return -EINVAL;
+ mutex_lock(&smem_module_init_notifier_lock);
+ ret = raw_notifier_chain_register(&smem_module_init_notifier_list, nb);
+ if (smem_module_inited)
+ nb->notifier_call(nb, 0, NULL);
+ mutex_unlock(&smem_module_init_notifier_lock);
+ return ret;
+}
+EXPORT_SYMBOL(smem_module_init_notifier_register);
+
+int smem_module_init_notifier_unregister(struct notifier_block *nb)
+{
+ int ret;
+ if (!nb)
+ return -EINVAL;
+ mutex_lock(&smem_module_init_notifier_lock);
+ ret = raw_notifier_chain_unregister(&smem_module_init_notifier_list,
+ nb);
+ mutex_unlock(&smem_module_init_notifier_lock);
+ return ret;
+}
+EXPORT_SYMBOL(smem_module_init_notifier_unregister);
+
+static void smem_module_init_notify(uint32_t state, void *data)
+{
+ mutex_lock(&smem_module_init_notifier_lock);
+ smem_module_inited = 1;
+ raw_notifier_call_chain(&smem_module_init_notifier_list,
+ state, data);
+ mutex_unlock(&smem_module_init_notifier_lock);
+}
+
+static int msm_smem_probe(struct platform_device *pdev)
+{
+ char *key;
+ struct resource *r;
+ phys_addr_t aux_mem_base;
+ resource_size_t aux_mem_size;
+ int temp_string_size = 11; /* max 3 digit count */
+ char temp_string[temp_string_size];
+ int ret;
+ struct ramdump_segment *ramdump_segments_tmp = NULL;
+ struct smem_area *smem_areas_tmp = NULL;
+ int smem_idx = 0;
+
+ if (!smem_initialized_check())
+ return -ENODEV;
+
+ key = "irq-reg-base";
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!r) {
+ pr_err("%s: missing '%s'\n", __func__, key);
+ return -ENODEV;
+ }
+
+ num_smem_areas = 1;
+ while (1) {
+ scnprintf(temp_string, temp_string_size, "aux-mem%d",
+ num_smem_areas);
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ temp_string);
+ if (!r)
+ break;
+
+ ++num_smem_areas;
+ if (num_smem_areas > 999) {
+ pr_err("%s: max num aux mem regions reached\n",
+ __func__);
+ break;
+ }
+ }
+ /* Initialize main SMEM region and SSR ramdump region */
+ key = "smem";
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!r) {
+ pr_err("%s: missing '%s'\n", __func__, key);
+ return -ENODEV;
+ }
+
+ smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
+ GFP_KERNEL);
+ if (!smem_areas_tmp) {
+ pr_err("%s: smem areas kmalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+
+ ramdump_segments_tmp = kmalloc_array(num_smem_areas,
+ sizeof(struct ramdump_segment), GFP_KERNEL);
+ if (!ramdump_segments_tmp) {
+ pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+ smem_areas_tmp[smem_idx].phys_addr = r->start;
+ smem_areas_tmp[smem_idx].size = resource_size(r);
+ smem_areas_tmp[smem_idx].virt_addr = MSM_SHARED_RAM_BASE;
+
+ ramdump_segments_tmp[smem_idx].address = r->start;
+ ramdump_segments_tmp[smem_idx].size = resource_size(r);
+ ++smem_idx;
+
+ /* Configure auxiliary SMEM regions */
+ while (1) {
+ scnprintf(temp_string, temp_string_size, "aux-mem%d",
+ smem_idx);
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ temp_string);
+ if (!r)
+ break;
+ aux_mem_base = r->start;
+ aux_mem_size = resource_size(r);
+
+ ramdump_segments_tmp[smem_idx].address = aux_mem_base;
+ ramdump_segments_tmp[smem_idx].size = aux_mem_size;
+
+ smem_areas_tmp[smem_idx].phys_addr = aux_mem_base;
+ smem_areas_tmp[smem_idx].size = aux_mem_size;
+ smem_areas_tmp[smem_idx].virt_addr = ioremap_nocache(
+ (unsigned long)(smem_areas_tmp[smem_idx].phys_addr),
+ smem_areas_tmp[smem_idx].size);
+ SMEM_DBG("%s: %s = %pa %pa -> %p", __func__, temp_string,
+ &aux_mem_base, &aux_mem_size,
+ smem_areas_tmp[smem_idx].virt_addr);
+
+ if (!smem_areas_tmp[smem_idx].virt_addr) {
+ pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
+ __func__,
+ &smem_areas_tmp[smem_idx].phys_addr,
+ &smem_areas_tmp[smem_idx].size);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+
+ if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+ (uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
+ smem_areas_tmp[smem_idx].size)) {
+ pr_err("%s: invalid virtual address block %i: %p:%pa\n",
+ __func__, smem_idx,
+ smem_areas_tmp[smem_idx].virt_addr,
+ &smem_areas_tmp[smem_idx].size);
+ ++smem_idx;
+ ret = -EINVAL;
+ goto free_smem_areas;
+ }
+
+ ++smem_idx;
+ if (smem_idx > 999) {
+ pr_err("%s: max num aux mem regions reached\n",
+ __func__);
+ break;
+ }
+ }
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret)
+ pr_err("%s: of_platform_populate failed %d\n", __func__, ret);
+
+ smem_areas = smem_areas_tmp;
+ smem_ramdump_segments = ramdump_segments_tmp;
+ return 0;
+
+free_smem_areas:
+ for (smem_idx = smem_idx - 1; smem_idx >= 1; --smem_idx)
+ iounmap(smem_areas_tmp[smem_idx].virt_addr);
+
+ num_smem_areas = 0;
+ kfree(ramdump_segments_tmp);
+ kfree(smem_areas_tmp);
+ return ret;
+}
+
+static struct of_device_id msm_smem_match_table[] = {
+ { .compatible = "qcom,smem" },
+ {},
+};
+
+static struct platform_driver msm_smem_driver = {
+ .probe = msm_smem_probe,
+ .driver = {
+ .name = "msm_smem",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_smem_match_table,
+ },
+};
+
+int __init msm_smem_init(void)
+{
+ static bool registered;
+ int rc;
+
+ if (registered)
+ return 0;
+
+ registered = true;
+
+ rc = init_smem_remote_spinlock();
+ if (rc) {
+ pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+ return rc;
+ }
+
+ rc = platform_driver_register(&msm_smem_driver);
+ if (rc) {
+ pr_err("%s: msm_smem_driver register failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ smem_module_init_notify(0, NULL);
+
+ return 0;
+}
+
+module_init(msm_smem_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 87f141d2..6f20e24 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -39,6 +39,7 @@
#include "smd_private.h"
#include "smd_rpc_sym.h"
#include "modem_notifier.h"
+#include "smem_private.h"
#define DEBUG
#undef DEBUG
@@ -2005,7 +2006,7 @@
return ret;
}
-static int smd_module_init_notifier(struct notifier_block *this,
+static int smem_module_init_notifier(struct notifier_block *this,
unsigned long code,
void *_cmd)
{
@@ -2016,12 +2017,12 @@
}
static struct notifier_block nb = {
- .notifier_call = smd_module_init_notifier,
+ .notifier_call = smem_module_init_notifier,
};
static int __init smem_log_init(void)
{
- return smd_module_init_notifier_register(&nb);
+ return smem_module_init_notifier_register(&nb);
}
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index c4f9a77..ceb8028 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -17,10 +17,6 @@
#include <mach/ramdump.h>
-#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
-extern remote_spinlock_t remote_spinlock;
-extern int spinlocks_initialized; /* only modify in init_smem_remote_spinlock */
-
#define SMD_HEAP_SIZE 512
struct smem_heap_info {
@@ -58,19 +54,26 @@
void __iomem *virt_addr;
};
-extern uint32_t num_smem_areas;
-extern struct smem_area *smem_areas;
-
-extern struct ramdump_segment *smem_ramdump_segments;
-
/* used for unit testing spinlocks */
remote_spinlock_t *smem_get_remote_spinlock(void);
-/*
- * used to ensure the remote spinlock is only inited once since local
- * spinlock init code appears non-reentrant
- */
-int init_smem_remote_spinlock(void);
-
bool smem_initialized_check(void);
+
+/**
+ * smem_module_init_notifier_register() - Register a smem module
+ * init notifier block
+ * @nb: Notifier block to be registered
+ *
+ * In order to mark the dependency on SMEM Driver module initialization
+ * register a notifier using this API. Once the smem module_init is
+ * done, notification will be passed to the registered module.
+ */
+int smem_module_init_notifier_register(struct notifier_block *nb);
+
+/**
+ * smem_module_init_notifier_register() - Unregister a smem module
+ * init notifier block
+ * @nb: Notifier block to be unregistered
+ */
+int smem_module_init_notifier_unregister(struct notifier_block *nb);
#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index ee262b0..4b69cf0 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -379,7 +379,7 @@
struct smp2p_out_list_item *out_item)
{
void *item_ptr = NULL;
- unsigned size;
+ unsigned size = 0;
if (!out_item)
return item_ptr;
@@ -1241,7 +1241,7 @@
{
unsigned long flags;
struct smp2p_out_list_item *out_item;
- uint32_t *entry_ptr;
+ uint32_t *entry_ptr = NULL;
if (remote_pid >= SMP2P_NUM_PROCS)
return -EINVAL;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 575cb49..41509f7 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -282,6 +282,24 @@
[185] = MSM_CPU_8974,
[186] = MSM_CPU_8974,
+ /* 8974AA IDs */
+ [208] = MSM_CPU_8974PRO_AA,
+ [211] = MSM_CPU_8974PRO_AA,
+ [214] = MSM_CPU_8974PRO_AA,
+ [217] = MSM_CPU_8974PRO_AA,
+
+ /* 8974AB IDs */
+ [209] = MSM_CPU_8974PRO_AB,
+ [212] = MSM_CPU_8974PRO_AB,
+ [215] = MSM_CPU_8974PRO_AB,
+ [218] = MSM_CPU_8974PRO_AB,
+
+ /* 8974AC IDs */
+ [194] = MSM_CPU_8974PRO_AC,
+ [210] = MSM_CPU_8974PRO_AC,
+ [213] = MSM_CPU_8974PRO_AC,
+ [216] = MSM_CPU_8974PRO_AC,
+
/* 8625 IDs */
[127] = MSM_CPU_8625,
[128] = MSM_CPU_8625,
diff --git a/block/row-iosched.c b/block/row-iosched.c
index e71f6af..3fa3b1a 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -97,7 +97,7 @@
/* Default values for idling on read queues (in msec) */
#define ROW_IDLE_TIME_MSEC 5
-#define ROW_READ_FREQ_MSEC 20
+#define ROW_READ_FREQ_MSEC 5
/**
* struct rowq_idling_data - parameters for idling on the queue
@@ -331,6 +331,10 @@
struct row_queue *rqueue = RQ_ROWQ(rq);
s64 diff_ms;
bool queue_was_empty = list_empty(&rqueue->fifo);
+ unsigned long bv_page_flags = 0;
+
+ if (rq->bio && rq->bio->bi_io_vec && rq->bio->bi_io_vec->bv_page)
+ bv_page_flags = rq->bio->bi_io_vec->bv_page->flags;
list_add_tail(&rq->queuelist, &rqueue->fifo);
rd->nr_reqs[rq_data_dir(rq)]++;
@@ -360,7 +364,9 @@
rqueue->idle_data.begin_idling = false;
return;
}
- if (diff_ms < rd->rd_idle_data.freq_ms) {
+
+ if ((bv_page_flags & (1L << PG_readahead)) ||
+ (diff_ms < rd->rd_idle_data.freq_ms)) {
rqueue->idle_data.begin_idling = true;
row_log_rowq(rd, rqueue->prio, "Enable idling");
} else {
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index f8185df..dadf87c 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -69,6 +69,29 @@
}
/**
+ * devfreq_set_freq_limits() - Set min and max frequency from freq_table
+ * @devfreq: the devfreq instance
+ */
+static void devfreq_set_freq_limits(struct devfreq *devfreq)
+{
+ int idx;
+ unsigned long min = ~0, max = 0;
+
+ if (!devfreq->profile->freq_table)
+ return;
+
+ for (idx = 0; idx < devfreq->profile->max_state; idx++) {
+ if (min > devfreq->profile->freq_table[idx])
+ min = devfreq->profile->freq_table[idx];
+ if (max < devfreq->profile->freq_table[idx])
+ max = devfreq->profile->freq_table[idx];
+ }
+
+ devfreq->min_freq = min;
+ devfreq->max_freq = max;
+}
+
+/**
* devfreq_get_freq_level() - Lookup freq_table for the frequency
* @devfreq: the devfreq instance
* @freq: the target frequency
@@ -506,6 +529,7 @@
devfreq->profile->max_state,
GFP_KERNEL);
devfreq->last_stat_updated = jiffies;
+ devfreq_set_freq_limits(devfreq);
dev_set_name(&devfreq->dev, dev_name(dev));
err = device_register(&devfreq->dev);
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index c72f942..bc7da1e 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -32,7 +32,7 @@
{
int ret = 0;
- if (event == DEVFREQ_GOV_START) {
+ if (event == DEVFREQ_GOV_START || event == DEVFREQ_GOV_RESUME) {
mutex_lock(&devfreq->lock);
ret = update_devfreq(devfreq);
mutex_unlock(&devfreq->lock);
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index 0c6bed5..6d43685 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -29,7 +29,7 @@
{
int ret = 0;
- if (event == DEVFREQ_GOV_START) {
+ if (event == DEVFREQ_GOV_START || event == DEVFREQ_GOV_RESUME) {
mutex_lock(&devfreq->lock);
ret = update_devfreq(devfreq);
mutex_unlock(&devfreq->lock);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index b1c1c5d..a80b0c6 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -94,8 +94,10 @@
}
info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
- info->page = page;
- info->order = orders[i];
+ if (info) {
+ info->page = page;
+ info->order = orders[i];
+ }
return info;
}
return NULL;
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 4a45313..4e3af1c 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -365,6 +365,9 @@
if (!ION_IS_CACHED(flags))
return 0;
+ if (flags & ION_FLAG_SECURE)
+ return 0;
+
table = ion_sg_table(client, handle);
if (IS_ERR_OR_NULL(table))
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index ecd3c0d..ed266dc 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -214,6 +214,11 @@
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
0x201, 0x200 },
+ /* 8226v2 */
+ { ADRENO_REV_A305B, 3, 0, 5, 0x12,
+ "a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
+ 512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
+ 0x201, 0x200 },
{ ADRENO_REV_A305C, 3, 0, 5, 0x20,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
@@ -253,6 +258,10 @@
struct adreno_perfcount_group *group;
unsigned int i, j;
+ /* perfcounter start does nothing on a2xx */
+ if (adreno_is_a2xx(adreno_dev))
+ return;
+
/* group id iter */
for (i = 0; i < counters->group_count; i++) {
group = &(counters->groups[i]);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 6710f82..5c454f1 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2430,6 +2430,7 @@
int result;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry;
+ int align;
/*
* Mask off unknown flags from userspace. This way the caller can
@@ -2441,6 +2442,16 @@
| KGSL_MEMALIGN_MASK
| KGSL_MEMFLAGS_USE_CPU_MAP;
+ /* Cap the alignment bits to the highest number we can handle */
+
+ align = (flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+ if (align >= 32) {
+ KGSL_CORE_ERR("Alignment too big, restricting to 2^31\n");
+
+ flags &= ~KGSL_MEMALIGN_MASK;
+ flags |= (31 << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
+ }
+
entry = kgsl_mem_entry_create();
if (entry == NULL)
return -ENOMEM;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index daeefd0..1fc7467 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -722,7 +722,7 @@
ret = -EINVAL;
else if (TYPE_IS_PMEM(priv->type) || TYPE_IS_MEM(priv->type)) {
if (priv->ion_handle) {
- args->ion_fd = ion_share_dma_buf(
+ args->ion_fd = ion_share_dma_buf_fd(
kgsl_drm_ion_client, priv->ion_handle);
if (args->ion_fd < 0) {
DRM_ERROR(
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 48c7301..abb7c35 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -70,7 +70,7 @@
),
TP_printk(
- "d_name=%s ctx=%u ib=0x%u numibs=%u timestamp=0x%x "
+ "d_name=%s ctx=%u ib=0x%u numibs=%u ts=%u "
"flags=0x%x(%s) result=%d type=%s",
__get_str(device_name),
__entry->drawctxt_id,
@@ -116,7 +116,7 @@
),
TP_printk(
- "d_name=%s context_id=%u type=%u timestamp=0x%x",
+ "d_name=%s context_id=%u type=%u ts=%u",
__get_str(device_name),
__entry->context_id,
__entry->type,
@@ -154,7 +154,7 @@
),
TP_printk(
- "d_name=%s context_id=%u curr_ts=0x%x timestamp=0x%x timeout=%u",
+ "d_name=%s ctx=%u curr_ts=%u ts=%u timeout=%u",
__get_str(device_name),
__entry->context_id,
__entry->curr_ts,
@@ -186,7 +186,7 @@
),
TP_printk(
- "d_name=%s curr_ts=0x%x result=%d",
+ "d_name=%s curr_ts=%u result=%d",
__get_str(device_name),
__entry->curr_ts,
__entry->result
@@ -209,7 +209,7 @@
),
TP_printk(
- "d_name=%s %s",
+ "d_name=%s flag=%s",
__get_str(device_name),
__entry->on ? "on" : "off"
)
@@ -304,7 +304,7 @@
),
TP_printk(
- "d_name=%s busy=%d elapsed=%d",
+ "d_name=%s busy=%u elapsed=%d",
__get_str(device_name),
__entry->busy,
__entry->elapsed
@@ -327,7 +327,7 @@
),
TP_printk(
- "d_name=%s %s",
+ "d_name=%s state=%s",
__get_str(device_name),
kgsl_pwrstate_to_str(__entry->state)
)
@@ -369,7 +369,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d flags=0x%08x",
+ "gpuaddr=0x%08x size=%u tgid=%u usage=%s id=%u flags=0x%08x",
__entry->gpuaddr, __entry->size, __entry->tgid,
__entry->usage, __entry->id, __entry->flags
)
@@ -401,7 +401,7 @@
),
TP_printk(
- "useraddr=%lx gpuaddr=0x%08x size=%d usage=%s id=%d"
+ "useraddr=0x%lx gpuaddr=0x%08x size=%u usage=%s id=%u"
" flags=0x%08x",
__entry->useraddr, __entry->gpuaddr, __entry->size,
__entry->usage, __entry->id, __entry->flags
@@ -432,7 +432,7 @@
),
TP_printk(
- "id=%d hint=0x%lx len=%ld addr=0x%lx",
+ "id=%u hint=0x%lx len=%lu addr=0x%lx",
__entry->id, __entry->hint, __entry->len, __entry->addr
)
);
@@ -465,7 +465,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage=%s id=%d",
+ "gpuaddr=0x%08x size=%u type=%d fd=%d tgid=%u usage=%s id=%u",
__entry->gpuaddr, __entry->size,
__entry->type, __entry->fd, __entry->tgid,
__entry->usage, __entry->id
@@ -499,7 +499,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s id=%d",
+ "gpuaddr=0x%08x size=%u type=%d tgid=%u usage=%s id=%u",
__entry->gpuaddr, __entry->size, __entry->type,
__entry->tgid, __entry->usage, __entry->id
)
@@ -531,7 +531,7 @@
),
TP_printk(
- "gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d op=%c%c",
+ "gpuaddr=0x%08x size=%u tgid=%u usage=%s id=%u op=%c%c",
__entry->gpuaddr, __entry->size, __entry->tgid, __entry->usage,
__entry->id,
(__entry->op & KGSL_GPUMEM_CACHE_CLEAN) ? 'c' : '.',
@@ -599,8 +599,8 @@
),
TP_printk(
- "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s id=%d ctx=%u"
- " curr_ts=0x%x free_ts=0x%x",
+ "d_name=%s gpuaddr=0x%08x size=%u type=%d usage=%s id=%u ctx=%u"
+ " curr_ts=%u free_ts=%u",
__get_str(device_name),
__entry->gpuaddr,
__entry->size,
@@ -700,7 +700,7 @@
),
TP_printk(
- "d_name=%s page=0x%08x pt=%d op=%s",
+ "d_name=%s page=0x%08x pt=%u op=%s",
__get_str(device_name), __entry->page, __entry->pt,
__get_str(op)
)
@@ -726,7 +726,7 @@
),
TP_printk(
- "d_name=%s reg=%x value=%x",
+ "d_name=%s reg=0x%x value=0x%x",
__get_str(device_name), __entry->offset, __entry->value
)
);
@@ -743,7 +743,7 @@
__entry->timestamp = timestamp;
),
TP_printk(
- "ctx=%d ts=%d",
+ "ctx=%u ts=%u",
__entry->id, __entry->timestamp)
);
@@ -762,7 +762,7 @@
__entry->age = age;
),
TP_printk(
- "ctx=%d ts=%d age=%u",
+ "ctx=%u ts=%u age=%u",
__entry->id, __entry->ts, __entry->age)
);
@@ -785,7 +785,7 @@
),
TP_printk(
- "d_name=%s active_cnt=%x func=%pf",
+ "d_name=%s active_cnt=%u func=%pf",
__get_str(device_name), __entry->count, (void *) __entry->ip
)
);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 4306b1d..309944e 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -1164,14 +1164,14 @@
rc = qpnp_vadc_read_reg(QPNP_INT_TEST_VAL, &fab_id);
if (rc < 0) {
pr_err("qpnp adc comp id failed with %d\n", rc);
- return rc;
+ goto fail;
}
vadc->id = fab_id;
rc = qpnp_vadc_warm_rst_configure();
if (rc < 0) {
pr_err("Setting perp reset on warm reset failed %d\n", rc);
- return rc;
+ goto fail;
}
vadc->vadc_initialized = true;
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index 204ad94..dd2e5d8 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -144,6 +144,13 @@
y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]);
z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]);
+ /* 8 bits output mode support */
+ if (!(tj9->ctrl_reg1 & RES_12BIT)) {
+ x <<= 4;
+ y <<= 4;
+ z <<= 4;
+ }
+
x >>= tj9->shift;
y >>= tj9->shift;
z >>= tj9->shift;
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 349b020..c01ab0e 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -29,7 +29,6 @@
#include <linux/input/synaptics_dsx.h>
#include "synaptics_i2c_rmi4.h"
-#define DEBUG_FW_UPDATE
#define SHOW_PROGRESS
#define MAX_FIRMWARE_ID_LEN 10
#define FORCE_UPDATE false
@@ -53,7 +52,13 @@
#define BLOCK_NUMBER_OFFSET 0
#define BLOCK_DATA_OFFSET 2
-#define NAME_BUFFER_SIZE 128
+#define RMI4_INFO_MAX_LEN 200
+
+#define RMI4_STORE_TS_INFO(buf, id, rev, fw_ver) \
+ snprintf(buf, RMI4_INFO_MAX_LEN, \
+ "controller\t= synaptics\n" \
+ "model\t\t= %d rev %d\n" \
+ "fw_ver\t\t= %d\n", id, rev, fw_ver)
enum falsh_config_area {
UI_CONFIG_AREA = 0x00,
@@ -77,7 +82,8 @@
enum flash_area {
NONE,
UI_FIRMWARE,
- CONFIG_AREA
+ CONFIG_AREA,
+ MISMATCH
};
enum image_file_option {
@@ -99,53 +105,6 @@
#define SLEEP_TIME_US 50
-static ssize_t fwu_sysfs_show_image(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t fwu_sysfs_store_image(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_write_config_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_read_config_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_config_area_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_image_size_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_block_size_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_config_id_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
static int fwu_wait_for_idle(int timeout_ms);
struct image_header_data {
@@ -163,10 +122,10 @@
unsigned char config_size[4];
/* 0x10-0x1F */
unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE];
- unsigned char reserved_1a;
- unsigned char reserved_1b;
- unsigned char reserved_1c;
- unsigned char reserved_1d;
+ unsigned char pkg_id_lsb;
+ unsigned char pkg_id_msb;
+ unsigned char pkg_id_rev_lsb;
+ unsigned char pkg_id_rev_msb;
unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
/* 0x20-0x2F */
unsigned char reserved_20_2f[0x10];
@@ -178,7 +137,7 @@
/* 0x50-0x53*/
unsigned char firmware_id[4];
} __packed;
- unsigned char data[54];
+ unsigned char data[0x54];
};
};
@@ -190,6 +149,8 @@
unsigned char bootloader_version;
unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ u16 package_id;
+ u16 package_revision_id;
unsigned int firmware_id;
bool is_contain_build_info;
};
@@ -290,59 +251,8 @@
struct f34_flash_properties flash_properties;
struct workqueue_struct *fwu_workqueue;
struct delayed_work fwu_work;
- char *firmware_name;
-};
-
-static struct bin_attribute dev_attr_data = {
- .attr = {
- .name = "data",
- .mode = (S_IRUGO | S_IWUGO),
- },
- .size = 0,
- .read = fwu_sysfs_show_image,
- .write = fwu_sysfs_store_image,
-};
-
-static struct device_attribute attrs[] = {
- __ATTR(force_update_fw, S_IWUGO,
- synaptics_rmi4_show_error,
- fwu_sysfs_force_reflash_store),
- __ATTR(update_fw, S_IWUGO,
- synaptics_rmi4_show_error,
- fwu_sysfs_do_reflash_store),
- __ATTR(writeconfig, S_IWUGO,
- synaptics_rmi4_show_error,
- fwu_sysfs_write_config_store),
- __ATTR(readconfig, S_IWUGO,
- synaptics_rmi4_show_error,
- fwu_sysfs_read_config_store),
- __ATTR(configarea, S_IWUGO,
- synaptics_rmi4_show_error,
- fwu_sysfs_config_area_store),
- __ATTR(imagesize, S_IWUGO,
- synaptics_rmi4_show_error,
- fwu_sysfs_image_size_store),
- __ATTR(blocksize, S_IRUGO,
- fwu_sysfs_block_size_show,
- synaptics_rmi4_store_error),
- __ATTR(fwblockcount, S_IRUGO,
- fwu_sysfs_firmware_block_count_show,
- synaptics_rmi4_store_error),
- __ATTR(configblockcount, S_IRUGO,
- fwu_sysfs_configuration_block_count_show,
- synaptics_rmi4_store_error),
- __ATTR(permconfigblockcount, S_IRUGO,
- fwu_sysfs_perm_config_block_count_show,
- synaptics_rmi4_store_error),
- __ATTR(blconfigblockcount, S_IRUGO,
- fwu_sysfs_bl_config_block_count_show,
- synaptics_rmi4_store_error),
- __ATTR(dispconfigblockcount, S_IRUGO,
- fwu_sysfs_disp_config_block_count_show,
- synaptics_rmi4_store_error),
- __ATTR(config_id, S_IRUGO,
- fwu_sysfs_config_id_show,
- synaptics_rmi4_store_error),
+ char firmware_name[NAME_BUFFER_SIZE];
+ char *ts_info;
};
static struct synaptics_rmi4_fwu_handle *fwu;
@@ -365,6 +275,26 @@
(unsigned int)ptr[0] * 0x1000000;
}
+static void synaptics_rmi4_update_debug_info(void)
+{
+ unsigned char pkg_id[4];
+ unsigned int build_id;
+ struct synaptics_rmi4_device_info *rmi;
+ /* read device package id */
+ fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f01_fd.query_base_addr + 17,
+ pkg_id,
+ sizeof(pkg_id));
+ rmi = &(fwu->rmi4_data->rmi4_mod_info);
+
+ build_id = (unsigned int)rmi->build_id[0] +
+ (unsigned int)rmi->build_id[1] * 0x100 +
+ (unsigned int)rmi->build_id[2] * 0x10000;
+
+ RMI4_STORE_TS_INFO(fwu->ts_info, pkg_id[1] << 8 | pkg_id[0],
+ pkg_id[3] << 8 | pkg_id[2], build_id);
+}
+
static void parse_header(struct image_header *header,
const unsigned char *fw_image)
{
@@ -375,25 +305,32 @@
header->config_size = extract_uint(data->config_size);
memcpy(header->product_id, data->product_id,
sizeof(data->product_id));
- header->product_id[sizeof(data->product_info)] = 0;
+ header->product_id[sizeof(data->product_id)] = 0;
+
memcpy(header->product_info, data->product_info,
sizeof(data->product_info));
header->is_contain_build_info =
(data->options_firmware_id == (1 << OPTION_BUILD_INFO));
if (header->is_contain_build_info) {
+ header->package_id = (data->pkg_id_rev_msb << 8) |
+ data->pkg_id_lsb;
+ header->package_revision_id = (data->pkg_id_rev_msb << 8) |
+ data->pkg_id_rev_lsb;
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s Package ID %d Rev %d\n", __func__,
+ header->package_id, header->package_revision_id);
+
header->firmware_id = extract_uint(data->firmware_id);
dev_info(&fwu->rmi4_data->i2c_client->dev,
"%s Firwmare build id %d\n", __func__,
header->firmware_id);
}
-#ifdef DEBUG_FW_UPDATE
- dev_info(&fwu->rmi4_data->i2c_client->dev,
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
"Firwmare size %d, config size %d\n",
header->image_size,
header->config_size);
-#endif
return;
}
@@ -544,11 +481,9 @@
{
int retval;
-#ifdef DEBUG_FW_UPDATE
- dev_info(&fwu->rmi4_data->i2c_client->dev,
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
"%s: Reset device\n",
__func__);
-#endif
retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
if (retval < 0) {
@@ -613,6 +548,7 @@
unsigned long imageFirmwareID;
unsigned char firmware_id[4];
unsigned char config_id[4];
+ unsigned char pkg_id[4];
char *strptr;
char *imagePR = kzalloc(sizeof(MAX_FIRMWARE_ID_LEN), GFP_KERNEL);
enum flash_area flash_area = NONE;
@@ -624,6 +560,24 @@
goto exit;
}
+ if (header->is_contain_build_info) {
+ /* if package id does not match, do not update firmware */
+ fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f01_fd.query_base_addr + 17,
+ pkg_id,
+ sizeof(pkg_id));
+
+ if (header->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
+ flash_area = MISMATCH;
+ goto exit;
+ }
+ if (header->package_revision_id !=
+ ((pkg_id[3] << 8) | pkg_id[2])) {
+ flash_area = MISMATCH;
+ goto exit;
+ }
+ }
+
retval = fwu_read_f01_device_status(&f01_device_status);
if (retval < 0) {
flash_area = NONE;
@@ -734,10 +688,13 @@
flash_area = CONFIG_AREA;
goto exit;
}
-
exit:
kfree(imagePR);
- if (flash_area == NONE)
+ if (flash_area == MISMATCH)
+ dev_info(&i2c_client->dev,
+ "%s: Package ID indicates mismatch of firmware and" \
+ " controller compatibility\n", __func__);
+ else if (flash_area == NONE)
dev_info(&i2c_client->dev,
"%s: Nothing needs to be updated\n", __func__);
else
@@ -759,9 +716,7 @@
bool f34found = false;
struct synaptics_rmi4_fn_desc rmi_fd;
-#ifdef DEBUG_FW_UPDATE
- dev_info(&fwu->rmi4_data->i2c_client->dev, "Scan PDT\n");
-#endif
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev, "Scan PDT\n");
for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
retval = fwu->fn_ptr->read(fwu->rmi4_data,
@@ -824,13 +779,11 @@
10 : 100;
#endif
-#ifdef DEBUG_FW_UPDATE
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"%s: Start to update %s blocks\n",
__func__,
command == CMD_WRITE_CONFIG_BLOCK ?
"config" : "firmware");
-#endif
retval = fwu->fn_ptr->write(fwu->rmi4_data,
fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
block_offset,
@@ -915,12 +868,11 @@
{
int retval;
-#ifdef DEBUG_FW_UPDATE
- dev_info(&fwu->rmi4_data->i2c_client->dev,
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
"Write bootloader ID 0x%02X 0x%02X\n",
fwu->bootloader_id[0],
fwu->bootloader_id[1]);
-#endif
+
retval = fwu->fn_ptr->write(fwu->rmi4_data,
fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
fwu->bootloader_id,
@@ -941,9 +893,8 @@
struct f01_device_status f01_device_status;
struct f01_device_control f01_device_control;
-#ifdef DEBUG_FW_UPDATE
- dev_info(&fwu->rmi4_data->i2c_client->dev, "Enter bootloader mode\n");
-#endif
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev, "Enter bootloader mode\n");
+
retval = fwu_read_f01_device_status(&f01_device_status);
if (retval < 0)
return retval;
@@ -1302,26 +1253,23 @@
pr_notice("%s: Start of reflash process\n", __func__);
- if (!fwu->rmi4_data->fw_image_name) {
- retval = 0;
+ if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) == 0) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"Firmware image name not given, skipping update\n");
- goto exit;
+ return 0;
+ }
+
+ if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
+ NAME_BUFFER_SIZE) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "Firmware image name exceeds max length (%d), " \
+ "skipping update\n", NAME_BUFFER_SIZE);
+ return 0;
}
if (fwu->ext_data_source)
fw_image = fwu->ext_data_source;
else {
- fwu->firmware_name = kcalloc(NAME_BUFFER_SIZE,
- sizeof(char), GFP_KERNEL);
- if (!fwu->firmware_name) {
- dev_err(&fwu->rmi4_data->i2c_client->dev,
- "%s Failed to allocate firmware name (%d).\n",
- __func__, NAME_BUFFER_SIZE);
- retval = -ENOMEM;
- goto memory_exit;
- }
-
snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
fwu->rmi4_data->fw_image_name);
dev_info(&fwu->rmi4_data->i2c_client->dev,
@@ -1336,8 +1284,7 @@
"%s: Firmware image %s not available\n",
__func__,
fwu->firmware_name);
- retval = -EINVAL;
- goto exit;
+ return -EINVAL;
}
dev_dbg(&fwu->rmi4_data->i2c_client->dev,
@@ -1363,6 +1310,8 @@
switch (flash_area) {
case NONE:
+ case MISMATCH:
+ retval = 0;
dev_info(&fwu->rmi4_data->i2c_client->dev,
"%s: No need to do reflash.\n",
__func__);
@@ -1408,13 +1357,11 @@
goto exit;
}
+exit:
if (fw_entry)
release_firmware(fw_entry);
pr_notice("%s: End of reflash process\n", __func__);
-exit:
- kfree(fwu->firmware_name);
-memory_exit:
return retval;
}
@@ -1428,10 +1375,21 @@
if (!fwu->initialized)
return -ENODEV;
+ fwu->rmi4_data->fw_updating = true;
+ if (fwu->rmi4_data->suspended == true) {
+ fwu->rmi4_data->fw_updating = false;
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "Cannot start fw upgrade while device is in suspend\n");
+ return -EBUSY;
+ }
+
fwu->ext_data_source = fw_data;
fwu->config_area = UI_CONFIG_AREA;
retval = fwu_start_reflash();
+ fwu->rmi4_data->fw_updating = false;
+
+ synaptics_rmi4_update_debug_info();
return retval;
}
@@ -1468,6 +1426,40 @@
return count;
}
+static ssize_t fwu_sysfs_fw_name_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ char *strptr;
+
+ if (count >= NAME_BUFFER_SIZE) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Input over %d characters long\n", NAME_BUFFER_SIZE);
+ return -EINVAL;
+ }
+
+ strptr = strnstr(buf, ".img",
+ count);
+ if (!strptr) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Input is not valid .img file\n");
+ return -EINVAL;
+ }
+
+ strlcpy(rmi4_data->fw_image_name, buf, count);
+ return count;
+}
+
+static ssize_t fwu_sysfs_fw_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0)
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ fwu->rmi4_data->fw_image_name);
+ else
+ return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+}
+
static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -1683,6 +1675,41 @@
config_id[0], config_id[1], config_id[2], config_id[3]);
}
+static ssize_t fwu_sysfs_package_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char pkg_id[4];
+ /* read device package id */
+ fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f01_fd.query_base_addr + 17,
+ pkg_id,
+ sizeof(pkg_id));
+
+ return snprintf(buf, PAGE_SIZE, "%d rev %d\n",
+ (pkg_id[1] << 8) | pkg_id[0],
+ (pkg_id[3] << 8) | pkg_id[2]);
+}
+
+static int synaptics_rmi4_debug_dump_info(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%s\n", fwu->ts_info);
+
+ return 0;
+}
+
+static int debugfs_dump_info_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, synaptics_rmi4_debug_dump_info,
+ inode->i_private);
+}
+
+static const struct file_operations debug_dump_info_fops = {
+ .owner = THIS_MODULE,
+ .open = debugfs_dump_info_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
unsigned char intr_mask)
{
@@ -1692,6 +1719,65 @@
return;
}
+static struct bin_attribute dev_attr_data = {
+ .attr = {
+ .name = "data",
+ .mode = (S_IRUGO | S_IWUGO),
+ },
+ .size = 0,
+ .read = fwu_sysfs_show_image,
+ .write = fwu_sysfs_store_image,
+};
+
+static struct device_attribute attrs[] = {
+ __ATTR(fw_name, S_IWUGO | S_IRUGO,
+ fwu_sysfs_fw_name_show,
+ fwu_sysfs_fw_name_store),
+ __ATTR(force_update_fw, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_force_reflash_store),
+ __ATTR(update_fw, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_do_reflash_store),
+ __ATTR(writeconfig, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_write_config_store),
+ __ATTR(readconfig, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_read_config_store),
+ __ATTR(configarea, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_config_area_store),
+ __ATTR(imagesize, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_image_size_store),
+ __ATTR(blocksize, S_IRUGO,
+ fwu_sysfs_block_size_show,
+ synaptics_rmi4_store_error),
+ __ATTR(fwblockcount, S_IRUGO,
+ fwu_sysfs_firmware_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(configblockcount, S_IRUGO,
+ fwu_sysfs_configuration_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(permconfigblockcount, S_IRUGO,
+ fwu_sysfs_perm_config_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(blconfigblockcount, S_IRUGO,
+ fwu_sysfs_bl_config_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(dispconfigblockcount, S_IRUGO,
+ fwu_sysfs_disp_config_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(config_id, S_IRUGO,
+ fwu_sysfs_config_id_show,
+ synaptics_rmi4_store_error),
+ __ATTR(package_id, S_IRUGO,
+ fwu_sysfs_package_id_show,
+ synaptics_rmi4_store_error),
+};
+
+
static void synaptics_rmi4_fwu_work(struct work_struct *work)
{
fwu_start_reflash();
@@ -1702,6 +1788,7 @@
int retval;
unsigned char attr_count;
struct pdt_properties pdt_props;
+ struct dentry *temp;
fwu = kzalloc(sizeof(*fwu), GFP_KERNEL);
if (!fwu) {
@@ -1765,7 +1852,7 @@
fwu->initialized = true;
fwu->force_update = FORCE_UPDATE;
- retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
+ retval = sysfs_create_bin_file(&rmi4_data->i2c_client->dev.kobj,
&dev_attr_data);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
@@ -1775,7 +1862,7 @@
}
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
+ retval = sysfs_create_file(&rmi4_data->i2c_client->dev.kobj,
&attrs[attr_count].attr);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
@@ -1786,6 +1873,25 @@
}
}
+ temp = debugfs_create_file("dump_info", S_IRUSR | S_IWUSR,
+ fwu->rmi4_data->dir, fwu->rmi4_data,
+ &debug_dump_info_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create debugfs dump info file\n",
+ __func__);
+ retval = PTR_ERR(temp);
+ goto exit_remove_attrs;
+ }
+
+ fwu->ts_info = kzalloc(RMI4_INFO_MAX_LEN, GFP_KERNEL);
+ if (!fwu->ts_info) {
+ dev_err(&rmi4_data->i2c_client->dev, "Not enough memory\n");
+ goto exit_free_ts_info;
+ }
+
+ synaptics_rmi4_update_debug_info();
+
#ifdef INSIDE_FIRMWARE_UPDATE
fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue");
INIT_DELAYED_WORK(&fwu->fwu_work, synaptics_rmi4_fwu_work);
@@ -1797,7 +1903,8 @@
init_completion(&remove_complete);
return 0;
-
+exit_free_ts_info:
+ debugfs_remove(temp);
exit_remove_attrs:
for (attr_count--; attr_count >= 0; attr_count--) {
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index b9dd4ae..9da095a 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -34,6 +34,7 @@
#define DRIVER_NAME "synaptics_rmi4_i2c"
#define INPUT_PHYS_NAME "synaptics_rmi4_i2c/input0"
+#define DEBUGFS_DIR_NAME "ts_debug"
#define RESET_DELAY 100
@@ -114,12 +115,6 @@
static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
-static ssize_t synaptics_rmi4_mode_suspend_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t synaptics_rmi4_mode_resume_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data);
@@ -243,12 +238,6 @@
__ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
synaptics_rmi4_full_pm_cycle_show,
synaptics_rmi4_full_pm_cycle_store),
- __ATTR(mode_suspend, S_IWUGO,
- synaptics_rmi4_show_error,
- synaptics_rmi4_mode_suspend_store),
- __ATTR(mode_resume, S_IWUGO,
- synaptics_rmi4_show_error,
- synaptics_rmi4_mode_resume_store),
#endif
__ATTR(reset, S_IWUGO,
synaptics_rmi4_show_error,
@@ -300,34 +289,30 @@
return count;
}
-static ssize_t synaptics_rmi4_mode_suspend_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static int synaptics_rmi4_debug_suspend_set(void *_data, u64 val)
{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ struct synaptics_rmi4_data *rmi4_data = _data;
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
+ if (val)
+ synaptics_rmi4_suspend(&rmi4_data->input_dev->dev);
+ else
+ synaptics_rmi4_resume(&rmi4_data->input_dev->dev);
- synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
-
- return count;
+ return 0;
}
-static ssize_t synaptics_rmi4_mode_resume_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t synaptics_rmi4_debug_suspend_get(void *_data, u64 *val)
{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ struct synaptics_rmi4_data *rmi4_data = _data;
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
+ *val = rmi4_data->suspended;
- synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
-
- return count;
+ return 0;
}
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, synaptics_rmi4_debug_suspend_get,
+ synaptics_rmi4_debug_suspend_set, "%lld\n");
+
#ifdef CONFIG_FB
static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
{
@@ -2061,6 +2046,7 @@
struct synaptics_rmi4_device_info *rmi;
struct synaptics_rmi4_platform_data *platform_data =
client->dev.platform_data;
+ struct dentry *temp;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -2118,6 +2104,8 @@
rmi4_data->touch_stopped = false;
rmi4_data->sensor_sleep = false;
rmi4_data->irq_enabled = false;
+ rmi4_data->fw_updating = false;
+ rmi4_data->suspended = false;
rmi4_data->i2c_read = synaptics_rmi4_i2c_read;
rmi4_data->i2c_write = synaptics_rmi4_i2c_write;
@@ -2127,7 +2115,9 @@
rmi4_data->flip_x = rmi4_data->board->x_flip;
rmi4_data->flip_y = rmi4_data->board->y_flip;
- rmi4_data->fw_image_name = rmi4_data->board->fw_image_name;
+ if (rmi4_data->board->fw_image_name)
+ snprintf(rmi4_data->fw_image_name, NAME_BUFFER_SIZE, "%s",
+ rmi4_data->board->fw_image_name);
rmi4_data->input_dev->name = DRIVER_NAME;
rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
@@ -2292,8 +2282,27 @@
goto err_enable_irq;
}
+ rmi4_data->dir = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
+ if (rmi4_data->dir == NULL || IS_ERR(rmi4_data->dir)) {
+ dev_err(&client->dev,
+ "%s: Failed to create debugfs directory, rc = %ld\n",
+ __func__, PTR_ERR(rmi4_data->dir));
+ retval = PTR_ERR(rmi4_data->dir);
+ goto err_create_debugfs_dir;
+ }
+
+ temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, rmi4_data->dir,
+ rmi4_data, &debug_suspend_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ dev_err(&client->dev,
+ "%s: Failed to create suspend debugfs file, rc = %ld\n",
+ __func__, PTR_ERR(temp));
+ retval = PTR_ERR(temp);
+ goto err_create_debugfs_file;
+ }
+
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
+ retval = sysfs_create_file(&client->dev.kobj,
&attrs[attr_count].attr);
if (retval < 0) {
dev_err(&client->dev,
@@ -2317,7 +2326,10 @@
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
}
-
+err_create_debugfs_file:
+ debugfs_remove_recursive(rmi4_data->dir);
+err_create_debugfs_dir:
+ free_irq(rmi4_data->irq, rmi4_data);
err_enable_irq:
cancel_delayed_work_sync(&rmi4_data->det_work);
flush_workqueue(rmi4_data->det_workqueue);
@@ -2372,6 +2384,7 @@
rmi = &(rmi4_data->rmi4_mod_info);
+ debugfs_remove_recursive(rmi4_data->dir);
cancel_delayed_work_sync(&rmi4_data->det_work);
flush_workqueue(rmi4_data->det_workqueue);
destroy_workqueue(rmi4_data->det_workqueue);
@@ -2659,19 +2672,32 @@
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
int retval;
- if (!rmi4_data->sensor_sleep) {
- rmi4_data->touch_stopped = true;
- wake_up(&rmi4_data->wait);
- synaptics_rmi4_irq_enable(rmi4_data, false);
- synaptics_rmi4_sensor_sleep(rmi4_data);
+ if (rmi4_data->suspended) {
+ dev_info(dev, "Already in suspend state\n");
+ return 0;
}
- retval = synaptics_rmi4_regulator_lpm(rmi4_data, true);
- if (retval < 0) {
- dev_err(dev, "failed to enter low power mode\n");
- return retval;
+ if (!rmi4_data->fw_updating) {
+ if (!rmi4_data->sensor_sleep) {
+ rmi4_data->touch_stopped = true;
+ wake_up(&rmi4_data->wait);
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+ synaptics_rmi4_sensor_sleep(rmi4_data);
+ }
+
+ retval = synaptics_rmi4_regulator_lpm(rmi4_data, true);
+ if (retval < 0) {
+ dev_err(dev, "failed to enter low power mode\n");
+ return retval;
+ }
+ } else {
+ dev_err(dev,
+ "Firmware updating, cannot go into suspend mode\n");
+ return 0;
}
+ rmi4_data->suspended = true;
+
return 0;
}
@@ -2690,6 +2716,11 @@
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
int retval;
+ if (!rmi4_data->suspended) {
+ dev_info(dev, "Already in awake state\n");
+ return 0;
+ }
+
retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
if (retval < 0) {
dev_err(dev, "failed to enter active power mode\n");
@@ -2700,6 +2731,8 @@
rmi4_data->touch_stopped = false;
synaptics_rmi4_irq_enable(rmi4_data, true);
+ rmi4_data->suspended = false;
+
return 0;
}
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 681b95c..5f6d6ce 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -34,6 +34,7 @@
#elif defined CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
+#include <linux/debugfs.h>
#define PDT_PROPS (0x00EF)
#define PDT_START (0x00E9)
@@ -68,6 +69,8 @@
#define MASK_2BIT 0x03
#define MASK_1BIT 0x01
+#define NAME_BUFFER_SIZE 128
+
/*
* struct synaptics_rmi4_fn_desc - function descriptor fields in PDT
* @query_base_addr: base address for query registers
@@ -183,6 +186,7 @@
* @fingers_on_2d: flag to indicate presence of fingers in 2d area
* @flip_x: set to TRUE if desired to flip direction on x-axis
* @flip_y: set to TRUE if desired to flip direction on y-axis
+ * @fw_updating: firmware is updating flag
* @sensor_sleep: flag to indicate sleep state of sensor
* @wait: wait queue for touch data polling in interrupt thread
* @i2c_read: pointer to i2c read function
@@ -202,7 +206,8 @@
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
- const char *fw_image_name;
+ struct dentry *dir;
+ char fw_image_name[NAME_BUFFER_SIZE];
unsigned char current_page;
unsigned char button_0d_enabled;
unsigned char full_pm_cycle;
@@ -224,6 +229,8 @@
bool sensor_sleep;
bool flip_x;
bool flip_y;
+ bool fw_updating;
+ bool suspended;
wait_queue_head_t wait;
int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
unsigned char *data, unsigned short length);
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index a400b58..175328e 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -39,6 +39,7 @@
#define MSM_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
static DEFINE_MUTEX(msm_iommu_lock);
+struct dump_regs_tbl dump_regs_tbl[MAX_DUMP_REGS];
static int __enable_regulators(struct msm_iommu_drvdata *drvdata)
{
@@ -769,7 +770,7 @@
struct msm_iommu_priv *priv;
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
- unsigned int par;
+ u64 par;
void __iomem *base;
phys_addr_t ret = 0;
int ctx;
@@ -802,6 +803,23 @@
__disable_clocks(iommu_drvdata);
if (par & CB_PAR_F) {
+ unsigned int level = (par & CB_PAR_PLVL) >> CB_PAR_PLVL_SHIFT;
+ pr_err("IOMMU translation fault!\n");
+ pr_err("name = %s\n", iommu_drvdata->name);
+ pr_err("context = %s (%d)\n", ctx_drvdata->name,
+ ctx_drvdata->num);
+ pr_err("Interesting registers:\n");
+ pr_err("PAR = %16llx [%s%s%s%s%s%s%s%sPLVL%u %s]\n", par,
+ (par & CB_PAR_F) ? "F " : "",
+ (par & CB_PAR_TF) ? "TF " : "",
+ (par & CB_PAR_AFF) ? "AFF " : "",
+ (par & CB_PAR_PF) ? "PF " : "",
+ (par & CB_PAR_EF) ? "EF " : "",
+ (par & CB_PAR_TLBMCF) ? "TLBMCF " : "",
+ (par & CB_PAR_TLBLKF) ? "TLBLKF " : "",
+ (par & CB_PAR_ATOT) ? "ATOT " : "",
+ level,
+ (par & CB_PAR_STAGE) ? "S2 " : "S1 ");
ret = 0;
} else {
/* We are dealing with a supersection */
@@ -857,49 +875,13 @@
static void __print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
{
- struct msm_iommu_context_reg regs[MAX_DUMP_REGS] = {
- [DUMP_REG_FAR0] = {
- .val = GET_FAR(base, ctx)
- },
- [DUMP_REG_FAR1] = {
- /* TODO: make GET_FAR 64-bit and take this from that */
- .val = 0
- },
- [DUMP_REG_PAR0] = {
- .val = GET_PAR(base, ctx)
- },
- [DUMP_REG_PAR1] = {
- /* TODO: make GET_PAR 64-bit and take this from that */
- .val = 0
- },
- [DUMP_REG_FSR] = {
- .val = fsr
- },
- [DUMP_REG_FSYNR0] = {
- .val = GET_FSYNR0(base, ctx)
- },
- [DUMP_REG_FSYNR1] = {
- .val = GET_FSYNR1(base, ctx)
- },
- [DUMP_REG_TTBR0] = {
- .val = GET_TTBR0(base, ctx)
- },
- [DUMP_REG_TTBR1] = {
- .val = GET_TTBR1(base, ctx)
- },
- [DUMP_REG_SCTLR] = {
- .val = GET_SCTLR(base, ctx)
- },
- [DUMP_REG_ACTLR] = {
- .val = GET_ACTLR(base, ctx)
- },
- [DUMP_REG_PRRR] = {
- .val = GET_PRRR(base, ctx)
- },
- [DUMP_REG_NMRR] = {
- .val = GET_NMRR(base, ctx)
- },
- };
+ struct msm_iommu_context_reg regs[MAX_DUMP_REGS];
+ unsigned int i;
+
+ for (i = DUMP_REG_FIRST; i < MAX_DUMP_REGS; ++i) {
+ regs[i].val = GET_CTX_REG(dump_regs_tbl[i].key, base, ctx);
+ regs[i].valid = 1;
+ }
print_ctx_regs(regs);
}
@@ -976,6 +958,29 @@
return __pa(priv->pt.fl_table);
}
+#define DUMP_REG_INIT(dump_reg, cb_reg) \
+ do { \
+ dump_regs_tbl[dump_reg].key = cb_reg; \
+ dump_regs_tbl[dump_reg].name = #cb_reg; \
+ } while (0)
+
+static void msm_iommu_build_dump_regs_table(void)
+{
+ DUMP_REG_INIT(DUMP_REG_FAR0, CB_FAR);
+ DUMP_REG_INIT(DUMP_REG_FAR1, CB_FAR + 4);
+ DUMP_REG_INIT(DUMP_REG_PAR0, CB_PAR);
+ DUMP_REG_INIT(DUMP_REG_PAR1, CB_PAR + 4);
+ DUMP_REG_INIT(DUMP_REG_FSR, CB_FSR);
+ DUMP_REG_INIT(DUMP_REG_FSYNR0, CB_FSYNR0);
+ DUMP_REG_INIT(DUMP_REG_FSYNR1, CB_FSYNR1);
+ DUMP_REG_INIT(DUMP_REG_TTBR0, CB_TTBR0);
+ DUMP_REG_INIT(DUMP_REG_TTBR1, CB_TTBR1);
+ DUMP_REG_INIT(DUMP_REG_SCTLR, CB_SCTLR);
+ DUMP_REG_INIT(DUMP_REG_ACTLR, CB_ACTLR);
+ DUMP_REG_INIT(DUMP_REG_PRRR, CB_PRRR);
+ DUMP_REG_INIT(DUMP_REG_NMRR, CB_NMRR);
+}
+
static struct iommu_ops msm_iommu_ops = {
.domain_init = msm_iommu_domain_init,
.domain_destroy = msm_iommu_domain_destroy,
@@ -995,6 +1000,8 @@
{
msm_iommu_pagetable_init();
bus_set_iommu(&platform_bus_type, &msm_iommu_ops);
+ msm_iommu_build_dump_regs_table();
+
return 0;
}
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 50f6df4..8d2cc8f 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -124,41 +124,8 @@
return ret;
}
-static struct dump_regs_tbl {
- /*
- * To keep things context-bank-agnostic, we only store the CB
- * register offset in `key'
- */
- unsigned long key;
- const char *name;
- int offset;
-} dump_regs_tbl[MAX_DUMP_REGS];
-
#define EXTRACT_DUMP_REG_KEY(addr, ctx) (addr & ((1 << CTX_SHIFT) - 1))
-#define DUMP_REG_INIT(dump_reg, cb_reg) \
- do { \
- dump_regs_tbl[dump_reg].key = cb_reg; \
- dump_regs_tbl[dump_reg].name = #cb_reg; \
- } while (0)
-
-static void msm_iommu_sec_build_dump_regs_table(void)
-{
- DUMP_REG_INIT(DUMP_REG_FAR0, CB_FAR);
- DUMP_REG_INIT(DUMP_REG_FAR1, CB_FAR + 4);
- DUMP_REG_INIT(DUMP_REG_PAR0, CB_PAR);
- DUMP_REG_INIT(DUMP_REG_PAR1, CB_PAR + 4);
- DUMP_REG_INIT(DUMP_REG_FSR, CB_FSR);
- DUMP_REG_INIT(DUMP_REG_FSYNR0, CB_FSYNR0);
- DUMP_REG_INIT(DUMP_REG_FSYNR1, CB_FSYNR1);
- DUMP_REG_INIT(DUMP_REG_TTBR0, CB_TTBR0);
- DUMP_REG_INIT(DUMP_REG_TTBR1, CB_TTBR1);
- DUMP_REG_INIT(DUMP_REG_SCTLR, CB_SCTLR);
- DUMP_REG_INIT(DUMP_REG_ACTLR, CB_ACTLR);
- DUMP_REG_INIT(DUMP_REG_PRRR, CB_PRRR);
- DUMP_REG_INIT(DUMP_REG_NMRR, CB_NMRR);
-}
-
static int msm_iommu_reg_dump_to_regs(
struct msm_iommu_context_reg ctx_regs[],
struct msm_scm_fault_regs_dump *dump, int cb_num)
@@ -799,9 +766,6 @@
bus_set_iommu(&msm_iommu_sec_bus_type, &msm_iommu_ops);
ret = msm_iommu_sec_ptbl_init();
- if (ret)
- goto fail;
- msm_iommu_sec_build_dump_regs_table();
fail:
return ret;
}
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index bac8678..fbcc243 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -97,6 +97,7 @@
#define FLASH_FAULT_DETECT(base) (base + 0x51)
#define FLASH_MAX_LEVEL 0x4F
+#define TORCH_MAX_LEVEL 0x0F
#define FLASH_NO_MASK 0x00
#define FLASH_MASK_1 0x20
@@ -159,6 +160,7 @@
#define QPNP_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
#define QPNP_LUT_RAMP_STEP_DEFAULT 255
#define PWM_LUT_MAX_SIZE 63
+#define PWM_GPLED_LUT_MAX_SIZE 31
#define RGB_LED_DISABLE 0x00
#define MPP_MAX_LEVEL LED_FULL
@@ -299,6 +301,10 @@
* @pwm_channel - pwm channel to be configured for led
* @pwm_period_us - period for pwm, in us
* @mode - mode the led operates in
+ * @old_duty_pcts - storage for duty pcts that may need to be reused
+ * @default_mode - default mode of LED as set in device tree
+ * @use_blink - use blink sysfs entry
+ * @blinking - device is currently blinking w/LPG mode
*/
struct pwm_config_data {
struct lut_params lut_params;
@@ -306,9 +312,11 @@
int pwm_channel;
u32 pwm_period_us;
struct pwm_duty_cycles *duty_cycles;
+ int *old_duty_pcts;
u8 mode;
- u8 enable;
+ u8 default_mode;
bool use_blink;
+ bool blinking;
};
/**
@@ -414,6 +422,7 @@
* struct qpnp_led_data - internal led data structure
* @led_classdev - led class device
* @delayed_work - delayed work for turning off the LED
+ * @work - workqueue for led
* @id - led index
* @base_reg - base register given in device tree
* @lock - to protect the transactions
@@ -427,11 +436,12 @@
struct led_classdev cdev;
struct spmi_device *spmi_dev;
struct delayed_work dwork;
+ struct work_struct work;
int id;
u16 base;
u8 reg;
u8 num_leds;
- spinlock_t lock;
+ struct mutex lock;
struct wled_config_data *wled_cfg;
struct flash_config_data *flash_cfg;
struct kpdbl_config_data *kpdbl_cfg;
@@ -566,6 +576,14 @@
int duty_us;
if (led->cdev.brightness) {
+ if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
+ if (!led->mpp_cfg->pwm_cfg->blinking) {
+ led->mpp_cfg->pwm_cfg->mode =
+ led->mpp_cfg->pwm_cfg->default_mode;
+ led->mpp_cfg->pwm_mode =
+ led->mpp_cfg->pwm_cfg->default_mode;
+ }
+ }
if (led->mpp_cfg->pwm_mode == PWM_MODE) {
pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
@@ -606,8 +624,13 @@
return rc;
}
} else {
- if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+ if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
+ led->mpp_cfg->pwm_cfg->mode =
+ led->mpp_cfg->pwm_cfg->default_mode;
+ led->mpp_cfg->pwm_mode =
+ led->mpp_cfg->pwm_cfg->default_mode;
pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
+ }
rc = qpnp_led_masked_write(led,
LED_MPP_MODE_CTRL(led->base),
LED_MPP_MODE_MASK,
@@ -629,6 +652,8 @@
}
}
+ if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+ led->mpp_cfg->pwm_cfg->blinking = false;
qpnp_dump_regs(led, mpp_debug_regs, ARRAY_SIZE(mpp_debug_regs));
return 0;
@@ -639,8 +664,12 @@
int rc;
int val = led->cdev.brightness;
- led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
- led->max_current);
+ if (led->flash_cfg->torch_enable)
+ led->flash_cfg->current_prgm =
+ (val * TORCH_MAX_LEVEL / led->max_current);
+ else
+ led->flash_cfg->current_prgm =
+ (val * FLASH_MAX_LEVEL / led->max_current);
led->flash_cfg->current_prgm =
led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
@@ -691,7 +720,7 @@
qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
FLASH_CURRENT_MASK,
- led->max_current);
+ TORCH_MAX_LEVEL);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
@@ -861,6 +890,9 @@
int rc;
if (led->cdev.brightness) {
+ if (!led->kpdbl_cfg->pwm_cfg->blinking)
+ led->kpdbl_cfg->pwm_cfg->mode =
+ led->kpdbl_cfg->pwm_cfg->default_mode;
rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
@@ -877,6 +909,8 @@
return rc;
}
} else {
+ led->kpdbl_cfg->pwm_cfg->mode =
+ led->kpdbl_cfg->pwm_cfg->default_mode;
pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
@@ -887,6 +921,7 @@
}
}
+ led->kpdbl_cfg->pwm_cfg->blinking = false;
qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
return 0;
@@ -898,6 +933,9 @@
int rc;
if (led->cdev.brightness) {
+ if (!led->rgb_cfg->pwm_cfg->blinking)
+ led->rgb_cfg->pwm_cfg->mode =
+ led->rgb_cfg->pwm_cfg->default_mode;
if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
@@ -924,6 +962,8 @@
return rc;
}
} else {
+ led->rgb_cfg->pwm_cfg->mode =
+ led->rgb_cfg->pwm_cfg->default_mode;
pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
rc = qpnp_led_masked_write(led,
RGB_LED_EN_CTL(led->base),
@@ -935,6 +975,7 @@
}
}
+ led->rgb_cfg->pwm_cfg->blinking = false;
qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
return 0;
@@ -943,9 +984,7 @@
static void qpnp_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- int rc, i;
struct qpnp_led_data *led;
- struct qpnp_led_data *led_array;
led = container_of(led_cdev, struct qpnp_led_data, cdev);
if (value < LED_OFF || value > led->cdev.max_brightness) {
@@ -953,6 +992,16 @@
return;
}
+ led->cdev.brightness = value;
+ schedule_work(&led->work);
+}
+
+static void __qpnp_led_work(struct qpnp_led_data *led,
+ enum led_brightness value)
+{
+ int rc, i;
+ struct qpnp_led_data *led_array;
+
if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1) {
if (!led->flash_cfg->flash_on && value > 0) {
led_array = dev_get_drvdata(&led->spmi_dev->dev);
@@ -980,8 +1029,7 @@
}
}
- spin_lock(&led->lock);
- led->cdev.brightness = value;
+ mutex_lock(&led->lock);
switch (led->id) {
case QPNP_ID_WLED:
@@ -1021,7 +1069,7 @@
dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
break;
}
- spin_unlock(&led->lock);
+ mutex_unlock(&led->lock);
if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1) {
if (led->flash_cfg->flash_on && !value) {
@@ -1050,6 +1098,16 @@
}
}
+static void qpnp_led_work(struct work_struct *work)
+{
+ struct qpnp_led_data *led = container_of(work,
+ struct qpnp_led_data, work);
+
+ __qpnp_led_work(led, led->cdev.brightness);
+
+ return;
+}
+
static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
{
switch (led->id) {
@@ -1341,28 +1399,424 @@
return 0;
}
+static ssize_t pwm_us_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ u32 pwm_us;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u32 previous_pwm_us;
+ struct pwm_config_data *pwm_cfg;
+
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ ret = kstrtou32(buf, 10, &pwm_us);
+ if (ret)
+ return ret;
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ pwm_cfg = led->mpp_cfg->pwm_cfg;
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ pwm_cfg = led->rgb_cfg->pwm_cfg;
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev,
+ "Invalid LED id type for pwm_us\n");
+ return -EINVAL;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE)
+ pwm_cfg->blinking = true;
+
+ previous_pwm_us = pwm_cfg->pwm_period_us;
+
+ pwm_cfg->pwm_period_us = pwm_us;
+ pwm_free(pwm_cfg->pwm_dev);
+ ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ if (ret) {
+ pwm_cfg->pwm_period_us = previous_pwm_us;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm with new pwm_us value\n");
+ return ret;
+ }
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return count;
+}
+
+static ssize_t pause_lo_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ u32 pause_lo;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u32 previous_pause_lo;
+ struct pwm_config_data *pwm_cfg;
+
+ ret = kstrtou32(buf, 10, &pause_lo);
+ if (ret)
+ return ret;
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ pwm_cfg = led->mpp_cfg->pwm_cfg;
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ pwm_cfg = led->rgb_cfg->pwm_cfg;
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev,
+ "Invalid LED id type for pause lo\n");
+ return -EINVAL;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE)
+ pwm_cfg->blinking = true;
+
+ previous_pause_lo = pwm_cfg->lut_params.lut_pause_lo;
+
+ pwm_free(pwm_cfg->pwm_dev);
+ pwm_cfg->lut_params.lut_pause_lo = pause_lo;
+ ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ if (ret) {
+ pwm_cfg->lut_params.lut_pause_lo = previous_pause_lo;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm with new pause lo value\n");
+ return ret;
+ }
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return count;
+}
+
+static ssize_t pause_hi_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ u32 pause_hi;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u32 previous_pause_hi;
+ struct pwm_config_data *pwm_cfg;
+
+ ret = kstrtou32(buf, 10, &pause_hi);
+ if (ret)
+ return ret;
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ pwm_cfg = led->mpp_cfg->pwm_cfg;
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ pwm_cfg = led->rgb_cfg->pwm_cfg;
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev,
+ "Invalid LED id type for pause hi\n");
+ return -EINVAL;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE)
+ pwm_cfg->blinking = true;
+
+ previous_pause_hi = pwm_cfg->lut_params.lut_pause_hi;
+
+ pwm_free(pwm_cfg->pwm_dev);
+ pwm_cfg->lut_params.lut_pause_hi = pause_hi;
+ ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ if (ret) {
+ pwm_cfg->lut_params.lut_pause_hi = previous_pause_hi;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm with new pause hi value\n");
+ return ret;
+ }
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return count;
+}
+
+static ssize_t start_idx_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ u32 start_idx;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u32 previous_start_idx;
+ struct pwm_config_data *pwm_cfg;
+
+ ret = kstrtou32(buf, 10, &start_idx);
+ if (ret)
+ return ret;
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ pwm_cfg = led->mpp_cfg->pwm_cfg;
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ pwm_cfg = led->rgb_cfg->pwm_cfg;
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev,
+ "Invalid LED id type for start idx\n");
+ return -EINVAL;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE)
+ pwm_cfg->blinking = true;
+
+ previous_start_idx = pwm_cfg->duty_cycles->start_idx;
+ pwm_cfg->duty_cycles->start_idx = start_idx;
+ pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
+ pwm_free(pwm_cfg->pwm_dev);
+ ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ if (ret) {
+ pwm_cfg->duty_cycles->start_idx = previous_start_idx;
+ pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm with new start idx value\n");
+ return ret;
+ }
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return count;
+}
+
+static ssize_t ramp_step_ms_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ u32 ramp_step_ms;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u32 previous_ramp_step_ms;
+ struct pwm_config_data *pwm_cfg;
+
+ ret = kstrtou32(buf, 10, &ramp_step_ms);
+ if (ret)
+ return ret;
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ pwm_cfg = led->mpp_cfg->pwm_cfg;
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ pwm_cfg = led->rgb_cfg->pwm_cfg;
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev,
+ "Invalid LED id type for ramp step\n");
+ return -EINVAL;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE)
+ pwm_cfg->blinking = true;
+
+ previous_ramp_step_ms = pwm_cfg->lut_params.ramp_step_ms;
+
+ pwm_free(pwm_cfg->pwm_dev);
+ pwm_cfg->lut_params.ramp_step_ms = ramp_step_ms;
+ ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ if (ret) {
+ pwm_cfg->lut_params.ramp_step_ms = previous_ramp_step_ms;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm with new ramp step value\n");
+ return ret;
+ }
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return count;
+}
+
+static ssize_t lut_flags_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ u32 lut_flags;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u32 previous_lut_flags;
+ struct pwm_config_data *pwm_cfg;
+
+ ret = kstrtou32(buf, 10, &lut_flags);
+ if (ret)
+ return ret;
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ pwm_cfg = led->mpp_cfg->pwm_cfg;
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ pwm_cfg = led->rgb_cfg->pwm_cfg;
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev,
+ "Invalid LED id type for lut flags\n");
+ return -EINVAL;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE)
+ pwm_cfg->blinking = true;
+
+ previous_lut_flags = pwm_cfg->lut_params.flags;
+
+ pwm_free(pwm_cfg->pwm_dev);
+ pwm_cfg->lut_params.flags = lut_flags;
+ ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ if (ret) {
+ pwm_cfg->lut_params.flags = previous_lut_flags;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm with new lut flags value\n");
+ return ret;
+ }
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return count;
+}
+
+static ssize_t duty_pcts_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ int num_duty_pcts = 0;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ char *buffer;
+ ssize_t ret;
+ int i = 0;
+ int max_duty_pcts;
+ struct pwm_config_data *pwm_cfg;
+ u32 previous_num_duty_pcts;
+ int value;
+ int *previous_duty_pcts;
+
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ pwm_cfg = led->mpp_cfg->pwm_cfg;
+ max_duty_pcts = PWM_LUT_MAX_SIZE;
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ pwm_cfg = led->rgb_cfg->pwm_cfg;
+ max_duty_pcts = PWM_LUT_MAX_SIZE;
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev,
+ "Invalid LED id type for duty pcts\n");
+ return -EINVAL;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE)
+ pwm_cfg->blinking = true;
+
+ buffer = (char *)buf;
+
+ for (i = 0; i < max_duty_pcts; i++) {
+ if (buffer == NULL)
+ break;
+ ret = sscanf((const char *)buffer, "%u,%s", &value, buffer);
+ pwm_cfg->old_duty_pcts[i] = value;
+ num_duty_pcts++;
+ if (ret <= 1)
+ break;
+ }
+
+ if (num_duty_pcts >= max_duty_pcts) {
+ dev_err(&led->spmi_dev->dev,
+ "Number of duty pcts given exceeds max (%d)\n",
+ max_duty_pcts);
+ return -EINVAL;
+ }
+
+ previous_num_duty_pcts = pwm_cfg->duty_cycles->num_duty_pcts;
+ previous_duty_pcts = pwm_cfg->duty_cycles->duty_pcts;
+
+ pwm_cfg->duty_cycles->num_duty_pcts = num_duty_pcts;
+ pwm_cfg->duty_cycles->duty_pcts = pwm_cfg->old_duty_pcts;
+ pwm_cfg->old_duty_pcts = previous_duty_pcts;
+ pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
+
+ pwm_free(pwm_cfg->pwm_dev);
+ ret = qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ if (ret)
+ goto restore;
+
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return count;
+
+restore:
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm with new duty pcts value\n");
+ pwm_cfg->duty_cycles->num_duty_pcts = previous_num_duty_pcts;
+ pwm_cfg->old_duty_pcts = pwm_cfg->duty_cycles->duty_pcts;
+ pwm_cfg->duty_cycles->duty_pcts = previous_duty_pcts;
+ pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ return ret;
+}
+
static void led_blink(struct qpnp_led_data *led,
struct pwm_config_data *pwm_cfg)
{
- u8 previous_mode;
-
- previous_mode = pwm_cfg->mode;
if (pwm_cfg->use_blink) {
if (led->cdev.brightness) {
+ pwm_cfg->blinking = true;
if (led->id == QPNP_ID_LED_MPP)
led->mpp_cfg->pwm_mode = LPG_MODE;
pwm_cfg->mode = LPG_MODE;
- pwm_free(pwm_cfg->pwm_dev);
- qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
- qpnp_led_set(&led->cdev, led->cdev.brightness);
- if (led->id == QPNP_ID_LED_MPP)
- led->mpp_cfg->pwm_mode = previous_mode;
- pwm_cfg->mode = previous_mode;
} else {
- pwm_free(pwm_cfg->pwm_dev);
- qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
- qpnp_led_set(&led->cdev, led->cdev.brightness);
+ pwm_cfg->blinking = false;
+ pwm_cfg->mode = pwm_cfg->default_mode;
+ if (led->id == QPNP_ID_LED_MPP)
+ led->mpp_cfg->pwm_mode = pwm_cfg->default_mode;
}
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
}
}
@@ -1399,6 +1853,13 @@
static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
+static DEVICE_ATTR(pwm_us, 0664, NULL, pwm_us_store);
+static DEVICE_ATTR(pause_lo, 0664, NULL, pause_lo_store);
+static DEVICE_ATTR(pause_hi, 0664, NULL, pause_hi_store);
+static DEVICE_ATTR(start_idx, 0664, NULL, start_idx_store);
+static DEVICE_ATTR(ramp_step_ms, 0664, NULL, ramp_step_ms_store);
+static DEVICE_ATTR(lut_flags, 0664, NULL, lut_flags_store);
+static DEVICE_ATTR(duty_pcts, 0664, NULL, duty_pcts_store);
static DEVICE_ATTR(blink, 0664, NULL, blink_store);
static struct attribute *led_attrs[] = {
@@ -1411,11 +1872,34 @@
.attrs = led_attrs,
};
+static struct attribute *pwm_attrs[] = {
+ &dev_attr_pwm_us.attr,
+ NULL
+};
+
+static struct attribute *lpg_attrs[] = {
+ &dev_attr_pause_lo.attr,
+ &dev_attr_pause_hi.attr,
+ &dev_attr_start_idx.attr,
+ &dev_attr_ramp_step_ms.attr,
+ &dev_attr_lut_flags.attr,
+ &dev_attr_duty_pcts.attr,
+ NULL
+};
+
static struct attribute *blink_attrs[] = {
&dev_attr_blink.attr,
NULL
};
+static const struct attribute_group pwm_attr_group = {
+ .attrs = pwm_attrs,
+};
+
+static const struct attribute_group lpg_attr_group = {
+ .attrs = lpg_attrs,
+};
+
static const struct attribute_group blink_attr_group = {
.attrs = blink_attrs,
};
@@ -1840,11 +2324,18 @@
return -EINVAL;
}
+ led->flash_cfg->torch_enable =
+ of_property_read_bool(node, "qcom,torch-enable");
+
rc = of_property_read_u32(node, "qcom,current", &val);
- if (!rc)
- led->flash_cfg->current_prgm = (val *
+ if (!rc) {
+ if (led->flash_cfg->torch_enable)
+ led->flash_cfg->current_prgm = (val *
+ TORCH_MAX_LEVEL / led->max_current);
+ else
+ led->flash_cfg->current_prgm = (val *
FLASH_MAX_LEVEL / led->max_current);
- else
+ } else
return -EINVAL;
rc = of_property_read_u32(node, "qcom,headroom", &val);
@@ -1883,9 +2374,6 @@
led->flash_cfg->safety_timer =
of_property_read_bool(node, "qcom,safety-timer");
- led->flash_cfg->torch_enable =
- of_property_read_bool(node, "qcom,torch-enable");
-
return 0;
}
@@ -1942,12 +2430,23 @@
pwm_cfg->duty_cycles->duty_pcts =
devm_kzalloc(&spmi_dev->dev,
- sizeof(int) * pwm_cfg->duty_cycles->num_duty_pcts,
+ sizeof(int) * PWM_LUT_MAX_SIZE,
GFP_KERNEL);
if (!pwm_cfg->duty_cycles->duty_pcts) {
dev_err(&spmi_dev->dev,
"Unable to allocate memory\n");
- rc = -ENOMEM;
+ rc = -ENOMEM;
+ goto bad_lpg_params;
+ }
+
+ pwm_cfg->old_duty_pcts =
+ devm_kzalloc(&spmi_dev->dev,
+ sizeof(int) * PWM_LUT_MAX_SIZE,
+ GFP_KERNEL);
+ if (!pwm_cfg->old_duty_pcts) {
+ dev_err(&spmi_dev->dev,
+ "Unable to allocate memory\n");
+ rc = -ENOMEM;
goto bad_lpg_params;
}
@@ -2062,6 +2561,7 @@
return -ENOMEM;
}
led->kpdbl_cfg->pwm_cfg->mode = led_mode;
+ led->kpdbl_cfg->pwm_cfg->default_mode = led_mode;
} else
return rc;
@@ -2130,6 +2630,7 @@
return -ENOMEM;
}
led->rgb_cfg->pwm_cfg->mode = led_mode;
+ led->rgb_cfg->pwm_cfg->default_mode = led_mode;
} else
return rc;
@@ -2196,6 +2697,7 @@
return -ENOMEM;
}
led->mpp_cfg->pwm_cfg->mode = led_mode;
+ led->mpp_cfg->pwm_cfg->default_mode = led_mode;
} else
return rc;
@@ -2331,7 +2833,8 @@
goto fail_id_check;
}
- spin_lock_init(&led->lock);
+ mutex_init(&led->lock);
+ INIT_WORK(&led->work, qpnp_led_work);
rc = qpnp_led_initialize(led);
if (rc < 0)
@@ -2360,27 +2863,60 @@
if (led->id == QPNP_ID_LED_MPP) {
if (!led->mpp_cfg->pwm_cfg)
break;
+ if (led->mpp_cfg->pwm_cfg->mode == PWM_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &pwm_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
if (led->mpp_cfg->pwm_cfg->use_blink) {
rc = sysfs_create_group(&led->cdev.dev->kobj,
&blink_attr_group);
if (rc)
goto fail_id_check;
+
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
+ } else if (led->mpp_cfg->pwm_cfg->mode == LPG_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
}
} else if ((led->id == QPNP_ID_RGB_RED) ||
(led->id == QPNP_ID_RGB_GREEN) ||
(led->id == QPNP_ID_RGB_BLUE)) {
+ if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &pwm_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
if (led->rgb_cfg->pwm_cfg->use_blink) {
rc = sysfs_create_group(&led->cdev.dev->kobj,
&blink_attr_group);
if (rc)
goto fail_id_check;
+
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
+ } else if (led->rgb_cfg->pwm_cfg->mode == LPG_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
}
}
/* configure default state */
if (led->default_on) {
led->cdev.brightness = led->cdev.max_brightness;
- qpnp_led_set(&led->cdev, led->cdev.brightness);
+ __qpnp_led_work(led, led->cdev.brightness);
+ schedule_work(&led->work);
if (led->turn_off_delay_ms > 0)
qpnp_led_turn_off(led);
} else
@@ -2392,8 +2928,11 @@
return 0;
fail_id_check:
- for (i = 0; i < parsed_leds; i++)
+ for (i = 0; i < parsed_leds; i++) {
+ mutex_destroy(&led_array[i].lock);
led_classdev_unregister(&led_array[i].cdev);
+ }
+
return rc;
}
@@ -2403,6 +2942,8 @@
int i, parsed_leds = led_array->num_leds;
for (i = 0; i < parsed_leds; i++) {
+ cancel_work_sync(&led_array[i].work);
+ mutex_destroy(&led_array[i].lock);
led_classdev_unregister(&led_array[i].cdev);
switch (led_array[i].id) {
case QPNP_ID_WLED:
@@ -2418,6 +2959,35 @@
case QPNP_ID_RGB_RED:
case QPNP_ID_RGB_GREEN:
case QPNP_ID_RGB_BLUE:
+ if (led_array[i].rgb_cfg->pwm_cfg->mode == PWM_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &pwm_attr_group);
+ if (led_array[i].rgb_cfg->pwm_cfg->use_blink) {
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &blink_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &lpg_attr_group);
+ } else if (led_array[i].rgb_cfg->pwm_cfg->mode\
+ == LPG_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &lpg_attr_group);
+ break;
+ case QPNP_ID_LED_MPP:
+ if (!led_array[i].mpp_cfg->pwm_cfg)
+ break;
+ if (led_array[i].mpp_cfg->pwm_cfg->mode == PWM_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &pwm_attr_group);
+ if (led_array[i].mpp_cfg->pwm_cfg->use_blink) {
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &blink_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &lpg_attr_group);
+ } else if (led_array[i].mpp_cfg->pwm_cfg->mode\
+ == LPG_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->\
+ kobj, &lpg_attr_group);
+ break;
default:
dev_err(&led_array[i].spmi_dev->dev,
"Invalid LED(%d)\n",
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index ec2e381..74ec99a 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -182,6 +182,15 @@
snapshot config = 3264 * 2448 at 18 fps.
2 lanes max fps is 18, 4 lanes max fps is 24.
+config s5k4e1
+ bool "Sensor s5k4e1 (BAYER 5MP)"
+ depends on MSMB_CAMERA
+ ---help---
+ Samsung 5 MP Bayer Sensor. It uses 2 mipi lanes,
+ supports 720P preview at 30 fps
+ and QSXGA snapshot at 15 fps.
+ This sensor driver does not support auto focus.
+
config MSM_V4L2_VIDEO_OVERLAY_DEVICE
tristate "Qualcomm MSM V4l2 video overlay device"
---help---
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index cb8d821..2db25a6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -39,7 +39,7 @@
#define VFE40_BURST_LEN 3
#define VFE40_STATS_BURST_LEN 2
#define VFE40_UB_SIZE 1536
-#define VFE40_EQUAL_SLICE_UB 286
+#define VFE40_EQUAL_SLICE_UB 228
#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
#define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2))
@@ -1299,7 +1299,7 @@
}
static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
- .num_wm = 4,
+ .num_wm = 5,
.num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index df72328..d238649 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -24,6 +24,9 @@
#include <linux/proc_fs.h>
#include <linux/msm_ion.h>
#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
#include <mach/iommu_domains.h>
#include <mach/iommu.h>
#include <mach/vreg.h>
@@ -36,6 +39,7 @@
#include "msm_cpp.h"
#include "msm_isp_util.h"
#include "msm_camera_io_util.h"
+#include <linux/debugfs.h>
#define MSM_CPP_DRV_NAME "msm_cpp"
@@ -43,6 +47,23 @@
#define CONFIG_MSM_CPP_DBG 0
+#define CPP_CMD_TIMEOUT_MS 300
+
+struct msm_cpp_timer_data_t {
+ struct cpp_device *cpp_dev;
+ struct msm_cpp_frame_info_t *processed_frame;
+};
+
+struct msm_cpp_timer_t {
+ uint8_t used;
+ struct msm_cpp_timer_data_t data;
+ struct timer_list cpp_timer;
+};
+
+struct msm_cpp_timer_t cpp_timers[2];
+static int del_timer_idx;
+static int set_timer_idx;
+
/* dump the frame command before writing to the hardware */
#define MSM_CPP_DUMP_FRM_CMD 0
@@ -109,6 +130,11 @@
{"micro_iface_clk", -1},
};
static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev);
+static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
+static void cpp_timer_callback(unsigned long data);
+
+uint8_t induce_error;
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev);
static void msm_cpp_write(u32 data, void __iomem *cpp_base)
{
@@ -472,7 +498,6 @@
tx_fifo[i] = msm_camera_io_r(cpp_dev->base +
MSM_CPP_MICRO_FIFO_TX_DATA);
}
-
spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx];
if (queue_cmd->cmd_used) {
@@ -494,6 +519,36 @@
spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
tasklet_schedule(&cpp_dev->cpp_tasklet);
+ } else if (irq_status & 0x7C0) {
+ pr_err("%s: fatal error: 0x%x\n", __func__, irq_status);
+ pr_err("%s: DEBUG_SP: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
+ pr_err("%s: DEBUG_T: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
+ pr_err("%s: DEBUG_N: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
+ pr_err("%s: DEBUG_R: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
+ pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
+ pr_err("%s: DEBUG_MO: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
+ pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
+ pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
+ pr_err("%s: DEBUG_GPI: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
+ pr_err("%s: DEBUG_GPO: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
+ pr_err("%s: DEBUG_T0: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
+ pr_err("%s: DEBUG_R0: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
+ pr_err("%s: DEBUG_T1: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
+ pr_err("%s: DEBUG_R1: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
}
msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
return IRQ_HANDLED;
@@ -509,6 +564,7 @@
uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
struct cpp_device *cpp_dev = (struct cpp_device *) data;
struct msm_cpp_tasklet_queue_cmd *queue_cmd;
+ struct msm_cpp_timer_t *timer = NULL;
while (atomic_read(&cpp_dev->irq_cnt)) {
spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
@@ -535,6 +591,25 @@
msg_id = tx_fifo[i+2];
if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
CPP_DBG("Frame done!!\n");
+ /* delete CPP timer */
+ CPP_DBG("delete timer %d.\n",
+ del_timer_idx);
+ timer = &cpp_timers[del_timer_idx];
+ del_timer(&timer->cpp_timer);
+ timer->used = 0;
+ timer->data.processed_frame = NULL;
+ del_timer_idx = 1 - del_timer_idx;
+ msm_cpp_notify_frame_done(cpp_dev);
+ } else if (msg_id ==
+ MSM_CPP_MSG_ID_FRAME_NACK) {
+ pr_err("NACK error from hw!!\n");
+ CPP_DBG("delete timer %d.\n",
+ del_timer_idx);
+ timer = &cpp_timers[del_timer_idx];
+ del_timer(&timer->cpp_timer);
+ timer->used = 0;
+ timer->data.processed_frame = NULL;
+ del_timer_idx = 1 - del_timer_idx;
msm_cpp_notify_frame_done(cpp_dev);
}
i += cmd_len + 2;
@@ -543,48 +618,6 @@
}
}
-static void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
-{
- disable_irq(cpp_dev->irq->start);
-
- msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
- msm_camera_io_w(0x1, cpp_dev->base +
- MSM_CPP_MICRO_BOOT_START);
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
-
- /*Trigger MC to jump to start address*/
- msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
- msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base);
-
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
- msm_cpp_poll(cpp_dev->base, 0x1);
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK);
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
-
- /*Get Bootloader Version*/
- msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base);
- pr_info("MC Bootloader Version: 0x%x\n",
- msm_cpp_read(cpp_dev->base));
-
- /*Get Firmware Version*/
- msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
- msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base);
- msm_cpp_write(0x1, cpp_dev->base);
- msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
- msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
-
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
- msm_cpp_poll(cpp_dev->base, 0x2);
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER);
- pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
- enable_irq(cpp_dev->irq->start);
- msm_camera_io_w_mb(0x8, cpp_dev->base +
- MSM_CPP_MICRO_IRQGEN_MASK);
- msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
- MSM_CPP_MICRO_IRQGEN_CLR);
-}
-
static int cpp_init_hardware(struct cpp_device *cpp_dev)
{
int rc = 0;
@@ -663,8 +696,15 @@
cpp_dev->taskletq_idx = 0;
atomic_set(&cpp_dev->irq_cnt, 0);
msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
- if (cpp_dev->is_firmware_loaded == 1)
- msm_cpp_boot_hw(cpp_dev);
+ if (cpp_dev->is_firmware_loaded == 1) {
+ disable_irq(cpp_dev->irq->start);
+ cpp_load_fw(cpp_dev, NULL);
+ enable_irq(cpp_dev->irq->start);
+ msm_camera_io_w_mb(0x7C8, cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_MASK);
+ msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_CLR);
+ }
return rc;
req_irq_fail:
iounmap(cpp_dev->cpp_hw_base);
@@ -713,47 +753,44 @@
const struct firmware *fw = NULL;
struct device *dev = &cpp_dev->pdev->dev;
- pr_debug("%s: FW file: %s\n", __func__, fw_name_bin);
- rc = request_firmware(&fw, fw_name_bin, dev);
- if (rc) {
- dev_err(dev, "Failed to locate blob %s from device %p, Error: %d\n",
- fw_name_bin, dev, rc);
- }
-
- CPP_DBG("HW Ver:0x%x\n",
- msm_camera_io_r(cpp_dev->base +
- MSM_CPP_MICRO_HW_VERSION));
-
+ msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
msm_camera_io_w(0x1, cpp_dev->base +
- MSM_CPP_MICRO_BOOT_START);
- /*Enable MC clock*/
- msm_camera_io_w(0x1, cpp_dev->base +
- MSM_CPP_MICRO_CLKEN_CTL);
-
+ MSM_CPP_MICRO_BOOT_START);
msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
- /*Start firmware loading*/
- msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
- msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
- msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
- if (NULL != fw)
- ptr_bin = (uint32_t *)fw->data;
+ if (fw_name_bin) {
+ pr_debug("%s: FW file: %s\n", __func__, fw_name_bin);
+ rc = request_firmware(&fw, fw_name_bin, dev);
+ if (rc) {
+ dev_err(dev,
+ "Fail to loc blob %s from dev %p, Error: %d\n",
+ fw_name_bin, dev, rc);
+ }
+ if (NULL != fw)
+ ptr_bin = (uint32_t *)fw->data;
- if (ptr_bin == NULL) {
- pr_err("ptr_bin is NULL\n");
- } else {
- for (i = 0; i < fw->size/4; i++) {
- if (ptr_bin) {
+ msm_camera_io_w(0x1, cpp_dev->base +
+ MSM_CPP_MICRO_BOOT_START);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+ msm_camera_io_w(0xFFFFFFFF, cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_CLR);
+
+ /*Start firmware loading*/
+ msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
+
+ if (ptr_bin) {
+ for (i = 0; i < fw->size/4; i++) {
msm_cpp_write(*ptr_bin, cpp_dev->base);
ptr_bin++;
}
}
+ if (fw)
+ release_firmware(fw);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
}
- if (fw)
- release_firmware(fw);
-
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
- msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
/*Trigger MC to jump to start address*/
msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
@@ -817,7 +854,6 @@
cpp_dev->cpp_open_cnt++;
if (cpp_dev->cpp_open_cnt == 1) {
cpp_init_hardware(cpp_dev);
- iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
cpp_init_mem(cpp_dev);
cpp_dev->state = CPP_STATE_IDLE;
}
@@ -852,9 +888,38 @@
cpp_dev->cpp_open_cnt--;
if (cpp_dev->cpp_open_cnt == 0) {
+ pr_err("%s: irq_status: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4));
+ pr_err("%s: DEBUG_SP: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
+ pr_err("%s: DEBUG_T: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
+ pr_err("%s: DEBUG_N: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
+ pr_err("%s: DEBUG_R: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
+ pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
+ pr_err("%s: DEBUG_MO: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
+ pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
+ pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
+ pr_err("%s: DEBUG_GPI: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
+ pr_err("%s: DEBUG_GPO: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
+ pr_err("%s: DEBUG_T0: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
+ pr_err("%s: DEBUG_R0: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
+ pr_err("%s: DEBUG_T1: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
+ pr_err("%s: DEBUG_R1: 0x%x\n", __func__,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
cpp_deinit_mem(cpp_dev);
- iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
cpp_release_hardware(cpp_dev);
cpp_dev->state = CPP_STATE_OFF;
}
@@ -969,23 +1034,140 @@
}
#endif
+void msm_cpp_do_timeout_work(struct work_struct *work)
+{
+ int ret;
+ uint32_t i = 0;
+ struct msm_cpp_frame_info_t *this_frame =
+ cpp_timers[del_timer_idx].data.processed_frame;
+ struct msm_cpp_frame_info_t *second_frame = NULL;
+
+ pr_err("cpp_timer_callback called idx:%d. (jiffies=%lu)\n",
+ del_timer_idx, jiffies);
+ pr_err("fatal: cpp_timer expired for identity=0x%x, frame_id=%03d",
+ this_frame->identity, this_frame->frame_id);
+ cpp_timers[del_timer_idx].used = 0;
+ cpp_timers[del_timer_idx].data.processed_frame = NULL;
+ del_timer_idx = 1 - del_timer_idx;
+
+ if (cpp_timers[del_timer_idx].used == 1) {
+ pr_err("deleting cpp_timer %d.\n", del_timer_idx);
+ del_timer(&cpp_timers[del_timer_idx].cpp_timer);
+ cpp_timers[del_timer_idx].used = 0;
+ second_frame = cpp_timers[del_timer_idx].data.processed_frame;
+ cpp_timers[del_timer_idx].data.processed_frame = NULL;
+ del_timer_idx = 1 - del_timer_idx;
+ }
+
+ disable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
+ pr_err("Reloading firmware\n");
+ cpp_load_fw(cpp_timers[del_timer_idx].data.cpp_dev, NULL);
+ pr_err("Firmware loading done\n");
+ enable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
+ msm_camera_io_w_mb(0x8, cpp_timers[del_timer_idx].data.cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_MASK);
+ msm_camera_io_w_mb(0xFFFF,
+ cpp_timers[del_timer_idx].data.cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_CLR);
+
+ cpp_timers[set_timer_idx].data.processed_frame = this_frame;
+ cpp_timers[set_timer_idx].used = 1;
+ pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
+ setup_timer(&cpp_timers[set_timer_idx].cpp_timer, cpp_timer_callback,
+ (unsigned long)&cpp_timers[0]);
+ pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+ CPP_CMD_TIMEOUT_MS, jiffies);
+ ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+ if (ret)
+ pr_err("error in mod_timer\n");
+
+ set_timer_idx = 1 - set_timer_idx;
+ pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
+ this_frame->identity, this_frame->frame_id);
+ msm_cpp_write(0x6, cpp_timers[set_timer_idx].data.cpp_dev->base);
+ msm_cpp_dump_frame_cmd(this_frame->cpp_cmd_msg,
+ this_frame->msg_len);
+ for (i = 0; i < this_frame->msg_len; i++)
+ msm_cpp_write(this_frame->cpp_cmd_msg[i],
+ cpp_timers[set_timer_idx].data.cpp_dev->base);
+
+
+ if (second_frame != NULL) {
+ cpp_timers[set_timer_idx].data.processed_frame = second_frame;
+ cpp_timers[set_timer_idx].used = 1;
+ pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
+ setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ cpp_timer_callback, (unsigned long)&cpp_timers[0]);
+ pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+ CPP_CMD_TIMEOUT_MS, jiffies);
+ ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+ if (ret)
+ pr_err("error in mod_timer\n");
+
+ set_timer_idx = 1 - set_timer_idx;
+ pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
+ second_frame->identity, second_frame->frame_id);
+ msm_cpp_write(0x6,
+ cpp_timers[set_timer_idx].data.cpp_dev->base);
+ msm_cpp_dump_frame_cmd(second_frame->cpp_cmd_msg,
+ second_frame->msg_len);
+ for (i = 0; i < second_frame->msg_len; i++)
+ msm_cpp_write(second_frame->cpp_cmd_msg[i],
+ cpp_timers[set_timer_idx].data.cpp_dev->base);
+ }
+}
+
+void cpp_timer_callback(unsigned long data)
+{
+ struct msm_cpp_work_t *work =
+ cpp_timers[set_timer_idx].data.cpp_dev->work;
+ queue_work(cpp_timers[set_timer_idx].data.cpp_dev->timer_wq,
+ (struct work_struct *)work);
+}
+
static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
struct msm_queue_cmd *frame_qcmd)
{
uint32_t i;
int32_t rc = -EAGAIN;
+ int ret;
struct msm_cpp_frame_info_t *process_frame;
if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
process_frame = frame_qcmd->command;
msm_enqueue(&cpp_dev->processing_q,
&frame_qcmd->list_frame);
+
+ cpp_timers[set_timer_idx].data.processed_frame = process_frame;
+ cpp_timers[set_timer_idx].used = 1;
+ /* install timer for cpp timeout */
+ CPP_DBG("Installing cpp_timer %d\n", set_timer_idx);
+ setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ cpp_timer_callback, (unsigned long)&cpp_timers[0]);
+ CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+ CPP_CMD_TIMEOUT_MS, jiffies);
+ ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+ if (ret)
+ pr_err("error in mod_timer\n");
+
+ set_timer_idx = 1 - set_timer_idx;
+
msm_cpp_write(0x6, cpp_dev->base);
msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
process_frame->msg_len);
- for (i = 0; i < process_frame->msg_len; i++)
- msm_cpp_write(process_frame->cpp_cmd_msg[i],
- cpp_dev->base);
+ for (i = 0; i < process_frame->msg_len; i++) {
+ if ((induce_error) && (i == 1)) {
+ pr_err("Induce error\n");
+ msm_cpp_write(process_frame->cpp_cmd_msg[i]-1,
+ cpp_dev->base);
+ induce_error--;
+ } else
+ msm_cpp_write(process_frame->cpp_cmd_msg[i],
+ cpp_dev->base);
+ }
do_gettimeofday(&(process_frame->in_time));
rc = 0;
}
@@ -1097,7 +1279,7 @@
&buff_mgr_info);
if (rc < 0) {
rc = -EAGAIN;
- pr_err("error getting buffer rc:%d\n", rc);
+ pr_debug("error getting buffer rc:%d\n", rc);
goto ERROR2;
}
new_frame->output_buffer_info[1].index = buff_mgr_info.index;
@@ -1184,7 +1366,6 @@
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
int rc = 0;
- char *fw_name_bin;
if (ioctl_ptr == NULL) {
pr_err("ioctl_ptr is null\n");
@@ -1206,8 +1387,11 @@
case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
if (cpp_dev->is_firmware_loaded == 0) {
- fw_name_bin = kzalloc(ioctl_ptr->len+1, GFP_KERNEL);
- if (!fw_name_bin) {
+ kfree(cpp_dev->fw_name_bin);
+ cpp_dev->fw_name_bin = NULL;
+ cpp_dev->fw_name_bin = kzalloc(ioctl_ptr->len+1,
+ GFP_KERNEL);
+ if (!cpp_dev->fw_name_bin) {
pr_err("%s:%d: malloc error\n", __func__,
__LINE__);
mutex_unlock(&cpp_dev->mutex);
@@ -1222,24 +1406,24 @@
pr_err("ioctl_ptr->len is 0\n");
return -EINVAL;
}
- rc = (copy_from_user(fw_name_bin,
+ rc = (copy_from_user(cpp_dev->fw_name_bin,
(void __user *)ioctl_ptr->ioctl_ptr,
ioctl_ptr->len) ? -EFAULT : 0);
if (rc) {
ERR_COPY_FROM_USER();
- kfree(fw_name_bin);
+ kfree(cpp_dev->fw_name_bin);
+ cpp_dev->fw_name_bin = NULL;
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
- *(fw_name_bin+ioctl_ptr->len) = '\0';
+ *(cpp_dev->fw_name_bin+ioctl_ptr->len) = '\0';
if (cpp_dev == NULL) {
pr_err("cpp_dev is null\n");
return -EINVAL;
}
disable_irq(cpp_dev->irq->start);
- cpp_load_fw(cpp_dev, fw_name_bin);
- kfree(fw_name_bin);
+ cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
enable_irq(cpp_dev->irq->start);
cpp_dev->is_firmware_loaded = 1;
}
@@ -1467,7 +1651,6 @@
return msm_register_domain(&cpp_fw_layout);
}
-
static int __devinit cpp_probe(struct platform_device *pdev)
{
struct cpp_device *cpp_dev;
@@ -1582,23 +1765,35 @@
cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num;
cpp_dev->state = CPP_STATE_BOOT;
cpp_init_hardware(cpp_dev);
+ iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
msm_camera_io_w(0x0, cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_MASK);
msm_camera_io_w(0xFFFF, cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_CLR);
-
+ msm_camera_io_w(0x80000000, cpp_dev->base + 0xF0);
cpp_release_hardware(cpp_dev);
cpp_dev->state = CPP_STATE_OFF;
+ msm_cpp_enable_debugfs(cpp_dev);
msm_queue_init(&cpp_dev->eventData_q, "eventdata");
msm_queue_init(&cpp_dev->processing_q, "frame");
INIT_LIST_HEAD(&cpp_dev->tasklet_q);
tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet,
(unsigned long)cpp_dev);
+ cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
+ cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
+ GFP_KERNEL);
+ INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
cpp_dev->cpp_open_cnt = 0;
cpp_dev->is_firmware_loaded = 0;
+ cpp_timers[0].data.cpp_dev = cpp_dev;
+ cpp_timers[1].data.cpp_dev = cpp_dev;
+ cpp_timers[0].used = 0;
+ cpp_timers[1].used = 0;
+ cpp_dev->fw_name_bin = NULL;
return rc;
+
ERROR3:
release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
ERROR2:
@@ -1628,6 +1823,7 @@
return 0;
}
+ iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
msm_sd_unregister(&cpp_dev->msm_sd);
release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
release_mem_region(cpp_dev->vbif_mem->start,
@@ -1635,6 +1831,8 @@
release_mem_region(cpp_dev->cpp_hw_mem->start,
resource_size(cpp_dev->cpp_hw_mem));
mutex_destroy(&cpp_dev->mutex);
+ kfree(cpp_dev->work);
+ destroy_workqueue(cpp_dev->timer_wq);
kfree(cpp_dev->cpp_clk);
kfree(cpp_dev);
return 0;
@@ -1660,6 +1858,30 @@
platform_driver_unregister(&cpp_driver);
}
+static int msm_cpp_debugfs_error_s(void *data, u64 val)
+{
+ pr_err("setting error inducement");
+ induce_error = val;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL,
+ msm_cpp_debugfs_error_s, "%llu\n");
+
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
+{
+ struct dentry *debugfs_base;
+ debugfs_base = debugfs_create_dir("msm_cpp", NULL);
+ if (!debugfs_base)
+ return -ENOMEM;
+
+ if (!debugfs_create_file("error", S_IRUGO | S_IWUSR, debugfs_base,
+ (void *)cpp_dev, &cpp_debugfs_error))
+ return -ENOMEM;
+
+ return 0;
+}
+
module_init(msm_cpp_init_module);
module_exit(msm_cpp_exit_module);
MODULE_DESCRIPTION("MSM CPP driver");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 36a5fa5..0a70d37 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -147,6 +147,11 @@
struct list_head native_buff_head;
};
+struct msm_cpp_work_t {
+ struct work_struct my_work;
+ struct cpp_device *cpp_dev;
+};
+
struct cpp_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
@@ -165,6 +170,9 @@
struct mutex mutex;
enum cpp_state state;
uint8_t is_firmware_loaded;
+ char *fw_name_bin;
+ struct workqueue_struct *timer_wq;
+ struct msm_cpp_work_t *work;
int domain_num;
struct iommu_domain *domain;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index 40931ef..18ac623 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
obj-$(CONFIG_IMX135) += imx135.o
obj-$(CONFIG_OV8825) += ov8825.o
+obj-$(CONFIG_s5k4e1) += s5k4e1.o
obj-$(CONFIG_OV2720) += ov2720.o
obj-$(CONFIG_OV9724) += ov9724.o
obj-$(CONFIG_HI256) += hi256.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index a6c5639..a27ca99 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -795,10 +795,7 @@
rc = msm_cci_config(sd, arg);
break;
case MSM_SD_SHUTDOWN: {
- struct msm_camera_cci_ctrl ctrl_cmd;
- ctrl_cmd.cmd = MSM_CCI_RELEASE;
- rc = msm_cci_config(sd, &ctrl_cmd);
- break;
+ return rc;
}
default:
rc = -ENOIOCTLCMD;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 3dd3a4e..e096e96 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -130,12 +130,6 @@
pr_err("%s failed e_ctrl is NULL\n", __func__);
return -EINVAL;
}
- if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
- rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
- &e_ctrl->i2c_client, MSM_CCI_INIT);
- if (rc < 0)
- pr_err("%s cci_init failed\n", __func__);
- }
CDBG("%s X\n", __func__);
return rc;
}
@@ -149,12 +143,6 @@
pr_err("%s failed e_ctrl is NULL\n", __func__);
return -EINVAL;
}
- if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
- rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
- &e_ctrl->i2c_client, MSM_CCI_RELEASE);
- if (rc < 0)
- pr_err("%s cci_init failed\n", __func__);
- }
CDBG("%s X\n", __func__);
return rc;
}
@@ -445,14 +433,18 @@
struct msm_eeprom_board_info *eb_info;
struct msm_camera_power_ctrl_t *power_info =
&e_ctrl->eboard_info->power_info;
- struct spi_device *spi = e_ctrl->i2c_client.spi_client->spi_master;
- struct device_node *of_node = spi->dev.of_node;
+ struct device_node *of_node = NULL;
struct msm_camera_gpio_conf *gconf = NULL;
uint16_t gpio_array_size = 0;
uint16_t *gpio_array = NULL;
eb_info = e_ctrl->eboard_info;
- rc = msm_camera_get_dt_power_setting_data(spi->dev.of_node,
+ if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
+ of_node = e_ctrl->i2c_client.
+ spi_client->spi_master->dev.of_node;
+ else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+ of_node = e_ctrl->pdev->dev.of_node;
+ rc = msm_camera_get_dt_power_setting_data(of_node,
&power_info->power_setting, &power_info->power_setting_size);
if (rc)
return rc;
@@ -787,26 +779,35 @@
goto board_free;
}
- if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
- rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
- &e_ctrl->i2c_client, MSM_CCI_INIT);
- if (rc < 0)
- pr_err("%s cci_init failed\n", __func__);
- }
+ rc = msm_eeprom_get_dt_data(e_ctrl);
+ if (rc)
+ goto board_free;
rc = msm_eeprom_alloc_memory_map(e_ctrl, of_node);
if (rc)
goto board_free;
+ rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+ &e_ctrl->i2c_client);
+ if (rc) {
+ pr_err("failed rc %d\n", rc);
+ goto memdata_free;
+ }
rc = read_eeprom_memory(e_ctrl);
if (rc < 0) {
pr_err("%s read_eeprom_memory failed\n", __func__);
- goto memdata_free;
+ goto power_down;
}
pr_err("%s line %d\n", __func__, __LINE__);
for (j = 0; j < e_ctrl->num_bytes; j++)
CDBG("memory_data[%d] = 0x%X\n", j, e_ctrl->memory_data[j]);
+ rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+ &e_ctrl->i2c_client);
+ if (rc) {
+ pr_err("failed rc %d\n", rc);
+ goto memdata_free;
+ }
v4l2_subdev_init(&e_ctrl->msm_sd.sd,
e_ctrl->eeprom_v4l2_subdev_ops);
v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl);
@@ -821,16 +822,13 @@
msm_sd_register(&e_ctrl->msm_sd);
- if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
- rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_util(
- &e_ctrl->i2c_client, MSM_CCI_RELEASE);
- if (rc < 0)
- pr_err("%s cci_init failed\n", __func__);
- }
e_ctrl->is_supported = 1;
CDBG("%s X\n", __func__);
return rc;
+power_down:
+ msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+ &e_ctrl->i2c_client);
memdata_free:
kfree(e_ctrl->memory_data);
kfree(eb_info->eeprom_map);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
index e2500a6..8cba04c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
@@ -183,10 +183,12 @@
pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__,
data->gpio_conf->gpio_num_info->gpio_num
[power_setting->seq_val]);
- gpio_set_value_cansleep(
- data->gpio_conf->gpio_num_info->gpio_num
- [power_setting->seq_val],
- power_setting->config_val);
+ if (data->gpio_conf->gpio_num_info->gpio_num
+ [power_setting->seq_val])
+ gpio_set_value_cansleep(
+ data->gpio_conf->gpio_num_info->gpio_num
+ [power_setting->seq_val],
+ power_setting->config_val);
break;
case SENSOR_VREG:
if (power_setting->seq_val >= CAM_VREG_MAX) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index 4190d7b..f1df703 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -16,6 +16,7 @@
#define HI256_SENSOR_NAME "hi256"
#define PLATFORM_DRIVER_NAME "msm_camera_hi256"
+#define CONFIG_MSMB_CAMERA_DEBUG
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_err(fmt, ##args)
@@ -29,6 +30,18 @@
static struct msm_sensor_power_setting hi256_power_setting[] = {
{
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 20,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 0,
+ },
+ {
.seq_type = SENSOR_VREG,
.seq_val = CAM_VIO,
.config_val = 0,
@@ -47,12 +60,6 @@
.delay = 0,
},
{
- .seq_type = SENSOR_GPIO,
- .seq_val = SENSOR_GPIO_STANDBY,
- .config_val = GPIO_OUT_HIGH,
- .delay = 10,
- },
- {
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
@@ -84,6 +91,41 @@
},
};
+static struct msm_camera_i2c_reg_conf hi256_uxga_settings[] = {
+ {0x03, 0x00},
+ {0x01, 0xf1},
+ {0x03, 0x20},
+ {0x10, 0x1c},
+ {0x03, 0x22},
+ {0x10, 0x69},
+ {0x03, 0x00},
+ {0x12, 0x00},
+ {0x20, 0x00},
+ {0x21, 0x0a},
+ {0x22, 0x00},
+ {0x23, 0x0a},
+ {0x40, 0x01},
+ {0x41, 0x68},
+ {0x42, 0x00},
+ {0x43, 0x12},
+ {0x03, 0x10},
+ {0x3f, 0x00},
+ {0x03, 0x12},
+ {0x20, 0x0f},
+ {0x21, 0x0f},
+ {0x90, 0x5d},
+ {0x03, 0x13},
+ {0x80, 0xfd},
+ {0x03, 0x00},
+ {0x10, 0x00},
+ {0x03, 0x48},
+ {0x72, 0x81},
+ {0x30, 0x0c},
+ {0x31, 0x80},
+ {0x03, 0x00},
+ {0x01, 0xf0},
+};
+
static struct msm_camera_i2c_reg_conf hi256_start_settings[] = {
{0x03, 0x00},
{0x01, 0xf0},
@@ -108,7 +150,7 @@
{0x10, 0x69},
{0x03, 0x00},
- {0x10, 0x90},
+ {0x10, 0x13},
{0x11, 0x93},
{0x12, 0x00},
{0x0b, 0xaa},
@@ -123,9 +165,9 @@
{0x26, 0x06},
{0x27, 0x40},
{0x40, 0x01},
- {0x41, 0x68},
+ {0x41, 0x78},
{0x42, 0x00},
- {0x43, 0x12},
+ {0x43, 0x14},
{0x45, 0x04},
{0x46, 0x18},
{0x47, 0xd8},
@@ -756,21 +798,21 @@
{0x7b, 0x22},
{0x7d, 0x23},
{0x83, 0x01},
- {0x84, 0x7c},
- {0x85, 0xdc},
+ {0x84, 0x5f},
+ {0x85, 0x90},
{0x86, 0x01},
- {0x87, 0xf4},
+ {0x87, 0x2c},
{0x88, 0x05},
- {0x89, 0xf3},
- {0x8a, 0x70},
- {0x8B, 0x7e},
- {0x8C, 0xf4},
- {0x8D, 0x69},
- {0x8E, 0x78},
- {0x9c, 0x17},
- {0x9d, 0x70},
+ {0x89, 0x7e},
+ {0x8a, 0x40},
+ {0x8B, 0x75},
+ {0x8C, 0x30},
+ {0x8D, 0x61},
+ {0x8E, 0x44},
+ {0x9c, 0x08},
+ {0x9d, 0x34},
{0x9e, 0x01},
- {0x9f, 0xf4},
+ {0x9f, 0x2c},
{0xb0, 0x18},
{0xb1, 0x14},
{0xb2, 0x80},
@@ -862,8 +904,8 @@
{0xb9, 0x00},
{0x03, 0x48},
{0x70, 0x03},
- {0x71, 0x78},
- {0x72, 0x85},
+ {0x71, 0x30},
+ {0x72, 0x81},
{0x73, 0x10},
{0x70, 0x85},
{0x03, 0x48},
@@ -929,6 +971,45 @@
},
};
+static struct msm_camera_i2c_reg_conf hi256_svga_settings[] = {
+ {0x03, 0x20},
+ {0x10, 0x1c},
+ {0x03, 0x22},
+ {0x10, 0x69},
+ {0x03, 0x00},
+ {0x10, 0x13},
+ {0x12, 0x00},
+ {0x20, 0x00},
+ {0x21, 0x04},
+ {0x22, 0x00},
+ {0x23, 0x07},
+ {0x40, 0x01},
+ {0x41, 0x78},
+ {0x42, 0x00},
+ {0x43, 0x14},
+ {0x03, 0x10},
+ {0x3f, 0x02},
+ {0x03, 0x12},
+ {0x20, 0x0f},
+ {0x21, 0x0f},
+ {0x90, 0x5d},
+ {0x03, 0x13},
+ {0x80, 0x00},
+ {0x03, 0x48},
+ {0x72, 0x81},
+ {0x30, 0x06},
+ {0x31, 0x40},
+ {0x03, 0x20},
+ {0x88, 0x05},
+ {0x89, 0x7e},
+ {0x8a, 0x40},
+ {0x03, 0x20},
+ {0x10, 0x9c},
+ {0x03, 0x22},
+ {0x10, 0xe9},
+};
+
+
static const struct i2c_device_id hi256_i2c_id[] = {
{HI256_SENSOR_NAME, (kernel_ulong_t)&hi256_s_ctrl},
{ }
@@ -1080,8 +1161,22 @@
ARRAY_SIZE(hi256_recommend_settings));
CDBG("init setting X");
break;
- case CFG_SET_RESOLUTION:
+ case CFG_SET_RESOLUTION: {
+ int val = 0;
+ if (copy_from_user(&val,
+ (void *)cdata->cfg.setting, sizeof(int))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ if (val == 0)
+ hi256_i2c_write_table(s_ctrl, &hi256_uxga_settings[0],
+ ARRAY_SIZE(hi256_uxga_settings));
+ else if (val == 1)
+ hi256_i2c_write_table(s_ctrl, &hi256_svga_settings[0],
+ ARRAY_SIZE(hi256_svga_settings));
break;
+ }
case CFG_SET_STOP_STREAM:
hi256_i2c_write_table(s_ctrl,
&hi256_stop_settings[0],
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 34f4428..7f474bb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1175,9 +1175,10 @@
case VIDIOC_MSM_SENSOR_CFG:
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
- case MSM_SD_SHUTDOWN:
msm_sensor_stop_stream(s_ctrl);
return 0;
+ case MSM_SD_SHUTDOWN:
+ return 0;
default:
return -ENOIOCTLCMD;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/s5k4e1.c b/drivers/media/platform/msm/camera_v2/sensor/s5k4e1.c
new file mode 100644
index 0000000..5c70df2
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/s5k4e1.c
@@ -0,0 +1,167 @@
+/* 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.
+ *
+ */
+#include "msm_sensor.h"
+#define s5k4e1_SENSOR_NAME "s5k4e1"
+DEFINE_MSM_MUTEX(s5k4e1_mut);
+
+static struct msm_sensor_ctrl_t s5k4e1_s_ctrl;
+
+static struct msm_sensor_power_setting s5k4e1_power_setting[] = {
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VIO,
+ .config_val = 0,
+ .delay = 0,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VANA,
+ .config_val = 0,
+ .delay = 0,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VDIG,
+ .config_val = 0,
+ .delay = 0,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 1,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 1,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
+ .seq_type = SENSOR_CLK,
+ .seq_val = SENSOR_CAM_MCLK,
+ .config_val = 24000000,
+ .delay = 1,
+ },
+ {
+ .seq_type = SENSOR_I2C_MUX,
+ .seq_val = 0,
+ .config_val = 0,
+ .delay = 1,
+ },
+};
+
+static struct v4l2_subdev_info s5k4e1_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+};
+
+static const struct i2c_device_id s5k4e1_i2c_id[] = {
+ {s5k4e1_SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl},
+ { }
+};
+
+static int32_t msm_s5k4e1_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &s5k4e1_s_ctrl);
+}
+
+static struct i2c_driver s5k4e1_i2c_driver = {
+ .id_table = s5k4e1_i2c_id,
+ .probe = msm_s5k4e1_i2c_probe,
+ .driver = {
+ .name = s5k4e1_SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client s5k4e1_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id s5k4e1_dt_match[] = {
+ {.compatible = "shinetech,s5k4e1", .data = &s5k4e1_s_ctrl},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, s5k4e1_dt_match);
+
+static struct platform_driver s5k4e1_platform_driver = {
+ .driver = {
+ .name = "shinetech,s5k4e1",
+ .owner = THIS_MODULE,
+ .of_match_table = s5k4e1_dt_match,
+ },
+};
+
+static int32_t s5k4e1_platform_probe(struct platform_device *pdev)
+{
+ int32_t rc = 0;
+ const struct of_device_id *match;
+ match = of_match_device(s5k4e1_dt_match, &pdev->dev);
+ rc = msm_sensor_platform_probe(pdev, match->data);
+ return rc;
+}
+
+static int __init s5k4e1_init_module(void)
+{
+ int32_t rc = 0;
+ pr_info("%s:%d\n", __func__, __LINE__);
+ rc = platform_driver_probe(&s5k4e1_platform_driver,
+ s5k4e1_platform_probe);
+ if (!rc)
+ return rc;
+ pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+ return i2c_add_driver(&s5k4e1_i2c_driver);
+}
+
+static void __exit s5k4e1_exit_module(void)
+{
+ pr_info("%s:%d\n", __func__, __LINE__);
+ if (s5k4e1_s_ctrl.pdev) {
+ msm_sensor_free_sensor_data(&s5k4e1_s_ctrl);
+ platform_driver_unregister(&s5k4e1_platform_driver);
+ } else
+ i2c_del_driver(&s5k4e1_i2c_driver);
+ return;
+}
+
+static struct msm_sensor_ctrl_t s5k4e1_s_ctrl = {
+ .sensor_i2c_client = &s5k4e1_sensor_i2c_client,
+ .power_setting_array.power_setting = s5k4e1_power_setting,
+ .power_setting_array.size = ARRAY_SIZE(s5k4e1_power_setting),
+ .msm_sensor_mutex = &s5k4e1_mut,
+ .sensor_v4l2_subdev_info = s5k4e1_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k4e1_subdev_info),
+};
+
+module_init(s5k4e1_init_module);
+module_exit(s5k4e1_exit_module);
+MODULE_DESCRIPTION("s5k4e1");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 0678fc2..bc3b93d 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -400,9 +400,11 @@
static int q6_hfi_apr_callback(struct apr_client_data *data, void *priv)
{
struct q6_hfi_device *device = priv;
+ struct hfi_msg_event_notify_packet pkt = {0};
+ void *payload = NULL;
int rc = 0;
- if (!data || !device || !data->payload_size) {
+ if (!data || !device) {
dprintk(VIDC_ERR, "%s - Invalid arguments", __func__);
return -EINVAL;
}
@@ -410,7 +412,23 @@
dprintk(VIDC_DBG, "%s opcode = %u payload size = %u", __func__,
data->opcode, data->payload_size);
- rc = q6_hfi_iface_eventq_write(device, data->payload);
+ if (data->opcode == RESET_EVENTS) {
+ dprintk(VIDC_ERR, "%s Received subsystem reset event: %d",
+ __func__, data->reset_event);
+ pkt.packet_type = HFI_MSG_EVENT_NOTIFY;
+ pkt.size = sizeof(pkt);
+ pkt.event_id = HFI_EVENT_SYS_ERROR;
+ pkt.event_data1 = data->opcode;
+ pkt.event_data2 = data->reset_event;
+ payload = &pkt;
+ } else if (data->payload_size > 0) {
+ payload = data->payload;
+ } else {
+ dprintk(VIDC_ERR, "%s - Invalid payload size", __func__);
+ return -EINVAL;
+ }
+
+ rc = q6_hfi_iface_eventq_write(device, payload);
if (rc) {
dprintk(VIDC_ERR, "%s failed to write to event queue",
__func__);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c60537a..6ea2346 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -41,6 +41,7 @@
#include <mach/subsystem_restart.h>
#include <mach/socinfo.h>
#include <mach/qseecomi.h>
+#include <asm/cacheflush.h>
#include "qseecom_legacy.h"
#include "qseecom_kernel.h"
@@ -515,7 +516,10 @@
qseecom.send_resp_flag = 0;
send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
send_data_rsp.listener_id = lstnr ;
-
+ if (ptr_svc)
+ msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
+ ptr_svc->sb_virt, ptr_svc->sb_length,
+ ION_IOC_CLEAN_INV_CACHES);
ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
(const void *)&send_data_rsp,
sizeof(send_data_rsp), resp,
@@ -641,6 +645,8 @@
load_req.mdt_len = load_img_req.mdt_len;
load_req.img_len = load_img_req.img_len;
load_req.phy_addr = pa;
+ msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
+ ION_IOC_CLEAN_INV_CACHES);
/* SCM_CALL to load the app and get the app_id back */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
@@ -880,10 +886,15 @@
pr_err("Unsupported cmd_id %d\n", req.cmd_id);
return -EINVAL;
}
-
+ msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ data->client.sb_virt, data->client.sb_length,
+ ION_IOC_CLEAN_INV_CACHES);
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
sizeof(send_svc_ireq),
&resp, sizeof(resp));
+ msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ data->client.sb_virt, data->client.sb_length,
+ ION_IOC_INV_CACHES);
if (ret) {
pr_err("qseecom_scm_call failed with err: %d\n", ret);
return ret;
@@ -952,6 +963,11 @@
(uint32_t)req->resp_buf));
send_data_req.rsp_len = req->resp_len;
+ msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ data->client.sb_virt,
+ (req->cmd_req_len + req->resp_len),
+ ION_IOC_CLEAN_INV_CACHES);
+
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
sizeof(send_data_req),
&resp, sizeof(resp));
@@ -974,6 +990,9 @@
ret = -EINVAL;
}
}
+ msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ data->client.sb_virt, data->client.sb_length,
+ ION_IOC_INV_CACHES);
return ret;
}
@@ -1005,6 +1024,8 @@
char *field;
int ret = 0;
int i = 0;
+ uint32_t len = 0;
+ struct scatterlist *sg;
for (i = 0; i < MAX_ION_FD; i++) {
struct sg_table *sg_ptr = NULL;
@@ -1035,6 +1056,7 @@
sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
goto err;
}
+ sg = sg_ptr->sgl;
if (sg_ptr->nents == 1) {
uint32_t *update;
update = (uint32_t *) field;
@@ -1043,12 +1065,11 @@
else
*update = (uint32_t)sg_dma_address(
sg_ptr->sgl);
+ len += (uint32_t)sg->length;
} else {
struct qseecom_sg_entry *update;
- struct scatterlist *sg;
int j = 0;
update = (struct qseecom_sg_entry *) field;
- sg = sg_ptr->sgl;
for (j = 0; j < sg_ptr->nents; j++) {
if (cleanup) {
update->phys_addr = 0;
@@ -1058,10 +1079,19 @@
sg_dma_address(sg);
update->len = sg->length;
}
+ len += sg->length;
update++;
sg = sg_next(sg);
}
}
+ if (cleanup)
+ msm_ion_do_cache_op(qseecom.ion_clnt,
+ ihandle, NULL, len,
+ ION_IOC_INV_CACHES);
+ else
+ msm_ion_do_cache_op(qseecom.ion_clnt,
+ ihandle, NULL, len,
+ ION_IOC_CLEAN_INV_CACHES);
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -1288,6 +1318,7 @@
return -EIO;
}
+ __cpuc_flush_dcache_area((void *)img_data, fw_size);
/* SCM_CALL to load the image */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
sizeof(struct qseecom_load_app_ireq),
@@ -1354,6 +1385,7 @@
return -EIO;
}
+ __cpuc_flush_dcache_area((void *)img_data, fw_size);
/* SCM_CALL to load the image */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
sizeof(struct qseecom_load_lib_image_ireq),
@@ -1985,7 +2017,8 @@
ret = -EIO;
goto qseecom_load_external_elf_set_cpu_err;
}
-
+ msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
+ ION_IOC_CLEAN_INV_CACHES);
/* SCM_CALL to load the external elf */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
sizeof(struct qseecom_load_app_ireq),
@@ -2498,7 +2531,7 @@
ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
(void *) &req, sizeof(req), NULL, 0);
if (ret) {
- pr_err("scm_call failed");
+ pr_err("qseecom_scm_call failed");
return ret;
}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index f01ddab..d975543 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3130,11 +3130,11 @@
/* Silent the block layer */
if (md) {
- rc = mmc_queue_suspend(&md->queue);
+ rc = mmc_queue_suspend(&md->queue, 1);
if (rc)
goto suspend_error;
list_for_each_entry(part_md, &md->part, part) {
- rc = mmc_queue_suspend(&part_md->queue);
+ rc = mmc_queue_suspend(&part_md->queue, 1);
if (rc)
goto suspend_error;
}
@@ -3161,11 +3161,11 @@
int rc = 0;
if (md) {
- rc = mmc_queue_suspend(&md->queue);
+ rc = mmc_queue_suspend(&md->queue, 0);
if (rc)
goto out;
list_for_each_entry(part_md, &md->part, part) {
- rc = mmc_queue_suspend(&part_md->queue);
+ rc = mmc_queue_suspend(&part_md->queue, 0);
if (rc)
goto out_resume;
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 0e024dd..507cd5b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -438,12 +438,13 @@
/**
* mmc_queue_suspend - suspend a MMC request queue
* @mq: MMC queue to suspend
+ * @wait: Wait till MMC request queue is empty
*
* Stop the block request queue, and wait for our thread to
* complete any outstanding requests. This ensures that we
* won't suspend while a request is being processed.
*/
-int mmc_queue_suspend(struct mmc_queue *mq)
+int mmc_queue_suspend(struct mmc_queue *mq, int wait)
{
struct request_queue *q = mq->queue;
unsigned long flags;
@@ -457,7 +458,7 @@
spin_unlock_irqrestore(q->queue_lock, flags);
rc = down_trylock(&mq->thread_sem);
- if (rc) {
+ if (rc && !wait) {
/*
* Failed to take the lock so better to abort the
* suspend because mmcqd thread is processing requests.
@@ -467,6 +468,9 @@
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
rc = -EBUSY;
+ } else if (rc && wait) {
+ down(&mq->thread_sem);
+ rc = 0;
}
}
return rc;
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 9280d1b..d1fe01c 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -60,7 +60,7 @@
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
const char *);
extern void mmc_cleanup_queue(struct mmc_queue *);
-extern int mmc_queue_suspend(struct mmc_queue *);
+extern int mmc_queue_suspend(struct mmc_queue *, int);
extern void mmc_queue_resume(struct mmc_queue *);
extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index b81af11..d8cff35 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -55,7 +55,7 @@
for (i = 0; i < nr_strings; i++) {
buffer[i] = string;
- strlcpy(string, buf, strlen(buf));
+ strlcpy(string, buf, strlen(buf) + 1);
string += strlen(string) + 1;
buf += strlen(buf) + 1;
}
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index f000df7..644a751 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -1307,6 +1307,8 @@
next_state = ECM_IPA_INITIALIZED;
else if (operation == ECM_IPA_CONNECT)
next_state = ECM_IPA_CONNECTED_AND_UP;
+ else if (operation == ECM_IPA_CLEANUP)
+ next_state = ECM_IPA_UNLOADED;
break;
case ECM_IPA_CONNECTED_AND_UP:
if (operation == ECM_IPA_STOP)
diff --git a/drivers/net/ethernet/msm/msm_rmnet_wwan.c b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
index 98bdccc..3e4605f 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_wwan.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
@@ -188,6 +188,9 @@
__func__, skb);
netif_wake_queue(dev);
}
+ if (a2_mux_is_ch_empty(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]))
+ ipa_rm_inactivity_timer_release_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
spin_unlock_irqrestore(&wwan_ptr->lock, flags);
}
@@ -533,6 +536,7 @@
__func__, skb);
}
spin_unlock_irqrestore(&wwan_ptr->lock, flags);
+ return ret;
exit:
ipa_rm_inactivity_timer_release_resource(
ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
@@ -548,6 +552,7 @@
static void wwan_tx_timeout(struct net_device *dev)
{
pr_warning("[%s] wwan_tx_timeout(), data stall in UL\n", dev->name);
+ ipa_bam_reg_dump();
}
/**
diff --git a/drivers/net/ethernet/msm/qfec.c b/drivers/net/ethernet/msm/qfec.c
index 164b734..e68c395 100644
--- a/drivers/net/ethernet/msm/qfec.c
+++ b/drivers/net/ethernet/msm/qfec.c
@@ -2921,6 +2921,8 @@
priv->mii.dev = dev;
priv->mii.mdio_read = qfec_mdio_read;
priv->mii.mdio_write = qfec_mdio_write;
+ /* initialize mdio clock */
+ priv->mdio_clk = GMII_ADR_REG_CR_62;
/* map register regions */
ret = qfec_map_resource(
diff --git a/drivers/net/ethernet/msm/qfec.h b/drivers/net/ethernet/msm/qfec.h
index 525fd9c..a25436f 100644
--- a/drivers/net/ethernet/msm/qfec.h
+++ b/drivers/net/ethernet/msm/qfec.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -411,6 +411,14 @@
# define GMII_ADR_REG_GR 0x000007c0 /* addr bits */
# define GMII_ADR_REG_RSVRD1 0x00000020 /* */
# define GMII_ADR_REG_CR 0x0000001c /* csr clock range */
+
+# define GMII_ADR_REG_CR_42 0x00000000 /* csr clock 42 */
+# define GMII_ADR_REG_CR_62 0x00000001 /* csr clock 62 */
+# define GMII_ADR_REG_CR_16 0x00000002 /* csr clock 16 */
+# define GMII_ADR_REG_CR_26 0x00000003 /* csr clock 26 */
+# define GMII_ADR_REG_CR_102 0x00000004 /* csr clock 102 */
+# define GMII_ADR_REG_CR_124 0x00000005 /* csr clock 124 */
+
# define GMII_ADR_REG_GW 0x00000002 /* gmii write */
# define GMII_ADR_REG_GB 0x00000001 /* gmii busy */
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index a3d7f12..5e22c35 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -112,6 +112,9 @@
#define CCU_PRONTO_LAST_ADDR1_OFFSET 0x10
#define CCU_PRONTO_LAST_ADDR2_OFFSET 0x14
+#define MSM_PRONTO_SAW2_BASE 0xfb219000
+#define PRONTO_SAW2_SPM_STS_OFFSET 0x0c
+
#define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
@@ -288,6 +291,7 @@
void __iomem *riva_ccu_base;
void __iomem *pronto_a2xb_base;
void __iomem *pronto_ccpu_base;
+ void __iomem *pronto_saw2_base;
void __iomem *fiq_reg;
int ssr_boot;
int nv_downloaded;
@@ -479,6 +483,10 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+ reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+
tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -1683,6 +1691,14 @@
ret = -ENOMEM;
goto fail_ioremap4;
}
+ penv->pronto_saw2_base = ioremap_nocache(MSM_PRONTO_SAW2_BASE,
+ SZ_32);
+ if (!penv->pronto_saw2_base) {
+ pr_err("%s: ioremap wcnss physical(saw2) failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto fail_ioremap5;
+ }
}
/* trigger initialization of the WCNSS */
@@ -1699,6 +1715,9 @@
fail_pil:
if (penv->riva_ccu_base)
iounmap(penv->riva_ccu_base);
+ if (penv->pronto_saw2_base)
+ iounmap(penv->pronto_saw2_base);
+fail_ioremap5:
if (penv->fiq_reg)
iounmap(penv->fiq_reg);
fail_ioremap4:
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 5af95927..3039b0d 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -39,3 +39,12 @@
into the kernel or say M to compile it as module.
endmenu
+
+config NFC_QNCI
+ bool "Qualcomm NCI based NFC Controller Driver for qca199x"
+ depends on I2C
+ select CRC_CCITT
+ help
+ This enables the NFC driver for QCA199x based devices.
+ This is for i2c connected version. NCI protocol logic
+ resides in the usermode and it has no other NFC dependencies.
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index ab99e85..35a71e8 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -5,5 +5,6 @@
obj-$(CONFIG_PN544_NFC) += pn544.o
obj-$(CONFIG_NFC_PN533) += pn533.o
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
+obj-$(CONFIG_NFC_QNCI) += nfc-nci.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
new file mode 100644
index 0000000..9e9a4ea
--- /dev/null
+++ b/drivers/nfc/nfc-nci.c
@@ -0,0 +1,764 @@
+/* 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include "nfc-nci.h"
+
+
+struct qca199x_platform_data {
+ unsigned int irq_gpio;
+ unsigned int dis_gpio;
+ unsigned int ven_gpio;
+ unsigned int reg;
+};
+
+static struct of_device_id msm_match_table[] = {
+ {.compatible = "qcom,nfc-nci"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_match_table);
+
+#define MAX_BUFFER_SIZE (780)
+/* Read data */
+#define PACKET_HEADER_SIZE_NCI (4)
+#define PACKET_TYPE_NCI (16)
+#define MAX_PACKET_SIZE (PACKET_HEADER_SIZE_NCI + 255)
+#define MAX_QCA_REG (116)
+
+static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
+
+struct qca199x_dev {
+ wait_queue_head_t read_wq;
+ struct mutex read_mutex;
+ struct i2c_client *client;
+ struct miscdevice qca199x_device;
+ unsigned int irq_gpio;
+ unsigned int dis_gpio;
+ unsigned int ven_gpio;
+ bool irq_enabled;
+ spinlock_t irq_enabled_lock;
+ unsigned int count_irq;
+};
+
+/*
+ * To allow filtering of nfc logging from user. This is set via
+ * IOCTL NFC_KERNEL_LOGGING_MODE.
+ */
+static int logging_level;
+
+static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
+{
+ qca199x_dev->count_irq = 0;
+}
+
+static void qca199x_disable_irq(struct qca199x_dev *qca199x_dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+ if (qca199x_dev->irq_enabled) {
+ disable_irq_nosync(qca199x_dev->client->irq);
+ qca199x_dev->irq_enabled = false;
+ }
+ spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+}
+
+static void qca199x_enable_irq(struct qca199x_dev *qca199x_dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+ if (!qca199x_dev->irq_enabled) {
+ qca199x_dev->irq_enabled = true;
+ enable_irq(qca199x_dev->client->irq);
+ }
+ spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+}
+
+static irqreturn_t qca199x_dev_irq_handler(int irq, void *dev_id)
+{
+ struct qca199x_dev *qca199x_dev = dev_id;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+ qca199x_dev->count_irq++;
+ spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+ wake_up(&qca199x_dev->read_wq);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int nfc_poll(struct file *filp, poll_table *wait)
+{
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+ unsigned int mask = 0;
+ unsigned long flags;
+
+
+ poll_wait(filp, &qca199x_dev->read_wq, wait);
+
+ spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+ if (qca199x_dev->count_irq > 0) {
+ qca199x_dev->count_irq--;
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+
+
+ return mask;
+}
+
+static ssize_t nfc_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+ unsigned char tmp[MAX_BUFFER_SIZE];
+ unsigned char len[PAYLOAD_HEADER_LENGTH];
+ int total, length, ret;
+
+ total = 0;
+ length = 0;
+ if (count > MAX_BUFFER_SIZE)
+ count = MAX_BUFFER_SIZE;
+
+ mutex_lock(&qca199x_dev->read_mutex);
+ /* Read the header */
+ ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
+ if (ret != PAYLOAD_HEADER_LENGTH)
+ goto err;
+ length = len[PAYLOAD_HEADER_LENGTH - 1];
+
+ /** make sure full packet fits in the buffer **/
+ if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) {
+ /* Read the packet */
+ ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
+ PAYLOAD_HEADER_LENGTH));
+ if (ret < 0)
+ goto err;
+ total = (length + PAYLOAD_HEADER_LENGTH);
+ }
+ mutex_unlock(&qca199x_dev->read_mutex);
+ if (total > 0) {
+ if ((total > count) || copy_to_user(buf, tmp, total)) {
+ dev_err(&qca199x_dev->client->dev,
+ "failed to copy to user space, total = %d\n",
+ total);
+ total = -EFAULT;
+ }
+ }
+err:
+ if (ret < 0)
+ mutex_unlock(&qca199x_dev->read_mutex);
+
+ return total;
+}
+
+static ssize_t nfc_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+ char tmp[MAX_BUFFER_SIZE];
+ int ret;
+
+ if (count > MAX_BUFFER_SIZE) {
+ dev_err(&qca199x_dev->client->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+ if (copy_from_user(tmp, buf, count)) {
+ dev_err(&qca199x_dev->client->dev,
+ "nfc-nci write: failed to copy from user space\n");
+ return -EFAULT;
+ }
+ mutex_lock(&qca199x_dev->read_mutex);
+ ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ if (ret != count) {
+ dev_err(&qca199x_dev->client->dev,
+ "NFC: failed to write %d\n", ret);
+ ret = -EIO;
+ }
+ mutex_unlock(&qca199x_dev->read_mutex);
+
+ return ret;
+}
+
+static int nfc_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+
+ struct qca199x_dev *qca199x_dev = container_of(filp->private_data,
+ struct qca199x_dev,
+ qca199x_device);
+
+ filp->private_data = qca199x_dev;
+ qca199x_init_stat(qca199x_dev);
+ qca199x_enable_irq(qca199x_dev);
+ dev_dbg(&qca199x_dev->client->dev,
+ "%d,%d\n", imajor(inode), iminor(inode));
+ return ret;
+}
+
+/*
+ * Wake/Sleep Mode
+ */
+int nfcc_wake(int level, struct nfc_info *info)
+{
+ int r = 0;
+ unsigned char raw_nci_sleep[] = {0x2F, 0x03, 0x00};
+ /* Change slave address to 0xE */
+ unsigned char raw_nci_wake[] = {0x10, 0x0F};
+ unsigned short slave_addr = 0xE;
+ unsigned short curr_addr;
+
+ struct i2c_client *client = info->i2c_dev;
+
+ dev_dbg(&client->dev, "nfcc_wake: %s: info: %p\n", __func__, info);
+
+ if (level == NFCC_SLEEP) {
+ r = nfc_i2c_write(client, &raw_nci_sleep[0],
+ sizeof(raw_nci_sleep));
+
+ if (r != sizeof(raw_nci_sleep))
+ return -EMSGSIZE;
+ info->state = NFCC_STATE_NORMAL_SLEEP;
+ } else {
+ curr_addr = client->addr;
+ client->addr = slave_addr;
+ r = nfc_i2c_write(client, &raw_nci_wake[0],
+ sizeof(raw_nci_wake));
+ /* Restore original NFCC slave I2C address */
+ client->addr = curr_addr;
+
+ if (r != sizeof(raw_nci_sleep))
+ return -EMSGSIZE;
+
+ info->state = NFCC_STATE_NORMAL_WAKE;
+ }
+ msleep(20);
+ return r;
+}
+
+/*
+ * Inside nfc_ioctl_power_states
+ *
+ * @brief ioctl functions
+ *
+ *
+ * Device control
+ * remove control via ioctl
+ * (arg = 0): NFC_DISABLE GPIO = 0
+ * (arg = 1): NFC_DISABLE GPIO = 1
+ * NOT USED (arg = 2): FW_DL GPIO = 0
+ * NOT USED (arg = 3): FW_DL GPIO = 1
+ * (arg = 4): NFCC_WAKE = 1
+ * (arg = 5): NFCC_WAKE = 0
+ *
+ *
+ */
+int nfc_ioctl_power_states(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int r = 0;
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+ struct nfc_info *info = container_of(filp->private_data,
+ struct nfc_info, miscdev);
+
+ struct i2c_client *client = info->i2c_dev;
+
+ r = gpio_request(qca199x_dev->dis_gpio, "nfc_reset_gpio");
+ if (r) {
+ dev_err(&client->dev, "unable to request gpio [%d]\n",
+ qca199x_dev->dis_gpio);
+ goto err_req;
+ }
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
+ r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+ if (r) {
+ dev_err(&client->dev, "unable to set direction for gpio [%d]\n",
+ qca199x_dev->irq_gpio);
+ goto err_req;
+ }
+
+ if (arg == 0) {
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
+ msleep(20);
+ } else if (arg == 1) {
+ gpio_set_value(qca199x_dev->dis_gpio, 1);
+ msleep(20);
+ } else if (arg == 2) {
+ msleep(20);
+ } else if (arg == 3) {
+ msleep(20);
+ } else if (arg == 4) {
+ nfcc_wake(NFCC_WAKE, info);
+ msleep(20);
+ } else if (arg == 5) {
+ nfcc_wake(NFCC_SLEEP, info);
+ msleep(20);
+ } else {
+ r = -ENOIOCTLCMD;
+ }
+
+err_req:
+ return r;
+}
+
+/*
+ * Inside nfc_ioctl_kernel_logging
+ *
+ * @brief nfc_ioctl_kernel_logging
+ *
+ * (arg = 0) ; NO_LOGGING
+ * (arg = 1) ; COMMS_LOGGING - BASIC LOGGING - Mainly just comms over I2C
+ * (arg = 2) ; FULL_LOGGING - ENABLE ALL - DBG messages for handlers etc.
+ * ; ! Be aware as amount of logging could impact behaviour !
+ *
+ *
+ */
+int nfc_ioctl_kernel_logging(unsigned long arg, struct file *filp)
+{
+ int retval = 0;
+ struct qca199x_dev *qca199x_dev = container_of(filp->private_data,
+ struct qca199x_dev,
+ qca199x_device);
+ if (arg == 0) {
+ dev_dbg(&qca199x_dev->client->dev,
+ "nfc_ioctl_kernel_logging : level = NO_LOGGING\n");
+ logging_level = 0;
+ } else if (arg == 1) {
+ dev_dbg(&qca199x_dev->client->dev,
+ "nfc_ioctl_kernel_logging: level = COMMS_LOGGING only\n");
+ logging_level = 1;
+ } else if (arg == 2) {
+ dev_dbg(&qca199x_dev->client->dev,
+ "nfc_ioctl_kernel_logging: level = FULL_LOGGING\n");
+ logging_level = 2;
+ }
+ return retval;
+}
+
+static long nfc_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
+{
+ int r = 0;
+
+ switch (cmd) {
+
+ case NFC_SET_PWR:
+ nfc_ioctl_power_states(pfile, cmd, arg);
+ break;
+ case NFCC_MODE:
+ break;
+ case NFC_KERNEL_LOGGING_MODE:
+ nfc_ioctl_kernel_logging(arg, pfile);
+ break;
+ case SET_RX_BLOCK:
+ break;
+ case SET_EMULATOR_TEST_POINT:
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ }
+ return r;
+}
+
+static const struct file_operations nfc_dev_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .poll = nfc_poll,
+ .read = nfc_read,
+ .write = nfc_write,
+ .open = nfc_open,
+ .unlocked_ioctl = nfc_ioctl
+};
+
+void dumpqca1990(struct i2c_client *client)
+{
+ int r = 0;
+ int i = 0;
+ unsigned char raw_reg_rd = {0x0};
+ unsigned short temp_addr;
+
+ temp_addr = client->addr;
+ client->addr = 0x0E;
+
+ for (i = 0; i < MAX_QCA_REG; i++) {
+ raw_reg_rd = i;
+ if (((i >= 0x0) && (i < 0x4)) || ((i > 0x7) && (i < 0xA)) ||
+ ((i > 0xF) && (i < 0x12)) || ((i > 0x39) && (i < 0x4d)) ||
+ ((i > 0x69) && (i < 0x74)) || (i == 0x18) || (i == 0x30) ||
+ (i == 0x58)) {
+ r = nfc_i2c_write(client, &raw_reg_rd, 1);
+ msleep(20);
+ r = i2c_master_recv(client, &raw_reg_rd, 1);
+ }
+ }
+ client->addr = temp_addr;
+}
+
+static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len)
+{
+ int r;
+
+ r = i2c_master_send(client, buf, len);
+ dev_dbg(&client->dev, "send: %d\n", r);
+ if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+ usleep_range(6000, 10000);
+ r = i2c_master_send(client, buf, len);
+ dev_dbg(&client->dev, "send2: %d\n", r);
+ }
+ if (r != len)
+ return -EREMOTEIO;
+
+ return r;
+}
+
+int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
+{
+ int r = 0;
+ unsigned char raw_1p8_CONTROL_011[] = {0x11, XTAL_CLOCK};
+ unsigned char raw_1P8_CONTROL_010[] = {0x10, PWR_EN};
+ unsigned char raw_1P8_X0_0B0[] = {0xB0, (FREQ_SEL)};
+ unsigned char raw_slave1[] = {0x09, NCI_I2C_SLAVE};
+ unsigned char raw_slave2[] = {0x8, 0x10};
+ unsigned char raw_s73[] = {0x73, 0x02};
+ unsigned char raw_slave1_rd = {0x0};
+ unsigned char raw_1P8_PAD_CFG_CLK_REQ[] = {0xA5, 0x1};
+ unsigned char buf[4];
+
+ /* Set I2C address to enable configuration of QCA1990 */
+ client->addr = curr_addr;
+ RAW(s73, 0x02);
+
+ r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+ usleep(1000);
+ RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+
+ r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+ sizeof(raw_1p8_CONTROL_011));
+ usleep(1000);
+ RAW(1P8_CONTROL_010, (0x8));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+
+ usleep(10000); /* 10ms wait */
+ RAW(1P8_CONTROL_010, (0xC));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(100); /* 100uS wait */
+ RAW(1P8_X0_0B0, (FREQ_SEL_19));
+ r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0], sizeof(raw_1P8_X0_0B0));
+ usleep(1000);
+
+ /* PWR_EN = 1 */
+ RAW(1P8_CONTROL_010, (0xd));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(20000); /* 20ms wait */
+ /* LS_EN = 1 */
+ RAW(1P8_CONTROL_010, 0xF);
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(20000); /* 20ms wait */
+
+ /* Enable the PMIC clock */
+ RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+ sizeof(raw_1P8_PAD_CFG_CLK_REQ));
+ usleep(1000);
+
+ RAW(slave2, 0x10);
+ r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+ usleep(1000);
+ {
+ r = i2c_master_send(client, buf, 1);
+ memset(buf, 0xAA, sizeof(buf));
+ r = i2c_master_recv(client, buf, 1);
+ }
+ RAW(slave1, NCI_I2C_SLAVE);
+ r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+ usleep(1000);
+
+ /* QCA199x NFCC CPU should now boot... */
+ r = i2c_master_recv(client, &raw_slave1_rd, 1);
+ /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+ client->addr = NCI_I2C_SLAVE;
+
+ return r;
+}
+
+static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata)
+{
+ int r = 0;
+ struct device_node *np = dev->of_node;
+
+ r = of_property_read_u32(np, "reg", &pdata->reg);
+ if (r)
+ return -EINVAL;
+
+ r = of_property_read_u32(np, "qcom,clk-gpio", &pdata->ven_gpio);
+ if (r)
+ return -EINVAL;
+
+ pdata->dis_gpio = of_get_named_gpio(np, "qcom,dis-gpio", 0);
+ if ((!gpio_is_valid(pdata->dis_gpio)))
+ return -EINVAL;
+
+ pdata->irq_gpio = of_get_named_gpio(np, "qcom,irq-gpio", 0);
+ if ((!gpio_is_valid(pdata->irq_gpio)))
+ return -EINVAL;
+
+ return r;
+}
+
+static int qca199x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int r = 0;
+ int irqn = 0;
+ struct clk *nfc_clk;
+ struct device_node *node = client->dev.of_node;
+ struct qca199x_platform_data *platform_data;
+ struct qca199x_dev *qca199x_dev;
+
+ if (client->dev.of_node) {
+ platform_data = devm_kzalloc(&client->dev,
+ sizeof(struct qca199x_platform_data), GFP_KERNEL);
+ if (!platform_data) {
+ dev_err(&client->dev,
+ "nfc-nci probe: Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ r = nfc_parse_dt(&client->dev, platform_data);
+ if (r)
+ return r;
+ } else {
+ platform_data = client->dev.platform_data;
+ }
+ if (!platform_data)
+ return -EINVAL;
+ dev_dbg(&client->dev,
+ "nfc-nci probe: %s, inside nfc-nci flags = %x\n",
+ __func__, client->flags);
+ if (platform_data == NULL) {
+ dev_err(&client->dev, "nfc-nci probe: failed\n");
+ return -ENODEV;
+ }
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "nfc-nci probe: need I2C_FUNC_I2C\n");
+ return -ENODEV;
+ }
+ qca199x_dev = kzalloc(sizeof(*qca199x_dev), GFP_KERNEL);
+ if (qca199x_dev == NULL) {
+ dev_err(&client->dev,
+ "nfc-nci probe: failed to allocate memory for module data\n");
+ return -ENOMEM;
+ }
+ if (gpio_is_valid(platform_data->irq_gpio)) {
+ r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
+ if (r) {
+ dev_err(&client->dev, "unable to request gpio [%d]\n",
+ platform_data->irq_gpio);
+ goto err_irq;
+ }
+ r = gpio_direction_input(platform_data->irq_gpio);
+ if (r) {
+
+ dev_err(&client->dev,
+ "unable to set direction for gpio [%d]\n",
+ platform_data->irq_gpio);
+ goto err_irq;
+ }
+ gpio_to_irq(0);
+ irqn = gpio_to_irq(platform_data->irq_gpio);
+ if (irqn < 0) {
+ r = irqn;
+ goto err_irq;
+ }
+ client->irq = irqn;
+
+ } else {
+ dev_err(&client->dev, "irq gpio not provided\n");
+ goto err_free_dev;
+ }
+ if (gpio_is_valid(platform_data->dis_gpio)) {
+ r = gpio_request(platform_data->dis_gpio, "nfc_reset_gpio");
+ if (r) {
+ dev_err(&client->dev,
+ "NFC: unable to request gpio [%d]\n",
+ platform_data->dis_gpio);
+ goto err_dis_gpio;
+ }
+ r = gpio_direction_output(platform_data->dis_gpio, 1);
+ if (r) {
+ dev_err(&client->dev,
+ "NFC: unable to set direction for gpio [%d]\n",
+ platform_data->dis_gpio);
+ goto err_dis_gpio;
+ }
+ } else {
+ dev_err(&client->dev, "dis gpio not provided\n");
+ goto err_irq;
+ }
+
+ nfc_clk = clk_get(&client->dev, "ref_clk");
+
+ if (nfc_clk == NULL)
+ goto err_dis_gpio;
+
+ r = clk_prepare_enable(nfc_clk);
+ if (r)
+ goto err_dis_gpio;
+
+ platform_data->ven_gpio = of_get_named_gpio(node,
+ "qcom,clk-gpio", 0);
+
+ if (gpio_is_valid(platform_data->ven_gpio)) {
+ r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio");
+ if (r) {
+ dev_err(&client->dev, "unable to request gpio [%d]\n",
+ platform_data->irq_gpio);
+ goto err_ven_gpio;
+ }
+ r = gpio_direction_input(platform_data->ven_gpio);
+ if (r) {
+
+ dev_err(&client->dev,
+ "unable to set direction for gpio [%d]\n",
+ platform_data->irq_gpio);
+ goto err_ven_gpio;
+ }
+
+ } else {
+
+ dev_err(&client->dev, "ven gpio not provided\n");
+ goto err_dis_gpio;
+ }
+ qca199x_dev->dis_gpio = platform_data->dis_gpio;
+ qca199x_dev->irq_gpio = platform_data->irq_gpio;
+ qca199x_dev->ven_gpio = platform_data->ven_gpio;
+ qca199x_dev->client = client;
+
+ /* init mutex and queues */
+ init_waitqueue_head(&qca199x_dev->read_wq);
+ mutex_init(&qca199x_dev->read_mutex);
+ spin_lock_init(&qca199x_dev->irq_enabled_lock);
+
+ qca199x_dev->qca199x_device.minor = MISC_DYNAMIC_MINOR;
+ qca199x_dev->qca199x_device.name = "nfc-nci";
+ qca199x_dev->qca199x_device.fops = &nfc_dev_fops;
+
+ r = misc_register(&qca199x_dev->qca199x_device);
+ if (r) {
+ dev_err(&client->dev, "misc_register failed\n");
+ goto err_misc_register;
+ }
+
+ logging_level = 0;
+ /* request irq. The irq is set whenever the chip has data available
+ * for reading. It is cleared when all data has been read.
+ */
+ nfcc_initialise(client, platform_data->reg);
+
+ qca199x_dev->irq_enabled = true;
+ r = request_irq(client->irq, qca199x_dev_irq_handler,
+ IRQF_TRIGGER_RISING, client->name, qca199x_dev);
+ if (r) {
+ dev_err(&client->dev, "nfc-nci probe: request_irq failed\n");
+ goto err_request_irq_failed;
+ }
+ qca199x_disable_irq(qca199x_dev);
+ i2c_set_clientdata(client, qca199x_dev);
+ dev_dbg(&client->dev,
+ "nfc-nci probe: %s, probing qca1990 exited successfully\n",
+ __func__);
+ return 0;
+
+err_request_irq_failed:
+ misc_deregister(&qca199x_dev->qca199x_device);
+err_misc_register:
+ mutex_destroy(&qca199x_dev->read_mutex);
+err_ven_gpio:
+ gpio_free(platform_data->ven_gpio);
+err_dis_gpio:
+ gpio_free(platform_data->dis_gpio);
+err_irq:
+ gpio_free(platform_data->irq_gpio);
+err_free_dev:
+ kfree(qca199x_dev);
+ return r;
+}
+
+static int qca199x_remove(struct i2c_client *client)
+{
+ struct qca199x_dev *qca199x_dev;
+
+ qca199x_dev = i2c_get_clientdata(client);
+ free_irq(client->irq, qca199x_dev);
+ misc_deregister(&qca199x_dev->qca199x_device);
+ mutex_destroy(&qca199x_dev->read_mutex);
+ gpio_free(qca199x_dev->irq_gpio);
+ gpio_free(qca199x_dev->dis_gpio);
+ gpio_free(qca199x_dev->ven_gpio);
+ kfree(qca199x_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id qca199x_id[] = {
+ {"qca199x-i2c", 0},
+ {}
+};
+
+static struct i2c_driver qca199x = {
+ .id_table = qca199x_id,
+ .probe = qca199x_probe,
+ .remove = qca199x_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "nfc-nci",
+ .of_match_table = msm_match_table,
+ },
+};
+
+/*
+ * module load/unload record keeping
+ */
+static int __init qca199x_dev_init(void)
+{
+ return i2c_add_driver(&qca199x);
+}
+module_init(qca199x_dev_init);
+
+static void __exit qca199x_dev_exit(void)
+{
+ i2c_del_driver(&qca199x);
+}
+module_exit(qca199x_dev_exit);
+
+MODULE_DESCRIPTION("NFC QCA199x");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
new file mode 100644
index 0000000..4398df7
--- /dev/null
+++ b/drivers/nfc/nfc-nci.h
@@ -0,0 +1,222 @@
+/* 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 __NFC_NCI_H
+#define __NFC_NCI_H
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include <linux/semaphore.h>
+#include <linux/completion.h>
+
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/miscdevice.h>
+
+struct nfc_device {
+ struct cdev cdev;
+ struct class *char_class;
+};
+
+enum ehandler_mode {
+ UNSOLICITED_READ_MODE = 0,
+ SOLICITED_READ_MODE
+};
+
+enum ekernel_logging_mode {
+ LEVEL_0 = 0, /* For Basic Comms, such asNCI TX/TX to NFCC */
+ LEVEL_1, /* Other Debug e.g. Notifications, ISR hit, etc ..*/
+ LEVEL_2,
+ LEVEL_3,
+ LEVEL_4,
+ LEVEL_5
+};
+
+struct DeviceMode {
+ enum ehandler_mode handle_flavour;
+} tDeviceMode;
+
+#define NFC_DRIVER_NAME "nfc-nci"
+#define NFC_I2C_DRIVER_NAME "NCI NFC I2C Interface",
+
+#define NCI_I2C_SLAVE (0x2C)
+#define NFC_I2C_BUS 3 /* 6, 10, 4, 5 */
+#define NFC_SET_PWR _IOW(0xE9, 0x01, unsigned int)
+#define NFCC_MODE _IOW(0xE9, 0x02, unsigned int)
+#define NFC_KERNEL_LOGGING_MODE _IOW(0xE9, 0x03, unsigned int)
+#define SET_RX_BLOCK _IOW(0xE9, 0x04, unsigned int)
+#define SET_EMULATOR_TEST_POINT _IOW(0xE9, 0x05, unsigned int)
+
+#define NFC_MAX_I2C_TRANSFER (0x0400)
+#define NFC_MSG_MAX_SIZE (0x21)
+
+#define NFC_RX_BUFFER_CNT_START (0x0)
+
+#define NFC_RX_BUFFER_BLOCK_SIZE (0x120) /* Bytes per Block */
+#define NFC_RX_BUFFER_PAGE_SIZE (0x1000) /* Page size Bytes */
+#define NFC_RX_BUFFER_PAGES (0x8)
+#define NFC_RX_ORDER_FREE_PAGES (0x3) /* Free 8 Pages */
+
+/* The total no. of Blocks */
+#define NFC_RX_BUFFER_CNT_LIMIT (unsigned short)( \
+ ( \
+ ((NFC_RX_BUFFER_PAGE_SIZE) *\
+ (NFC_RX_BUFFER_PAGES))/\
+ (NFC_RX_BUFFER_BLOCK_SIZE)\
+ ) \
+ ) \
+
+#define PAYLOAD_HEADER_LENGTH (0x3)
+#define PAYLOAD_LENGTH_MAX (256)
+#define BYTE (0x8)
+#define NCI_IDENTIFIER (0x10)
+
+/** Power Management Related **/
+
+#define NFCC_WAKE (0x01)
+#define NFCC_SLEEP (0x00)
+
+#define XTAL_CLOCK (0X00)
+#define REFERENCE_CLOCK (0X01)
+
+/* LDO Trim Settings */
+#define IPTAT_TRIM (0x1F)
+#define V1P1_TRIM (0x0F)
+#define V1P8_TRIM (0x0F)
+#define VBATT_OK_THRESHOLD (0x07)
+
+#define PWR_EN (0x08) /* Enable 1.1V LDO Regulator */
+#define LS_EN (0x04) /* Enable 1.1V->1.8V Level Shifters */
+
+/* Write '1' to cause wake event to NFCC. If set NFCC will not go to SLEEP */
+#define NCI_WAKE (0x02)
+
+#define NCI_ENA (0x01) /* Write '1' to enable PLL */
+#define FREQ_SEL (0x00) /* XO Frequency Select */
+#define FREQ_SEL_13 (0x00) /* XO Frequency Select = 13.56MHz */
+#define FREQ_SEL_19 (0x01) /* XO Frequency Select = 19.20 MHz */
+#define FREQ_SEL_26 (0x02) /* XO Frequency Select = 26.00 MHz */
+#define FREQ_SEL_27 (0x03) /* XO Frequency Select = 27.12 MHz */
+#define FREQ_SEL_37 (0x04) /* XO Frequency Select = 37.40 MHz */
+#define FREQ_SEL_38 (0x05) /* XO Frequency Select = 38.40 MHz */
+#define FREQ_SEL_40 (0x06) /* XO Frequency Select = 40.00 MHz */
+#define FREQ_SEL_48 (0x07) /* XO Frequency Select = 48.00 MHz */
+#define FREQ_SEL_27 (0x03) /* XO Frequency Select */
+
+
+#define QUALIFY_REFCLK (0x80)
+#define QUALIFY_OSC (0x40)
+#define LOCALBIASXTAL (0x20)
+#define BIAS2X_FORCE (0x10)
+#define BIAS2X (0x08)
+#define LBIAS2X (0x04)
+#define SMALLRF (0x02)
+#define SMALLRBIAS (0x01)
+
+/* Select as appropriate */
+#define CRYSTAL_OSC ((QUALIFY_REFCLK) | (QUALIFY_OSC) | \
+ (LOCALBIASXTAL) | (BIAS2X_FORCE) | \
+ (BIAS2X) | (LBIAS2X) | (SMALLRF) | (SMALLRBIAS))
+
+#define CDACIN (0x3F) /* Tuning range for load capacitor at X1*/
+#define CDACOUT (0x3F) /* Tuning range for load capacitor at X2*/
+
+#define RAW(reg, value) (raw_##reg[1] = value)
+
+/* Logging macro with threshold control */
+#define PRINTK(LEVEL, THRESHOLD, pString, ...) ( \
+ if (LEVEL > THRESHOLD) { \
+ pr_info(pString, ##__VA_ARGS__); \
+ } \
+ )
+
+/* board config */
+struct nfc_platform_data {
+ int (*request_resources) (struct i2c_client *client);
+ void (*free_resources) (void);
+ void (*enable) (int fw);
+ int (*test) (void);
+ void (*disable) (void);
+};
+/*
+ * Internal NFCC Hardware states. At present these may not be possible to
+ * detect in software as possibly no power when
+ * in monitor state! Also, need to detect DISABLE control GPIO from PMIC.
+ */
+enum nfcc_hardware_state {
+ NFCC_STATE_MONITOR, /* VBAT < h/w Critcal Voltage */
+ /* VBAT > H/W Critical Voltage;
+ Lowest Power Mode - DISABLE = 1; only
+ possible when phone is ON */
+ NFCC_STATE_HPD,
+ /* VBAT > H/W Critical Voltage; DISABLE = 0;
+ Only possible when phone is ON */
+ NFCC_STSTE_ULPM,
+ /* VBAT > H/W Critical Voltage; DISABLE = 0;
+ Powered by PMIC & VBAT; 1.8V I/O supply on; VDDPX available, boot is
+ initiated by host over I2C */
+ NFCC_STATE_NORMAL_REGION1,
+ /* VBAT > H/W Critical Voltage; DISABLE = 0;
+ Powered by VBAT; 1.8V I/O supply on; VDDPX available, boot is initiated
+ by host over I2C */
+ NFCC_STATE_NORMAL_REGION2,
+};
+
+/* We assume here that VBATT > h/w Critical Voltage */
+enum nfcc_state {
+ /* Assume In ULPM state, ready for initialisation, cannot detect for
+ Monitor or HPD states */
+ NFCC_STATE_COLD,
+ /* (VDDPX==1) && (Following I2C initialisation). In Region 1 or Region2
+ state WAKE */
+ NFCC_STATE_NORMAL_WAKE,
+ /* (VDDPX==1) && (Following I2C initialisation). In Region 1 or Region2
+ state SLEEP */
+ NFCC_STATE_NORMAL_SLEEP,
+};
+
+
+enum nfcc_irq {
+ NFCC_NO_INT,
+ NFCC_INT,
+};
+
+
+struct nfc_info {
+ struct miscdevice miscdev;
+ struct i2c_client *i2c_dev;
+ struct regulator_bulk_data regs[3];
+ enum nfcc_state state;
+ wait_queue_head_t read_wait;
+ loff_t read_offset;
+ struct mutex read_mutex;
+ struct mutex mutex;
+ u8 *buf;
+ size_t buflen;
+ spinlock_t irq_enabled_lock;
+ unsigned int count_irq;
+ enum nfcc_irq read_irq;
+};
+
+
+struct nfc_i2c_platform_data {
+ unsigned int nfc_irq_gpio;
+ unsigned int nfc_clk_en_gpio;
+ unsigned int dis_gpio;
+ unsigned int irq_gpio;
+ unsigned int ven_gpio;
+ unsigned int firm_gpio;
+ unsigned int reg;
+};
+#endif
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 4921ec2..ae9277e 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -1469,6 +1469,35 @@
return ret;
}
+/**
+ * a2_mux_is_ch_empty() - checks if channel is empty.
+ * @lcid: logical channel ID
+ *
+ * Returns: true if the channel is empty,
+ * false otherwise
+ */
+int a2_mux_is_ch_empty(enum a2_mux_logical_channel_id lcid)
+{
+ unsigned long flags;
+ int ret;
+
+ if (lcid >= A2_MUX_NUM_CHANNELS ||
+ lcid < 0)
+ return -EINVAL;
+ if (!a2_mux_ctx->a2_mux_initialized)
+ return -ENODEV;
+ spin_lock_irqsave(&a2_mux_ctx->bam_ch[lcid].lock, flags);
+ a2_mux_ctx->bam_ch[lcid].use_wm = 1;
+ ret = a2_mux_ctx->bam_ch[lcid].num_tx_pkts == 0;
+ if (!bam_ch_is_local_open(lcid)) {
+ ret = -ENODEV;
+ IPAERR("%s: port not open: %d\n", __func__,
+ a2_mux_ctx->bam_ch[lcid].status);
+ }
+ spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[lcid].lock, flags);
+ return ret;
+}
+
static int a2_mux_initialize_context(int handle)
{
int i;
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 0724aa3..f5d7b6e 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -140,7 +140,7 @@
static bool hdr_tbl_lcl = 1;
module_param(hdr_tbl_lcl, bool, 0644);
MODULE_PARM_DESC(hdr_tbl_lcl, "where hdr tbl resides 1-local; 0-system");
-static bool ip4_rt_tbl_lcl = 1;
+static bool ip4_rt_tbl_lcl;
module_param(ip4_rt_tbl_lcl, bool, 0644);
MODULE_PARM_DESC(ip4_rt_tbl_lcl,
"where ip4 rt tables reside 1-local; 0-system");
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 83c4db0..f9401f0 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -468,7 +468,7 @@
{
int i;
- ipa_ctx->smem_pipe_mem = smem_alloc(SMEM_BAM_PIPE_MEMORY,
+ ipa_ctx->smem_pipe_mem = smem_alloc2(SMEM_BAM_PIPE_MEMORY,
IPA_SMEM_PIPE_MEM_SZ);
if (!ipa_ctx->smem_pipe_mem) {
IPAERR("smem alloc failed\n");
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index e98c9b7..f20f37f 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -203,6 +203,7 @@
}
memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
+ ipa_enable_data_path(ipa_ep_idx);
ep->valid = 1;
ep->client = in->client;
@@ -380,7 +381,6 @@
return -EPERM;
}
- ipa_enable_data_path(clnt_hdl);
memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
ipa_dec_client_disable_clks();
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index 87ddf59..c429414 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -113,6 +113,7 @@
{
int nbytes;
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA_VERSION=0x%x\n"
@@ -143,6 +144,7 @@
ipa_read_reg(ipa_ctx->mmio, IPA_FILTER_OFST_v2),
ipa_read_reg(ipa_ctx->mmio, IPA_SHARED_MEM_SIZE_OFST_v2)
);
+ ipa_dec_client_disable_clks();
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
@@ -241,6 +243,7 @@
end_idx = start_idx + 1;
}
pos = *ppos;
+ ipa_inc_client_enable_clks();
for (i = start_idx; i < end_idx; i++) {
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
@@ -292,13 +295,16 @@
*ppos = pos;
ret = simple_read_from_buffer(ubuf, count, ppos, dbg_buff,
nbytes);
- if (ret < 0)
+ if (ret < 0) {
+ ipa_dec_client_disable_clks();
return ret;
+ }
size += ret;
ubuf += nbytes;
count -= nbytes;
}
+ ipa_dec_client_disable_clks();
*ppos = pos + size;
return size;
@@ -500,6 +506,32 @@
set = &ipa_ctx->rt_tbl_set[ip];
mutex_lock(&ipa_ctx->lock);
+ if (ip == IPA_IP_v6) {
+ if (ipa_ctx->ip6_rt_tbl_lcl) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN - cnt,
+ "Table Resides on local memory\n");
+ cnt += nbytes;
+ } else {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN - cnt,
+ "Table Resides on system(ddr) memory\n");
+ cnt += nbytes;
+ }
+ } else if (ip == IPA_IP_v4) {
+ if (ipa_ctx->ip4_rt_tbl_lcl) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN - cnt,
+ "Table Resides on local memory\n");
+ cnt += nbytes;
+ } else {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN - cnt,
+ "Table Resides on system(ddr) memory\n");
+ cnt += nbytes;
+ }
+ }
+
list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
i = 0;
list_for_each_entry(entry, &tbl->head_rt_rule_list, link) {
@@ -683,12 +715,14 @@
if (kstrtou32(dbg_buff, 0, &option))
return -EFAULT;
+ ipa_inc_client_enable_clks();
if (option == 1)
ipa_write_reg(ipa_ctx->mmio, IPA_DEBUG_CNT_CTRL_n_OFST(0),
IPA_DBG_CNTR_ON);
else
ipa_write_reg(ipa_ctx->mmio, IPA_DEBUG_CNT_CTRL_n_OFST(0),
IPA_DBG_CNTR_OFF);
+ ipa_dec_client_disable_clks();
return count;
}
@@ -698,10 +732,12 @@
{
int nbytes;
+ ipa_inc_client_enable_clks();
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA_DEBUG_CNT_REG_0=0x%x\n",
ipa_read_reg(ipa_ctx->mmio,
IPA_DEBUG_CNT_REG_n_OFST(0)));
+ ipa_dec_client_disable_clks();
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 1f232d4..e2856cf 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -641,7 +641,7 @@
switch (notify->event_id) {
case SPS_EVENT_EOT:
tx_pkt = notify->data.transfer.user;
- queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+ schedule_work(&tx_pkt->work);
break;
default:
IPAERR("recieved unexpected event id %d\n", notify->event_id);
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index edb9fb1..2d75141 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -634,12 +634,13 @@
return -EINVAL;
}
ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, ep);
- if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND ||
- ipa_ctx->ep[ipa_ep_idx].valid == 0) {
- IPAERR("ep not valid and/or connected ep_idx=%d\n", ipa_ep_idx);
-
+ if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) {
+ IPAERR("ep not valid ep=%d\n", ep);
return -EINVAL;
}
+ if (ipa_ctx->ep[ipa_ep_idx].valid == 0)
+ IPADBG("ep not connected ep_idx=%d\n", ipa_ep_idx);
+
tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][ip];
IPADBG("add ep flt rule ip=%d ep=%d\n", ip, ep);
diff --git a/drivers/platform/msm/ipa/ipa_ram_mmap.h b/drivers/platform/msm/ipa/ipa_ram_mmap.h
index 78093b8..20eb52a 100644
--- a/drivers/platform/msm/ipa/ipa_ram_mmap.h
+++ b/drivers/platform/msm/ipa/ipa_ram_mmap.h
@@ -21,16 +21,19 @@
#define IPA_RAM_NAT_OFST 0
#define IPA_RAM_NAT_SIZE 0
#define IPA_RAM_HDR_OFST (IPA_RAM_NAT_OFST + IPA_RAM_NAT_SIZE)
-#define IPA_RAM_HDR_SIZE 1280
+#define IPA_RAM_HDR_SIZE 1664
#define IPA_RAM_V4_FLT_OFST (IPA_RAM_HDR_OFST + IPA_RAM_HDR_SIZE)
-#define IPA_RAM_V4_FLT_SIZE 1408
+#define IPA_RAM_V4_FLT_SIZE 2176
#define IPA_RAM_V4_RT_OFST (IPA_RAM_V4_FLT_OFST + IPA_RAM_V4_FLT_SIZE)
-#define IPA_RAM_V4_RT_SIZE 2176
+#define IPA_RAM_V4_RT_SIZE 512
#define IPA_RAM_V6_FLT_OFST (IPA_RAM_V4_RT_OFST + IPA_RAM_V4_RT_SIZE)
-#define IPA_RAM_V6_FLT_SIZE 1280
+#define IPA_RAM_V6_FLT_SIZE 1792
#define IPA_RAM_V6_RT_OFST (IPA_RAM_V6_FLT_OFST + IPA_RAM_V6_FLT_SIZE)
#define IPA_RAM_V6_RT_SIZE 512
#define IPA_RAM_END_OFST (IPA_RAM_V6_RT_OFST + IPA_RAM_V6_RT_SIZE)
+
#define IPA_RAM_V6_RT_SIZE_DDR 16384
+#define IPA_RAM_V4_RT_SIZE_DDR 16384
#endif /* _IPA_RAM_MMAP_H_ */
+
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index e057c5a..64c77a0 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -119,12 +119,12 @@
{
int result;
- read_lock(&ipa_rm_ctx->lock);
+ write_lock(&ipa_rm_ctx->lock);
result = ipa_rm_dep_graph_add_dependency(
ipa_rm_ctx->dep_graph,
resource_name,
depends_on_name);
- read_unlock(&ipa_rm_ctx->lock);
+ write_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_add_dependency);
@@ -145,12 +145,12 @@
enum ipa_rm_resource_name depends_on_name)
{
int result;
- read_lock(&ipa_rm_ctx->lock);
+ write_lock(&ipa_rm_ctx->lock);
result = ipa_rm_dep_graph_delete_dependency(
ipa_rm_ctx->dep_graph,
resource_name,
depends_on_name);
- read_unlock(&ipa_rm_ctx->lock);
+ write_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_delete_dependency);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 5c27c40..8c0adbd 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -377,7 +377,8 @@
}
if (ip == IPA_IP_v4) {
- avail = IPA_RAM_V4_RT_SIZE;
+ avail = ipa_ctx->ip4_rt_tbl_lcl ? IPA_RAM_V4_RT_SIZE :
+ IPA_RAM_V4_RT_SIZE_DDR;
size = sizeof(struct ipa_ip_v4_routing_init);
} else {
avail = ipa_ctx->ip6_rt_tbl_lcl ? IPA_RAM_V6_RT_SIZE :
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 21a6dc4..e38b796 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -13,7 +13,9 @@
#include <net/ip.h>
#include <linux/genalloc.h> /* gen_pool_alloc() */
#include <linux/io.h>
+#include <linux/ratelimit.h>
#include "ipa_i.h"
+
static const int ipa_ofst_meq32[] = { IPA_OFFSET_MEQ32_0,
IPA_OFFSET_MEQ32_1, -1 };
static const int ipa_ofst_meq128[] = { IPA_OFFSET_MEQ128_0,
@@ -46,6 +48,7 @@
if (ipa_ctx->ipa_hw_type != IPA_HW_v1_0)
ipa_route_offset = IPA_ROUTE_OFST_v2;
+ ipa_inc_client_enable_clks();
ipa_write_reg(ipa_ctx->mmio, ipa_route_offset,
IPA_SETFIELD(route->route_dis,
IPA_ROUTE_ROUTE_DIS_SHFT,
@@ -59,6 +62,7 @@
IPA_SETFIELD(route->route_def_hdr_ofst,
IPA_ROUTE_ROUTE_DEF_HDR_OFST_SHFT,
IPA_ROUTE_ROUTE_DEF_HDR_OFST_BMSK));
+ ipa_dec_client_disable_clks();
return 0;
}
@@ -75,10 +79,12 @@
if (ipa_ctx->ipa_hw_type != IPA_HW_v1_0)
ipa_filter_ofst = IPA_FILTER_OFST_v2;
+ ipa_inc_client_enable_clks();
ipa_write_reg(ipa_ctx->mmio, ipa_filter_ofst,
IPA_SETFIELD(!disable,
IPA_FILTER_FILTER_EN_SHFT,
IPA_FILTER_FILTER_EN_BMSK));
+ ipa_dec_client_disable_clks();
return 0;
}
@@ -707,6 +713,7 @@
}
/* copy over EP cfg */
ipa_ctx->ep[clnt_hdl].cfg.nat = *ipa_ep_cfg;
+ ipa_inc_client_enable_clks();
/* clnt_hdl is used as pipe_index */
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
ipa_write_reg(ipa_ctx->mmio,
@@ -720,6 +727,7 @@
IPA_SETFIELD(ipa_ctx->ep[clnt_hdl].cfg.nat.nat_en,
IPA_ENDP_INIT_NAT_n_NAT_EN_SHFT,
IPA_ENDP_INIT_NAT_n_NAT_EN_BMSK));
+ ipa_dec_client_disable_clks();
return 0;
}
@@ -772,12 +780,14 @@
IPA_ENDP_INIT_HDR_n_HDR_A5_MUX_SHFT,
IPA_ENDP_INIT_HDR_n_HDR_A5_MUX_BMSK);
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_HDR_n_OFST_v1(clnt_hdl), val);
else
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_HDR_n_OFST_v2(clnt_hdl), val);
+ ipa_dec_client_disable_clks();
return 0;
}
@@ -826,12 +836,14 @@
IPA_ENDP_INIT_MODE_n_DEST_PIPE_INDEX_SHFT,
IPA_ENDP_INIT_MODE_n_DEST_PIPE_INDEX_BMSK);
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_MODE_n_OFST_v1(clnt_hdl), val);
else
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_MODE_n_OFST_v2(clnt_hdl), val);
+ ipa_dec_client_disable_clks();
return 0;
}
@@ -871,12 +883,14 @@
IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_SHFT,
IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_BMSK);
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_AGGR_n_OFST_v1(clnt_hdl), val);
else
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_AGGR_n_OFST_v2(clnt_hdl), val);
+ ipa_dec_client_disable_clks();
return 0;
}
@@ -919,6 +933,7 @@
/* always use the "default" routing tables whose indices are 0 */
ipa_ctx->ep[clnt_hdl].rt_tbl_idx = 0;
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_ROUTE_n_OFST_v1(clnt_hdl),
@@ -932,6 +947,7 @@
IPA_ENDP_INIT_ROUTE_n_ROUTE_TABLE_INDEX_SHFT,
IPA_ENDP_INIT_ROUTE_n_ROUTE_TABLE_INDEX_BMSK));
}
+ ipa_dec_client_disable_clks();
return 0;
}
@@ -970,12 +986,14 @@
return -EPERM;
} else {
ipa_ctx->ep[clnt_hdl].holb = *ipa_ep_cfg;
+ ipa_inc_client_enable_clks();
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(clnt_hdl),
ipa_ep_cfg->en);
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(clnt_hdl),
ipa_ep_cfg->tmr_val);
+ ipa_dec_client_disable_clks();
IPAERR("cfg holb %u ep=%d tmr=%d\n", ipa_ep_cfg->en, clnt_hdl,
ipa_ep_cfg->tmr_val);
}
@@ -1229,6 +1247,7 @@
{
u32 reg_val;
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
reg_val = ipa_read_reg(ipa_ctx->mmio,
IPA_AGGREGATION_SPARE_REG_2_OFST);
@@ -1243,6 +1262,7 @@
(reg_val & 0xfffffffe));
}
+ ipa_dec_client_disable_clks();
return 0;
}
EXPORT_SYMBOL(ipa_set_aggr_mode);
@@ -1262,11 +1282,12 @@
{
u32 reg_val;
+ if (sig == NULL) {
+ IPAERR("bad argument for ipa_set_qcncm_ndp_sig/n");
+ return -EINVAL;
+ }
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
- if (sig == NULL) {
- IPAERR("bad argument for ipa_set_qcncm_ndp_sig/n");
- return -EINVAL;
- }
reg_val = ipa_read_reg(ipa_ctx->mmio,
IPA_AGGREGATION_SPARE_REG_2_OFST);
ipa_write_reg(ipa_ctx->mmio,
@@ -1281,6 +1302,7 @@
(sig[1] << 12) | (sig[2] << 4) |
(reg_val & 0xf000000f));
}
+ ipa_dec_client_disable_clks();
return 0;
}
EXPORT_SYMBOL(ipa_set_qcncm_ndp_sig);
@@ -1296,6 +1318,7 @@
{
u32 reg_val;
+ ipa_inc_client_enable_clks();
if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
reg_val = ipa_read_reg(ipa_ctx->mmio,
IPA_AGGREGATION_SPARE_REG_1_OFST);
@@ -1308,6 +1331,7 @@
ipa_write_reg(ipa_ctx->mmio, IPA_SINGLE_NDP_MODE_OFST,
(enable & 0x1) | (reg_val & 0xfffffffe));
}
+ ipa_dec_client_disable_clks();
return 0;
}
EXPORT_SYMBOL(ipa_set_single_ndp_per_mbim);
@@ -1322,10 +1346,12 @@
int ipa_set_hw_timer_fix_for_mbim_aggr(bool enable)
{
u32 reg_val;
+ ipa_inc_client_enable_clks();
reg_val = ipa_read_reg(ipa_ctx->mmio, IPA_AGGREGATION_SPARE_REG_1_OFST);
ipa_write_reg(ipa_ctx->mmio, IPA_AGGREGATION_SPARE_REG_1_OFST,
(enable << IPA_AGGREGATION_HW_TIMER_FIX_MBIM_AGGR_SHFT) |
(reg_val & ~IPA_AGGREGATION_HW_TIMER_FIX_MBIM_AGGR_BMSK));
+ ipa_dec_client_disable_clks();
return 0;
}
EXPORT_SYMBOL(ipa_set_hw_timer_fix_for_mbim_aggr);
@@ -1358,3 +1384,26 @@
else
return 0;
}
+
+/**
+ * ipa_bam_reg_dump() - Dump selected BAM registers for IPA and DMA-BAM
+ *
+ * Function is rate limited to avoid flooding kernel log buffer
+ */
+void ipa_bam_reg_dump(void)
+{
+ static DEFINE_RATELIMIT_STATE(_rs, 500*HZ, 1);
+ if (__ratelimit(&_rs)) {
+ ipa_inc_client_enable_clks();
+ pr_err("IPA BAM START\n");
+ sps_get_bam_debug_info(ipa_ctx->bam_handle, 5, 1048575, 0, 0);
+ sps_get_bam_debug_info(ipa_ctx->bam_handle, 93, 0, 0, 0);
+ pr_err("BAM-DMA BAM START\n");
+ sps_get_bam_debug_info(sps_dma_get_bam_handle(), 5, 1044480,
+ 0, 0);
+ sps_get_bam_debug_info(sps_dma_get_bam_handle(), 93, 0, 0, 0);
+ ipa_dec_client_disable_clks();
+ }
+}
+EXPORT_SYMBOL(ipa_bam_reg_dump);
+
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index fae09fc..4889a79 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -153,7 +153,6 @@
bool prod_stopped;
struct completion prod_avail[MAX_BAMS];
- struct completion cons_released[MAX_BAMS];
struct completion prod_released[MAX_BAMS];
struct mutex suspend_resume_mutex;
@@ -175,7 +174,6 @@
static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param, bool trigger_cb_per_pipe);
static void wait_for_prod_release(enum usb_bam cur_bam);
-static void wait_for_cons_release(enum usb_bam cur_bam);
void msm_bam_set_hsic_host_dev(struct device *dev)
{
@@ -936,7 +934,6 @@
__func__, bam_enable_strings[cur_bam]);
info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&info.cons_released[cur_bam]);
spin_lock(&usb_bam_lock);
if (!ctx.pipes_enabled_per_bam[cur_bam]) {
@@ -1078,7 +1075,6 @@
pr_debug("%s producer already released\n", __func__);
init_completion(&info.prod_released[cur_bam]);
- init_completion(&info.cons_released[cur_bam]);
pr_debug("%s: Releasing %s_PROD\n", __func__,
bam_enable_strings[cur_bam]);
ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
@@ -1908,19 +1904,6 @@
return 0;
}
-static void wait_for_cons_release(enum usb_bam cur_bam)
-{
- pr_debug("%s: Waiting for CONS release\n", __func__);
- if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
- if (!wait_for_completion_timeout(&info.cons_released[cur_bam],
- USB_BAM_TIMEOUT))
- pr_err("%s: Timeout wainting for CONS_RELEASE\n",
- __func__);
- } else
- pr_debug("%s Didn't need to wait for CONS release\n",
- __func__);
-}
-
int usb_bam_disconnect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
int ret;
@@ -1987,7 +1970,6 @@
pipe_connect->priv = NULL;
cur_bam = pipe_connect->bam_type;
- wait_for_cons_release(cur_bam);
/* close IPA -> USB pipe */
ret = ipa_disconnect(ipa_params->cons_clnt_hdl);
if (ret) {
@@ -2542,8 +2524,6 @@
ctx.is_bam_inactivity[i] = false;
init_completion(&info.prod_avail[i]);
complete(&info.prod_avail[i]);
- init_completion(&info.cons_released[i]);
- complete(&info.cons_released[i]);
init_completion(&info.prod_released[i]);
complete(&info.prod_released[i]);
info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 14cba58..12aef1c 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -45,8 +45,10 @@
#define BMS1_OCV_USE_LIMIT_CTL 0x4C
/* Delay control */
#define BMS1_S1_DELAY_CTL 0x5A
-/* CC interrupt threshold */
-#define BMS1_CC_THR0 0x7A
+/* OCV interrupt threshold */
+#define BMS1_OCV_THR0 0x50
+/* SW CC interrupt threshold */
+#define BMS1_SW_CC_THR0 0xA0
/* OCV for r registers */
#define BMS1_OCV_FOR_R_DATA0 0x80
#define BMS1_VSENSE_FOR_R_DATA0 0x82
@@ -120,6 +122,16 @@
int chargecycles;
};
+struct bms_irq {
+ unsigned int irq;
+ unsigned long disabled;
+};
+
+struct bms_wakeup_source {
+ struct wakeup_source source;
+ unsigned long disabled;
+};
+
struct qpnp_bms_chip {
struct device *dev;
struct power_supply bms_psy;
@@ -176,7 +188,7 @@
int low_soc_calc_threshold;
int low_soc_calculate_soc_ms;
int calculate_soc_ms;
- struct wake_lock soc_wake_lock;
+ struct bms_wakeup_source soc_wake_source;
struct wake_lock cv_wake_lock;
uint16_t ocv_reading_at_100;
@@ -248,6 +260,8 @@
u8 charge_increase;
int fcc_new_sysfs;
int fcc_update_complete;
+ struct bms_irq sw_cc_thr_irq;
+ struct bms_irq ocv_thr_irq;
};
static struct of_device_id qpnp_bms_match_table[] = {
@@ -371,6 +385,38 @@
return qpnp_masked_write_base(chip, chip->base + addr, mask, val);
}
+static void bms_stay_awake(struct bms_wakeup_source *source)
+{
+ if (__test_and_clear_bit(0, &source->disabled)) {
+ __pm_stay_awake(&source->source);
+ pr_debug("enabled source %s\n", source->source.name);
+ }
+}
+
+static void bms_relax(struct bms_wakeup_source *source)
+{
+ if (!__test_and_set_bit(0, &source->disabled)) {
+ __pm_relax(&source->source);
+ pr_debug("disabled source %s\n", source->source.name);
+ }
+}
+
+static void enable_bms_irq(struct bms_irq *irq)
+{
+ if (__test_and_clear_bit(0, &irq->disabled)) {
+ enable_irq(irq->irq);
+ pr_debug("enabled irq %d\n", irq->irq);
+ }
+}
+
+static void disable_bms_irq(struct bms_irq *irq)
+{
+ if (!__test_and_set_bit(0, &irq->disabled)) {
+ disable_irq(irq->irq);
+ pr_debug("disabled irq %d\n", irq->irq);
+ }
+}
+
#define HOLD_OREG_DATA BIT(0)
static int lock_output_data(struct qpnp_bms_chip *chip)
{
@@ -412,7 +458,6 @@
#define VADC_CALIB_UV 625000
#define VBATT_MUL_FACTOR 3
-
static int adjust_vbatt_reading(struct qpnp_bms_chip *chip, int reading_uv)
{
s64 numerator, denominator;
@@ -490,6 +535,30 @@
return result_uv;
}
+static s64 cc_reverse_adjust_for_gain(s64 uv)
+{
+ struct qpnp_iadc_calib calibration;
+ int gain;
+ s64 result_uv;
+
+ qpnp_iadc_get_gain_and_offset(&calibration);
+ gain = (int)calibration.gain_raw - (int)calibration.offset_raw;
+
+ pr_debug("reverse adjusting_uv = %lld\n", uv);
+ if (gain == 0) {
+ pr_debug("gain is %d, not adjusting\n", gain);
+ return uv;
+ }
+ pr_debug("adjusting by factor: %hu/%lld = %lld%%\n",
+ gain, QPNP_ADC_GAIN_IDEAL,
+ div64_s64((s64)gain * 100LL,
+ (s64)QPNP_ADC_GAIN_IDEAL));
+
+ result_uv = div64_s64(uv * (s64)gain, QPNP_ADC_GAIN_IDEAL);
+ pr_debug("result_uv = %lld\n", result_uv);
+ return result_uv;
+}
+
static int convert_vsense_to_uv(struct qpnp_bms_chip *chip,
int16_t reading)
{
@@ -565,6 +634,20 @@
}
#define CC_36_BIT_MASK 0xFFFFFFFFFLL
+static uint64_t convert_s64_to_s36(int64_t raw64)
+{
+ return (uint64_t) raw64 & CC_36_BIT_MASK;
+}
+
+#define SIGN_EXTEND_36_TO_64_MASK (-1LL ^ CC_36_BIT_MASK)
+static int64_t convert_s36_to_s64(uint64_t raw36)
+{
+ raw36 = raw36 & CC_36_BIT_MASK;
+ /* convert 36 bit signed value into 64 signed value */
+ return (raw36 >> 35) == 0LL ?
+ raw36 : (SIGN_EXTEND_36_TO_64_MASK | raw36);
+}
+
static int read_cc_raw(struct qpnp_bms_chip *chip, int64_t *reading,
int cc_type)
{
@@ -582,12 +665,7 @@
return -ENXIO;
}
- raw_reading = raw_reading & CC_36_BIT_MASK;
- /* convert 36 bit signed value into 64 signed value */
- *reading = (raw_reading >> 35) == 0LL ?
- raw_reading : ((-1LL ^ CC_36_BIT_MASK) | raw_reading);
- pr_debug("before conversion: %llx, after conversion: %llx\n",
- raw_reading, *reading);
+ *reading = convert_s36_to_s64(raw_reading);
return 0;
}
@@ -1282,6 +1360,59 @@
return rc;
}
+/* Returns estimated battery resistance */
+static int get_prop_bms_batt_resistance(struct qpnp_bms_chip *chip)
+{
+ return chip->rbatt_mohm * 1000;
+}
+
+/* Returns instantaneous current in uA */
+static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
+{
+ int rc, result_ua;
+
+ rc = get_battery_current(chip, &result_ua);
+ if (rc) {
+ pr_err("failed to get current: %d\n", rc);
+ return rc;
+ }
+ return result_ua;
+}
+
+/* Returns coulomb counter in uAh */
+static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
+{
+ int64_t cc_raw;
+
+ mutex_lock(&chip->bms_output_lock);
+ lock_output_data(chip);
+ read_cc_raw(chip, &cc_raw, false);
+ unlock_output_data(chip);
+ mutex_unlock(&chip->bms_output_lock);
+
+ return calculate_cc(chip, cc_raw, CC, NORESET);
+}
+
+/* Returns shadow coulomb counter in uAh */
+static int get_prop_bms_charge_counter_shadow(struct qpnp_bms_chip *chip)
+{
+ int64_t cc_raw;
+
+ mutex_lock(&chip->bms_output_lock);
+ lock_output_data(chip);
+ read_cc_raw(chip, &cc_raw, true);
+ unlock_output_data(chip);
+ mutex_unlock(&chip->bms_output_lock);
+
+ return calculate_cc(chip, cc_raw, SHDW_CC, NORESET);
+}
+
+/* Returns full charge design in uAh */
+static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
+{
+ return chip->fcc_mah * 1000;
+}
+
static int calculate_delta_time(unsigned long *time_stamp, int *delta_time_s)
{
unsigned long now_tm_sec = 0;
@@ -1920,6 +2051,92 @@
}
}
+static int64_t convert_cc_uah_to_raw(struct qpnp_bms_chip *chip, int64_t cc_uah)
+{
+ int64_t cc_uv, cc_pvh, cc_raw;
+
+ cc_pvh = cc_uah * chip->r_sense_uohm;
+ cc_uv = div_s64(cc_pvh * SLEEP_CLK_HZ * SECONDS_PER_HOUR,
+ CC_READING_TICKS * 1000000LL);
+ cc_raw = div_s64(cc_uv * CC_READING_RESOLUTION_D,
+ CC_READING_RESOLUTION_N);
+ return cc_raw;
+}
+
+#define CC_STEP_INCREMENT_UAH 1500
+#define OCV_STEP_INCREMENT 0x10
+static void configure_soc_wakeup(struct qpnp_bms_chip *chip,
+ struct soc_params *params,
+ int batt_temp, int target_soc)
+{
+ int target_ocv_uv;
+ int64_t target_cc_uah, cc_raw_64, current_shdw_cc_raw_64;
+ int64_t current_shdw_cc_uah, iadc_comp_factor;
+ uint64_t cc_raw, current_shdw_cc_raw;
+ int16_t ocv_raw, current_ocv_raw;
+
+ current_shdw_cc_raw = 0;
+ mutex_lock(&chip->bms_output_lock);
+ lock_output_data(chip);
+ qpnp_read_wrapper(chip, (u8 *)¤t_ocv_raw,
+ chip->base + BMS1_OCV_FOR_SOC_DATA0, 2);
+ unlock_output_data(chip);
+ mutex_unlock(&chip->bms_output_lock);
+ current_shdw_cc_uah = get_prop_bms_charge_counter_shadow(chip);
+ current_shdw_cc_raw_64 = convert_cc_uah_to_raw(chip,
+ current_shdw_cc_uah);
+
+ /*
+ * Calculate the target shadow coulomb counter threshold for when
+ * the SoC changes.
+ *
+ * Since the BMS driver resets the shadow coulomb counter every
+ * 20 seconds when the device is awake, calculate the threshold as
+ * a delta from the current shadow coulomb count.
+ */
+ target_cc_uah = (100 - target_soc)
+ * (params->fcc_uah - params->uuc_uah)
+ / 100 - current_shdw_cc_uah;
+ if (target_cc_uah < 0) {
+ /*
+ * If the target cc is below 0, that means we have already
+ * passed the point where SoC should have fallen.
+ * Set a wakeup in a few more mAh and check back again
+ */
+ target_cc_uah = CC_STEP_INCREMENT_UAH;
+ }
+ iadc_comp_factor = 100000;
+ qpnp_iadc_comp_result(&iadc_comp_factor);
+ target_cc_uah = div64_s64(target_cc_uah * 100000, iadc_comp_factor);
+ target_cc_uah = cc_reverse_adjust_for_gain(target_cc_uah);
+ cc_raw_64 = convert_cc_uah_to_raw(chip, target_cc_uah);
+ cc_raw = convert_s64_to_s36(cc_raw_64);
+
+ find_ocv_for_soc(chip, params, batt_temp, target_soc, &target_ocv_uv);
+ ocv_raw = convert_vbatt_uv_to_raw(chip, target_ocv_uv);
+
+ /*
+ * If the current_ocv_raw was updated since reaching 100% and is lower
+ * than the calculated target ocv threshold, set the new target
+ * threshold 1.5mAh lower in order to check if the SoC changed yet.
+ */
+ if (current_ocv_raw != chip->ocv_reading_at_100
+ && current_ocv_raw < ocv_raw)
+ ocv_raw = current_ocv_raw - OCV_STEP_INCREMENT;
+
+ qpnp_write_wrapper(chip, (u8 *)&cc_raw,
+ chip->base + BMS1_SW_CC_THR0, 5);
+ qpnp_write_wrapper(chip, (u8 *)&ocv_raw,
+ chip->base + BMS1_OCV_THR0, 2);
+
+ pr_debug("current sw_cc_raw = 0x%llx, current ocv = 0x%hx\n",
+ current_shdw_cc_raw, (uint16_t)current_ocv_raw);
+ pr_debug("target_cc_uah = %lld, raw64 = 0x%llx, raw 36 = 0x%llx, ocv_raw = 0x%hx\n",
+ target_cc_uah,
+ (uint64_t)cc_raw_64, cc_raw,
+ (uint16_t)ocv_raw);
+}
+
#define SLEEP_RECALC_INTERVAL 3
static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
@@ -2022,7 +2239,13 @@
/* always clamp soc due to BMS hw/sw immaturities */
new_calculated_soc = clamp_soc_based_on_voltage(chip,
new_calculated_soc);
-
+ /*
+ * If the battery is full, configure the cc threshold so the system
+ * wakes up after SoC changes
+ */
+ if (is_battery_full(chip))
+ configure_soc_wakeup(chip, ¶ms,
+ batt_temp, bound_soc(new_calculated_soc - 1));
done_calculating:
mutex_lock(&chip->last_soc_mutex);
previous_soc = chip->calculated_soc;
@@ -2101,8 +2324,7 @@
struct qpnp_vadc_result result;
struct raw_soc_params raw;
- if (!wake_lock_active(&chip->soc_wake_lock))
- wake_lock(&chip->soc_wake_lock);
+ bms_stay_awake(&chip->soc_wake_source);
mutex_lock(&chip->vbat_monitor_mutex);
qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
mutex_unlock(&chip->vbat_monitor_mutex);
@@ -2127,7 +2349,7 @@
mutex_unlock(&chip->last_ocv_uv_mutex);
}
}
- wake_unlock(&chip->soc_wake_lock);
+ bms_relax(&chip->soc_wake_source);
return soc;
}
@@ -2681,8 +2903,20 @@
pr_debug("charging ended\n");
charging_ended(chip);
}
+
+ if (status == POWER_SUPPLY_STATUS_FULL) {
+ pr_debug("battery full\n");
+ enable_bms_irq(&chip->ocv_thr_irq);
+ enable_bms_irq(&chip->sw_cc_thr_irq);
+ } else if (chip->battery_status
+ == POWER_SUPPLY_STATUS_FULL) {
+ pr_debug("battery not full any more\n");
+ disable_bms_irq(&chip->ocv_thr_irq);
+ disable_bms_irq(&chip->sw_cc_thr_irq);
+ }
+
chip->battery_status = status;
- /* a new battery was inserted or removed, so force a soc
+ /* battery charge status has changed, so force a soc
* recalculation to update the SoC */
schedule_work(&chip->recalc_work);
}
@@ -2716,59 +2950,6 @@
return report_state_of_charge(chip);
}
-/* Returns estimated battery resistance */
-static int get_prop_bms_batt_resistance(struct qpnp_bms_chip *chip)
-{
- return chip->rbatt_mohm * 1000;
-}
-
-/* Returns instantaneous current in uA */
-static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
-{
- int rc, result_ua;
-
- rc = get_battery_current(chip, &result_ua);
- if (rc) {
- pr_err("failed to get current: %d\n", rc);
- return rc;
- }
- return result_ua;
-}
-
-/* Returns coulomb counter in uAh */
-static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
-{
- int64_t cc_raw;
-
- mutex_lock(&chip->bms_output_lock);
- lock_output_data(chip);
- read_cc_raw(chip, &cc_raw, CC);
- unlock_output_data(chip);
- mutex_unlock(&chip->bms_output_lock);
-
- return calculate_cc(chip, cc_raw, CC, NORESET);
-}
-
-/* Returns shadow coulomb counter in uAh */
-static int get_prop_bms_charge_counter_shadow(struct qpnp_bms_chip *chip)
-{
- int64_t cc_raw;
-
- mutex_lock(&chip->bms_output_lock);
- lock_output_data(chip);
- read_cc_raw(chip, &cc_raw, SHDW_CC);
- unlock_output_data(chip);
- mutex_unlock(&chip->bms_output_lock);
-
- return calculate_cc(chip, cc_raw, SHDW_CC, NORESET);
-}
-
-/* Returns full charge design in uAh */
-static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
-{
- return chip->fcc_mah * 1000;
-}
-
static void qpnp_bms_external_power_changed(struct power_supply *psy)
{
struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
@@ -3019,6 +3200,26 @@
chip->shutdown_soc_invalid);
}
+static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_bms_chip *chip = _chip;
+
+ pr_debug("ocv_thr irq triggered\n");
+ bms_stay_awake(&chip->soc_wake_source);
+ schedule_work(&chip->recalc_work);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bms_sw_cc_thr_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_bms_chip *chip = _chip;
+
+ pr_debug("sw_cc_thr irq triggered\n");
+ bms_stay_awake(&chip->soc_wake_source);
+ schedule_work(&chip->recalc_work);
+ return IRQ_HANDLED;
+}
+
#define PALLADIUM_ID_MIN 0x7F40
#define PALLADIUM_ID_MAX 0x7F5A
#define DESAY_5200_ID_MIN 0x7F7F
@@ -3199,6 +3400,35 @@
chip->first_time_calc_uuc = 1;
}
+#define SPMI_SETUP_IRQ(irq_name) \
+do { \
+ chip->irq_name##_irq.irq = spmi_get_irq_byname(chip->spmi, \
+ resource, #irq_name); \
+ if (chip->irq_name##_irq.irq < 0) { \
+ pr_err("Unable to get " #irq_name " irq\n"); \
+ return -ENXIO; \
+ } \
+ rc = devm_request_irq(chip->dev, chip->irq_name##_irq.irq, \
+ bms_##irq_name##_irq_handler, \
+ IRQF_TRIGGER_RISING, #irq_name, chip); \
+ if (rc < 0) { \
+ pr_err("Unable to request " #irq_name " irq: %d\n", rc);\
+ return -ENXIO; \
+ } \
+} while (0)
+
+static int bms_setup_irqs(struct qpnp_bms_chip *chip,
+ struct spmi_resource *resource)
+{
+ int rc;
+
+ SPMI_SETUP_IRQ(sw_cc_thr);
+ enable_irq_wake(chip->sw_cc_thr_irq.irq);
+ SPMI_SETUP_IRQ(ocv_thr);
+ enable_irq_wake(chip->ocv_thr_irq.irq);
+ return 0;
+}
+
#define REG_OFFSET_PERP_TYPE 0x04
#define REG_OFFSET_PERP_SUBTYPE 0x05
#define BMS_BMS_TYPE 0xD
@@ -3246,6 +3476,11 @@
if (type == BMS_BMS_TYPE && subtype == BMS_BMS1_SUBTYPE) {
chip->base = resource->start;
+ rc = bms_setup_irqs(chip, spmi_resource);
+ if (rc) {
+ pr_err("Could not register irqs\n");
+ return rc;
+ }
} else if (type == BMS_IADC_TYPE
&& (subtype == BMS_IADC1_SUBTYPE
|| subtype == BMS_IADC2_SUBTYPE)) {
@@ -3509,8 +3744,7 @@
mutex_init(&chip->soc_invalidation_mutex);
mutex_init(&chip->last_soc_mutex);
- wake_lock_init(&chip->soc_wake_lock, WAKE_LOCK_SUSPEND,
- "qpnp_soc_lock");
+ wakeup_source_init(&chip->soc_wake_source.source, "qpnp_soc_wake");
wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_low_voltage_lock");
wake_lock_init(&chip->cv_wake_lock, WAKE_LOCK_SUSPEND,
@@ -3588,7 +3822,7 @@
power_supply_unregister(&chip->bms_psy);
error_setup:
dev_set_drvdata(&spmi->dev, NULL);
- wake_lock_destroy(&chip->soc_wake_lock);
+ wakeup_source_trash(&chip->soc_wake_source.source);
wake_lock_destroy(&chip->low_voltage_wake_lock);
wake_lock_destroy(&chip->cv_wake_lock);
error_resource:
@@ -3640,9 +3874,8 @@
- (int)(time_since_last_recalc * 1000));
}
- if (!wake_lock_active(&chip->soc_wake_lock)
- && time_until_next_recalc == 0)
- wake_lock(&chip->soc_wake_lock);
+ if (time_until_next_recalc == 0)
+ bms_stay_awake(&chip->soc_wake_source);
schedule_delayed_work(&chip->calculate_soc_delayed_work,
round_jiffies_relative(msecs_to_jiffies
(time_until_next_recalc)));
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 4a3ea76..97d47db 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -325,35 +325,7 @@
}
pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
if (pstat != 0) {
- int i = 0;
- for (i = dev->pipe_b; i < MSM_SLIM_NPORTS; i++) {
- if (pstat & 1 << i) {
- u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn,
- i, dev->ver));
- if (val & (1 << 19)) {
- dev->ctrl.ports[i].err =
- SLIM_P_DISCONNECT;
- dev->pipes[i-dev->pipe_b].connected =
- false;
- /*
- * SPS will call completion since
- * ERROR flags are registered
- */
- } else if (val & (1 << 2))
- dev->ctrl.ports[i].err =
- SLIM_P_OVERFLOW;
- else if (val & (1 << 3))
- dev->ctrl.ports[i].err =
- SLIM_P_UNDERFLOW;
- }
- writel_relaxed(1, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
- dev->ver));
- }
- /*
- * Guarantee that port interrupt bit(s) clearing writes go
- * through before exiting ISR
- */
- mb();
+ return msm_slim_port_irq_handler(dev, pstat);
}
return IRQ_HANDLED;
@@ -446,16 +418,13 @@
if (mc != SLIM_MSG_MC_DISCONNECT_PORT)
dev->err = msm_slim_connect_pipe_port(dev, *puc);
else {
- struct msm_slim_endp *endpoint = &dev->pipes[*puc];
- struct sps_register_event sps_event;
- memset(&sps_event, 0, sizeof(sps_event));
- sps_register_event(endpoint->sps, &sps_event);
- sps_disconnect(endpoint->sps);
/*
* Remove channel disconnects master-side ports from
* channel. No need to send that again on the bus
+ * Only disable port
*/
- dev->pipes[*puc].connected = false;
+ writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
+ (*puc + dev->port_b), dev->ver));
mutex_unlock(&dev->tx_lock);
if (msgv >= 0)
msm_slim_put_ctrl(dev);
@@ -468,7 +437,7 @@
msm_slim_put_ctrl(dev);
return dev->err;
}
- *(puc) = *(puc) + dev->pipe_b;
+ *(puc) = *(puc) + dev->port_b;
}
if (txn->mt == SLIM_MSG_MT_CORE &&
mc == SLIM_MSG_MC_BEGIN_RECONFIGURATION)
@@ -1258,7 +1227,8 @@
dev->ctrl.set_laddr = msm_set_laddr;
dev->ctrl.xfer_msg = msm_xfer_msg;
dev->ctrl.wakeup = msm_clk_pause_wakeup;
- dev->ctrl.config_port = msm_config_port;
+ dev->ctrl.alloc_port = msm_alloc_port;
+ dev->ctrl.dealloc_port = msm_dealloc_port;
dev->ctrl.port_xfer = msm_slim_port_xfer;
dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
/* Reserve some messaging BW for satellite-apps driver communication */
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 6962d53..509c1e8 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -89,6 +89,7 @@
struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
+ u32 pstat;
if (stat & NGD_INT_TX_MSG_SENT) {
writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
@@ -147,6 +148,10 @@
mb();
dev_err(dev->dev, "NGD IE VE change");
}
+
+ pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
+ if (pstat != 0)
+ return msm_slim_port_irq_handler(dev, pstat);
return IRQ_HANDLED;
}
@@ -357,19 +362,16 @@
txn->mc == SLIM_USR_MC_CONNECT_SINK ||
txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
wbuf[0] == dev->pgdla) {
- if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
+ if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
else {
- struct msm_slim_endp *endpoint = &dev->pipes[wbuf[1]];
- struct sps_register_event sps_event;
- memset(&sps_event, 0, sizeof(sps_event));
- sps_register_event(endpoint->sps, &sps_event);
- sps_disconnect(endpoint->sps);
/*
* Remove channel disconnects master-side ports from
* channel. No need to send that again on the bus
+ * Only disable port
*/
- dev->pipes[wbuf[1]].connected = false;
+ writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
+ (wbuf[1] + dev->port_b), dev->ver));
mutex_unlock(&dev->tx_lock);
msm_slim_put_ctrl(dev);
return 0;
@@ -1083,7 +1085,8 @@
dev->ctrl.allocbw = ngd_allocbw;
dev->ctrl.xfer_msg = ngd_xfer_msg;
dev->ctrl.wakeup = ngd_clk_pause_wakeup;
- dev->ctrl.config_port = msm_config_port;
+ dev->ctrl.alloc_port = msm_alloc_port;
+ dev->ctrl.dealloc_port = msm_dealloc_port;
dev->ctrl.port_xfer = msm_slim_port_xfer;
dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
dev->bam_mem = bam_mem;
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 0166196..a63ee76 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -73,6 +73,52 @@
#endif
}
+irqreturn_t msm_slim_port_irq_handler(struct msm_slim_ctrl *dev, u32 pstat)
+{
+ int i;
+ u32 int_en = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+ dev->ver));
+ /*
+ * different port-interrupt than what we enabled, ignore.
+ * This may happen if overflow/underflow is reported, but
+ * was disabled due to unavailability of buffers provided by
+ * client.
+ */
+ if ((pstat & int_en) == 0)
+ return IRQ_HANDLED;
+ for (i = dev->port_b; i < MSM_SLIM_NPORTS; i++) {
+ if (pstat & (1 << i)) {
+ u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn,
+ i, dev->ver));
+ if (val & MSM_PORT_OVERFLOW) {
+ dev->ctrl.ports[i-dev->port_b].err =
+ SLIM_P_OVERFLOW;
+ } else if (val & MSM_PORT_UNDERFLOW) {
+ dev->ctrl.ports[i-dev->port_b].err =
+ SLIM_P_UNDERFLOW;
+ }
+ }
+ }
+ /*
+ * Disable port interrupt here. Re-enable when more
+ * buffers are provided for this port.
+ */
+ writel_relaxed((int_en & (~pstat)),
+ PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+ dev->ver));
+ /* clear port interrupts */
+ writel_relaxed(pstat, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
+ dev->ver));
+ pr_info("disabled overflow/underflow for port 0x%x", pstat);
+
+ /*
+ * Guarantee that port interrupt bit(s) clearing writes go
+ * through before exiting ISR
+ */
+ mb();
+ return IRQ_HANDLED;
+}
+
int msm_slim_init_endpoint(struct msm_slim_ctrl *dev, struct msm_slim_endp *ep)
{
int ret;
@@ -138,17 +184,27 @@
void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn)
{
u32 set_cfg = DEF_WATERMARK | DEF_ALIGN | DEF_PACK | ENABLE_PORT;
- u32 int_port = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
- dev->ver));
writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_CFGn, pn, dev->ver));
writel_relaxed(DEF_BLKSZ, PGD_PORT(PGD_PORT_BLKn, pn, dev->ver));
writel_relaxed(DEF_TRANSZ, PGD_PORT(PGD_PORT_TRANn, pn, dev->ver));
- writel_relaxed((int_port | 1 << pn) , PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
- dev->ver));
/* Make sure that port registers are updated before returning */
mb();
}
+static void msm_slim_disconn_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
+{
+ struct msm_slim_endp *endpoint = &dev->pipes[pn];
+ struct sps_register_event sps_event;
+ writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn, (pn + dev->port_b),
+ dev->ver));
+ /* Make sure port register is updated */
+ mb();
+ memset(&sps_event, 0, sizeof(sps_event));
+ sps_register_event(endpoint->sps, &sps_event);
+ sps_disconnect(endpoint->sps);
+ dev->pipes[pn].connected = false;
+}
+
int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
{
struct msm_slim_endp *endpoint = &dev->pipes[pn];
@@ -162,16 +218,26 @@
cfg->options = SPS_O_DESC_DONE | SPS_O_ERROR |
SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
- if (dev->pipes[pn].connected) {
- ret = sps_set_config(dev->pipes[pn].sps, cfg);
- if (ret) {
- dev_err(dev->dev, "sps pipe-port set config erro:%x\n",
- ret);
- return ret;
+ if (dev->pipes[pn].connected &&
+ dev->ctrl.ports[pn].state == SLIM_P_CFG) {
+ return -EISCONN;
+ } else if (dev->pipes[pn].connected) {
+ writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn, (pn + dev->port_b),
+ dev->ver));
+ /* Make sure port disabling goes through */
+ mb();
+ /* Is pipe already connected in desired direction */
+ if ((dev->ctrl.ports[pn].flow == SLIM_SRC &&
+ cfg->mode == SPS_MODE_DEST) ||
+ (dev->ctrl.ports[pn].flow == SLIM_SINK &&
+ cfg->mode == SPS_MODE_SRC)) {
+ msm_hw_set_port(dev, pn + dev->port_b);
+ return 0;
}
+ msm_slim_disconn_pipe_port(dev, pn);
}
- stat = readl_relaxed(PGD_PORT(PGD_PORT_STATn, (pn + dev->pipe_b),
+ stat = readl_relaxed(PGD_PORT(PGD_PORT_STATn, (pn + dev->port_b),
dev->ver));
if (dev->ctrl.ports[pn].flow == SLIM_SRC) {
cfg->destination = dev->bam.hdl;
@@ -191,17 +257,21 @@
cfg->mode = SPS_MODE_SRC;
}
/* Space for desciptor FIFOs */
- cfg->desc.size = MSM_SLIM_DESC_NUM * sizeof(struct sps_iovec);
- cfg->config = SPS_CONFIG_DEFAULT;
- ret = sps_connect(dev->pipes[pn].sps, cfg);
+ ret = msm_slim_sps_mem_alloc(dev, &cfg->desc,
+ MSM_SLIM_DESC_NUM * sizeof(struct sps_iovec));
+ if (ret)
+ pr_err("mem alloc for descr failed:%d", ret);
+ else
+ ret = sps_connect(dev->pipes[pn].sps, cfg);
+
if (!ret) {
dev->pipes[pn].connected = true;
- msm_hw_set_port(dev, pn + dev->pipe_b);
+ msm_hw_set_port(dev, pn + dev->port_b);
}
return ret;
}
-int msm_config_port(struct slim_controller *ctrl, u8 pn)
+int msm_alloc_port(struct slim_controller *ctrl, u8 pn)
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
struct msm_slim_endp *endpoint;
@@ -209,7 +279,7 @@
if (ctrl->ports[pn].req == SLIM_REQ_HALF_DUP ||
ctrl->ports[pn].req == SLIM_REQ_MULTI_CH)
return -EPROTONOSUPPORT;
- if (pn >= (MSM_SLIM_NPORTS - dev->pipe_b))
+ if (pn >= (MSM_SLIM_NPORTS - dev->port_b))
return -ENODEV;
endpoint = &dev->pipes[pn];
@@ -218,6 +288,22 @@
return ret;
}
+void msm_dealloc_port(struct slim_controller *ctrl, u8 pn)
+{
+ struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+ struct msm_slim_endp *endpoint;
+ if (pn >= (MSM_SLIM_NPORTS - dev->port_b))
+ return;
+ endpoint = &dev->pipes[pn];
+ if (dev->pipes[pn].connected)
+ msm_slim_disconn_pipe_port(dev, pn);
+ if (endpoint->sps) {
+ struct sps_connect *config = &endpoint->config;
+ msm_slim_free_endpoint(endpoint);
+ msm_slim_sps_mem_free(dev, &config->desc);
+ }
+}
+
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
u8 pn, u8 **done_buf, u32 *done_len)
{
@@ -241,6 +327,25 @@
return SLIM_P_INPROGRESS;
}
+static void msm_slim_port_cb(struct sps_event_notify *ev)
+{
+
+ struct completion *comp = ev->data.transfer.user;
+ struct sps_iovec *iovec = &ev->data.transfer.iovec;
+
+ if (ev->event_id == SPS_EVENT_DESC_DONE) {
+
+ pr_debug("desc done iovec = (0x%x 0x%x 0x%x)\n",
+ iovec->addr, iovec->size, iovec->flags);
+
+ } else {
+ pr_err("%s: ERR event %d\n",
+ __func__, ev->event_id);
+ }
+ if (comp)
+ complete(comp);
+}
+
int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
u32 len, struct completion *comp)
{
@@ -251,20 +356,29 @@
return -ENODEV;
- ctrl->ports[pn].xcomp = comp;
sreg.options = (SPS_EVENT_DESC_DONE|SPS_EVENT_ERROR);
sreg.mode = SPS_TRIGGER_WAIT;
- sreg.xfer_done = comp;
- sreg.callback = NULL;
- sreg.user = &ctrl->ports[pn];
+ sreg.xfer_done = NULL;
+ sreg.callback = msm_slim_port_cb;
+ sreg.user = NULL;
ret = sps_register_event(dev->pipes[pn].sps, &sreg);
if (ret) {
dev_dbg(dev->dev, "sps register event error:%x\n", ret);
return ret;
}
- ret = sps_transfer_one(dev->pipes[pn].sps, (u32)iobuf, len, NULL,
+ ret = sps_transfer_one(dev->pipes[pn].sps, (u32)iobuf, len, comp,
SPS_IOVEC_FLAG_INT);
dev_dbg(dev->dev, "sps submit xfer error code:%x\n", ret);
+ if (!ret) {
+ /* Enable port interrupts */
+ u32 int_port = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+ dev->ver));
+ if (!(int_port & (1 << (dev->port_b + pn))))
+ writel_relaxed((int_port | (1 << (dev->port_b + pn))),
+ PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver));
+ /* Make sure that port registers are updated before returning */
+ mb();
+ }
return ret;
}
@@ -680,7 +794,7 @@
if ((sec_props.ees[dev->ee].pipe_mask >> i) & 0x1)
break;
}
- dev->pipe_b = i - 7;
+ dev->port_b = i - 7;
/* Register the BAM device with the SPS driver */
ret = sps_register_bam_device(&bam_props, &bam_handle);
@@ -750,6 +864,12 @@
if (dev->use_tx_msgqs >= MSM_MSGQ_ENABLED)
msm_slim_remove_ep(dev, &dev->tx_msgq, &dev->use_tx_msgqs);
if (dereg) {
+ int i;
+ for (i = dev->port_b; i < MSM_SLIM_NPORTS; i++) {
+ if (dev->pipes[i - dev->port_b].connected)
+ msm_dealloc_port(&dev->ctrl,
+ i - dev->port_b);
+ }
sps_deregister_bam_device(dev->bam.hdl);
dev->bam.hdl = 0L;
}
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index f8f625e..896e196 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -13,6 +13,7 @@
#ifndef _SLIM_MSM_H
#define _SLIM_MSM_H
+#include <linux/irq.h>
#include <linux/kthread.h>
#include <mach/msm_qmi_interface.h>
@@ -152,6 +153,12 @@
PGD_VE_STAT_V1 = 0x1710,
};
+enum msm_slim_port_status {
+ MSM_PORT_OVERFLOW = 1 << 2,
+ MSM_PORT_UNDERFLOW = 1 << 3,
+ MSM_PORT_DISCONNECT = 1 << 19,
+};
+
enum msm_ctrl_state {
MSM_CTRL_AWAKE,
MSM_CTRL_SLEEPING,
@@ -177,7 +184,6 @@
struct sps_connect config;
struct sps_register_event event;
struct sps_mem_buffer buf;
- struct completion *xcomp;
bool connected;
};
@@ -224,7 +230,7 @@
u8 pgdla;
enum msm_slim_msgq use_rx_msgqs;
enum msm_slim_msgq use_tx_msgqs;
- int pipe_b;
+ int port_b;
struct completion reconf;
bool reconf_busy;
bool chan_active;
@@ -271,11 +277,13 @@
int msm_slim_rx_dequeue(struct msm_slim_ctrl *dev, u8 *buf);
int msm_slim_get_ctrl(struct msm_slim_ctrl *dev);
void msm_slim_put_ctrl(struct msm_slim_ctrl *dev);
+irqreturn_t msm_slim_port_irq_handler(struct msm_slim_ctrl *dev, u32 pstat);
int msm_slim_init_endpoint(struct msm_slim_ctrl *dev, struct msm_slim_endp *ep);
void msm_slim_free_endpoint(struct msm_slim_endp *ep);
void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn);
+int msm_alloc_port(struct slim_controller *ctrl, u8 pn);
+void msm_dealloc_port(struct slim_controller *ctrl, u8 pn);
int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
-int msm_config_port(struct slim_controller *ctrl, u8 pn);
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
u8 pn, u8 **done_buf, u32 *done_len);
int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index e9f056e..201470f 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1089,8 +1089,11 @@
}
break;
}
- if (i >= ctrl->nports)
+ if (i >= ctrl->nports) {
ret = -EDQUOT;
+ goto alloc_err;
+ }
+ ret = 0;
for (j = i; j < i + nphysp; j++) {
ctrl->ports[j].state = SLIM_P_UNCFG;
ctrl->ports[j].req = req;
@@ -1098,7 +1101,8 @@
ctrl->ports[j].flow = SLIM_SINK;
else
ctrl->ports[j].flow = SLIM_SRC;
- ret = ctrl->config_port(ctrl, j);
+ if (ctrl->alloc_port)
+ ret = ctrl->alloc_port(ctrl, j);
if (ret) {
for (; j >= i; j--)
ctrl->ports[j].state = SLIM_P_FREE;
@@ -1126,17 +1130,26 @@
for (i = 0; i < nports; i++) {
u8 pn;
pn = SLIM_HDL_TO_PORT(hdl[i]);
- if (ctrl->ports[pn].state == SLIM_P_CFG) {
- int j;
- dev_err(&ctrl->dev, "Can't dealloc connected port:%d",
- i);
+
+ if (pn >= ctrl->nports || ctrl->ports[pn].state == SLIM_P_CFG) {
+ int j, ret;
+ if (pn >= ctrl->nports) {
+ dev_err(&ctrl->dev, "invalid port number");
+ ret = -EINVAL;
+ } else {
+ dev_err(&ctrl->dev,
+ "Can't dealloc connected port:%d", i);
+ ret = -EISCONN;
+ }
for (j = i - 1; j >= 0; j--) {
pn = SLIM_HDL_TO_PORT(hdl[j]);
ctrl->ports[pn].state = SLIM_P_UNCFG;
}
mutex_unlock(&ctrl->m_ctrl);
- return -EISCONN;
+ return ret;
}
+ if (ctrl->dealloc_port)
+ ctrl->dealloc_port(ctrl, pn);
ctrl->ports[pn].state = SLIM_P_FREE;
}
mutex_unlock(&ctrl->m_ctrl);
@@ -1215,6 +1228,8 @@
* Channel specified in chanh needs to be allocated first.
* Returns -EALREADY if source is already configured for this channel.
* Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid direction is specified for non-manager port,
+ * or if the manager side port number is out of bounds, or in incorrect state
*/
int slim_connect_src(struct slim_device *sb, u32 srch, u16 chanh)
{
@@ -1223,12 +1238,23 @@
u8 chan = SLIM_HDL_TO_CHIDX(chanh);
struct slim_ich *slc = &ctrl->chans[chan];
enum slim_port_flow flow = SLIM_HDL_TO_FLOW(srch);
+ u8 la = SLIM_HDL_TO_LA(srch);
- if (flow != SLIM_SRC)
+ /* manager ports don't have direction when they are allocated */
+ if (la != SLIM_LA_MANAGER && flow != SLIM_SRC)
return -EINVAL;
mutex_lock(&ctrl->sched.m_reconf);
+ if (la == SLIM_LA_MANAGER) {
+ u8 pn = SLIM_HDL_TO_PORT(srch);
+ if (pn >= ctrl->nports ||
+ ctrl->ports[pn].state != SLIM_P_UNCFG) {
+ ret = -EINVAL;
+ goto connect_src_err;
+ }
+ }
+
if (slc->state == SLIM_CH_FREE) {
ret = -ENOTCONN;
goto connect_src_err;
@@ -1264,6 +1290,9 @@
* Channel specified in chanh needs to be allocated first.
* Returns -EALREADY if sink is already configured for this channel.
* Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid parameters are passed, or invalid direction is
+ * specified for non-manager port, or if the manager side port number is out of
+ * bounds, or in incorrect state
*/
int slim_connect_sink(struct slim_device *sb, u32 *sinkh, int nsink, u16 chanh)
{
@@ -1290,8 +1319,14 @@
for (j = 0; j < nsink; j++) {
enum slim_port_flow flow = SLIM_HDL_TO_FLOW(sinkh[j]);
- if (flow != SLIM_SINK)
+ u8 la = SLIM_HDL_TO_LA(sinkh[j]);
+ u8 pn = SLIM_HDL_TO_PORT(sinkh[j]);
+ if (la != SLIM_LA_MANAGER && flow != SLIM_SINK)
ret = -EINVAL;
+ else if (la == SLIM_LA_MANAGER &&
+ (pn >= ctrl->nports ||
+ ctrl->ports[pn].state != SLIM_P_UNCFG))
+ ret = -EINVAL;
else
ret = connect_port_ch(ctrl, chan, sinkh[j], SLIM_SINK);
if (ret) {
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 88074b9..a9c073b 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -69,6 +69,26 @@
ULPI_CLR(ULPI_MISC_A));
}
+/* Link power management will reduce power consumption by
+ * short time HW suspend/resume.
+ */
+static void ci13xxx_msm_set_l1(struct ci13xxx *udc)
+{
+ int temp;
+ struct device *dev = udc->gadget.dev.parent;
+
+ dev_dbg(dev, "Enable link power management\n");
+
+ /* Enable remote wakeup and L1 for IN EPs */
+ writel_relaxed(0xffff0000, USB_L1_EP_CTRL);
+
+ temp = readl_relaxed(USB_L1_CONFIG);
+ temp |= L1_CONFIG_LPM_EN | L1_CONFIG_REMOTE_WAKEUP |
+ L1_CONFIG_GATE_SYS_CLK | L1_CONFIG_PHY_LPM |
+ L1_CONFIG_PLL;
+ writel_relaxed(temp, USB_L1_CONFIG);
+}
+
static void ci13xxx_msm_connect(void)
{
struct ci13xxx *udc = _udc;
@@ -109,6 +129,9 @@
writel_relaxed(0, USB_AHBBURST);
writel_relaxed(0x08, USB_AHBMODE);
+ if (udc->gadget.l1_supported)
+ ci13xxx_msm_set_l1(udc);
+
if (phy && (phy->flags & ENABLE_SECONDARY_PHY)) {
int temp;
@@ -234,6 +257,7 @@
struct resource *res;
int ret;
struct ci13xxx_platform_data *pdata = pdev->dev.platform_data;
+ bool is_l1_supported = false;
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
@@ -245,6 +269,8 @@
else
ci13xxx_msm_udc_driver.nz_itc =
1 << (pdata->log2_itc-1);
+
+ is_l1_supported = pdata->l1_supported;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -265,6 +291,8 @@
goto iounmap;
}
+ _udc->gadget.l1_supported = is_l1_supported;
+
_udc_ctxt.irq = platform_get_irq(pdev, 0);
if (_udc_ctxt.irq < 0) {
dev_err(&pdev->dev, "IRQ not found\n");
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index de4a233..27d67e3 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -515,7 +515,8 @@
/*
* A SuperSpeed device shall include the USB2.0 extension descriptor
- * and shall support LPM when operating in USB2.0 HS mode.
+ * and shall support LPM when operating in USB2.0 HS mode, as well as
+ * a HS device when operating in USB2.1 HS mode.
*/
usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++;
@@ -525,33 +526,37 @@
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
- /*
- * The Superspeed USB Capability descriptor shall be implemented by all
- * SuperSpeed devices.
- */
- ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
- bos->bNumDeviceCaps++;
- le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
- ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
- ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
- ss_cap->bmAttributes = 0; /* LTM is not supported yet */
- ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
- USB_FULL_SPEED_OPERATION |
- USB_HIGH_SPEED_OPERATION |
- USB_5GBPS_OPERATION);
- ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+ if (gadget_is_superspeed(cdev->gadget)) {
+ /*
+ * The Superspeed USB Capability descriptor shall be
+ * implemented by all SuperSpeed devices.
+ */
+ ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+ bos->bNumDeviceCaps++;
+ le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+ ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+ ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+ ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+ ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+ ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+ USB_FULL_SPEED_OPERATION |
+ USB_HIGH_SPEED_OPERATION |
+ USB_5GBPS_OPERATION);
+ ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
- /* Get Controller configuration */
- if (cdev->gadget->ops->get_config_params)
- cdev->gadget->ops->get_config_params(&dcd_config_params);
- else {
- dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
- dcd_config_params.bU2DevExitLat =
- cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+ /* Get Controller configuration */
+ if (cdev->gadget->ops->get_config_params)
+ cdev->gadget->ops->get_config_params
+ (&dcd_config_params);
+ else {
+ dcd_config_params.bU1devExitLat =
+ USB_DEFAULT_U1_DEV_EXIT_LAT;
+ dcd_config_params.bU2DevExitLat =
+ cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+ }
+ ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+ ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
}
- ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
- ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
return le16_to_cpu(bos->wTotalLength);
}
@@ -1124,6 +1129,9 @@
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
DBG(cdev, "Config SS device in HS\n");
}
+ } else if (gadget->l1_supported) {
+ cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+ DBG(cdev, "Config HS device with LPM(L1)\n");
}
value = min(w_length, (u16) sizeof cdev->desc);
@@ -1164,7 +1172,8 @@
value = min(w_length, (u16) value);
break;
case USB_DT_BOS:
- if (gadget_is_superspeed(gadget)) {
+ if (gadget_is_superspeed(gadget) ||
+ gadget->l1_supported) {
value = bos_desc(cdev);
value = min(w_length, (u16) value);
}
@@ -1371,6 +1380,10 @@
reset_config(cdev);
if (composite->disconnect)
composite->disconnect(cdev);
+ if (cdev->delayed_status != 0) {
+ INFO(cdev, "delayed status mismatch..resetting\n");
+ cdev->delayed_status = 0;
+ }
spin_unlock_irqrestore(&cdev->lock, flags);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 3322da5..577a4fe 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -200,7 +200,6 @@
int ret;
pr_debug("%s: Connect workqueue started", __func__);
- usb_bam_reset_complete();
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
if (d->func_type == USB_FUNC_MBIM) {
@@ -268,17 +267,18 @@
}
}
} else { /* transport type is USB_GADGET_XPORT_BAM2BAM */
- ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
- if (ret) {
- pr_err("usb_bam_connect (src) failed: err:%d\n", ret);
- return;
+ usb_bam_reset_complete();
+ ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (src) failed: err:%d\n", ret);
+ return;
+ }
+ ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (dst) failed: err:%d\n", ret);
+ return;
+ }
}
- ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
- if (ret) {
- pr_err("usb_bam_connect (dst) failed: err:%d\n", ret);
- return;
- }
-}
if (!port->port_usb) {
pr_err("port_usb is NULL");
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 14c3323..ef45d49 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1895,6 +1895,8 @@
"hsic,consider-ipa-handshake"));
pdata->ahb_async_bridge_bypass = of_property_read_bool(node,
"qcom,ahb-async-bridge-bypass");
+ pdata->disable_cerr = of_property_read_bool(node,
+ "hsic,disable-cerr");
return pdata;
}
@@ -1982,8 +1984,10 @@
mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
mehci->enable_hbm = pdata->enable_hbm;
- if (pdata)
+ if (pdata) {
mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
+ mehci->ehci.disable_cerr = pdata->disable_cerr;
+ }
ret = msm_hsic_init_gdsc(mehci, 1);
if (ret) {
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 0b89dd0..823229b 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -1,6 +1,6 @@
/* ehci-msm.c - HSUSB Host Controller Driver Implementation
*
- * Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
*
* Partly derived from ehci-fsl.c and ehci-hcd.c
* Copyright (c) 2000-2004 by David Brownell
@@ -260,15 +260,23 @@
static int ehci_msm_pm_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
+ int ret;
dev_dbg(dev, "ehci-msm PM resume\n");
if (!hcd->rh_registered)
return 0;
- ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+ /* Notify OTG to bring hw out of LPM before restoring wakeup flags */
+ ret = usb_phy_set_suspend(phy, 0);
+ if (ret)
+ return ret;
- return usb_phy_set_suspend(phy, 0);
+ ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+ /* Resume root-hub to handle USB event if any else initiate LPM again */
+ usb_hcd_resume_root_hub(hcd);
+
+ return ret;
}
#endif
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 6727996..5bb8772 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -25,7 +25,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/wakelock.h>
+#include <linux/pm_wakeup.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -36,6 +36,7 @@
#include <mach/clk.h>
#include <mach/msm_xo.h>
#include <mach/msm_iomap.h>
+#include <linux/debugfs.h>
#define MSM_USB_BASE (hcd->regs)
@@ -62,7 +63,7 @@
bool pmic_gpio_dp_irq_enabled;
uint32_t pmic_gpio_int_cnt;
atomic_t pm_usage_cnt;
- struct wake_lock wlock;
+ struct wakeup_source ws;
struct work_struct phy_susp_fail_work;
int async_irq;
bool async_irq_enabled;
@@ -683,7 +684,7 @@
enable_irq_wake(mhcd->async_irq);
enable_irq(mhcd->async_irq);
}
- wake_unlock(&mhcd->wlock);
+ pm_relax(mhcd->dev);
dev_info(mhcd->dev, "EHCI USB in low power mode\n");
@@ -716,7 +717,7 @@
}
spin_unlock_irqrestore(&mhcd->wakeup_lock, flags);
- wake_lock(&mhcd->wlock);
+ pm_stay_awake(mhcd->dev);
/* Vote for TCXO when waking up the phy */
if (!IS_ERR(mhcd->xo_clk)) {
@@ -801,7 +802,7 @@
dev_dbg(mhcd->dev, "%s: hsusb host remote wakeup interrupt cnt: %u\n",
__func__, mhcd->async_int_cnt);
- wake_lock(&mhcd->wlock);
+ pm_stay_awake(mhcd->dev);
spin_lock(&mhcd->wakeup_lock);
if (mhcd->async_irq_enabled) {
@@ -832,7 +833,7 @@
__func__, mhcd->pmic_gpio_int_cnt);
- wake_lock(&mhcd->wlock);
+ pm_stay_awake(mhcd->dev);
if (mhcd->pmic_gpio_dp_irq_enabled) {
mhcd->pmic_gpio_dp_irq_enabled = 0;
@@ -896,6 +897,135 @@
return 0;
}
+#if defined(CONFIG_DEBUG_FS)
+static u32 addr;
+#define BUF_SIZE 32
+static ssize_t debug_read_phy_data(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_hcd *mhcd = file->private_data;
+ char *kbuf;
+ size_t c = 0;
+ u32 data = 0;
+ int ret = 0;
+
+ kbuf = kzalloc(sizeof(char) * BUF_SIZE, GFP_KERNEL);
+ pm_runtime_get(mhcd->dev);
+ data = msm_ulpi_read(mhcd, addr);
+ pm_runtime_put(mhcd->dev);
+ if (data < 0) {
+ dev_err(mhcd->dev,
+ "%s(): ulpi read timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ c = scnprintf(kbuf, BUF_SIZE, "addr: 0x%x: data: 0x%x\n", addr, data);
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, kbuf, c);
+
+ kfree(kbuf);
+
+ return ret;
+}
+
+static ssize_t debug_write_phy_data(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_hcd *mhcd = file->private_data;
+ char kbuf[10];
+ u32 data = 0;
+
+ memset(kbuf, 0, 10);
+
+ if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ return -EFAULT;
+
+ if (sscanf(kbuf, "%x", &data) != 1)
+ return -EINVAL;
+
+ pm_runtime_get(mhcd->dev);
+ if (msm_ulpi_write(mhcd, data, addr) < 0) {
+ dev_err(mhcd->dev,
+ "%s(): ulpi write timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ pm_runtime_put(mhcd->dev);
+
+ return count;
+}
+
+static ssize_t debug_phy_write_addr(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char kbuf[10];
+ u32 temp;
+
+ memset(kbuf, 0, 10);
+
+ if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ return -EFAULT;
+
+ if (sscanf(kbuf, "%x", &temp) != 1)
+ return -EINVAL;
+
+ if (temp > 0x3F)
+ return -EINVAL;
+
+ addr = temp;
+
+ return count;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+const struct file_operations debug_rw_phy_ops = {
+ .open = debug_open,
+ .read = debug_read_phy_data,
+ .write = debug_write_phy_data,
+};
+
+const struct file_operations debug_write_phy_ops = {
+ .open = debug_open,
+ .write = debug_phy_write_addr,
+};
+
+static struct dentry *dent_ehci;
+
+static int ehci_debugfs_init(struct msm_hcd *mhcd)
+{
+ struct dentry *debug_phy_data;
+ struct dentry *debug_phy_addr;
+
+ dent_ehci = debugfs_create_dir(dev_name(mhcd->dev), 0);
+ if (IS_ERR(dent_ehci))
+ return -ENOENT;
+
+ debug_phy_data = debugfs_create_file("phy_reg_data", 0666,
+ dent_ehci, mhcd, &debug_rw_phy_ops);
+ if (!debug_phy_data) {
+ debugfs_remove(dent_ehci);
+ return -ENOENT;
+ }
+
+ debug_phy_addr = debugfs_create_file("phy_reg_addr", 0666,
+ dent_ehci, mhcd, &debug_write_phy_ops);
+ if (!debug_phy_addr) {
+ debugfs_remove_recursive(dent_ehci);
+ return -ENOENT;
+ }
+ return 0;
+}
+#else
+static int ehci_debugfs_init(struct msm_hcd *mhcd)
+{
+ return 0;
+}
+#endif
+
static struct hc_driver msm_hc2_driver = {
.description = hcd_name,
.product_desc = "Qualcomm EHCI Host Controller",
@@ -1178,8 +1308,8 @@
msm_ehci_vbus_power(mhcd, 1);
device_init_wakeup(&pdev->dev, 1);
- wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
- wake_lock(&mhcd->wlock);
+ wakeup_source_init(&mhcd->ws, dev_name(&pdev->dev));
+ pm_stay_awake(mhcd->dev);
INIT_WORK(&mhcd->phy_susp_fail_work, msm_ehci_phy_susp_fail_work);
/*
* This pdev->dev is assigned parent of root-hub by USB core,
@@ -1205,6 +1335,9 @@
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ if (ehci_debugfs_init(mhcd) < 0)
+ dev_err(mhcd->dev, "%s: debugfs init failed\n", __func__);
+
return 0;
vbus_deinit:
@@ -1271,10 +1404,13 @@
msm_ehci_init_vddcx(mhcd, 0);
msm_ehci_init_clocks(mhcd, 0);
- wake_lock_destroy(&mhcd->wlock);
+ wakeup_source_trash(&mhcd->ws);
iounmap(hcd->regs);
usb_put_hcd(hcd);
+#if defined(CONFIG_DEBUG_FS)
+ debugfs_remove_recursive(dent_ehci);
+#endif
return 0;
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index db49c07..b029be2 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -637,7 +637,8 @@
qtd->urb = urb;
token = QTD_STS_ACTIVE;
- token |= (EHCI_TUNE_CERR << 10);
+ if (!ehci->disable_cerr)
+ token |= (EHCI_TUNE_CERR << 10);
/* for split transactions, SplitXState initialized to zero */
len = urb->transfer_buffer_length;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index edf2a73..0498a6a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -154,6 +154,7 @@
unsigned susp_sof_bug:1; /*Chip Idea HC*/
unsigned resume_sof_bug:1;/*Chip Idea HC*/
unsigned reset_sof_bug:1; /*Chip Idea HC*/
+ bool disable_cerr;
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 717103d..1b6d15e 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -21,6 +21,7 @@
*/
#include <linux/gfp.h>
+#include <linux/slab.h>
#include <asm/unaligned.h>
#include "xhci.h"
@@ -472,6 +473,149 @@
}
}
+static void xhci_single_step_completion(struct urb *urb)
+{
+ struct completion *done = urb->context;
+
+ complete(done);
+}
+
+/*
+ * Allocate a URB and initialize the various fields of it.
+ * This API is used by the single_step_set_feature test of
+ * EHSET where IN packet of the GetDescriptor request is
+ * sent 15secs after the SETUP packet.
+ * Return NULL if failed.
+ */
+static struct urb *xhci_request_single_step_set_feature_urb(
+ struct usb_device *udev,
+ void *dr,
+ void *buf,
+ struct completion *done)
+{
+ struct urb *urb;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_host_endpoint *ep;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return NULL;
+
+ urb->pipe = usb_rcvctrlpipe(udev, 0);
+ ep = udev->ep_in[usb_pipeendpoint(urb->pipe)];
+ if (!ep) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ /*
+ * Initialize the various URB fields as these are used by the HCD
+ * driver to queue it and as well as when completion happens.
+ */
+ urb->ep = ep;
+ urb->dev = udev;
+ urb->setup_packet = dr;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb->complete = xhci_single_step_completion;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->transfer_flags = URB_DIR_IN;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ usb_hcd_map_urb_for_dma(hcd, urb, GFP_KERNEL);
+ urb->context = done;
+ return urb;
+}
+
+/*
+ * This function implements the USB_PORT_FEAT_TEST handling of the
+ * SINGLE_STEP_SET_FEATURE test mode as defined in the Embedded
+ * High-Speed Electrical Test (EHSET) specification. This simply
+ * issues a GetDescriptor control transfer, with an inserted 15-second
+ * delay after the end of the SETUP stage and before the IN token of
+ * the DATA stage is set. The idea is that this gives the test operator
+ * enough time to configure the oscilloscope to perform a measurement
+ * of the response time between the DATA and ACK packets that follow.
+ */
+static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+ int retval;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct usb_device_descriptor *buf;
+ unsigned long flags;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ /* Obtain udev of the rhub's child port */
+ udev = hcd->self.root_hub->children[port];
+ if (!udev) {
+ xhci_err(xhci, "No device attached to the RootHub\n");
+ return -ENODEV;
+ }
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* Fill Setup packet for GetDescriptor */
+ dr->bRequestType = USB_DIR_IN;
+ dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+ dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+ urb = xhci_request_single_step_set_feature_urb(udev, dr, buf, &done);
+ if (!urb)
+ goto cleanup;
+
+ /* Now complete just the SETUP stage */
+ spin_lock_irqsave(&xhci->lock, flags);
+ retval = xhci_submit_single_step_set_feature(hcd, urb, 1);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ if (retval)
+ goto out1;
+
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ xhci_err(xhci, "%s SETUP stage timed out on ep0\n", __func__);
+ goto out1;
+ }
+
+ /* Sleep for 15 seconds; HC will send SOFs during this period */
+ msleep(15 * 1000);
+
+ /* Complete remaining DATA and status stages. Re-use same URB */
+ urb->status = -EINPROGRESS;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ retval = xhci_submit_single_step_set_feature(hcd, urb, 0);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ if (!retval && !wait_for_completion_timeout(&done,
+ msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ xhci_err(xhci, "%s IN stage timed out on ep0\n", __func__);
+ }
+out1:
+ usb_free_urb(urb);
+cleanup:
+ kfree(dr);
+ kfree(buf);
+ return retval;
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
@@ -778,6 +922,11 @@
temp = xhci_readl(xhci, port_array[wIndex] + 1);
temp |= test_mode << 28;
xhci_writel(xhci, temp, port_array[wIndex] + 1);
+ } else if (test_mode == 6) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ retval = xhci_ehset_single_step_set_feature(hcd,
+ wIndex);
+ spin_lock_irqsave(&xhci->lock, flags);
} else {
goto error;
}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 323b481..b3f3fa8 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3215,6 +3215,150 @@
return 0;
}
+/*
+ * Variant of xhci_queue_ctrl_tx() used to implement EHSET
+ * SINGLE_STEP_SET_FEATURE test mode. It differs in that the control
+ * transfer is broken up so that the SETUP stage can happen and call
+ * the URB's completion handler before the DATA/STATUS stages are
+ * executed by the xHC hardware. This assumes the control transfer is a
+ * GetDescriptor, with a DATA stage in the IN direction, and an OUT
+ * STATUS stage.
+ *
+ * This function is called twice, usually with a 15-second delay in between.
+ * - with is_setup==true, the SETUP stage for the control request
+ * (GetDescriptor) is queued in the TRB ring and sent to HW immediately
+ * - with is_setup==false, the DATA and STATUS TRBs are queued and exceuted
+ *
+ * Caller must have locked xhci->lock
+ */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
+ int is_setup)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_ring *ep_ring;
+ int num_trbs;
+ int ret;
+ unsigned int slot_id, ep_index;
+ struct usb_ctrlrequest *setup;
+ struct xhci_generic_trb *start_trb;
+ int start_cycle;
+ u32 field, length_field;
+ struct urb_priv *urb_priv;
+ struct xhci_td *td;
+
+ ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+ if (!ep_ring)
+ return -EINVAL;
+
+ /* Need buffer for data stage */
+ if (urb->transfer_buffer_length <= 0)
+ return -EINVAL;
+
+ /*
+ * Need to copy setup packet into setup TRB, so we can't use the setup
+ * DMA address.
+ */
+ if (!urb->setup_packet)
+ return -EINVAL;
+ setup = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ slot_id = urb->dev->slot_id;
+ ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+
+ urb_priv = kzalloc(sizeof(struct urb_priv) +
+ sizeof(struct xhci_td *), GFP_ATOMIC);
+ if (!urb_priv)
+ return -ENOMEM;
+
+ td = urb_priv->td[0] = kzalloc(sizeof(struct xhci_td), GFP_ATOMIC);
+ if (!td) {
+ kfree(urb_priv);
+ return -ENOMEM;
+ }
+
+ urb_priv->length = 1;
+ urb_priv->td_cnt = 0;
+ urb->hcpriv = urb_priv;
+
+ num_trbs = is_setup ? 1 : 2;
+
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
+ ep_index, urb->stream_id,
+ num_trbs, urb, 0, GFP_ATOMIC);
+ if (ret < 0) {
+ kfree(td);
+ kfree(urb_priv);
+ return ret;
+ }
+
+ /*
+ * Don't give the first TRB to the hardware (by toggling the cycle bit)
+ * until we've finished creating all the other TRBs. The ring's cycle
+ * state may change as we enqueue the other TRBs, so save it too.
+ */
+ start_trb = &ep_ring->enqueue->generic;
+ start_cycle = ep_ring->cycle_state;
+
+ if (is_setup) {
+ /* Queue only the setup TRB */
+ field = TRB_IDT | TRB_IOC | TRB_TYPE(TRB_SETUP);
+ if (start_cycle == 0)
+ field |= 0x1;
+
+ /* xHCI 1.0 6.4.1.2.1: Transfer Type field */
+ if (xhci->hci_version == 0x100) {
+ if (setup->bRequestType & USB_DIR_IN)
+ field |= TRB_TX_TYPE(TRB_DATA_IN);
+ else
+ field |= TRB_TX_TYPE(TRB_DATA_OUT);
+ }
+
+ /* Save the DMA address of the last TRB in the TD */
+ td->last_trb = ep_ring->enqueue;
+
+ queue_trb(xhci, ep_ring, false,
+ setup->bRequestType | setup->bRequest << 8 |
+ le16_to_cpu(setup->wValue) << 16,
+ le16_to_cpu(setup->wIndex) |
+ le16_to_cpu(setup->wLength) << 16,
+ TRB_LEN(8) | TRB_INTR_TARGET(0),
+ field);
+ } else {
+ /* Queue data TRB */
+ field = TRB_ISP | TRB_TYPE(TRB_DATA);
+ if (start_cycle == 0)
+ field |= 0x1;
+ if (setup->bRequestType & USB_DIR_IN)
+ field |= TRB_DIR_IN;
+
+ length_field = TRB_LEN(urb->transfer_buffer_length) |
+ xhci_td_remainder(urb->transfer_buffer_length) |
+ TRB_INTR_TARGET(0);
+ queue_trb(xhci, ep_ring, true,
+ lower_32_bits(urb->transfer_dma),
+ upper_32_bits(urb->transfer_dma),
+ length_field,
+ field);
+
+ /* Save the DMA address of the last TRB in the TD */
+ td->last_trb = ep_ring->enqueue;
+
+ /* Queue status TRB */
+ field = TRB_IOC | TRB_TYPE(TRB_STATUS);
+ if (!(setup->bRequestType & USB_DIR_IN))
+ field |= TRB_DIR_IN;
+
+ queue_trb(xhci, ep_ring, false,
+ 0,
+ 0,
+ TRB_INTR_TARGET(0),
+ field | ep_ring->cycle_state);
+ }
+
+ giveback_first_trb(xhci, slot_id, ep_index, 0, start_cycle, start_trb);
+ return 0;
+}
+
static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
struct urb *urb, int i)
{
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 8f3651b..e47f46c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1823,4 +1823,8 @@
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
+/* EHSET */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
+ int is_setup);
+
#endif /* __LINUX_XHCI_HCD_H */
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index a074e2d..c0b2771 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -851,6 +851,24 @@
return 0;
}
+static void msm_otg_bus_vote(struct msm_otg *motg, enum usb_bus_vote vote)
+{
+ int ret;
+ struct msm_otg_platform_data *pdata = motg->pdata;
+
+ /* Check if target allows min_vote to be same as no_vote */
+ if (vote >= pdata->bus_scale_table->num_usecases)
+ vote = USB_NO_PERF_VOTE;
+
+ if (motg->bus_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ motg->bus_perf_client, vote);
+ if (ret)
+ dev_err(motg->phy.dev, "%s: Failed to vote (%d)\n"
+ "for bus bw %d\n", __func__, vote, ret);
+ }
+}
+
#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
@@ -1040,6 +1058,8 @@
if (bus)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+ msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+
atomic_set(&motg->in_lpm, 1);
/* Enable ASYNC IRQ (if present) during LPM */
if (motg->async_irq)
@@ -1068,6 +1088,9 @@
disable_irq(motg->irq);
wake_lock(&motg->wlock);
+ /* Some platforms require BUS vote to enable/disable clocks */
+ msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+
/* Vote for TCXO when waking up the phy */
if (motg->lpm_flags & XO_SHUTDOWN) {
if (!IS_ERR(motg->xo_clk)) {
@@ -1550,7 +1573,6 @@
static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
{
- int ret;
struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
struct msm_otg_platform_data *pdata = motg->pdata;
@@ -1568,29 +1590,18 @@
pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
/* Configure BUS performance parameters for MAX bandwidth */
- if (motg->bus_perf_client && debug_bus_voting_enabled) {
- ret = msm_bus_scale_client_update_request(
- motg->bus_perf_client, 1);
- if (ret)
- dev_err(motg->phy.dev, "%s: Failed to vote for "
- "bus bandwidth %d\n", __func__, ret);
- }
+ if (debug_bus_voting_enabled)
+ msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+
usb_gadget_vbus_connect(otg->gadget);
} else {
dev_dbg(otg->phy->dev, "gadget off\n");
usb_gadget_vbus_disconnect(otg->gadget);
/* Configure BUS performance parameters to default */
- if (motg->bus_perf_client) {
- ret = msm_bus_scale_client_update_request(
- motg->bus_perf_client, 0);
- if (ret)
- dev_err(motg->phy.dev, "%s: Failed to devote "
- "for bus bw %d\n", __func__, ret);
- }
+ msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
if (pdata->setup_gpio)
pdata->setup_gpio(OTG_STATE_UNDEFINED);
}
-
}
static int msm_otg_set_peripheral(struct usb_otg *otg,
@@ -3469,7 +3480,6 @@
size_t count, loff_t *ppos)
{
char buf[8];
- int ret;
struct seq_file *s = file->private_data;
struct msm_otg *motg = s->private;
@@ -3483,13 +3493,7 @@
debug_bus_voting_enabled = true;
} else {
debug_bus_voting_enabled = false;
- if (motg->bus_perf_client) {
- ret = msm_bus_scale_client_update_request(
- motg->bus_perf_client, 0);
- if (ret)
- dev_err(motg->phy.dev, "%s: Failed to devote "
- "for bus bw %d\n", __func__, ret);
- }
+ msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
}
return count;
@@ -3712,6 +3716,7 @@
ofdev->dev.platform_data;
ci_pdata.log2_itc = otg_pdata->log2_itc;
ci_pdata.usb_core_id = 0;
+ ci_pdata.l1_supported = otg_pdata->l1_supported;
retval = platform_device_add_data(pdev, &ci_pdata,
sizeof(ci_pdata));
if (retval)
@@ -3843,6 +3848,9 @@
if (pdata->pmic_id_irq < 0)
pdata->pmic_id_irq = 0;
+ pdata->l1_supported = of_property_read_bool(node,
+ "qcom,hsusb-l1-supported");
+
return pdata;
}
@@ -3881,17 +3889,17 @@
pdata = pdev->dev.platform_data;
}
- motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
+ motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
if (!motg) {
dev_err(&pdev->dev, "unable to allocate msm_otg\n");
return -ENOMEM;
}
- motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+ motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
+ GFP_KERNEL);
if (!motg->phy.otg) {
dev_err(&pdev->dev, "unable to allocate usb_otg\n");
- ret = -ENOMEM;
- goto free_motg;
+ return -ENOMEM;
}
the_msm_otg = motg;
@@ -3899,6 +3907,19 @@
phy = &motg->phy;
phy->dev = &pdev->dev;
+ if (motg->pdata->bus_scale_table) {
+ motg->bus_perf_client =
+ msm_bus_scale_register_client(motg->pdata->bus_scale_table);
+ if (!motg->bus_perf_client) {
+ dev_err(motg->phy.dev, "%s: Failed to register BUS\n"
+ "scaling client!!\n", __func__);
+ } else {
+ debug_bus_voting_enabled = true;
+ /* Some platforms require BUS vote to control clocks */
+ msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+ }
+ }
+
/*
* ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
* PHY treat ACA ID_GND as float and no interrupt is generated. But
@@ -3907,7 +3928,7 @@
if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
ret = -EINVAL;
- goto free_otg;
+ goto devote_bus_bw;
}
/* initialize reset counter */
@@ -4202,16 +4223,6 @@
pm_runtime_use_autosuspend(&pdev->dev);
}
- if (motg->pdata->bus_scale_table) {
- motg->bus_perf_client =
- msm_bus_scale_register_client(motg->pdata->bus_scale_table);
- if (!motg->bus_perf_client)
- dev_err(motg->phy.dev, "%s: Failed to register BUS "
- "scaling client!!\n", __func__);
- else
- debug_bus_voting_enabled = true;
- }
-
motg->usb_psy.name = "usb";
motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
@@ -4279,10 +4290,12 @@
clk_put(motg->clk);
if (!IS_ERR(motg->phy_reset_clk))
clk_put(motg->phy_reset_clk);
-free_otg:
- kfree(motg->phy.otg);
-free_motg:
- kfree(motg);
+devote_bus_bw:
+ if (motg->bus_perf_client) {
+ msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+ msm_bus_scale_unregister_client(motg->bus_perf_client);
+ }
+
return ret;
}
@@ -4363,11 +4376,11 @@
clk_put(motg->clk);
clk_put(motg->core_clk);
- if (motg->bus_perf_client)
+ if (motg->bus_perf_client) {
+ msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
msm_bus_scale_unregister_client(motg->bus_perf_client);
+ }
- kfree(motg->phy.otg);
- kfree(motg);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index e5b6603..91e70a7 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -539,13 +539,6 @@
return 0;
}
-static int mdp3_iommu_fault_handler(struct iommu_domain *domain,
- struct device *dev, unsigned long iova, int flags, void *token)
-{
- pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
- return 0;
-}
-
int mdp3_iommu_attach(int context)
{
struct mdp3_iommu_ctx_map *context_map;
@@ -621,9 +614,6 @@
else
return PTR_ERR(mdp3_iommu_domains[i].domain);
}
- iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
- mdp3_iommu_fault_handler,
- NULL);
}
mdp3_res->domains = mdp3_iommu_domains;
@@ -826,20 +816,16 @@
struct ion_client *iclient = mdp3_res->ion_client;
int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
- if (!data->srcp_file) {
- pr_debug("No img to put\n");
- return 0;
- }
- if (data->flags & MDP_BLIT_SRC_GEM) {
- pr_debug("memory source MDP_BLIT_SRC_GEM\n");
- } else if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
- pr_debug("fb mem buf=0x%x\n", data->addr);
+ if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
+ pr_info("mdp3_put_img fb mem buf=0x%x\n", data->addr);
fput_light(data->srcp_file, data->p_need);
data->srcp_file = NULL;
- } else {
+ } else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
ion_free(iclient, data->srcp_ihdl);
data->srcp_ihdl = NULL;
+ } else {
+ return -EINVAL;
}
return 0;
}
@@ -855,16 +841,9 @@
start = (unsigned long *) &data->addr;
len = (unsigned long *) &data->len;
- data->flags |= img->flags;
+ data->flags = img->flags;
data->p_need = 0;
- if (img->flags & MDP_BLIT_SRC_GEM) {
- data->srcp_file = NULL;
- ret = kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
- &data->addr, &data->len);
- if (!ret)
- goto done;
- }
if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
file = fget_light(img->memory_id, &data->p_need);
if (file == NULL) {
@@ -889,8 +868,7 @@
data->srcp_file = file;
if (!ret)
goto done;
- }
- if (iclient) {
+ } else if (iclient) {
data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
pr_err("error on ion_import_fd\n");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index fdd9666..f43d1ed 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -525,6 +525,7 @@
off_error:
mdp3_session->status = 0;
+ mdp3_bufq_deinit(&mdp3_session->bufq_out);
mutex_unlock(&mdp3_session->lock);
if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST)
mdp3_overlay_unset(mfd, mdp3_session->overlay.id);
@@ -576,14 +577,11 @@
int rc = 0;
struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
- mdp3_ctrl_pan_display(mfd);
-
mutex_lock(&mdp3_session->lock);
if (mdp3_session->overlay.id == ndx && ndx == 1) {
mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
mdp3_bufq_deinit(&mdp3_session->bufq_in);
- mdp3_bufq_deinit(&mdp3_session->bufq_out);
} else {
rc = -EINVAL;
}
@@ -665,7 +663,7 @@
mdp3_bufq_push(&mdp3_session->bufq_out, data);
}
- if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
+ if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
data = mdp3_bufq_pop(&mdp3_session->bufq_out);
mdp3_put_img(data);
}
@@ -715,7 +713,7 @@
mdp3_session->intf);
} else {
pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
- mdp3_session->intf->stop(mdp3_session->intf);
+ mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
}
pan_error:
mutex_unlock(&mdp3_session->lock);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 3ddabb4..3b65405 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -816,6 +816,7 @@
mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_VSYNC |
MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
+ init_completion(&dma->dma_comp);
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 366209b..fb0e8ba 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -416,6 +416,14 @@
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
+ if (ret) {
+ pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
+ ret);
+ mdss_dsi_panel_power_on(pdata, 0);
+ return ret;
+ }
+
/* disable DSI phy */
mdss_dsi_phy_enable(ctrl_pdata, 0);
@@ -479,6 +487,7 @@
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
+ mdss_dsi_disable_bus_clocks(ctrl_pdata);
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
@@ -593,6 +602,13 @@
}
mdss_dsi_op_mode_config(mipi->mode, pdata);
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ if (mipi->vsync_enable && mipi->hw_vsync_mode
+ && gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+ mdss_dsi_set_tear_on(ctrl_pdata);
+ }
+ }
+
pr_debug("%s-:\n", __func__);
return ret;
@@ -601,6 +617,7 @@
static int mdss_dsi_blank(struct mdss_panel_data *pdata)
{
int ret = 0;
+ struct mipi_panel_info *mipi;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
pr_debug("%s+:\n", __func__);
@@ -612,9 +629,17 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ mipi = &pdata->panel_info.mipi;
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ if (mipi->vsync_enable && mipi->hw_vsync_mode
+ && gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+ mdss_dsi_set_tear_off(ctrl_pdata);
+ }
+ }
+
if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
ret = ctrl_pdata->off(pdata);
if (ret) {
@@ -1143,15 +1168,6 @@
return rc;
}
- rc = mdss_dsi_enable_bus_clocks(ctrl_pdata);
- if (rc) {
- pr_err("%s: failed to enable bus clocks. rc=%d\n",
- __func__, rc);
- rc = mdss_dsi_panel_power_on(
- &(ctrl_pdata->panel_data), 0);
- return rc;
- }
-
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
ctrl_pdata->ctrl_state |=
(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 965a23f..8a8e4ca 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -382,6 +382,8 @@
void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
struct mdss_panel_data *pdata);
+void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 72e3c64..2f29b3d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -80,6 +80,7 @@
mutex_lock(&ctrl->mutex);
if (enable) {
if (ctrl->clk_cnt == 0) {
+ mdss_dsi_enable_bus_clocks(ctrl);
mdss_dsi_prepare_clocks(ctrl);
mdss_dsi_clk_enable(ctrl);
}
@@ -90,6 +91,7 @@
if (ctrl->clk_cnt == 0) {
mdss_dsi_clk_disable(ctrl);
mdss_dsi_unprepare_clocks(ctrl);
+ mdss_dsi_disable_bus_clocks(ctrl);
}
}
}
@@ -1098,6 +1100,40 @@
pr_debug("%s: BTA done, status = %d\n", __func__, status);
}
+static char set_tear_on[2] = {0x35, 0x00};
+static struct dsi_cmd_desc dsi_tear_on_cmd = {
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on};
+
+static char set_tear_off[2] = {0x34, 0x00};
+static struct dsi_cmd_desc dsi_tear_off_cmd = {
+ {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off)}, set_tear_off};
+
+void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_on_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_off_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
int mdss_dsi_cmd_reg_tx(u32 data,
unsigned char *ctrl_base)
{
@@ -1638,7 +1674,7 @@
if (status) {
MIPI_OUTP(base + 0x0068, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -1649,7 +1685,7 @@
status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */
if (status & 0x0111) {
MIPI_OUTP(base + 0x00c0, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -1661,7 +1697,7 @@
if (status & 0x011111) {
MIPI_OUTP(base + 0x00b4, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -1673,7 +1709,7 @@
if (status & 0x44444489) {
MIPI_OUTP(base + 0x000c, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -1685,7 +1721,7 @@
if (status & 0x80000000) {
MIPI_OUTP(base + 0x0008, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 287f2cd..91e5660 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2250,6 +2250,8 @@
*/
hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM].clk_config[0].rate = 0;
+ hdmi_cec_deconfig(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
+
hdmi_tx_core_off(hdmi_ctrl);
if (hdmi_ctrl->hpd_off_pending) {
@@ -2257,8 +2259,6 @@
hdmi_ctrl->hpd_off_pending = false;
}
- hdmi_cec_deconfig(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
-
mutex_lock(&hdmi_ctrl->mutex);
hdmi_ctrl->panel_power_on = false;
mutex_unlock(&hdmi_ctrl->mutex);
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 809db43..31058f8 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include "mdss_io_util.h"
#define MAX_I2C_CMDS 16
@@ -160,19 +161,6 @@
curr_vreg->vreg_name);
goto vreg_set_voltage_fail;
}
- if (curr_vreg->peak_current >= 0) {
- rc = regulator_set_optimum_mode(
- curr_vreg->vreg,
- curr_vreg->peak_current);
- if (rc < 0) {
- DEV_ERR(
- "%pS->%s: %s set opt m fail\n",
- __builtin_return_address(0),
- __func__,
- curr_vreg->vreg_name);
- goto vreg_set_opt_mode_fail;
- }
- }
}
}
} else {
@@ -183,10 +171,6 @@
curr_vreg->vreg) > 0)
? DSS_REG_LDO : DSS_REG_VS;
if (type == DSS_REG_LDO) {
- if (curr_vreg->peak_current >= 0) {
- regulator_set_optimum_mode(
- curr_vreg->vreg, 0);
- }
regulator_set_voltage(curr_vreg->vreg,
0, curr_vreg->max_voltage);
}
@@ -201,10 +185,6 @@
if (type == DSS_REG_LDO)
regulator_set_optimum_mode(curr_vreg->vreg, 0);
-vreg_set_opt_mode_fail:
-if (type == DSS_REG_LDO)
- regulator_set_voltage(curr_vreg->vreg, 0, curr_vreg->max_voltage);
-
vreg_set_voltage_fail:
regulator_put(curr_vreg->vreg);
curr_vreg->vreg = NULL;
@@ -229,9 +209,19 @@
DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
__builtin_return_address(0), __func__,
in_vreg[i].vreg_name, rc);
- goto disable_vreg;
+ goto vreg_set_opt_mode_fail;
+ }
+ msleep(in_vreg[i].pre_on_sleep);
+ rc = regulator_set_optimum_mode(in_vreg[i].vreg,
+ in_vreg[i].peak_current);
+ if (rc < 0) {
+ DEV_ERR("%pS->%s: %s set opt m fail\n",
+ __builtin_return_address(0), __func__,
+ in_vreg[i].vreg_name);
+ goto vreg_set_opt_mode_fail;
}
rc = regulator_enable(in_vreg[i].vreg);
+ msleep(in_vreg[i].post_on_sleep);
if (rc < 0) {
DEV_ERR("%pS->%s: %s enable failed\n",
__builtin_return_address(0), __func__,
@@ -241,14 +231,26 @@
}
} else {
for (i = num_vreg-1; i >= 0; i--)
- if (regulator_is_enabled(in_vreg[i].vreg))
+ if (regulator_is_enabled(in_vreg[i].vreg)) {
+ msleep(in_vreg[i].pre_off_sleep);
+ regulator_set_optimum_mode(in_vreg[i].vreg, 0);
regulator_disable(in_vreg[i].vreg);
+ msleep(in_vreg[i].post_off_sleep);
+ }
}
return rc;
disable_vreg:
- for (i--; i >= 0; i--)
+ regulator_set_optimum_mode(in_vreg[i].vreg, 0);
+
+vreg_set_opt_mode_fail:
+ for (i--; i >= 0; i--) {
+ msleep(in_vreg[i].pre_off_sleep);
+ regulator_set_optimum_mode(in_vreg[i].vreg, 0);
regulator_disable(in_vreg[i].vreg);
+ msleep(in_vreg[i].post_off_sleep);
+ }
+
return rc;
} /* msm_dss_enable_vreg */
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
index 23341d6..cb0fb70 100644
--- a/drivers/video/msm/mdss/mdss_io_util.h
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -53,6 +53,10 @@
int min_voltage;
int max_voltage;
int peak_current;
+ int pre_on_sleep;
+ int post_on_sleep;
+ int pre_off_sleep;
+ int post_off_sleep;
};
struct dss_gpio {
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index c4bf67e..fc8c6e3 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -703,13 +703,6 @@
return 0;
}
-static int mdss_iommu_fault_handler(struct iommu_domain *domain,
- struct device *dev, unsigned long iova, int flags, void *token)
-{
- pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
- return 0;
-}
-
int mdss_iommu_attach(struct mdss_data_type *mdata)
{
struct iommu_domain *domain;
@@ -796,7 +789,6 @@
iomap->domain_idx);
return -EINVAL;
}
- iommu_set_fault_handler(domain, mdss_iommu_fault_handler, NULL);
iomap->ctx = msm_iommu_get_ctx(iomap->ctx_name);
if (!iomap->ctx) {
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index ab4ae4b..7cae18c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -312,6 +312,8 @@
u8 vert_deci;
struct mdss_mdp_img_rect src;
struct mdss_mdp_img_rect dst;
+ u32 phase_step_x;
+ u32 phase_step_y;
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
@@ -428,6 +430,7 @@
struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
struct msm_fb_data_type *mfd);
int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
@@ -545,6 +548,7 @@
int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
+int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase);
int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd);
int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 9eaff61..86f632c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -517,6 +517,7 @@
case MIPI_VIDEO_PANEL:
return mdss_mdp_video_reconfigure_splash_done(ctl);
case MIPI_CMD_PANEL:
+ return mdss_mdp_cmd_reconfigure_splash_done(ctl);
default:
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index bd4f3ea..d0c1818 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -26,20 +26,20 @@
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KOFF_TIMEOUT msecs_to_jiffies(84)
+#define STOP_TIMEOUT msecs_to_jiffies(16 * (VSYNC_EXPIRE_TICK + 2))
+
struct mdss_mdp_cmd_ctx {
struct mdss_mdp_ctl *ctl;
u32 pp_num;
u8 ref_cnt;
- struct completion vsync_comp;
struct completion pp_comp;
struct completion stop_comp;
mdp_vsync_handler_t send_vsync;
int panel_on;
int koff_cnt;
int clk_enabled;
- int clk_control;
int vsync_enabled;
- int expire;
+ int rdptr_enabled;
struct mutex clk_mtx;
spinlock_t clk_lock;
struct work_struct clk_work;
@@ -54,6 +54,50 @@
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
+static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_mixer *mixer;
+ u32 cnt = 0xffff; /* init it to an invalid value */
+ u32 init;
+ u32 height;
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+ if (!mixer) {
+ mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
+ if (!mixer) {
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ goto exit;
+ }
+ }
+
+ init = mdss_mdp_pingpong_read
+ (mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL) & 0xffff;
+
+ height = mdss_mdp_pingpong_read
+ (mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT) & 0xffff;
+
+ if (height < init) {
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ goto exit;
+ }
+
+ cnt = mdss_mdp_pingpong_read
+ (mixer, MDSS_MDP_REG_PP_INT_COUNT_VAL) & 0xffff;
+
+ if (cnt < init) /* wrap around happened at height */
+ cnt += (height - init);
+ else
+ cnt -= init;
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ pr_debug("cnt=%d init=%d height=%d\n", cnt, init, height);
+exit:
+ return cnt;
+}
+
/*
* TE configuration:
* dsi byte clock calculated base on 70 fps
@@ -146,6 +190,45 @@
return 0;
}
+static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
+{
+ unsigned long flags;
+ mutex_lock(&ctx->clk_mtx);
+ if (!ctx->clk_enabled) {
+ ctx->clk_enabled = 1;
+ mdss_mdp_ctl_intf_event
+ (ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ }
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ if (!ctx->rdptr_enabled)
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
+ ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
+ mutex_unlock(&ctx->clk_mtx);
+}
+
+static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
+{
+ unsigned long flags;
+ int set_clk_off = 0;
+
+ mutex_lock(&ctx->clk_mtx);
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ if (!ctx->rdptr_enabled)
+ set_clk_off = 1;
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
+
+ if (ctx->clk_enabled && set_clk_off) {
+ ctx->clk_enabled = 0;
+ mdss_mdp_ctl_intf_event
+ (ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ complete(&ctx->stop_comp);
+ }
+ mutex_unlock(&ctx->clk_mtx);
+}
+
static void mdss_mdp_cmd_readptr_done(void *arg)
{
struct mdss_mdp_ctl *ctl = arg;
@@ -157,11 +240,6 @@
return;
}
- complete_all(&ctx->vsync_comp);
-
- pr_debug("%s: num=%d ctx=%d expire=%d koff=%d\n", __func__, ctl->num,
- ctx->pp_num, ctx->expire, ctx->koff_cnt);
-
vsync_time = ktime_get();
ctl->vsync_cnt++;
@@ -169,18 +247,17 @@
if (ctx->send_vsync)
ctx->send_vsync(ctl, vsync_time);
- if (ctx->expire) {
- ctx->expire--;
- if (ctx->expire == 0) {
- if (ctx->koff_cnt <= 0) {
- ctx->clk_control = 1;
- schedule_work(&ctx->clk_work);
- } else {
- /* put off one vsync */
- ctx->expire += 1;
- }
- }
+ if (!ctx->vsync_enabled) {
+ if (ctx->rdptr_enabled)
+ ctx->rdptr_enabled--;
}
+
+ if (ctx->rdptr_enabled == 0) {
+ mdss_mdp_irq_disable_nosync
+ (MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
+ schedule_work(&ctx->clk_work);
+ }
+
spin_unlock(&ctx->clk_lock);
}
@@ -199,8 +276,15 @@
complete_all(&ctx->pp_comp);
- if (ctx->koff_cnt)
+ if (ctx->koff_cnt) {
ctx->koff_cnt--;
+ if (ctx->koff_cnt) {
+ pr_err("%s: too many kickoffs=%d!\n", __func__,
+ ctx->koff_cnt);
+ ctx->koff_cnt = 0;
+ }
+ } else
+ pr_err("%s: should not have pingpong interrupt!\n", __func__);
pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d kcnt=%d\n", __func__,
ctl->num, ctl->intf_num, ctx->pp_num, ctx->koff_cnt);
@@ -210,7 +294,6 @@
static void clk_ctrl_work(struct work_struct *work)
{
- unsigned long flags;
struct mdss_mdp_cmd_ctx *ctx =
container_of(work, typeof(*ctx), clk_work);
@@ -219,38 +302,14 @@
return;
}
- pr_debug("%s:ctx=%p num=%d\n", __func__, ctx, ctx->pp_num);
-
- mutex_lock(&ctx->clk_mtx);
- spin_lock_irqsave(&ctx->clk_lock, flags);
- if (ctx->clk_control && ctx->clk_enabled) {
- ctx->clk_enabled = 0;
- ctx->clk_control = 0;
- spin_unlock_irqrestore(&ctx->clk_lock, flags);
- /*
- * make sure dsi link is idle here
- */
- ctx->vsync_enabled = 0;
- mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
- ctx->pp_num);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- /* disable dsi clock */
- mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
- (void *)0);
- complete(&ctx->stop_comp);
- pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid);
- } else {
- spin_unlock_irqrestore(&ctx->clk_lock, flags);
- }
- mutex_unlock(&ctx->clk_mtx);
+ mdss_mdp_cmd_clk_off(ctx);
}
-static int mdss_mdp_cmd_vsync_ctrl(struct mdss_mdp_ctl *ctl,
- struct mdss_mdp_vsync_handler *handler)
+static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_vsync_handler *handle)
{
struct mdss_mdp_cmd_ctx *ctx;
unsigned long flags;
- int enable;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
if (!ctx) {
@@ -258,81 +317,62 @@
return -ENODEV;
}
- enable = (handler->vsync_handler != NULL);
-
- mutex_lock(&ctx->clk_mtx);
-
- pr_debug("%s: ctx=%p ctx=%d enabled=%d %d clk_enabled=%d clk_ctrl=%d\n",
- __func__, ctx, ctx->pp_num, ctx->vsync_enabled, enable,
- ctx->clk_enabled, ctx->clk_control);
-
- if (ctx->vsync_enabled == enable) {
- mutex_unlock(&ctx->clk_mtx);
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ if (ctx->vsync_enabled) {
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
return 0;
}
+ ctx->vsync_enabled = 1;
+ ctx->send_vsync = handle->vsync_handler;
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
- if (enable) {
- spin_lock_irqsave(&ctx->clk_lock, flags);
- ctx->clk_control = 0;
- ctx->expire = 0;
- ctx->send_vsync = handler->vsync_handler;
- spin_unlock_irqrestore(&ctx->clk_lock, flags);
- if (ctx->clk_enabled == 0) {
- mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL,
- (void *)1);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
- ctx->pp_num);
- ctx->vsync_enabled = 1;
- ctx->clk_enabled = 1;
- pr_debug("%s: SET_CLK_ON, pid=%d\n", __func__,
- current->pid);
- }
- } else {
- spin_lock_irqsave(&ctx->clk_lock, flags);
- ctx->expire = VSYNC_EXPIRE_TICK;
- spin_unlock_irqrestore(&ctx->clk_lock, flags);
- }
- mutex_unlock(&ctx->clk_mtx);
+ mdss_mdp_cmd_clk_on(ctx);
return 0;
}
-static void mdss_mdp_cmd_chk_clock(struct mdss_mdp_cmd_ctx *ctx)
+static int mdss_mdp_cmd_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_vsync_handler *handle)
{
- unsigned long flags;
- int set_clk_on = 0;
+ struct mdss_mdp_cmd_ctx *ctx;
+ unsigned long flags;
+
+ ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
if (!ctx) {
- pr_err("invalid ctx\n");
- return;
+ pr_err("%s: invalid ctx\n", __func__);
+ return -ENODEV;
}
- mutex_lock(&ctx->clk_mtx);
-
- pr_debug("%s: ctx=%p num=%d clk_enabled=%d\n", __func__,
- ctx, ctx->pp_num, ctx->clk_enabled);
spin_lock_irqsave(&ctx->clk_lock, flags);
- ctx->koff_cnt++;
- ctx->clk_control = 0;
- ctx->expire = VSYNC_EXPIRE_TICK;
- if (ctx->clk_enabled == 0) {
- set_clk_on++;
- ctx->clk_enabled = 1;
+ if (!ctx->vsync_enabled) {
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
+ return 0;
}
+ ctx->vsync_enabled = 0;
+ ctx->send_vsync = NULL;
+ ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
spin_unlock_irqrestore(&ctx->clk_lock, flags);
+ return 0;
+}
- if (set_clk_on) {
- mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
- (void *)1);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- ctx->vsync_enabled = 1;
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
- pr_debug("%s: ctx=%p num=%d SET_CLK_ON\n", __func__,
- ctx, ctx->pp_num);
- }
- mutex_unlock(&ctx->clk_mtx);
+int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_panel_data *pdata;
+ int ret = 0;
+
+ pdata = ctl->panel_data;
+
+ pdata->panel_info.cont_splash_enabled = 0;
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
+ NULL);
+
+ mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return ret;
}
static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
@@ -374,6 +414,7 @@
int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
+ unsigned long flags;
int rc;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -392,18 +433,19 @@
WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
}
- mdss_mdp_cmd_chk_clock(ctx);
+ mdss_mdp_cmd_clk_on(ctx);
/*
* tx dcs command if had any
*/
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
- INIT_COMPLETION(ctx->vsync_comp);
INIT_COMPLETION(ctx->pp_comp);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
-
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ ctx->koff_cnt++;
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
mb();
return 0;
@@ -412,8 +454,8 @@
int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_cmd_ctx *ctx;
+ unsigned long flags;
int need_wait = 0;
- struct mdss_mdp_vsync_handler null_handle;
int ret;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -421,25 +463,27 @@
pr_err("invalid ctx\n");
return -ENODEV;
}
-
- pr_debug("%s:+ vaync_enable=%d expire=%d\n", __func__,
- ctx->vsync_enabled, ctx->expire);
-
- mutex_lock(&ctx->clk_mtx);
- if (ctx->vsync_enabled) {
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ if (ctx->rdptr_enabled) {
INIT_COMPLETION(ctx->stop_comp);
need_wait = 1;
}
- mutex_unlock(&ctx->clk_mtx);
+ if (ctx->vsync_enabled) {
+ pr_err("%s: vsync should be disabled\n", __func__);
+ ctx->vsync_enabled = 0;
+ }
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
- if (need_wait)
- wait_for_completion_interruptible(&ctx->stop_comp);
+ if (need_wait) {
+ if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT)
+ <= 0) {
+ WARN(1, "stop cmd time out\n");
+ mdss_mdp_cmd_clk_off(ctx);
+ }
+ }
ctx->panel_on = 0;
- null_handle.vsync_handler = NULL;
- mdss_mdp_cmd_vsync_ctrl(ctl, &null_handle);
-
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
NULL, NULL);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
@@ -499,7 +543,6 @@
ctx->ctl = ctl;
ctx->pp_num = mixer->num;
- init_completion(&ctx->vsync_comp);
init_completion(&ctx->pp_comp);
init_completion(&ctx->stop_comp);
spin_lock_init(&ctx->clk_lock);
@@ -524,9 +567,9 @@
ctl->stop_fnc = mdss_mdp_cmd_stop;
ctl->display_fnc = mdss_mdp_cmd_kickoff;
ctl->wait_pingpong = mdss_mdp_cmd_wait4pingpong;
- ctl->add_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
- ctl->remove_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
-
+ ctl->add_vsync_handler = mdss_mdp_cmd_add_vsync_handler;
+ ctl->remove_vsync_handler = mdss_mdp_cmd_remove_vsync_handler;
+ ctl->read_line_cnt_fnc = mdss_mdp_cmd_line_count;
pr_debug("%s:-\n", __func__);
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 8b10900..780ff94 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -180,6 +180,11 @@
pr_err("BWC: unequal src img and rect w,h\n");
return -EINVAL;
}
+
+ if (req->flags & MDP_DECIMATION_EN) {
+ pr_err("Can't enable BWC decode && decimate\n");
+ return -EINVAL;
+ }
}
if (req->flags & MDP_DEINTERLACE) {
@@ -283,7 +288,7 @@
req->id = rot->session_id;
} else {
pr_err("Unable to setup rotator session\n");
- mdss_mdp_rotator_release(rot->session_id);
+ mdss_mdp_rotator_release(rot);
}
return ret;
@@ -315,6 +320,30 @@
return 0;
}
+static int __mdss_mdp_overlay_setup_scaling(struct mdss_mdp_pipe *pipe)
+{
+ u32 src;
+ int rc;
+
+ src = pipe->src.w >> pipe->horz_deci;
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.w, &pipe->phase_step_x);
+ if (rc) {
+ pr_err("Horizontal scaling calculation failed=%d! %d->%d\n",
+ rc, src, pipe->dst.w);
+ return rc;
+ }
+
+ src = pipe->src.h >> pipe->vert_deci;
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.h, &pipe->phase_step_y);
+ if (rc) {
+ pr_err("Vertical scaling calculation failed=%d! %d->%d\n",
+ rc, src, pipe->dst.h);
+ return rc;
+ }
+
+ return 0;
+}
+
static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
struct mdss_mdp_pipe **ppipe)
@@ -535,6 +564,10 @@
goto exit_fail;
}
+ ret = __mdss_mdp_overlay_setup_scaling(pipe);
+ if (ret)
+ goto exit_fail;
+
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -861,10 +894,17 @@
pr_debug("unset ndx=%x\n", ndx);
- if (ndx & MDSS_MDP_ROT_SESSION_MASK)
- ret = mdss_mdp_rotator_release(ndx);
- else
+ if (ndx & MDSS_MDP_ROT_SESSION_MASK) {
+ struct mdss_mdp_rotator_session *rot;
+ rot = mdss_mdp_rotator_session_get(ndx);
+ if (rot) {
+ mdss_mdp_overlay_free_buf(&rot->src_buf);
+ mdss_mdp_overlay_free_buf(&rot->dst_buf);
+ ret = mdss_mdp_rotator_release(rot);
+ }
+ } else {
ret = mdss_mdp_overlay_release(mfd, ndx);
+ }
done:
mutex_unlock(&mdp5_data->ov_lock);
@@ -925,7 +965,6 @@
struct msmfb_overlay_data *req)
{
struct mdss_mdp_rotator_session *rot;
- struct mdss_mdp_data src_data, dst_data;
int ret;
u32 flgs;
@@ -937,26 +976,26 @@
flgs = rot->flags & MDP_SECURE_OVERLAY_SESSION;
- ret = mdss_mdp_overlay_get_buf(mfd, &src_data, &req->data, 1, flgs);
+ mdss_mdp_overlay_free_buf(&rot->src_buf);
+ ret = mdss_mdp_overlay_get_buf(mfd, &rot->src_buf, &req->data, 1, flgs);
if (ret) {
pr_err("src_data pmem error\n");
return ret;
}
- ret = mdss_mdp_overlay_get_buf(mfd, &dst_data, &req->dst_data, 1, flgs);
+ mdss_mdp_overlay_free_buf(&rot->dst_buf);
+ ret = mdss_mdp_overlay_get_buf(mfd, &rot->dst_buf,
+ &req->dst_data, 1, flgs);
if (ret) {
pr_err("dst_data pmem error\n");
goto dst_buf_fail;
}
- ret = mdss_mdp_rotator_queue(rot, &src_data, &dst_data);
+ ret = mdss_mdp_rotator_queue(rot, &rot->src_buf, &rot->dst_buf);
if (ret)
pr_err("rotator queue error session id=%x\n", req->id);
- mdss_mdp_overlay_free_buf(&dst_data);
dst_buf_fail:
- mdss_mdp_overlay_free_buf(&src_data);
-
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 963d3fb..4dd9dcb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -607,39 +607,6 @@
return 0;
}
-static int mdss_mdp_leading_zero(u32 num)
-{
- u32 bit = 0x80000000;
- int i;
-
- for (i = 0; i < 32; i++) {
- if (bit & num)
- return i;
- bit >>= 1;
- }
-
- return i;
-}
-
-static u32 mdss_mdp_scale_phase_step(int f_num, u32 src, u32 dst)
-{
- u32 val, s;
- int n;
-
- n = mdss_mdp_leading_zero(src);
- if (n > f_num)
- n = f_num;
- s = src << n; /* maximum to reduce lose of resolution */
- val = s / dst;
- if (n < f_num) {
- n = f_num - n;
- val <<= n;
- val |= ((s % dst) << n) / dst;
- }
-
- return val;
-}
-
static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
{
u32 scale_config = 0;
@@ -705,13 +672,14 @@
}
scale_config |= MDSS_MDP_SCALEY_EN;
+ phasey_step = pipe->phase_step_y;
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
- u32 chr_dst_h = pipe->dst.h;
+ u32 chroma_shift = 0;
if (!pipe->vert_deci &&
((chroma_sample == MDSS_MDP_CHROMA_420) ||
(chroma_sample == MDSS_MDP_CHROMA_H1V2)))
- chr_dst_h *= 2; /* 2x upsample chroma */
+ chroma_shift = 1; /* 2x upsample chroma */
if (src_h <= pipe->dst.h) {
scale_config |= /* G/Y, A */
@@ -722,17 +690,14 @@
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
(MDSS_MDP_SCALE_FILTER_PCMN << 18);
- if (src_h <= chr_dst_h)
+ if ((src_h >> chroma_shift) <= pipe->dst.h)
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_BIL << 14);
else
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 14);
- phasey_step = mdss_mdp_scale_phase_step(
- PHASE_STEP_SHIFT, src_h, chr_dst_h);
-
- writel_relaxed(phasey_step, pipe->base +
+ writel_relaxed(phasey_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
} else {
if (src_h <= pipe->dst.h)
@@ -744,9 +709,6 @@
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
(MDSS_MDP_SCALE_FILTER_PCMN << 18);
}
-
- phasey_step = mdss_mdp_scale_phase_step(
- PHASE_STEP_SHIFT, src_h, pipe->dst.h);
}
if ((src_w != pipe->dst.w) ||
@@ -762,14 +724,15 @@
}
scale_config |= MDSS_MDP_SCALEX_EN;
+ phasex_step = pipe->phase_step_x;
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
- u32 chr_dst_w = pipe->dst.w;
+ u32 chroma_shift = 0;
if (!pipe->horz_deci &&
((chroma_sample == MDSS_MDP_CHROMA_420) ||
(chroma_sample == MDSS_MDP_CHROMA_H2V1)))
- chr_dst_w *= 2; /* 2x upsample chroma */
+ chroma_shift = 1; /* 2x upsample chroma */
if (src_w <= pipe->dst.w) {
scale_config |= /* G/Y, A */
@@ -780,16 +743,14 @@
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
(MDSS_MDP_SCALE_FILTER_PCMN << 16);
- if (src_w <= chr_dst_w)
+ if ((src_w >> chroma_shift) <= pipe->dst.w)
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_BIL << 12);
else
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 12);
- phasex_step = mdss_mdp_scale_phase_step(
- PHASE_STEP_SHIFT, src_w, chr_dst_w);
- writel_relaxed(phasex_step, pipe->base +
+ writel_relaxed(phasex_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
} else {
if (src_w <= pipe->dst.w)
@@ -801,9 +762,6 @@
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
(MDSS_MDP_SCALE_FILTER_PCMN << 16);
}
-
- phasex_step = mdss_mdp_scale_phase_step(
- PHASE_STEP_SHIFT, src_w, pipe->dst.w);
}
writel_relaxed(scale_config, pipe->base +
@@ -3371,6 +3329,14 @@
ret = 1;
else if (ptr >= 0x3200 || ptr == 0x100)
ret = 1;
+ else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
+ ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
+ ret = 1;
+ else if (ptr == 0x618 || ptr == 0x718 || ptr == 0x818 ||
+ ptr == 0x918 || ptr == 0xa18)
+ ret = 1;
+ else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
+ ret = 1;
}
end:
return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index f9894cc..8c45df8 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -366,18 +366,12 @@
return 0;
}
-int mdss_mdp_rotator_release(u32 ndx)
+int mdss_mdp_rotator_release(struct mdss_mdp_rotator_session *rot)
{
int rc = 0;
- struct mdss_mdp_rotator_session *rot;
+
mutex_lock(&rotator_lock);
- rot = mdss_mdp_rotator_session_get(ndx);
- if (rot) {
- mdss_mdp_rotator_finish(rot);
- } else {
- pr_warn("unknown session id=%x\n", ndx);
- rc = -ENOENT;
- }
+ rc = mdss_mdp_rotator_finish(rot);
mutex_unlock(&rotator_lock);
return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 3401fe8..43c9e6a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -39,6 +39,9 @@
u8 busy;
u8 no_wait;
+ struct mdss_mdp_data src_buf;
+ struct mdss_mdp_data dst_buf;
+
struct list_head head;
struct mdss_mdp_rotator_session *next;
};
@@ -67,7 +70,7 @@
struct mdss_mdp_data *src_data,
struct mdss_mdp_data *dst_data);
-int mdss_mdp_rotator_release(u32 ndx);
+int mdss_mdp_rotator_release(struct mdss_mdp_rotator_session *rot);
int mdss_mdp_rotator_release_all(void);
#endif /* MDSS_MDP_ROTATOR_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b29b0eb..c7beb0e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -561,3 +561,23 @@
return ret;
}
+
+int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase)
+{
+ u32 unit, residue;
+
+ if (dst == 0)
+ return -EINVAL;
+
+ unit = 1 << PHASE_STEP_SHIFT;
+ *out_phase = mult_frac(src, unit, dst);
+
+ /* check if overflow is possible */
+ if (src > dst) {
+ residue = *out_phase & (unit - 1);
+ if (residue && ((residue * dst) < (unit - residue)))
+ return -EOVERFLOW;
+ }
+
+ return 0;
+}
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index 51a90b7..ee1c2ff 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -22,8 +22,9 @@
extern int fragmentation_index(struct zone *zone, unsigned int order);
extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
int order, gfp_t gfp_mask, nodemask_t *mask,
- bool sync);
+ bool sync, bool *contended);
extern int compact_pgdat(pg_data_t *pgdat, int order);
+extern void reset_isolation_suitable(pg_data_t *pgdat);
extern unsigned long compaction_suitable(struct zone *zone, int order);
/* Do not skip compaction more than 64 times */
@@ -61,10 +62,20 @@
return zone->compact_considered < (1UL << zone->compact_defer_shift);
}
+/* Returns true if restarting compaction after many failures */
+static inline bool compaction_restarting(struct zone *zone, int order)
+{
+ if (order < zone->compact_order_failed)
+ return false;
+
+ return zone->compact_defer_shift == COMPACT_MAX_DEFER_SHIFT &&
+ zone->compact_considered >= 1UL << zone->compact_defer_shift;
+}
+
#else
static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
int order, gfp_t gfp_mask, nodemask_t *nodemask,
- bool sync)
+ bool sync, bool *contended)
{
return COMPACT_CONTINUE;
}
@@ -74,6 +85,10 @@
return COMPACT_CONTINUE;
}
+static inline void reset_isolation_suitable(pg_data_t *pgdat)
+{
+}
+
static inline unsigned long compaction_suitable(struct zone *zone, int order)
{
return COMPACT_SKIPPED;
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 73b94af..384f37a 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -118,10 +118,10 @@
/* This needs to be modified manually now, when we add
a new RANGE of SSIDs to the msg_mask_tbl */
#define MSG_MASK_TBL_CNT 24
-#define EVENT_LAST_ID 0x09B2
+#define EVENT_LAST_ID 0x09BE
#define MSG_SSID_0 0
-#define MSG_SSID_0_LAST 97
+#define MSG_SSID_0_LAST 96
#define MSG_SSID_1 500
#define MSG_SSID_1_LAST 506
#define MSG_SSID_2 1000
@@ -137,7 +137,7 @@
#define MSG_SSID_7 4600
#define MSG_SSID_7_LAST 4613
#define MSG_SSID_8 5000
-#define MSG_SSID_8_LAST 5029
+#define MSG_SSID_8_LAST 5030
#define MSG_SSID_9 5500
#define MSG_SSID_9_LAST 5516
#define MSG_SSID_10 6000
@@ -178,7 +178,7 @@
static const uint32_t msg_bld_masks_0[] = {
MSG_LVL_LOW,
MSG_LVL_MED,
- MSG_LVL_MED,
+ MSG_LVL_LOW,
MSG_LVL_ERROR,
MSG_LVL_LOW,
MSG_LVL_MED,
@@ -186,20 +186,20 @@
MSG_LVL_HIGH,
MSG_LVL_ERROR,
MSG_LVL_LOW,
- MSG_LVL_ERROR,
+ MSG_LVL_LOW,
MSG_LVL_ERROR,
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_HIGH,
MSG_LVL_HIGH,
- MSG_LVL_HIGH,
+ MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_ERROR,
MSG_LVL_LOW,
MSG_LVL_MED,
MSG_LVL_MED,
- MSG_LVL_MED,
+ MSG_LVL_LOW,
MSG_LVL_MED,
MSG_LVL_LOW,
MSG_LVL_MED,
@@ -214,7 +214,7 @@
MSG_MASK_6|MSG_MASK_7|MSG_MASK_8|MSG_MASK_9|MSG_MASK_10| \
MSG_MASK_11|MSG_MASK_12|MSG_MASK_13|MSG_MASK_14| \
MSG_MASK_15|MSG_MASK_16|MSG_MASK_17,
- MSG_LVL_MED,
+ MSG_LVL_LOW,
MSG_LVL_MED,
MSG_LVL_HIGH,
MSG_LVL_HIGH,
@@ -238,7 +238,7 @@
MSG_LVL_MED|MSG_MASK_5 | \
MSG_MASK_6|MSG_MASK_7|MSG_MASK_8|MSG_MASK_9|MSG_MASK_10,
MSG_LVL_MED,
- MSG_LVL_MED,
+ MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_MED,
MSG_LVL_LOW,
@@ -290,7 +290,6 @@
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
- MSG_LVL_LOW
};
static const uint32_t msg_bld_masks_1[] = {
@@ -436,6 +435,7 @@
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
+ MSG_LVL_MED,
MSG_LVL_MED
};
@@ -725,7 +725,7 @@
/* LOG CODES */
#define LOG_0 0x0
-#define LOG_1 0x17FA
+#define LOG_1 0x1807
#define LOG_2 0x0
#define LOG_3 0x0
#define LOG_4 0x4910
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index f94efd2..14d38a5 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -66,7 +66,6 @@
struct lruvec *mem_cgroup_lru_add_list(struct zone *, struct page *,
enum lru_list);
void mem_cgroup_lru_del_list(struct page *, enum lru_list);
-void mem_cgroup_lru_del(struct page *);
struct lruvec *mem_cgroup_lru_move_lists(struct zone *, struct page *,
enum lru_list, enum lru_list);
@@ -79,6 +78,8 @@
extern void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
int order);
+bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
+ struct mem_cgroup *memcg);
int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg);
extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
@@ -92,10 +93,13 @@
int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup)
{
struct mem_cgroup *memcg;
+ int match;
+
rcu_read_lock();
memcg = mem_cgroup_from_task(rcu_dereference((mm)->owner));
+ match = __mem_cgroup_same_or_subtree(cgroup, memcg);
rcu_read_unlock();
- return cgroup == memcg;
+ return match;
}
extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg);
@@ -262,10 +266,6 @@
{
}
-static inline void mem_cgroup_lru_del(struct page *page)
-{
-}
-
static inline struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone,
struct page *page,
enum lru_list from,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 3cc3062..b98b4b9 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -344,17 +344,6 @@
/* Architecture-specific MM context */
mm_context_t context;
- /* Swap token stuff */
- /*
- * Last value of global fault stamp as seen by this process.
- * In other words, this value gives an indication of how long
- * it has been since this task got the token.
- * Look at mm/thrash.c
- */
- unsigned int faultstamp;
- unsigned int token_priority;
- unsigned int last_interval;
-
unsigned long flags; /* Must use atomic bitops to access the bits */
struct core_state *core_state; /* coredumping support */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index d63232a..7539e03 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -204,16 +204,14 @@
#define LRU_ALL_EVICTABLE (LRU_ALL_FILE | LRU_ALL_ANON)
#define LRU_ALL ((1 << NR_LRU_LISTS) - 1)
-/* Isolate inactive pages */
-#define ISOLATE_INACTIVE ((__force isolate_mode_t)0x1)
-/* Isolate active pages */
-#define ISOLATE_ACTIVE ((__force isolate_mode_t)0x2)
/* Isolate clean file */
-#define ISOLATE_CLEAN ((__force isolate_mode_t)0x4)
+#define ISOLATE_CLEAN ((__force isolate_mode_t)0x1)
/* Isolate unmapped file */
-#define ISOLATE_UNMAPPED ((__force isolate_mode_t)0x8)
+#define ISOLATE_UNMAPPED ((__force isolate_mode_t)0x2)
/* Isolate for asynchronous migration */
-#define ISOLATE_ASYNC_MIGRATE ((__force isolate_mode_t)0x10)
+#define ISOLATE_ASYNC_MIGRATE ((__force isolate_mode_t)0x4)
+/* Isolate unevictable pages */
+#define ISOLATE_UNEVICTABLE ((__force isolate_mode_t)0x8)
/* LRU Isolation modes. */
typedef unsigned __bitwise__ isolate_mode_t;
@@ -378,6 +376,14 @@
*/
spinlock_t lock;
int all_unreclaimable; /* All pages pinned */
+#if defined CONFIG_COMPACTION || defined CONFIG_CMA
+ /* Set to true when the PG_migrate_skip bits should be cleared */
+ bool compact_blockskip_flush;
+
+ /* pfns where compaction scanners should start */
+ unsigned long compact_cached_free_pfn;
+ unsigned long compact_cached_migrate_pfn;
+#endif
#ifdef CONFIG_MEMORY_HOTPLUG
/* see spanned/present_pages for more description */
seqlock_t span_seqlock;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index c88d2a9..86e4c91 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -108,6 +108,7 @@
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
PG_compound_lock,
#endif
+ PG_readahead, /* page in a readahead window */
__NR_PAGEFLAGS,
/* Filesystems */
diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h
index 19ef95d..eed27f4 100644
--- a/include/linux/pageblock-flags.h
+++ b/include/linux/pageblock-flags.h
@@ -30,6 +30,9 @@
PB_migrate,
PB_migrate_end = PB_migrate + 3 - 1,
/* 3 bits required for migrate types */
+#ifdef CONFIG_COMPACTION
+ PB_migrate_skip,/* If set the block is skipped by compaction */
+#endif /* CONFIG_COMPACTION */
NR_PAGEBLOCK_BITS
};
@@ -65,10 +68,22 @@
void set_pageblock_flags_group(struct page *page, unsigned long flags,
int start_bitidx, int end_bitidx);
+#ifdef CONFIG_COMPACTION
+#define get_pageblock_skip(page) \
+ get_pageblock_flags_group(page, PB_migrate_skip, \
+ PB_migrate_skip + 1)
+#define clear_pageblock_skip(page) \
+ set_pageblock_flags_group(page, 0, PB_migrate_skip, \
+ PB_migrate_skip + 1)
+#define set_pageblock_skip(page) \
+ set_pageblock_flags_group(page, 1, PB_migrate_skip, \
+ PB_migrate_skip + 1)
+#endif /* CONFIG_COMPACTION */
+
#define get_pageblock_flags(page) \
- get_pageblock_flags_group(page, 0, NR_PAGEBLOCK_BITS-1)
+ get_pageblock_flags_group(page, 0, PB_migrate_end)
#define set_pageblock_flags(page, flags) \
set_pageblock_flags_group(page, flags, \
- 0, NR_PAGEBLOCK_BITS-1)
+ 0, PB_migrate_end)
#endif /* PAGEBLOCK_FLAGS_H */
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index 2683fd7..bd2ca82 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -26,14 +26,14 @@
#ifdef CONFIG_ARCH_MSM8974
int __init krait_power_init(void);
-void secondary_cpu_hs_init(void *base_ptr);
+void secondary_cpu_hs_init(void *base_ptr, int cpu);
#else
static inline int __init krait_power_init(void)
{
return -ENOSYS;
}
-static inline void secondary_cpu_hs_init(void *base_ptr) {}
+static inline void secondary_cpu_hs_init(void *base_ptr, int cpu) {}
#endif
#endif
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index fd07c45..a5ddc60 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -67,6 +67,17 @@
struct list_head same_anon_vma; /* locked by anon_vma->mutex */
};
+enum ttu_flags {
+ TTU_UNMAP = 0, /* unmap mode */
+ TTU_MIGRATION = 1, /* migration mode */
+ TTU_MUNLOCK = 2, /* munlock mode */
+ TTU_ACTION_MASK = 0xff,
+
+ TTU_IGNORE_MLOCK = (1 << 8), /* ignore mlock */
+ TTU_IGNORE_ACCESS = (1 << 9), /* don't age */
+ TTU_IGNORE_HWPOISON = (1 << 10),/* corrupted page is recoverable */
+};
+
#ifdef CONFIG_MMU
static inline void get_anon_vma(struct anon_vma *anon_vma)
{
@@ -161,16 +172,6 @@
int page_referenced_one(struct page *, struct vm_area_struct *,
unsigned long address, unsigned int *mapcount, unsigned long *vm_flags);
-enum ttu_flags {
- TTU_UNMAP = 0, /* unmap mode */
- TTU_MIGRATION = 1, /* migration mode */
- TTU_MUNLOCK = 2, /* munlock mode */
- TTU_ACTION_MASK = 0xff,
-
- TTU_IGNORE_MLOCK = (1 << 8), /* ignore mlock */
- TTU_IGNORE_ACCESS = (1 << 9), /* don't age */
- TTU_IGNORE_HWPOISON = (1 << 10),/* corrupted page is recoverable */
-};
#define TTU_ACTION(x) ((x) & TTU_ACTION_MASK)
bool is_vma_temporary_stack(struct vm_area_struct *vma);
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 5c5b777..132135e 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -511,8 +511,11 @@
* @wakeup: This function pointer implements controller-specific procedure
* to wake it up from clock-pause. Framework will call this to bring
* the controller out of clock pause.
- * @config_port: Configure a port and make it ready for data transfer. This is
- * called by framework after connect_port message is sent successfully.
+ * @alloc_port: Allocate a port and make it ready for data transfer. This is
+ * called by framework to make sure controller can take necessary steps
+ * to initialize its port
+ * @dealloc_port: Counter-part of alloc_port. This is called by framework so
+ * that controller can free resources associated with this port
* @framer_handover: If this controller has multiple framers, this API will
* be called to switch between framers if controller desires to change
* the active framer.
@@ -557,7 +560,9 @@
int (*get_laddr)(struct slim_controller *ctrl,
const u8 *ea, u8 elen, u8 *laddr);
int (*wakeup)(struct slim_controller *ctrl);
- int (*config_port)(struct slim_controller *ctrl,
+ int (*alloc_port)(struct slim_controller *ctrl,
+ u8 port);
+ void (*dealloc_port)(struct slim_controller *ctrl,
u8 port);
int (*framer_handover)(struct slim_controller *ctrl,
struct slim_framer *new_framer);
@@ -795,6 +800,8 @@
* Channel specified in chanh needs to be allocated first.
* Returns -EALREADY if source is already configured for this channel.
* Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid direction is specified for non-manager port,
+ * or if the manager side port number is out of bounds, or in incorrect state
*/
extern int slim_connect_src(struct slim_device *sb, u32 srch, u16 chanh);
@@ -808,6 +815,9 @@
* Channel specified in chanh needs to be allocated first.
* Returns -EALREADY if sink is already configured for this channel.
* Returns -ENOTCONN if channel is not allocated
+ * Returns -EINVAL if invalid parameters are passed, or invalid direction is
+ * specified for non-manager port, or if the manager side port number is out of
+ * bounds, or in incorrect state
*/
extern int slim_connect_sink(struct slim_device *sb, u32 *sinkh, int nsink,
u16 chanh);
diff --git a/include/linux/swap.h b/include/linux/swap.h
index b1fd5c7..d5bd6ee 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -251,7 +251,7 @@
/* linux/mm/vmscan.c */
extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
gfp_t gfp_mask, nodemask_t *mask);
-extern int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file);
+extern int __isolate_lru_page(struct page *page, isolate_mode_t mode);
extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
gfp_t gfp_mask, bool noswap);
extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
@@ -355,23 +355,6 @@
extern int try_to_free_swap(struct page *);
struct backing_dev_info;
-/* linux/mm/thrash.c */
-extern struct mm_struct *swap_token_mm;
-extern void grab_swap_token(struct mm_struct *);
-extern void __put_swap_token(struct mm_struct *);
-extern void disable_swap_token(struct mem_cgroup *memcg);
-
-static inline int has_swap_token(struct mm_struct *mm)
-{
- return (mm == swap_token_mm);
-}
-
-static inline void put_swap_token(struct mm_struct *mm)
-{
- if (has_swap_token(mm))
- __put_swap_token(mm);
-}
-
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
extern void
mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout);
@@ -476,24 +459,6 @@
return entry;
}
-/* linux/mm/thrash.c */
-static inline void put_swap_token(struct mm_struct *mm)
-{
-}
-
-static inline void grab_swap_token(struct mm_struct *mm)
-{
-}
-
-static inline int has_swap_token(struct mm_struct *mm)
-{
- return 0;
-}
-
-static inline void disable_swap_token(struct mem_cgroup *memcg)
-{
-}
-
static inline void
mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
{
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 82044f7..fea832e 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -545,6 +545,7 @@
const char *name;
struct device dev;
u8 usb_core_id;
+ bool l1_supported;
};
static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 04b99b7..bfed960 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -42,6 +42,20 @@
#define MSM_VENDOR_ID BIT(16)
/**
+ * Requested USB votes for BUS bandwidth
+ *
+ * USB_NO_PERF_VOTE BUS Vote for inactive USB session or disconnect
+ * USB_MAX_PERF_VOTE Maximum BUS bandwidth vote
+ * USB_MIN_PERF_VOTE Minimum BUS bandwidth vote (for some hw same as NO_PERF)
+ *
+ */
+enum usb_bus_vote {
+ USB_NO_PERF_VOTE = 0,
+ USB_MAX_PERF_VOTE,
+ USB_MIN_PERF_VOTE,
+};
+
+/**
* Supported USB modes
*
* USB_PERIPHERAL Only peripheral mode is supported.
@@ -207,6 +221,7 @@
* @log2_itc: value of 2^(log2_itc-1) will be used as the
* interrupt threshold (ITC), when log2_itc is
* between 1 to 7.
+ * @l1_supported: enable link power management support.
*/
struct msm_otg_platform_data {
int *phy_init_seq;
@@ -231,6 +246,7 @@
struct msm_bus_scale_pdata *bus_scale_table;
const char *mhl_dev_name;
int log2_itc;
+ bool l1_supported;
};
/* phy related flags */
@@ -414,6 +430,7 @@
*/
int log2_itc;
void *prv_data;
+ bool l1_supported;
};
struct msm_hsic_host_platform_data {
@@ -440,6 +457,7 @@
bool disable_park_mode;
bool consider_ipa_handshake;
bool ahb_async_bridge_bypass;
+ bool disable_cerr;
};
struct msm_usb_host_platform_data {
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 0d57d93..f3f4c3b 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -39,6 +39,15 @@
#define USB_USBINTR (MSM_USB_BASE + 0x0148)
#define USB_FRINDEX (MSM_USB_BASE + 0x014C)
+#define USB_L1_EP_CTRL (MSM_USB_BASE + 0x0250)
+#define USB_L1_CONFIG (MSM_USB_BASE + 0x0254)
+
+#define L1_CONFIG_LPM_EN BIT(4)
+#define L1_CONFIG_REMOTE_WAKEUP BIT(5)
+#define L1_CONFIG_GATE_SYS_CLK BIT(7)
+#define L1_CONFIG_PHY_LPM BIT(10)
+#define L1_CONFIG_PLL BIT(11)
+
#define PORTSC_PHCD (1 << 23) /* phy suspend mode */
#define PORTSC_PTS_MASK (3 << 30)
#define PORTSC_PTS_ULPI (3 << 30)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 5c7ae02..81187aa 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1836,12 +1836,6 @@
V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP
};
-#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
- (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
-enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
- V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
- V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
-};
#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26)
enum v4l2_mpeg_vidc_perf_level {
@@ -1851,9 +1845,17 @@
};
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+27)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 27)
+
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+28)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 28)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 29)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index 06f8e38..8bbb324 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -37,8 +37,12 @@
KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
KSWAPD_SKIP_CONGESTION_WAIT,
PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+#ifdef CONFIG_MIGRATION
+ PGMIGRATE_SUCCESS, PGMIGRATE_FAIL,
+#endif
#ifdef CONFIG_COMPACTION
- COMPACTBLOCKS, COMPACTPAGES, COMPACTPAGEFAILED,
+ COMPACTMIGRATE_SCANNED, COMPACTFREE_SCANNED,
+ COMPACTISOLATED,
COMPACTSTALL, COMPACTFAIL, COMPACTSUCCESS,
#endif
#ifdef CONFIG_HUGETLB_PAGE
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 0d3b5a0..7e98ef3 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6930,8 +6930,8 @@
} __packed;
/* Ultrasound supported formats */
-#define US_POINT_EPOS_FORMAT 0x00012310
-#define US_RAW_FORMAT 0x0001127C
-#define US_PROX_FORMAT 0x0001272B
+#define US_POINT_EPOS_FORMAT_V2 0x0001272D
+#define US_RAW_FORMAT_V2 0x0001272C
+#define US_PROX_FORMAT_V2 0x0001272E
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index f64560e..bab3b87 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -13,7 +13,7 @@
#define RECLAIM_WB_ANON 0x0001u
#define RECLAIM_WB_FILE 0x0002u
#define RECLAIM_WB_MIXED 0x0010u
-#define RECLAIM_WB_SYNC 0x0004u
+#define RECLAIM_WB_SYNC 0x0004u /* Unused, all reclaim async */
#define RECLAIM_WB_ASYNC 0x0008u
#define show_reclaim_flags(flags) \
@@ -25,15 +25,15 @@
{RECLAIM_WB_ASYNC, "RECLAIM_WB_ASYNC"} \
) : "RECLAIM_WB_NONE"
-#define trace_reclaim_flags(page, sync) ( \
+#define trace_reclaim_flags(page) ( \
(page_is_file_cache(page) ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
- (sync & RECLAIM_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC) \
+ (RECLAIM_WB_ASYNC) \
)
-#define trace_shrink_flags(file, sync) ( \
- (sync & RECLAIM_MODE_SYNC ? RECLAIM_WB_MIXED : \
- (file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON)) | \
- (sync & RECLAIM_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC) \
+#define trace_shrink_flags(file) \
+ ( \
+ (file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
+ (RECLAIM_WB_ASYNC) \
)
TRACE_EVENT(mm_vmscan_kswapd_sleep,
@@ -263,22 +263,16 @@
unsigned long nr_requested,
unsigned long nr_scanned,
unsigned long nr_taken,
- unsigned long nr_lumpy_taken,
- unsigned long nr_lumpy_dirty,
- unsigned long nr_lumpy_failed,
isolate_mode_t isolate_mode,
int file),
- TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file),
+ TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
TP_STRUCT__entry(
__field(int, order)
__field(unsigned long, nr_requested)
__field(unsigned long, nr_scanned)
__field(unsigned long, nr_taken)
- __field(unsigned long, nr_lumpy_taken)
- __field(unsigned long, nr_lumpy_dirty)
- __field(unsigned long, nr_lumpy_failed)
__field(isolate_mode_t, isolate_mode)
__field(int, file)
),
@@ -288,22 +282,16 @@
__entry->nr_requested = nr_requested;
__entry->nr_scanned = nr_scanned;
__entry->nr_taken = nr_taken;
- __entry->nr_lumpy_taken = nr_lumpy_taken;
- __entry->nr_lumpy_dirty = nr_lumpy_dirty;
- __entry->nr_lumpy_failed = nr_lumpy_failed;
__entry->isolate_mode = isolate_mode;
__entry->file = file;
),
- TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu contig_taken=%lu contig_dirty=%lu contig_failed=%lu file=%d",
+ TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
__entry->isolate_mode,
__entry->order,
__entry->nr_requested,
__entry->nr_scanned,
__entry->nr_taken,
- __entry->nr_lumpy_taken,
- __entry->nr_lumpy_dirty,
- __entry->nr_lumpy_failed,
__entry->file)
);
@@ -313,13 +301,10 @@
unsigned long nr_requested,
unsigned long nr_scanned,
unsigned long nr_taken,
- unsigned long nr_lumpy_taken,
- unsigned long nr_lumpy_dirty,
- unsigned long nr_lumpy_failed,
isolate_mode_t isolate_mode,
int file),
- TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
+ TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
);
@@ -329,13 +314,10 @@
unsigned long nr_requested,
unsigned long nr_scanned,
unsigned long nr_taken,
- unsigned long nr_lumpy_taken,
- unsigned long nr_lumpy_dirty,
- unsigned long nr_lumpy_failed,
isolate_mode_t isolate_mode,
int file),
- TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
+ TP_ARGS(order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
);
@@ -395,88 +377,6 @@
show_reclaim_flags(__entry->reclaim_flags))
);
-TRACE_EVENT(replace_swap_token,
- TP_PROTO(struct mm_struct *old_mm,
- struct mm_struct *new_mm),
-
- TP_ARGS(old_mm, new_mm),
-
- TP_STRUCT__entry(
- __field(struct mm_struct*, old_mm)
- __field(unsigned int, old_prio)
- __field(struct mm_struct*, new_mm)
- __field(unsigned int, new_prio)
- ),
-
- TP_fast_assign(
- __entry->old_mm = old_mm;
- __entry->old_prio = old_mm ? old_mm->token_priority : 0;
- __entry->new_mm = new_mm;
- __entry->new_prio = new_mm->token_priority;
- ),
-
- TP_printk("old_token_mm=%p old_prio=%u new_token_mm=%p new_prio=%u",
- __entry->old_mm, __entry->old_prio,
- __entry->new_mm, __entry->new_prio)
-);
-
-DECLARE_EVENT_CLASS(put_swap_token_template,
- TP_PROTO(struct mm_struct *swap_token_mm),
-
- TP_ARGS(swap_token_mm),
-
- TP_STRUCT__entry(
- __field(struct mm_struct*, swap_token_mm)
- ),
-
- TP_fast_assign(
- __entry->swap_token_mm = swap_token_mm;
- ),
-
- TP_printk("token_mm=%p", __entry->swap_token_mm)
-);
-
-DEFINE_EVENT(put_swap_token_template, put_swap_token,
- TP_PROTO(struct mm_struct *swap_token_mm),
- TP_ARGS(swap_token_mm)
-);
-
-DEFINE_EVENT_CONDITION(put_swap_token_template, disable_swap_token,
- TP_PROTO(struct mm_struct *swap_token_mm),
- TP_ARGS(swap_token_mm),
- TP_CONDITION(swap_token_mm != NULL)
-);
-
-TRACE_EVENT_CONDITION(update_swap_token_priority,
- TP_PROTO(struct mm_struct *mm,
- unsigned int old_prio,
- struct mm_struct *swap_token_mm),
-
- TP_ARGS(mm, old_prio, swap_token_mm),
-
- TP_CONDITION(mm->token_priority != old_prio),
-
- TP_STRUCT__entry(
- __field(struct mm_struct*, mm)
- __field(unsigned int, old_prio)
- __field(unsigned int, new_prio)
- __field(struct mm_struct*, swap_token_mm)
- __field(unsigned int, swap_token_prio)
- ),
-
- TP_fast_assign(
- __entry->mm = mm;
- __entry->old_prio = old_prio;
- __entry->new_prio = mm->token_priority;
- __entry->swap_token_mm = swap_token_mm;
- __entry->swap_token_prio = swap_token_mm ? swap_token_mm->token_priority : 0;
- ),
-
- TP_printk("mm=%p old_prio=%u new_prio=%u swap_token_mm=%p token_prio=%u",
- __entry->mm, __entry->old_prio, __entry->new_prio,
- __entry->swap_token_mm, __entry->swap_token_prio)
-);
-
#endif /* _TRACE_VMSCAN_H */
/* This part must be outside protection */
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 2f0d7542..01f68c4 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4902,7 +4902,7 @@
* @root: the css supporsed to be an ancestor of the child.
*
* Returns true if "root" is an ancestor of "child" in its hierarchy. Because
- * this function reads css->id, this use rcu_dereference() and rcu_read_lock().
+ * this function reads css->id, the caller must hold rcu_read_lock().
* But, considering usual usage, the csses should be valid objects after test.
* Assuming that the caller will do some action to the child if this returns
* returns true, the caller must take "child";s reference count.
@@ -4914,18 +4914,18 @@
{
struct css_id *child_id;
struct css_id *root_id;
- bool ret = true;
- rcu_read_lock();
child_id = rcu_dereference(child->id);
+ if (!child_id)
+ return false;
root_id = rcu_dereference(root->id);
- if (!child_id
- || !root_id
- || (child_id->depth < root_id->depth)
- || (child_id->stack[root_id->depth] != root_id->id))
- ret = false;
- rcu_read_unlock();
- return ret;
+ if (!root_id)
+ return false;
+ if (child_id->depth < root_id->depth)
+ return false;
+ if (child_id->stack[root_id->depth] != root_id->id)
+ return false;
+ return true;
}
void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index fd126f8..aafa4c1 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5118,7 +5118,7 @@
static int perf_swevent_init(struct perf_event *event)
{
- int event_id = event->attr.config;
+ u64 event_id = event->attr.config;
if (event->attr.type != PERF_TYPE_SOFTWARE)
return -ENOENT;
diff --git a/kernel/fork.c b/kernel/fork.c
index 0de735c..a8bf721 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -597,7 +597,6 @@
list_del(&mm->mmlist);
spin_unlock(&mmlist_lock);
}
- put_swap_token(mm);
if (mm->binfmt)
module_put(mm->binfmt->module);
mmdrop(mm);
@@ -815,10 +814,6 @@
memcpy(mm, oldmm, sizeof(*mm));
mm_init_cpumask(mm);
- /* Initializing for Swap token stuff */
- mm->token_priority = 0;
- mm->last_interval = 0;
-
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
mm->pmd_huge_pte = NULL;
#endif
@@ -896,10 +891,6 @@
goto fail_nomem;
good_mm:
- /* Initializing for Swap token stuff */
- mm->token_priority = 0;
- mm->last_interval = 0;
-
tsk->mm = mm;
tsk->active_mm = mm;
return 0;
diff --git a/mm/Makefile b/mm/Makefile
index 8aada89..ccecbf9 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -25,7 +25,7 @@
obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
obj-$(CONFIG_BOUNCE) += bounce.o
-obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o
+obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o
obj-$(CONFIG_HAS_DMA) += dmapool.o
obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o
diff --git a/mm/compaction.c b/mm/compaction.c
index 353f1c5..673142d 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -16,6 +16,21 @@
#include <linux/sysfs.h>
#include "internal.h"
+#ifdef CONFIG_COMPACTION
+static inline void count_compact_event(enum vm_event_item item)
+{
+ count_vm_event(item);
+}
+
+static inline void count_compact_events(enum vm_event_item item, long delta)
+{
+ count_vm_events(item, delta);
+}
+#else
+#define count_compact_event(item) do { } while (0)
+#define count_compact_events(item, delta) do { } while (0)
+#endif
+
#if defined CONFIG_COMPACTION || defined CONFIG_CMA
#define CREATE_TRACE_POINTS
@@ -50,44 +65,228 @@
return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE;
}
+#ifdef CONFIG_COMPACTION
+/* Returns true if the pageblock should be scanned for pages to isolate. */
+static inline bool isolation_suitable(struct compact_control *cc,
+ struct page *page)
+{
+ if (cc->ignore_skip_hint)
+ return true;
+
+ return !get_pageblock_skip(page);
+}
+
+/*
+ * This function is called to clear all cached information on pageblocks that
+ * should be skipped for page isolation when the migrate and free page scanner
+ * meet.
+ */
+static void __reset_isolation_suitable(struct zone *zone)
+{
+ unsigned long start_pfn = zone->zone_start_pfn;
+ unsigned long end_pfn = zone->zone_start_pfn + zone->spanned_pages;
+ unsigned long pfn;
+
+ zone->compact_cached_migrate_pfn = start_pfn;
+ zone->compact_cached_free_pfn = end_pfn;
+ zone->compact_blockskip_flush = false;
+
+ /* Walk the zone and mark every pageblock as suitable for isolation */
+ for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
+ struct page *page;
+
+ cond_resched();
+
+ if (!pfn_valid(pfn))
+ continue;
+
+ page = pfn_to_page(pfn);
+ if (zone != page_zone(page))
+ continue;
+
+ clear_pageblock_skip(page);
+ }
+}
+
+void reset_isolation_suitable(pg_data_t *pgdat)
+{
+ int zoneid;
+
+ for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
+ struct zone *zone = &pgdat->node_zones[zoneid];
+ if (!populated_zone(zone))
+ continue;
+
+ /* Only flush if a full compaction finished recently */
+ if (zone->compact_blockskip_flush)
+ __reset_isolation_suitable(zone);
+ }
+}
+
+/*
+ * If no pages were isolated then mark this pageblock to be skipped in the
+ * future. The information is later cleared by __reset_isolation_suitable().
+ */
+static void update_pageblock_skip(struct compact_control *cc,
+ struct page *page, unsigned long nr_isolated,
+ bool migrate_scanner)
+{
+ struct zone *zone = cc->zone;
+ if (!page)
+ return;
+
+ if (!nr_isolated) {
+ unsigned long pfn = page_to_pfn(page);
+ set_pageblock_skip(page);
+
+ /* Update where compaction should restart */
+ if (migrate_scanner) {
+ if (!cc->finished_update_migrate &&
+ pfn > zone->compact_cached_migrate_pfn)
+ zone->compact_cached_migrate_pfn = pfn;
+ } else {
+ if (!cc->finished_update_free &&
+ pfn < zone->compact_cached_free_pfn)
+ zone->compact_cached_free_pfn = pfn;
+ }
+ }
+}
+#else
+static inline bool isolation_suitable(struct compact_control *cc,
+ struct page *page)
+{
+ return true;
+}
+
+static void update_pageblock_skip(struct compact_control *cc,
+ struct page *page, unsigned long nr_isolated,
+ bool migrate_scanner)
+{
+}
+#endif /* CONFIG_COMPACTION */
+
+static inline bool should_release_lock(spinlock_t *lock)
+{
+ return need_resched() || spin_is_contended(lock);
+}
+
+/*
+ * Compaction requires the taking of some coarse locks that are potentially
+ * very heavily contended. Check if the process needs to be scheduled or
+ * if the lock is contended. For async compaction, back out in the event
+ * if contention is severe. For sync compaction, schedule.
+ *
+ * Returns true if the lock is held.
+ * Returns false if the lock is released and compaction should abort
+ */
+static bool compact_checklock_irqsave(spinlock_t *lock, unsigned long *flags,
+ bool locked, struct compact_control *cc)
+{
+ if (should_release_lock(lock)) {
+ if (locked) {
+ spin_unlock_irqrestore(lock, *flags);
+ locked = false;
+ }
+
+ /* async aborts if taking too long or contended */
+ if (!cc->sync) {
+ cc->contended = true;
+ return false;
+ }
+
+ cond_resched();
+ }
+
+ if (!locked)
+ spin_lock_irqsave(lock, *flags);
+ return true;
+}
+
+static inline bool compact_trylock_irqsave(spinlock_t *lock,
+ unsigned long *flags, struct compact_control *cc)
+{
+ return compact_checklock_irqsave(lock, flags, false, cc);
+}
+
+/* Returns true if the page is within a block suitable for migration to */
+static bool suitable_migration_target(struct page *page)
+{
+ int migratetype = get_pageblock_migratetype(page);
+
+ /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
+ if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)
+ return false;
+
+ /* If the page is a large free page, then allow migration */
+ if (PageBuddy(page) && page_order(page) >= pageblock_order)
+ return true;
+
+ /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */
+ if (migrate_async_suitable(migratetype))
+ return true;
+
+ /* Otherwise skip the block */
+ return false;
+}
+
/*
* Isolate free pages onto a private freelist. Caller must hold zone->lock.
* If @strict is true, will abort returning 0 on any invalid PFNs or non-free
* pages inside of the pageblock (even though it may still end up isolating
* some pages).
*/
-static unsigned long isolate_freepages_block(unsigned long blockpfn,
+static unsigned long isolate_freepages_block(struct compact_control *cc,
+ unsigned long blockpfn,
unsigned long end_pfn,
struct list_head *freelist,
bool strict)
{
int nr_scanned = 0, total_isolated = 0;
- struct page *cursor;
+ struct page *cursor, *valid_page = NULL;
+ unsigned long nr_strict_required = end_pfn - blockpfn;
+ unsigned long flags;
+ bool locked = false;
cursor = pfn_to_page(blockpfn);
- /* Isolate free pages. This assumes the block is valid */
+ /* Isolate free pages. */
for (; blockpfn < end_pfn; blockpfn++, cursor++) {
int isolated, i;
struct page *page = cursor;
- if (!pfn_valid_within(blockpfn)) {
- if (strict)
- return 0;
- continue;
- }
nr_scanned++;
-
- if (!PageBuddy(page)) {
- if (strict)
- return 0;
+ if (!pfn_valid_within(blockpfn))
continue;
- }
+ if (!valid_page)
+ valid_page = page;
+ if (!PageBuddy(page))
+ continue;
+
+ /*
+ * The zone lock must be held to isolate freepages.
+ * Unfortunately this is a very coarse lock and can be
+ * heavily contended if there are parallel allocations
+ * or parallel compactions. For async compaction do not
+ * spin on the lock and we acquire the lock as late as
+ * possible.
+ */
+ locked = compact_checklock_irqsave(&cc->zone->lock, &flags,
+ locked, cc);
+ if (!locked)
+ break;
+
+ /* Recheck this is a suitable migration target under lock */
+ if (!strict && !suitable_migration_target(page))
+ break;
+
+ /* Recheck this is a buddy page under lock */
+ if (!PageBuddy(page))
+ continue;
/* Found a free page, break it into order-0 pages */
isolated = split_free_page(page);
if (!isolated && strict)
- return 0;
+ break;
total_isolated += isolated;
for (i = 0; i < isolated; i++) {
list_add(&page->lru, freelist);
@@ -102,6 +301,25 @@
}
trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
+
+ /*
+ * If strict isolation is requested by CMA then check that all the
+ * pages requested were isolated. If there were any failures, 0 is
+ * returned and CMA will fail.
+ */
+ if (strict && nr_strict_required > total_isolated)
+ total_isolated = 0;
+
+ if (locked)
+ spin_unlock_irqrestore(&cc->zone->lock, flags);
+
+ /* Update the pageblock-skip if the whole pageblock was scanned */
+ if (blockpfn == end_pfn)
+ update_pageblock_skip(cc, valid_page, total_isolated, false);
+
+ count_compact_events(COMPACTFREE_SCANNED, nr_scanned);
+ if (total_isolated)
+ count_compact_events(COMPACTISOLATED, total_isolated);
return total_isolated;
}
@@ -119,17 +337,14 @@
* a free page).
*/
unsigned long
-isolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn)
+isolate_freepages_range(struct compact_control *cc,
+ unsigned long start_pfn, unsigned long end_pfn)
{
- unsigned long isolated, pfn, block_end_pfn, flags;
- struct zone *zone = NULL;
+ unsigned long isolated, pfn, block_end_pfn;
LIST_HEAD(freelist);
- if (pfn_valid(start_pfn))
- zone = page_zone(pfn_to_page(start_pfn));
-
for (pfn = start_pfn; pfn < end_pfn; pfn += isolated) {
- if (!pfn_valid(pfn) || zone != page_zone(pfn_to_page(pfn)))
+ if (!pfn_valid(pfn) || cc->zone != page_zone(pfn_to_page(pfn)))
break;
/*
@@ -139,10 +354,8 @@
block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
block_end_pfn = min(block_end_pfn, end_pfn);
- spin_lock_irqsave(&zone->lock, flags);
- isolated = isolate_freepages_block(pfn, block_end_pfn,
+ isolated = isolate_freepages_block(cc, pfn, block_end_pfn,
&freelist, true);
- spin_unlock_irqrestore(&zone->lock, flags);
/*
* In strict mode, isolate_freepages_block() returns 0 if
@@ -173,7 +386,7 @@
}
/* Update the number of anon and file isolated pages in the zone */
-static void acct_isolated(struct zone *zone, struct compact_control *cc)
+static void acct_isolated(struct zone *zone, bool locked, struct compact_control *cc)
{
struct page *page;
unsigned int count[2] = { 0, };
@@ -181,8 +394,14 @@
list_for_each_entry(page, &cc->migratepages, lru)
count[!!page_is_file_cache(page)]++;
- __mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
- __mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+ /* If locked we can use the interrupt unsafe versions */
+ if (locked) {
+ __mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
+ __mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+ } else {
+ mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
+ mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+ }
}
/* Similar to reclaim, but different enough that they don't share logic */
@@ -206,6 +425,7 @@
* @cc: Compaction control structure.
* @low_pfn: The first PFN of the range.
* @end_pfn: The one-past-the-last PFN of the range.
+ * @unevictable: true if it allows to isolate unevictable pages
*
* Isolate all pages that can be migrated from the range specified by
* [low_pfn, end_pfn). Returns zero if there is a fatal signal
@@ -221,12 +441,15 @@
*/
unsigned long
isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
- unsigned long low_pfn, unsigned long end_pfn)
+ unsigned long low_pfn, unsigned long end_pfn, bool unevictable)
{
unsigned long last_pageblock_nr = 0, pageblock_nr;
unsigned long nr_scanned = 0, nr_isolated = 0;
struct list_head *migratelist = &cc->migratepages;
- isolate_mode_t mode = ISOLATE_ACTIVE|ISOLATE_INACTIVE;
+ isolate_mode_t mode = 0;
+ unsigned long flags;
+ bool locked = false;
+ struct page *page = NULL, *valid_page = NULL;
/*
* Ensure that there are not too many pages isolated from the LRU
@@ -246,25 +469,14 @@
/* Time to isolate some pages for migration */
cond_resched();
- spin_lock_irq(&zone->lru_lock);
for (; low_pfn < end_pfn; low_pfn++) {
- struct page *page;
- bool locked = true;
-
/* give a chance to irqs before checking need_resched() */
- if (!((low_pfn+1) % SWAP_CLUSTER_MAX)) {
- spin_unlock_irq(&zone->lru_lock);
- locked = false;
+ if (locked && !((low_pfn+1) % SWAP_CLUSTER_MAX)) {
+ if (should_release_lock(&zone->lru_lock)) {
+ spin_unlock_irqrestore(&zone->lru_lock, flags);
+ locked = false;
+ }
}
- if (need_resched() || spin_is_contended(&zone->lru_lock)) {
- if (locked)
- spin_unlock_irq(&zone->lru_lock);
- cond_resched();
- spin_lock_irq(&zone->lru_lock);
- if (fatal_signal_pending(current))
- break;
- } else if (!locked)
- spin_lock_irq(&zone->lru_lock);
/*
* migrate_pfn does not necessarily start aligned to a
@@ -293,6 +505,14 @@
if (page_zone(page) != zone)
continue;
+ if (!valid_page)
+ valid_page = page;
+
+ /* If isolation recently failed, do not retry */
+ pageblock_nr = low_pfn >> pageblock_order;
+ if (!isolation_suitable(cc, page))
+ goto next_pageblock;
+
/* Skip if free */
if (PageBuddy(page))
continue;
@@ -302,24 +522,43 @@
* migration is optimistic to see if the minimum amount of work
* satisfies the allocation
*/
- pageblock_nr = low_pfn >> pageblock_order;
if (!cc->sync && last_pageblock_nr != pageblock_nr &&
!migrate_async_suitable(get_pageblock_migratetype(page))) {
- low_pfn += pageblock_nr_pages;
- low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;
- last_pageblock_nr = pageblock_nr;
- continue;
+ cc->finished_update_migrate = true;
+ goto next_pageblock;
}
+ /* Check may be lockless but that's ok as we recheck later */
if (!PageLRU(page))
continue;
/*
- * PageLRU is set, and lru_lock excludes isolation,
- * splitting and collapsing (collapsing has already
- * happened if PageLRU is set).
+ * PageLRU is set. lru_lock normally excludes isolation
+ * splitting and collapsing (collapsing has already happened
+ * if PageLRU is set) but the lock is not necessarily taken
+ * here and it is wasteful to take it just to check transhuge.
+ * Check TransHuge without lock and skip the whole pageblock if
+ * it's either a transhuge or hugetlbfs page, as calling
+ * compound_order() without preventing THP from splitting the
+ * page underneath us may return surprising results.
*/
if (PageTransHuge(page)) {
+ if (!locked)
+ goto next_pageblock;
+ low_pfn += (1 << compound_order(page)) - 1;
+ continue;
+ }
+
+ /* Check if it is ok to still hold the lock */
+ locked = compact_checklock_irqsave(&zone->lru_lock, &flags,
+ locked, cc);
+ if (!locked || fatal_signal_pending(current))
+ break;
+
+ /* Recheck PageLRU and PageTransHuge under lock */
+ if (!PageLRU(page))
+ continue;
+ if (PageTransHuge(page)) {
low_pfn += (1 << compound_order(page)) - 1;
continue;
}
@@ -327,13 +566,17 @@
if (!cc->sync)
mode |= ISOLATE_ASYNC_MIGRATE;
+ if (unevictable)
+ mode |= ISOLATE_UNEVICTABLE;
+
/* Try isolate the page */
- if (__isolate_lru_page(page, mode, 0) != 0)
+ if (__isolate_lru_page(page, mode) != 0)
continue;
VM_BUG_ON(PageTransCompound(page));
/* Successfully isolated */
+ cc->finished_update_migrate = true;
del_page_from_lru_list(zone, page, page_lru(page));
list_add(&page->lru, migratelist);
cc->nr_migratepages++;
@@ -344,42 +587,35 @@
++low_pfn;
break;
}
+
+ continue;
+
+next_pageblock:
+ low_pfn += pageblock_nr_pages;
+ low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;
+ last_pageblock_nr = pageblock_nr;
}
- acct_isolated(zone, cc);
+ acct_isolated(zone, locked, cc);
- spin_unlock_irq(&zone->lru_lock);
+ if (locked)
+ spin_unlock_irqrestore(&zone->lru_lock, flags);
+
+ /* Update the pageblock-skip if the whole pageblock was scanned */
+ if (low_pfn == end_pfn)
+ update_pageblock_skip(cc, valid_page, nr_isolated, true);
trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
+ count_compact_events(COMPACTMIGRATE_SCANNED, nr_scanned);
+ if (nr_isolated)
+ count_compact_events(COMPACTISOLATED, nr_isolated);
+
return low_pfn;
}
#endif /* CONFIG_COMPACTION || CONFIG_CMA */
#ifdef CONFIG_COMPACTION
-
-/* Returns true if the page is within a block suitable for migration to */
-static bool suitable_migration_target(struct page *page)
-{
-
- int migratetype = get_pageblock_migratetype(page);
-
- /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
- if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)
- return false;
-
- /* If the page is a large free page, then allow migration */
- if (PageBuddy(page) && page_order(page) >= pageblock_order)
- return true;
-
- /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */
- if (migrate_async_suitable(migratetype))
- return true;
-
- /* Otherwise skip the block */
- return false;
-}
-
/*
* Based on information in the current compact_control, find blocks
* suitable for isolating free pages from and then isolate them.
@@ -389,7 +625,6 @@
{
struct page *page;
unsigned long high_pfn, low_pfn, pfn, zone_end_pfn, end_pfn;
- unsigned long flags;
int nr_freepages = cc->nr_freepages;
struct list_head *freelist = &cc->freepages;
@@ -437,29 +672,34 @@
if (!suitable_migration_target(page))
continue;
- /*
- * Found a block suitable for isolating free pages from. Now
- * we disabled interrupts, double check things are ok and
- * isolate the pages. This is to minimise the time IRQs
- * are disabled
- */
+ /* If isolation recently failed, do not retry */
+ if (!isolation_suitable(cc, page))
+ continue;
+
+ /* Found a block suitable for isolating free pages from */
isolated = 0;
- spin_lock_irqsave(&zone->lock, flags);
- if (suitable_migration_target(page)) {
- end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);
- isolated = isolate_freepages_block(pfn, end_pfn,
- freelist, false);
- nr_freepages += isolated;
- }
- spin_unlock_irqrestore(&zone->lock, flags);
+
+ /*
+ * As pfn may not start aligned, pfn+pageblock_nr_page
+ * may cross a MAX_ORDER_NR_PAGES boundary and miss
+ * a pfn_valid check. Ensure isolate_freepages_block()
+ * only scans within a pageblock
+ */
+ end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
+ end_pfn = min(end_pfn, zone_end_pfn);
+ isolated = isolate_freepages_block(cc, pfn, end_pfn,
+ freelist, false);
+ nr_freepages += isolated;
/*
* Record the highest PFN we isolated pages from. When next
* looking for free pages, the search will restart here as
* page migration may have returned some pages to the allocator
*/
- if (isolated)
+ if (isolated) {
+ cc->finished_update_free = true;
high_pfn = max(high_pfn, pfn);
+ }
}
/* split_free_page does not map the pages */
@@ -544,8 +784,8 @@
}
/* Perform the isolation */
- low_pfn = isolate_migratepages_range(zone, cc, low_pfn, end_pfn);
- if (!low_pfn)
+ low_pfn = isolate_migratepages_range(zone, cc, low_pfn, end_pfn, false);
+ if (!low_pfn || cc->contended)
return ISOLATE_ABORT;
cc->migrate_pfn = low_pfn;
@@ -563,8 +803,18 @@
return COMPACT_PARTIAL;
/* Compaction run completes if the migrate and free scanner meet */
- if (cc->free_pfn <= cc->migrate_pfn)
+ if (cc->free_pfn <= cc->migrate_pfn) {
+ /*
+ * Mark that the PG_migrate_skip information should be cleared
+ * by kswapd when it goes to sleep. kswapd does not set the
+ * flag itself as the decision to be clear should be directly
+ * based on an allocation request.
+ */
+ if (!current_is_kswapd())
+ zone->compact_blockskip_flush = true;
+
return COMPACT_COMPLETE;
+ }
/*
* order == -1 is expected when compacting via
@@ -582,12 +832,14 @@
/* Direct compactor: Is a suitable page free? */
for (order = cc->order; order < MAX_ORDER; order++) {
+ struct free_area *area = &zone->free_area[order];
+
/* Job done if page is free of the right migratetype */
- if (!list_empty(&zone->free_area[order].free_list[cc->migratetype]))
+ if (!list_empty(&area->free_list[cc->migratetype]))
return COMPACT_PARTIAL;
/* Job done if allocation would set block type */
- if (order >= pageblock_order && zone->free_area[order].nr_free)
+ if (cc->order >= pageblock_order && area->nr_free)
return COMPACT_PARTIAL;
}
@@ -647,6 +899,8 @@
static int compact_zone(struct zone *zone, struct compact_control *cc)
{
int ret;
+ unsigned long start_pfn = zone->zone_start_pfn;
+ unsigned long end_pfn = zone->zone_start_pfn + zone->spanned_pages;
ret = compaction_suitable(zone, cc->order);
switch (ret) {
@@ -659,10 +913,29 @@
;
}
- /* Setup to move all movable pages to the end of the zone */
- cc->migrate_pfn = zone->zone_start_pfn;
- cc->free_pfn = cc->migrate_pfn + zone->spanned_pages;
- cc->free_pfn &= ~(pageblock_nr_pages-1);
+ /*
+ * Setup to move all movable pages to the end of the zone. Used cached
+ * information on where the scanners should start but check that it
+ * is initialised by ensuring the values are within zone boundaries.
+ */
+ cc->migrate_pfn = zone->compact_cached_migrate_pfn;
+ cc->free_pfn = zone->compact_cached_free_pfn;
+ if (cc->free_pfn < start_pfn || cc->free_pfn > end_pfn) {
+ cc->free_pfn = end_pfn & ~(pageblock_nr_pages-1);
+ zone->compact_cached_free_pfn = cc->free_pfn;
+ }
+ if (cc->migrate_pfn < start_pfn || cc->migrate_pfn > end_pfn) {
+ cc->migrate_pfn = start_pfn;
+ zone->compact_cached_migrate_pfn = cc->migrate_pfn;
+ }
+
+ /*
+ * Clear pageblock skip if there were failures recently and compaction
+ * is about to be retried after being deferred. kswapd does not do
+ * this reset as it'll reset the cached information when going to sleep.
+ */
+ if (compaction_restarting(zone, cc->order) && !current_is_kswapd())
+ __reset_isolation_suitable(zone);
migrate_prep_local();
@@ -673,6 +946,8 @@
switch (isolate_migratepages(zone, cc)) {
case ISOLATE_ABORT:
ret = COMPACT_PARTIAL;
+ putback_lru_pages(&cc->migratepages);
+ cc->nr_migratepages = 0;
goto out;
case ISOLATE_NONE:
continue;
@@ -687,10 +962,6 @@
update_nr_listpages(cc);
nr_remaining = cc->nr_migratepages;
- count_vm_event(COMPACTBLOCKS);
- count_vm_events(COMPACTPAGES, nr_migrate - nr_remaining);
- if (nr_remaining)
- count_vm_events(COMPACTPAGEFAILED, nr_remaining);
trace_mm_compaction_migratepages(nr_migrate - nr_remaining,
nr_remaining);
@@ -698,8 +969,11 @@
if (err) {
putback_lru_pages(&cc->migratepages);
cc->nr_migratepages = 0;
+ if (err == -ENOMEM) {
+ ret = COMPACT_PARTIAL;
+ goto out;
+ }
}
-
}
out:
@@ -712,8 +986,9 @@
static unsigned long compact_zone_order(struct zone *zone,
int order, gfp_t gfp_mask,
- bool sync)
+ bool sync, bool *contended)
{
+ unsigned long ret;
struct compact_control cc = {
.nr_freepages = 0,
.nr_migratepages = 0,
@@ -725,7 +1000,13 @@
INIT_LIST_HEAD(&cc.freepages);
INIT_LIST_HEAD(&cc.migratepages);
- return compact_zone(zone, &cc);
+ ret = compact_zone(zone, &cc);
+
+ VM_BUG_ON(!list_empty(&cc.freepages));
+ VM_BUG_ON(!list_empty(&cc.migratepages));
+
+ *contended = cc.contended;
+ return ret;
}
int sysctl_extfrag_threshold = 500;
@@ -737,12 +1018,14 @@
* @gfp_mask: The GFP mask of the current allocation
* @nodemask: The allowed nodes to allocate from
* @sync: Whether migration is synchronous or not
+ * @contended: Return value that is true if compaction was aborted due to lock contention
+ * @page: Optionally capture a free page of the requested order during compaction
*
* This is the main entry point for direct page compaction.
*/
unsigned long try_to_compact_pages(struct zonelist *zonelist,
int order, gfp_t gfp_mask, nodemask_t *nodemask,
- bool sync)
+ bool sync, bool *contended)
{
enum zone_type high_zoneidx = gfp_zone(gfp_mask);
int may_enter_fs = gfp_mask & __GFP_FS;
@@ -752,15 +1035,11 @@
int rc = COMPACT_SKIPPED;
int alloc_flags = 0;
- /*
- * Check whether it is worth even starting compaction. The order check is
- * made because an assumption is made that the page allocator can satisfy
- * the "cheaper" orders without taking special steps
- */
+ /* Check if the GFP flags allow compaction */
if (!order || !may_enter_fs || !may_perform_io)
return rc;
- count_vm_event(COMPACTSTALL);
+ count_compact_event(COMPACTSTALL);
#ifdef CONFIG_CMA
if (allocflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
@@ -771,7 +1050,8 @@
nodemask) {
int status;
- status = compact_zone_order(zone, order, gfp_mask, sync);
+ status = compact_zone_order(zone, order, gfp_mask, sync,
+ contended);
rc = max(status, rc);
/* If a normal allocation would succeed, stop compacting */
@@ -808,7 +1088,7 @@
if (cc->order > 0) {
int ok = zone_watermark_ok(zone, cc->order,
low_wmark_pages(zone), 0, 0);
- if (ok && cc->order > zone->compact_order_failed)
+ if (ok && cc->order >= zone->compact_order_failed)
zone->compact_order_failed = cc->order + 1;
/* Currently async compaction is never deferred. */
else if (!ok && cc->sync)
@@ -843,7 +1123,7 @@
}
/* Compact all nodes in the system */
-static int compact_nodes(void)
+static void compact_nodes(void)
{
int nid;
@@ -852,8 +1132,6 @@
for_each_online_node(nid)
compact_node(nid);
-
- return COMPACT_COMPLETE;
}
/* The written value is actually unused, all memory is compacted */
@@ -864,7 +1142,7 @@
void __user *buffer, size_t *length, loff_t *ppos)
{
if (write)
- return compact_nodes();
+ compact_nodes();
return 0;
}
diff --git a/mm/internal.h b/mm/internal.h
index 8c6fd44..3439ef4 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -120,17 +120,24 @@
unsigned long free_pfn; /* isolate_freepages search base */
unsigned long migrate_pfn; /* isolate_migratepages search base */
bool sync; /* Synchronous migration */
+ bool ignore_skip_hint; /* Scan blocks even if marked skip */
+ bool finished_update_free; /* True when the zone cached pfns are
+ * no longer being updated
+ */
+ bool finished_update_migrate;
int order; /* order a direct compactor needs */
int migratetype; /* MOVABLE, RECLAIMABLE etc */
struct zone *zone;
+ bool contended; /* True if a lock was contended */
};
unsigned long
-isolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn);
+isolate_freepages_range(struct compact_control *cc,
+ unsigned long start_pfn, unsigned long end_pfn);
unsigned long
isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
- unsigned long low_pfn, unsigned long end_pfn);
+ unsigned long low_pfn, unsigned long end_pfn, bool unevictable);
#endif
@@ -356,3 +363,6 @@
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
#define ALLOC_CMA 0x80 /* allow allocations from CMA areas */
+
+unsigned long reclaim_clean_pages_from_list(struct zone *zone,
+ struct list_head *page_list);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7685d4a..d436634 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1116,11 +1116,6 @@
mz->lru_size[lru] -= 1 << compound_order(page);
}
-void mem_cgroup_lru_del(struct page *page)
-{
- mem_cgroup_lru_del_list(page, page_lru(page));
-}
-
/**
* mem_cgroup_lru_move_lists - account for moving a page between lrus
* @zone: zone of the page
@@ -1149,15 +1144,25 @@
* Checks whether given mem is same or in the root_mem_cgroup's
* hierarchy subtree
*/
-static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
- struct mem_cgroup *memcg)
+bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
+ struct mem_cgroup *memcg)
{
- if (root_memcg != memcg) {
- return (root_memcg->use_hierarchy &&
- css_is_ancestor(&memcg->css, &root_memcg->css));
- }
+ if (root_memcg == memcg)
+ return true;
+ if (!root_memcg->use_hierarchy)
+ return false;
+ return css_is_ancestor(&memcg->css, &root_memcg->css);
+}
- return true;
+static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
+ struct mem_cgroup *memcg)
+{
+ bool ret;
+
+ rcu_read_lock();
+ ret = __mem_cgroup_same_or_subtree(root_memcg, memcg);
+ rcu_read_unlock();
+ return ret;
}
int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg)
@@ -5610,7 +5615,6 @@
if (mm) {
if (mc.to)
mem_cgroup_move_charge(mm);
- put_swap_token(mm);
mmput(mm);
}
if (mc.to)
diff --git a/mm/memory.c b/mm/memory.c
index 2111354..b6ab040 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2935,7 +2935,6 @@
delayacct_set_flag(DELAYACCT_PF_SWAPIN);
page = lookup_swap_cache(entry);
if (!page) {
- grab_swap_token(mm); /* Contend for token _before_ read-in */
page = swapin_readahead(entry,
GFP_HIGHUSER_MOVABLE, vma, address);
if (!page) {
@@ -2965,6 +2964,7 @@
}
locked = lock_page_or_retry(page, mm, flags);
+
delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
if (!locked) {
ret |= VM_FAULT_RETRY;
diff --git a/mm/migrate.c b/mm/migrate.c
index 79a791f..4f5c02e 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -969,6 +969,7 @@
{
int retry = 1;
int nr_failed = 0;
+ int nr_succeeded = 0;
int pass = 0;
struct page *page;
struct page *page2;
@@ -997,6 +998,7 @@
trace_migrate_retry(retry);
break;
case 0:
+ nr_succeeded++;
break;
default:
/* Permanent failure */
@@ -1007,6 +1009,10 @@
}
rc = 0;
out:
+ if (nr_succeeded)
+ count_vm_events(PGMIGRATE_SUCCESS, nr_succeeded);
+ if (nr_failed)
+ count_vm_events(PGMIGRATE_FAIL, nr_failed);
if (!swapwrite)
current->flags &= ~PF_SWAPWRITE;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8a93508..9cc2f45 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1441,6 +1441,45 @@
set_page_refcounted(page + i);
}
+static int __isolate_free_page(struct page *page, unsigned int order)
+{
+ unsigned long watermark;
+ struct zone *zone;
+ int mt;
+
+ BUG_ON(!PageBuddy(page));
+
+ zone = page_zone(page);
+ mt = get_pageblock_migratetype(page);
+
+ if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt)) {
+ /* Obey watermarks as if the page was being allocated */
+ watermark = low_wmark_pages(zone) + (1 << order);
+ if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+ return 0;
+
+ __mod_zone_freepage_state(zone, -(1UL << order), mt);
+ }
+
+ /* Remove page from free list */
+ list_del(&page->lru);
+ zone->free_area[order].nr_free--;
+ rmv_page_order(page);
+
+ /* Set the pageblock if the isolated page is at least a pageblock */
+ if (order >= pageblock_order - 1) {
+ struct page *endpage = page + (1 << order) - 1;
+ for (; page < endpage; page += pageblock_nr_pages) {
+ mt = get_pageblock_migratetype(page);
+ if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt))
+ set_pageblock_migratetype(page,
+ MIGRATE_MOVABLE);
+ }
+ }
+
+ return 1UL << order;
+}
+
/*
* Similar to split_page except the page is already free. As this is only
* being used for migration, the migratetype of the block also changes.
@@ -1454,45 +1493,18 @@
int split_free_page(struct page *page)
{
unsigned int order;
- unsigned long watermark;
- struct zone *zone;
- int mt;
+ int nr_pages;
- BUG_ON(!PageBuddy(page));
-
- zone = page_zone(page);
order = page_order(page);
- mt = get_pageblock_migratetype(page);
- /* Obey watermarks as if the page was being allocated */
- watermark = low_wmark_pages(zone) + (1 << order);
- if (!is_migrate_cma(mt) && mt != MIGRATE_ISOLATE &&
- !zone_watermark_ok(zone, 0, watermark, 0, 0))
+ nr_pages = __isolate_free_page(page, order);
+ if (!nr_pages)
return 0;
- /* Remove page from free list */
- list_del(&page->lru);
- zone->free_area[order].nr_free--;
- rmv_page_order(page);
-
- if (unlikely(mt != MIGRATE_ISOLATE))
- __mod_zone_freepage_state(zone, -(1UL << order), mt);
-
/* Split into individual pages */
set_page_refcounted(page);
split_page(page, order);
-
- if (order >= pageblock_order - 1) {
- struct page *endpage = page + (1 << order) - 1;
- for (; page < endpage; page += pageblock_nr_pages) {
- mt = get_pageblock_migratetype(page);
- if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt))
- set_pageblock_migratetype(page,
- MIGRATE_MOVABLE);
- }
- }
-
- return 1 << order;
+ return nr_pages;
}
/*
@@ -2134,11 +2146,9 @@
struct zonelist *zonelist, enum zone_type high_zoneidx,
nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
int migratetype, bool sync_migration,
- bool *deferred_compaction,
+ bool *contended_compaction, bool *deferred_compaction,
unsigned long *did_some_progress)
{
- struct page *page;
-
if (!order)
return NULL;
@@ -2149,9 +2159,12 @@
current->flags |= PF_MEMALLOC;
*did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
- nodemask, sync_migration);
+ nodemask, sync_migration,
+ contended_compaction);
current->flags &= ~PF_MEMALLOC;
+
if (*did_some_progress != COMPACT_SKIPPED) {
+ struct page *page;
/* Page migration frees to the PCP lists but we want merging */
drain_pages(get_cpu());
@@ -2162,6 +2175,7 @@
alloc_flags, preferred_zone,
migratetype);
if (page) {
+ preferred_zone->compact_blockskip_flush = false;
preferred_zone->compact_considered = 0;
preferred_zone->compact_defer_shift = 0;
if (order >= preferred_zone->compact_order_failed)
@@ -2195,7 +2209,7 @@
struct zonelist *zonelist, enum zone_type high_zoneidx,
nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
int migratetype, bool sync_migration,
- bool *deferred_compaction,
+ bool *contended_compaction, bool *deferred_compaction,
unsigned long *did_some_progress)
{
return NULL;
@@ -2362,6 +2376,7 @@
unsigned long did_some_progress;
bool sync_migration = false;
bool deferred_compaction = false;
+ bool contended_compaction = false;
/*
* In the slowpath, we sanity check order to avoid ever trying to
@@ -2443,6 +2458,7 @@
nodemask,
alloc_flags, preferred_zone,
migratetype, sync_migration,
+ &contended_compaction,
&deferred_compaction,
&did_some_progress);
if (page)
@@ -2452,10 +2468,11 @@
/*
* If compaction is deferred for high-order allocations, it is because
* sync compaction recently failed. In this is the case and the caller
- * has requested the system not be heavily disrupted, fail the
- * allocation now instead of entering direct reclaim
+ * requested a movable allocation that does not heavily disrupt the
+ * system then fail the allocation instead of entering direct reclaim.
*/
- if (deferred_compaction && (gfp_mask & __GFP_NO_KSWAPD))
+ if ((deferred_compaction || contended_compaction) &&
+ (gfp_mask & __GFP_NO_KSWAPD))
goto nopage;
/* Try direct reclaim and then allocating */
@@ -2526,6 +2543,7 @@
nodemask,
alloc_flags, preferred_zone,
migratetype, sync_migration,
+ &contended_compaction,
&deferred_compaction,
&did_some_progress);
if (page)
@@ -5592,26 +5610,28 @@
}
/*
- * This is designed as sub function...plz see page_isolation.c also.
- * set/clear page block's type to be ISOLATE.
- * page allocater never alloc memory from ISOLATE block.
+ * This function checks whether pageblock includes unmovable pages or not.
+ * If @count is not zero, it is okay to include less @count unmovable pages
+ *
+ * PageLRU check wihtout isolation or lru_lock could race so that
+ * MIGRATE_MOVABLE block might include unmovable pages. It means you can't
+ * expect this function should be exact.
*/
-
-static int
-__count_immobile_pages(struct zone *zone, struct page *page, int count)
+static bool
+__has_unmovable_pages(struct zone *zone, struct page *page, int count)
{
unsigned long pfn, iter, found;
int mt;
/*
* For avoiding noise data, lru_add_drain_all() should be called
- * If ZONE_MOVABLE, the zone never contains immobile pages
+ * If ZONE_MOVABLE, the zone never contains unmovable pages
*/
if (zone_idx(zone) == ZONE_MOVABLE)
- return true;
+ return false;
mt = get_pageblock_migratetype(page);
if (mt == MIGRATE_MOVABLE || is_migrate_cma(mt))
- return true;
+ return false;
pfn = page_to_pfn(page);
for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
@@ -5621,11 +5641,18 @@
continue;
page = pfn_to_page(check);
- if (!page_count(page)) {
+ /*
+ * We can't use page_count without pin a page
+ * because another CPU can free compound page.
+ * This check already skips compound tails of THP
+ * because their page->_count is zero at all time.
+ */
+ if (!atomic_read(&page->_count)) {
if (PageBuddy(page))
iter += (1 << page_order(page)) - 1;
continue;
}
+
if (!PageLRU(page))
found++;
/*
@@ -5642,9 +5669,9 @@
* page at boot.
*/
if (found > count)
- return false;
+ return true;
}
- return true;
+ return false;
}
bool is_pageblock_removable_nolock(struct page *page)
@@ -5668,7 +5695,7 @@
zone->zone_start_pfn + zone->spanned_pages <= pfn)
return false;
- return __count_immobile_pages(zone, page, 0);
+ return !__has_unmovable_pages(zone, page, 0);
}
int set_migratetype_isolate(struct page *page)
@@ -5707,12 +5734,12 @@
* FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
* We just check MOVABLE pages.
*/
- if (__count_immobile_pages(zone, page, arg.pages_found))
+ if (!__has_unmovable_pages(zone, page, arg.pages_found))
ret = 0;
-
/*
- * immobile means "not-on-lru" paes. If immobile is larger than
- * removable-by-driver pages reported by notifier, we'll fail.
+ * Unmovable means "not-on-lru" pages. If Unmovable pages are
+ * larger than removable-by-driver pages reported by notifier,
+ * we'll fail.
*/
out:
@@ -5775,34 +5802,27 @@
}
/* [start, end) must belong to a single zone. */
-static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
+static int __alloc_contig_migrate_range(struct compact_control *cc,
+ unsigned long start, unsigned long end)
{
/* This function is based on compact_zone() from compaction.c. */
-
+ unsigned long nr_reclaimed;
unsigned long pfn = start;
unsigned int tries = 0;
int ret = 0;
- struct compact_control cc = {
- .nr_migratepages = 0,
- .order = -1,
- .zone = page_zone(pfn_to_page(start)),
- .sync = true,
- };
- INIT_LIST_HEAD(&cc.migratepages);
-
migrate_prep();
- while (pfn < end || !list_empty(&cc.migratepages)) {
+ while (pfn < end || !list_empty(&cc->migratepages)) {
if (fatal_signal_pending(current)) {
ret = -EINTR;
break;
}
- if (list_empty(&cc.migratepages)) {
- cc.nr_migratepages = 0;
- pfn = isolate_migratepages_range(cc.zone, &cc,
- pfn, end);
+ if (list_empty(&cc->migratepages)) {
+ cc->nr_migratepages = 0;
+ pfn = isolate_migratepages_range(cc->zone, cc,
+ pfn, end, true);
if (!pfn) {
ret = -EINTR;
break;
@@ -5813,12 +5833,16 @@
break;
}
- ret = migrate_pages(&cc.migratepages,
+ nr_reclaimed = reclaim_clean_pages_from_list(cc->zone, &cc->migratepages);
+
+ cc->nr_migratepages -= nr_reclaimed;
+
+ ret = migrate_pages(&cc->migratepages,
__alloc_contig_migrate_alloc,
0, false, MIGRATE_SYNC);
}
- putback_lru_pages(&cc.migratepages);
+ putback_lru_pages(&cc->migratepages);
return ret > 0 ? 0 : ret;
}
@@ -5849,6 +5873,15 @@
unsigned long outer_start, outer_end;
int ret = 0, order;
+ struct compact_control cc = {
+ .nr_migratepages = 0,
+ .order = -1,
+ .zone = page_zone(pfn_to_page(start)),
+ .sync = true,
+ .ignore_skip_hint = true,
+ };
+ INIT_LIST_HEAD(&cc.migratepages);
+
/*
* What we do here is we mark all pageblocks in range as
* MIGRATE_ISOLATE. Because pageblock and max order pages may
@@ -5880,7 +5913,7 @@
zone->cma_alloc = 1;
- ret = __alloc_contig_migrate_range(start, end);
+ ret = __alloc_contig_migrate_range(&cc, start, end);
if (ret)
goto done;
@@ -5924,7 +5957,7 @@
/* Grab isolated pages from freelists. */
- outer_end = isolate_freepages_range(outer_start, end);
+ outer_end = isolate_freepages_range(&cc, outer_start, end);
if (!outer_end) {
ret = -EBUSY;
goto done;
@@ -5945,8 +5978,15 @@
void free_contig_range(unsigned long pfn, unsigned nr_pages)
{
- for (; nr_pages--; ++pfn)
- __free_page(pfn_to_page(pfn));
+ unsigned int count = 0;
+
+ for (; nr_pages--; pfn++) {
+ struct page *page = pfn_to_page(pfn);
+
+ count += page_count(page) != 1;
+ __free_page(page);
+ }
+ WARN(count != 0, "%d pages are still in use!\n", count);
}
#endif
@@ -6053,6 +6093,7 @@
#ifdef CONFIG_MEMORY_FAILURE
{1UL << PG_hwpoison, "hwpoison" },
#endif
+ {1UL << PG_readahead, "PG_readahead" },
{-1UL, NULL },
};
diff --git a/mm/readahead.c b/mm/readahead.c
index 728a7a3..56f8a24 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -184,6 +184,9 @@
if (!page)
break;
page->index = page_offset;
+
+ page->flags |= (1L << PG_readahead);
+
list_add(&page->lru, &page_pool);
if (page_idx == nr_to_read - lookahead_size)
SetPageReadahead(page);
diff --git a/mm/rmap.c b/mm/rmap.c
index 5b5ad58..0f3b7cd 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -755,12 +755,6 @@
pte_unmap_unlock(pte, ptl);
}
- /* Pretend the page is referenced if the task has the
- swap token and is in the middle of a page fault. */
- if (mm != current->mm && has_swap_token(mm) &&
- rwsem_is_locked(&mm->mmap_sem))
- referenced++;
-
(*mapcount)--;
if (referenced)
diff --git a/mm/thrash.c b/mm/thrash.c
deleted file mode 100644
index 57ad495..0000000
--- a/mm/thrash.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * mm/thrash.c
- *
- * Copyright (C) 2004, Red Hat, Inc.
- * Copyright (C) 2004, Rik van Riel <riel@redhat.com>
- * Released under the GPL, see the file COPYING for details.
- *
- * Simple token based thrashing protection, using the algorithm
- * described in: http://www.cse.ohio-state.edu/hpcs/WWW/HTML/publications/abs05-1.html
- *
- * Sep 2006, Ashwin Chaugule <ashwin.chaugule@celunite.com>
- * Improved algorithm to pass token:
- * Each task has a priority which is incremented if it contended
- * for the token in an interval less than its previous attempt.
- * If the token is acquired, that task's priority is boosted to prevent
- * the token from bouncing around too often and to let the task make
- * some progress in its execution.
- */
-
-#include <linux/jiffies.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/swap.h>
-#include <linux/memcontrol.h>
-
-#include <trace/events/vmscan.h>
-
-#define TOKEN_AGING_INTERVAL (0xFF)
-
-static DEFINE_SPINLOCK(swap_token_lock);
-struct mm_struct *swap_token_mm;
-static struct mem_cgroup *swap_token_memcg;
-
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR
-static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
-{
- struct mem_cgroup *memcg;
-
- memcg = try_get_mem_cgroup_from_mm(mm);
- if (memcg)
- css_put(mem_cgroup_css(memcg));
-
- return memcg;
-}
-#else
-static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
-{
- return NULL;
-}
-#endif
-
-void grab_swap_token(struct mm_struct *mm)
-{
- int current_interval;
- unsigned int old_prio = mm->token_priority;
- static unsigned int global_faults;
- static unsigned int last_aging;
-
- global_faults++;
-
- current_interval = global_faults - mm->faultstamp;
-
- if (!spin_trylock(&swap_token_lock))
- return;
-
- /* First come first served */
- if (!swap_token_mm)
- goto replace_token;
-
- /*
- * Usually, we don't need priority aging because long interval faults
- * makes priority decrease quickly. But there is one exception. If the
- * token owner task is sleeping, it never make long interval faults.
- * Thus, we need a priority aging mechanism instead. The requirements
- * of priority aging are
- * 1) An aging interval is reasonable enough long. Too short aging
- * interval makes quick swap token lost and decrease performance.
- * 2) The swap token owner task have to get priority aging even if
- * it's under sleep.
- */
- if ((global_faults - last_aging) > TOKEN_AGING_INTERVAL) {
- swap_token_mm->token_priority /= 2;
- last_aging = global_faults;
- }
-
- if (mm == swap_token_mm) {
- mm->token_priority += 2;
- goto update_priority;
- }
-
- if (current_interval < mm->last_interval)
- mm->token_priority++;
- else {
- if (likely(mm->token_priority > 0))
- mm->token_priority--;
- }
-
- /* Check if we deserve the token */
- if (mm->token_priority > swap_token_mm->token_priority)
- goto replace_token;
-
-update_priority:
- trace_update_swap_token_priority(mm, old_prio, swap_token_mm);
-
-out:
- mm->faultstamp = global_faults;
- mm->last_interval = current_interval;
- spin_unlock(&swap_token_lock);
- return;
-
-replace_token:
- mm->token_priority += 2;
- trace_replace_swap_token(swap_token_mm, mm);
- swap_token_mm = mm;
- swap_token_memcg = swap_token_memcg_from_mm(mm);
- last_aging = global_faults;
- goto out;
-}
-
-/* Called on process exit. */
-void __put_swap_token(struct mm_struct *mm)
-{
- spin_lock(&swap_token_lock);
- if (likely(mm == swap_token_mm)) {
- trace_put_swap_token(swap_token_mm);
- swap_token_mm = NULL;
- swap_token_memcg = NULL;
- }
- spin_unlock(&swap_token_lock);
-}
-
-static bool match_memcg(struct mem_cgroup *a, struct mem_cgroup *b)
-{
- if (!a)
- return true;
- if (!b)
- return true;
- if (a == b)
- return true;
- return false;
-}
-
-void disable_swap_token(struct mem_cgroup *memcg)
-{
- /* memcg reclaim don't disable unrelated mm token. */
- if (match_memcg(memcg, swap_token_memcg)) {
- spin_lock(&swap_token_lock);
- if (match_memcg(memcg, swap_token_memcg)) {
- trace_disable_swap_token(swap_token_mm);
- swap_token_mm = NULL;
- swap_token_memcg = NULL;
- }
- spin_unlock(&swap_token_lock);
- }
-}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 33dc256..c69f5e2 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -53,24 +53,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/vmscan.h>
-/*
- * reclaim_mode determines how the inactive list is shrunk
- * RECLAIM_MODE_SINGLE: Reclaim only order-0 pages
- * RECLAIM_MODE_ASYNC: Do not block
- * RECLAIM_MODE_SYNC: Allow blocking e.g. call wait_on_page_writeback
- * RECLAIM_MODE_LUMPYRECLAIM: For high-order allocations, take a reference
- * page from the LRU and reclaim all pages within a
- * naturally aligned range
- * RECLAIM_MODE_COMPACTION: For high-order allocations, reclaim a number of
- * order-0 pages and then compact the zone
- */
-typedef unsigned __bitwise__ reclaim_mode_t;
-#define RECLAIM_MODE_SINGLE ((__force reclaim_mode_t)0x01u)
-#define RECLAIM_MODE_ASYNC ((__force reclaim_mode_t)0x02u)
-#define RECLAIM_MODE_SYNC ((__force reclaim_mode_t)0x04u)
-#define RECLAIM_MODE_LUMPYRECLAIM ((__force reclaim_mode_t)0x08u)
-#define RECLAIM_MODE_COMPACTION ((__force reclaim_mode_t)0x10u)
-
struct scan_control {
/* Incremented by the number of inactive pages that were scanned */
unsigned long nr_scanned;
@@ -96,11 +78,8 @@
int order;
- /*
- * Intend to reclaim enough continuous memory rather than reclaim
- * enough amount of memory. i.e, mode for high order allocation.
- */
- reclaim_mode_t reclaim_mode;
+ /* Scan (total_size >> priority) pages at once */
+ int priority;
/*
* The memory cgroup that hit its limit and as a result is the
@@ -164,26 +143,16 @@
{
return !sc->target_mem_cgroup;
}
-
-static bool scanning_global_lru(struct mem_cgroup_zone *mz)
-{
- return !mz->mem_cgroup;
-}
#else
static bool global_reclaim(struct scan_control *sc)
{
return true;
}
-
-static bool scanning_global_lru(struct mem_cgroup_zone *mz)
-{
- return true;
-}
#endif
static struct zone_reclaim_stat *get_reclaim_stat(struct mem_cgroup_zone *mz)
{
- if (!scanning_global_lru(mz))
+ if (!mem_cgroup_disabled())
return mem_cgroup_get_reclaim_stat(mz->mem_cgroup, mz->zone);
return &mz->zone->reclaim_stat;
@@ -192,7 +161,7 @@
static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz,
enum lru_list lru)
{
- if (!scanning_global_lru(mz))
+ if (!mem_cgroup_disabled())
return mem_cgroup_zone_nr_lru_pages(mz->mem_cgroup,
zone_to_nid(mz->zone),
zone_idx(mz->zone),
@@ -364,39 +333,6 @@
return ret;
}
-static void set_reclaim_mode(int priority, struct scan_control *sc,
- bool sync)
-{
- reclaim_mode_t syncmode = sync ? RECLAIM_MODE_SYNC : RECLAIM_MODE_ASYNC;
-
- /*
- * Initially assume we are entering either lumpy reclaim or
- * reclaim/compaction.Depending on the order, we will either set the
- * sync mode or just reclaim order-0 pages later.
- */
- if (COMPACTION_BUILD)
- sc->reclaim_mode = RECLAIM_MODE_COMPACTION;
- else
- sc->reclaim_mode = RECLAIM_MODE_LUMPYRECLAIM;
-
- /*
- * Avoid using lumpy reclaim or reclaim/compaction if possible by
- * restricting when its set to either costly allocations or when
- * under memory pressure
- */
- if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
- sc->reclaim_mode |= syncmode;
- else if (sc->order && priority < DEF_PRIORITY - 2)
- sc->reclaim_mode |= syncmode;
- else
- sc->reclaim_mode = RECLAIM_MODE_SINGLE | RECLAIM_MODE_ASYNC;
-}
-
-static void reset_reclaim_mode(struct scan_control *sc)
-{
- sc->reclaim_mode = RECLAIM_MODE_SINGLE | RECLAIM_MODE_ASYNC;
-}
-
static inline int is_page_cache_freeable(struct page *page)
{
/*
@@ -416,10 +352,6 @@
return 1;
if (bdi == current->backing_dev_info)
return 1;
-
- /* lumpy reclaim for hugepage often need a lot of write */
- if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
- return 1;
return 0;
}
@@ -523,8 +455,7 @@
/* synchronous write or broken a_ops? */
ClearPageReclaim(page);
}
- trace_mm_vmscan_writepage(page,
- trace_reclaim_flags(page, sc->reclaim_mode));
+ trace_mm_vmscan_writepage(page, trace_reclaim_flags(page));
inc_zone_page_state(page, NR_VMSCAN_WRITE);
return PAGE_SUCCESS;
}
@@ -701,19 +632,15 @@
};
static enum page_references page_check_references(struct page *page,
- struct mem_cgroup_zone *mz,
struct scan_control *sc)
{
int referenced_ptes, referenced_page;
unsigned long vm_flags;
- referenced_ptes = page_referenced(page, 1, mz->mem_cgroup, &vm_flags);
+ referenced_ptes = page_referenced(page, 1, sc->target_mem_cgroup,
+ &vm_flags);
referenced_page = TestClearPageReferenced(page);
- /* Lumpy reclaim - ignore references */
- if (sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM)
- return PAGEREF_RECLAIM;
-
/*
* Mlock lost the isolation race with us. Let try_to_unmap()
* move the page to the unevictable list.
@@ -763,11 +690,12 @@
* shrink_page_list() returns the number of reclaimed pages
*/
static unsigned long shrink_page_list(struct list_head *page_list,
- struct mem_cgroup_zone *mz,
+ struct zone *zone,
struct scan_control *sc,
- int priority,
+ enum ttu_flags ttu_flags,
unsigned long *ret_nr_dirty,
- unsigned long *ret_nr_writeback)
+ unsigned long *ret_nr_writeback,
+ bool force_reclaim)
{
LIST_HEAD(ret_pages);
LIST_HEAD(free_pages);
@@ -780,10 +708,10 @@
cond_resched();
while (!list_empty(page_list)) {
- enum page_references references;
struct address_space *mapping;
struct page *page;
int may_enter_fs;
+ enum page_references references = PAGEREF_RECLAIM_CLEAN;
cond_resched();
@@ -794,7 +722,7 @@
goto keep;
VM_BUG_ON(PageActive(page));
- VM_BUG_ON(page_zone(page) != mz->zone);
+ VM_BUG_ON(page_zone(page) != zone);
sc->nr_scanned++;
@@ -813,22 +741,13 @@
if (PageWriteback(page)) {
nr_writeback++;
- /*
- * Synchronous reclaim cannot queue pages for
- * writeback due to the possibility of stack overflow
- * but if it encounters a page under writeback, wait
- * for the IO to complete.
- */
- if ((sc->reclaim_mode & RECLAIM_MODE_SYNC) &&
- may_enter_fs)
- wait_on_page_writeback(page);
- else {
- unlock_page(page);
- goto keep_lumpy;
- }
+ unlock_page(page);
+ goto keep;
}
- references = page_check_references(page, mz, sc);
+ if (!force_reclaim)
+ references = page_check_references(page, sc);
+
switch (references) {
case PAGEREF_ACTIVATE:
goto activate_locked;
@@ -858,7 +777,7 @@
* processes. Try to unmap it here.
*/
if (page_mapped(page) && mapping) {
- switch (try_to_unmap(page, TTU_UNMAP)) {
+ switch (try_to_unmap(page, ttu_flags)) {
case SWAP_FAIL:
goto activate_locked;
case SWAP_AGAIN:
@@ -879,7 +798,8 @@
* unless under significant pressure.
*/
if (page_is_file_cache(page) &&
- (!current_is_kswapd() || priority >= DEF_PRIORITY - 2)) {
+ (!current_is_kswapd() ||
+ sc->priority >= DEF_PRIORITY - 2)) {
/*
* Immediately reclaim when written back.
* Similar in principal to deactivate_page()
@@ -908,7 +828,7 @@
goto activate_locked;
case PAGE_SUCCESS:
if (PageWriteback(page))
- goto keep_lumpy;
+ goto keep;
if (PageDirty(page))
goto keep;
@@ -994,7 +914,6 @@
try_to_free_swap(page);
unlock_page(page);
putback_lru_page(page);
- reset_reclaim_mode(sc);
continue;
activate_locked:
@@ -1007,8 +926,6 @@
keep_locked:
unlock_page(page);
keep:
- reset_reclaim_mode(sc);
-keep_lumpy:
list_add(&page->lru, &ret_pages);
VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
}
@@ -1020,7 +937,7 @@
* will encounter the same problem
*/
if (nr_dirty && nr_dirty == nr_congested && global_reclaim(sc))
- zone_set_flag(mz->zone, ZONE_CONGESTED);
+ zone_set_flag(zone, ZONE_CONGESTED);
free_hot_cold_page_list(&free_pages, 1);
@@ -1031,6 +948,33 @@
return nr_reclaimed;
}
+unsigned long reclaim_clean_pages_from_list(struct zone *zone,
+ struct list_head *page_list)
+{
+ struct scan_control sc = {
+ .gfp_mask = GFP_KERNEL,
+ .priority = DEF_PRIORITY,
+ .may_unmap = 1,
+ };
+ unsigned long ret, dummy1, dummy2;
+ struct page *page, *next;
+ LIST_HEAD(clean_pages);
+
+ list_for_each_entry_safe(page, next, page_list, lru) {
+ if (page_is_file_cache(page) && !PageDirty(page)) {
+ ClearPageActive(page);
+ list_move(&page->lru, &clean_pages);
+ }
+ }
+
+ ret = shrink_page_list(&clean_pages, zone, &sc,
+ TTU_UNMAP|TTU_IGNORE_ACCESS,
+ &dummy1, &dummy2, true);
+ list_splice(&clean_pages, page_list);
+ __mod_zone_page_state(zone, NR_ISOLATED_FILE, -ret);
+ return ret;
+}
+
/*
* Attempt to remove the specified page from its LRU. Only take this page
* if it is of the appropriate PageActive status. Pages which are being
@@ -1041,35 +985,16 @@
*
* returns 0 on success, -ve errno on failure.
*/
-int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
+int __isolate_lru_page(struct page *page, isolate_mode_t mode)
{
- bool all_lru_mode;
int ret = -EINVAL;
/* Only take pages on the LRU. */
if (!PageLRU(page))
return ret;
- all_lru_mode = (mode & (ISOLATE_ACTIVE|ISOLATE_INACTIVE)) ==
- (ISOLATE_ACTIVE|ISOLATE_INACTIVE);
-
- /*
- * When checking the active state, we need to be sure we are
- * dealing with comparible boolean values. Take the logical not
- * of each.
- */
- if (!all_lru_mode && !PageActive(page) != !(mode & ISOLATE_ACTIVE))
- return ret;
-
- if (!all_lru_mode && !!page_is_file_cache(page) != file)
- return ret;
-
- /*
- * When this function is being called for lumpy reclaim, we
- * initially look into all LRU pages, active, inactive and
- * unevictable; only give shrink_page_list evictable pages.
- */
- if (PageUnevictable(page))
+ /* Compaction should not handle unevictable pages but CMA can do so */
+ if (PageUnevictable(page) && !(mode & ISOLATE_UNEVICTABLE))
return ret;
ret = -EBUSY;
@@ -1135,52 +1060,38 @@
* Appropriate locks must be held before calling this function.
*
* @nr_to_scan: The number of pages to look through on the list.
- * @mz: The mem_cgroup_zone to pull pages from.
+ * @lruvec: The LRU vector to pull pages from.
* @dst: The temp list to put pages on to.
* @nr_scanned: The number of pages that were scanned.
* @sc: The scan_control struct for this reclaim session
* @mode: One of the LRU isolation modes
- * @active: True [1] if isolating active pages
- * @file: True [1] if isolating file [!anon] pages
+ * @lru: LRU list id for isolating
*
* returns how many pages were moved onto *@dst.
*/
static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
- struct mem_cgroup_zone *mz, struct list_head *dst,
+ struct lruvec *lruvec, struct list_head *dst,
unsigned long *nr_scanned, struct scan_control *sc,
- isolate_mode_t mode, int active, int file)
+ isolate_mode_t mode, enum lru_list lru)
{
- struct lruvec *lruvec;
struct list_head *src;
unsigned long nr_taken = 0;
- unsigned long nr_lumpy_taken = 0;
- unsigned long nr_lumpy_dirty = 0;
- unsigned long nr_lumpy_failed = 0;
unsigned long scan;
- int lru = LRU_BASE;
+ int file = is_file_lru(lru);
- lruvec = mem_cgroup_zone_lruvec(mz->zone, mz->mem_cgroup);
- if (active)
- lru += LRU_ACTIVE;
- if (file)
- lru += LRU_FILE;
src = &lruvec->lists[lru];
for (scan = 0; scan < nr_to_scan && !list_empty(src); scan++) {
struct page *page;
- unsigned long pfn;
- unsigned long end_pfn;
- unsigned long page_pfn;
- int zone_id;
page = lru_to_page(src);
prefetchw_prev_lru_page(page, src, flags);
VM_BUG_ON(!PageLRU(page));
- switch (__isolate_lru_page(page, mode, file)) {
+ switch (__isolate_lru_page(page, mode)) {
case 0:
- mem_cgroup_lru_del(page);
+ mem_cgroup_lru_del_list(page, lru);
list_move(&page->lru, dst);
nr_taken += hpage_nr_pages(page);
break;
@@ -1193,84 +1104,6 @@
default:
BUG();
}
-
- if (!sc->order || !(sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM))
- continue;
-
- /*
- * Attempt to take all pages in the order aligned region
- * surrounding the tag page. Only take those pages of
- * the same active state as that tag page. We may safely
- * round the target page pfn down to the requested order
- * as the mem_map is guaranteed valid out to MAX_ORDER,
- * where that page is in a different zone we will detect
- * it from its zone id and abort this block scan.
- */
- zone_id = page_zone_id(page);
- page_pfn = page_to_pfn(page);
- pfn = page_pfn & ~((1 << sc->order) - 1);
- end_pfn = pfn + (1 << sc->order);
- for (; pfn < end_pfn; pfn++) {
- struct page *cursor_page;
-
- /* The target page is in the block, ignore it. */
- if (unlikely(pfn == page_pfn))
- continue;
-
- /* Avoid holes within the zone. */
- if (unlikely(!pfn_valid_within(pfn)))
- break;
-
- cursor_page = pfn_to_page(pfn);
-
- /* Check that we have not crossed a zone boundary. */
- if (unlikely(page_zone_id(cursor_page) != zone_id))
- break;
-
- /*
- * If we don't have enough swap space, reclaiming of
- * anon page which don't already have a swap slot is
- * pointless.
- */
- if (nr_swap_pages <= 0 && PageSwapBacked(cursor_page) &&
- !PageSwapCache(cursor_page))
- break;
-
- if (__isolate_lru_page(cursor_page, mode, file) == 0) {
- unsigned int isolated_pages;
-
- mem_cgroup_lru_del(cursor_page);
- list_move(&cursor_page->lru, dst);
- isolated_pages = hpage_nr_pages(cursor_page);
- nr_taken += isolated_pages;
- nr_lumpy_taken += isolated_pages;
- if (PageDirty(cursor_page))
- nr_lumpy_dirty += isolated_pages;
- scan++;
- pfn += isolated_pages - 1;
- } else {
- /*
- * Check if the page is freed already.
- *
- * We can't use page_count() as that
- * requires compound_head and we don't
- * have a pin on the page here. If a
- * page is tail, we may or may not
- * have isolated the head, so assume
- * it's not free, it'd be tricky to
- * track the head status without a
- * page pin.
- */
- if (!PageTail(cursor_page) &&
- !atomic_read(&cursor_page->_count))
- continue;
- break;
- }
- }
-
- /* If we break out of the loop above, lumpy reclaim failed */
- if (pfn < end_pfn)
- nr_lumpy_failed++;
}
*nr_scanned = scan;
@@ -1278,7 +1111,6 @@
trace_mm_vmscan_lru_isolate(sc->order,
nr_to_scan, scan,
nr_taken,
- nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed,
mode, file);
return nr_taken;
}
@@ -1407,112 +1239,25 @@
list_splice(&pages_to_free, page_list);
}
-static noinline_for_stack void
-update_isolated_counts(struct mem_cgroup_zone *mz,
- struct list_head *page_list,
- unsigned long *nr_anon,
- unsigned long *nr_file)
-{
- struct zone *zone = mz->zone;
- unsigned int count[NR_LRU_LISTS] = { 0, };
- unsigned long nr_active = 0;
- struct page *page;
- int lru;
-
- /*
- * Count pages and clear active flags
- */
- list_for_each_entry(page, page_list, lru) {
- int numpages = hpage_nr_pages(page);
- lru = page_lru_base_type(page);
- if (PageActive(page)) {
- lru += LRU_ACTIVE;
- ClearPageActive(page);
- nr_active += numpages;
- }
- count[lru] += numpages;
- }
-
- preempt_disable();
- __count_vm_events(PGDEACTIVATE, nr_active);
-
- __mod_zone_page_state(zone, NR_ACTIVE_FILE,
- -count[LRU_ACTIVE_FILE]);
- __mod_zone_page_state(zone, NR_INACTIVE_FILE,
- -count[LRU_INACTIVE_FILE]);
- __mod_zone_page_state(zone, NR_ACTIVE_ANON,
- -count[LRU_ACTIVE_ANON]);
- __mod_zone_page_state(zone, NR_INACTIVE_ANON,
- -count[LRU_INACTIVE_ANON]);
-
- *nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
- *nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
-
- __mod_zone_page_state(zone, NR_ISOLATED_ANON, *nr_anon);
- __mod_zone_page_state(zone, NR_ISOLATED_FILE, *nr_file);
- preempt_enable();
-}
-
-/*
- * Returns true if a direct reclaim should wait on pages under writeback.
- *
- * If we are direct reclaiming for contiguous pages and we do not reclaim
- * everything in the list, try again and wait for writeback IO to complete.
- * This will stall high-order allocations noticeably. Only do that when really
- * need to free the pages under high memory pressure.
- */
-static inline bool should_reclaim_stall(unsigned long nr_taken,
- unsigned long nr_freed,
- int priority,
- struct scan_control *sc)
-{
- int lumpy_stall_priority;
-
- /* kswapd should not stall on sync IO */
- if (current_is_kswapd())
- return false;
-
- /* Only stall on lumpy reclaim */
- if (sc->reclaim_mode & RECLAIM_MODE_SINGLE)
- return false;
-
- /* If we have reclaimed everything on the isolated list, no stall */
- if (nr_freed == nr_taken)
- return false;
-
- /*
- * For high-order allocations, there are two stall thresholds.
- * High-cost allocations stall immediately where as lower
- * order allocations such as stacks require the scanning
- * priority to be much higher before stalling.
- */
- if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
- lumpy_stall_priority = DEF_PRIORITY;
- else
- lumpy_stall_priority = DEF_PRIORITY / 3;
-
- return priority <= lumpy_stall_priority;
-}
-
/*
* shrink_inactive_list() is a helper for shrink_zone(). It returns the number
* of reclaimed pages
*/
static noinline_for_stack unsigned long
shrink_inactive_list(unsigned long nr_to_scan, struct mem_cgroup_zone *mz,
- struct scan_control *sc, int priority, int file)
+ struct scan_control *sc, enum lru_list lru)
{
LIST_HEAD(page_list);
unsigned long nr_scanned;
unsigned long nr_reclaimed = 0;
unsigned long nr_taken;
- unsigned long nr_anon;
- unsigned long nr_file;
unsigned long nr_dirty = 0;
unsigned long nr_writeback = 0;
- isolate_mode_t isolate_mode = ISOLATE_INACTIVE;
+ isolate_mode_t isolate_mode = 0;
+ int file = is_file_lru(lru);
struct zone *zone = mz->zone;
struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
+ struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, mz->mem_cgroup);
while (unlikely(too_many_isolated(zone, file, sc))) {
congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -1522,10 +1267,6 @@
return SWAP_CLUSTER_MAX;
}
- set_reclaim_mode(priority, sc, false);
- if (sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM)
- isolate_mode |= ISOLATE_ACTIVE;
-
lru_add_drain();
if (!sc->may_unmap)
@@ -1535,8 +1276,12 @@
spin_lock_irq(&zone->lru_lock);
- nr_taken = isolate_lru_pages(nr_to_scan, mz, &page_list, &nr_scanned,
- sc, isolate_mode, 0, file);
+ nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &page_list,
+ &nr_scanned, sc, isolate_mode, lru);
+
+ __mod_zone_page_state(zone, NR_LRU_BASE + lru, -nr_taken);
+ __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
+
if (global_reclaim(sc)) {
zone->pages_scanned += nr_scanned;
if (current_is_kswapd())
@@ -1551,22 +1296,12 @@
if (nr_taken == 0)
return 0;
- update_isolated_counts(mz, &page_list, &nr_anon, &nr_file);
-
- nr_reclaimed = shrink_page_list(&page_list, mz, sc, priority,
- &nr_dirty, &nr_writeback);
-
- /* Check if we should syncronously wait for writeback */
- if (should_reclaim_stall(nr_taken, nr_reclaimed, priority, sc)) {
- set_reclaim_mode(priority, sc, true);
- nr_reclaimed += shrink_page_list(&page_list, mz, sc,
- priority, &nr_dirty, &nr_writeback);
- }
+ nr_reclaimed = shrink_page_list(&page_list, zone, sc, TTU_UNMAP,
+ &nr_dirty, &nr_writeback, false);
spin_lock_irq(&zone->lru_lock);
- reclaim_stat->recent_scanned[0] += nr_anon;
- reclaim_stat->recent_scanned[1] += nr_file;
+ reclaim_stat->recent_scanned[file] += nr_taken;
if (global_reclaim(sc)) {
if (current_is_kswapd())
@@ -1579,8 +1314,7 @@
putback_inactive_pages(mz, &page_list);
- __mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
- __mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
+ __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
spin_unlock_irq(&zone->lru_lock);
@@ -1609,14 +1343,15 @@
* DEF_PRIORITY-6 For SWAP_CLUSTER_MAX isolated pages, throttle if any
* isolated page is PageWriteback
*/
- if (nr_writeback && nr_writeback >= (nr_taken >> (DEF_PRIORITY-priority)))
+ if (nr_writeback && nr_writeback >=
+ (nr_taken >> (DEF_PRIORITY - sc->priority)))
wait_iff_congested(zone, BLK_RW_ASYNC, HZ/10);
trace_mm_vmscan_lru_shrink_inactive(zone->zone_pgdat->node_id,
zone_idx(zone),
nr_scanned, nr_reclaimed,
- priority,
- trace_shrink_flags(file, sc->reclaim_mode));
+ sc->priority,
+ trace_shrink_flags(file));
return nr_reclaimed;
}
@@ -1679,7 +1414,7 @@
static void shrink_active_list(unsigned long nr_to_scan,
struct mem_cgroup_zone *mz,
struct scan_control *sc,
- int priority, int file)
+ enum lru_list lru)
{
unsigned long nr_taken;
unsigned long nr_scanned;
@@ -1690,13 +1425,13 @@
struct page *page;
struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
unsigned long nr_rotated = 0;
- isolate_mode_t isolate_mode = ISOLATE_ACTIVE;
+ isolate_mode_t isolate_mode = 0;
+ int file = is_file_lru(lru);
struct zone *zone = mz->zone;
+ struct lruvec *lruvec = mem_cgroup_zone_lruvec(zone, mz->mem_cgroup);
lru_add_drain();
- reset_reclaim_mode(sc);
-
if (!sc->may_unmap)
isolate_mode |= ISOLATE_UNMAPPED;
if (!sc->may_writepage)
@@ -1704,18 +1439,15 @@
spin_lock_irq(&zone->lru_lock);
- nr_taken = isolate_lru_pages(nr_to_scan, mz, &l_hold, &nr_scanned, sc,
- isolate_mode, 1, file);
+ nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &l_hold,
+ &nr_scanned, sc, isolate_mode, lru);
if (global_reclaim(sc))
zone->pages_scanned += nr_scanned;
reclaim_stat->recent_scanned[file] += nr_taken;
__count_zone_vm_events(PGREFILL, zone, nr_scanned);
- if (file)
- __mod_zone_page_state(zone, NR_ACTIVE_FILE, -nr_taken);
- else
- __mod_zone_page_state(zone, NR_ACTIVE_ANON, -nr_taken);
+ __mod_zone_page_state(zone, NR_LRU_BASE + lru, -nr_taken);
__mod_zone_page_state(zone, NR_ISOLATED_ANON + file, nr_taken);
spin_unlock_irq(&zone->lru_lock);
@@ -1737,7 +1469,8 @@
}
}
- if (page_referenced(page, 0, mz->mem_cgroup, &vm_flags)) {
+ if (page_referenced(page, 0, sc->target_mem_cgroup,
+ &vm_flags)) {
nr_rotated += hpage_nr_pages(page);
/*
* Identify referenced, file-backed active pages and
@@ -1770,10 +1503,8 @@
*/
reclaim_stat->recent_rotated[file] += nr_rotated;
- move_active_pages_to_lru(zone, &l_active, &l_hold,
- LRU_ACTIVE + file * LRU_FILE);
- move_active_pages_to_lru(zone, &l_inactive, &l_hold,
- LRU_BASE + file * LRU_FILE);
+ move_active_pages_to_lru(zone, &l_active, &l_hold, lru);
+ move_active_pages_to_lru(zone, &l_inactive, &l_hold, lru - LRU_ACTIVE);
__mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
spin_unlock_irq(&zone->lru_lock);
@@ -1811,7 +1542,7 @@
if (!total_swap_pages)
return 0;
- if (!scanning_global_lru(mz))
+ if (!mem_cgroup_disabled())
return mem_cgroup_inactive_anon_is_low(mz->mem_cgroup,
mz->zone);
@@ -1850,7 +1581,7 @@
*/
static int inactive_file_is_low(struct mem_cgroup_zone *mz)
{
- if (!scanning_global_lru(mz))
+ if (!mem_cgroup_disabled())
return mem_cgroup_inactive_file_is_low(mz->mem_cgroup,
mz->zone);
@@ -1867,25 +1598,24 @@
static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
struct mem_cgroup_zone *mz,
- struct scan_control *sc, int priority)
+ struct scan_control *sc)
{
int file = is_file_lru(lru);
if (is_active_lru(lru)) {
if (inactive_list_is_low(mz, file))
- shrink_active_list(nr_to_scan, mz, sc, priority, file);
+ shrink_active_list(nr_to_scan, mz, sc, lru);
return 0;
}
- return shrink_inactive_list(nr_to_scan, mz, sc, priority, file);
+ return shrink_inactive_list(nr_to_scan, mz, sc, lru);
}
-static int vmscan_swappiness(struct mem_cgroup_zone *mz,
- struct scan_control *sc)
+static int vmscan_swappiness(struct scan_control *sc)
{
if (global_reclaim(sc))
return vm_swappiness;
- return mem_cgroup_swappiness(mz->mem_cgroup);
+ return mem_cgroup_swappiness(sc->target_mem_cgroup);
}
/*
@@ -1897,7 +1627,7 @@
* nr[0] = anon pages to scan; nr[1] = file pages to scan
*/
static void get_scan_count(struct mem_cgroup_zone *mz, struct scan_control *sc,
- unsigned long *nr, int priority)
+ unsigned long *nr)
{
unsigned long anon, file, free;
unsigned long anon_prio, file_prio;
@@ -1953,8 +1683,8 @@
* With swappiness at 100, anonymous and file have the same priority.
* This scanning priority is essentially the inverse of IO cost.
*/
- anon_prio = vmscan_swappiness(mz, sc);
- file_prio = 200 - vmscan_swappiness(mz, sc);
+ anon_prio = vmscan_swappiness(sc);
+ file_prio = 200 - vmscan_swappiness(sc);
/*
* OK, so we have swap space and a fair amount of page cache
@@ -1983,10 +1713,10 @@
* proportional to the fraction of recently scanned pages on
* each list that were recently referenced and in active use.
*/
- ap = (anon_prio + 1) * (reclaim_stat->recent_scanned[0] + 1);
+ ap = anon_prio * (reclaim_stat->recent_scanned[0] + 1);
ap /= reclaim_stat->recent_rotated[0] + 1;
- fp = (file_prio + 1) * (reclaim_stat->recent_scanned[1] + 1);
+ fp = file_prio * (reclaim_stat->recent_scanned[1] + 1);
fp /= reclaim_stat->recent_rotated[1] + 1;
spin_unlock_irq(&mz->zone->lru_lock);
@@ -1999,8 +1729,8 @@
unsigned long scan;
scan = zone_nr_lru_pages(mz, lru);
- if (priority || noswap) {
- scan >>= priority;
+ if (sc->priority || noswap || !vmscan_swappiness(sc)) {
+ scan >>= sc->priority;
if (!scan && force_scan)
scan = SWAP_CLUSTER_MAX;
scan = div64_u64(scan * fraction[file], denominator);
@@ -2009,12 +1739,23 @@
}
}
+/* Use reclaim/compaction for costly allocs or under memory pressure */
+static bool in_reclaim_compaction(struct scan_control *sc)
+{
+ if (COMPACTION_BUILD && sc->order &&
+ (sc->order > PAGE_ALLOC_COSTLY_ORDER ||
+ sc->priority < DEF_PRIORITY - 2))
+ return true;
+
+ return false;
+}
+
/*
- * Reclaim/compaction depends on a number of pages being freed. To avoid
- * disruption to the system, a small number of order-0 pages continue to be
- * rotated and reclaimed in the normal fashion. However, by the time we get
- * back to the allocator and call try_to_compact_zone(), we ensure that
- * there are enough free pages for it to be likely successful
+ * Reclaim/compaction is used for high-order allocation requests. It reclaims
+ * order-0 pages before compacting the zone. should_continue_reclaim() returns
+ * true if more pages should be reclaimed such that when the page allocator
+ * calls try_to_compact_zone() that it will have enough free pages to succeed.
+ * It will give up earlier than that if there is difficulty reclaiming pages.
*/
static inline bool should_continue_reclaim(struct mem_cgroup_zone *mz,
unsigned long nr_reclaimed,
@@ -2025,7 +1766,7 @@
unsigned long inactive_lru_pages;
/* If not in reclaim/compaction mode, stop */
- if (!(sc->reclaim_mode & RECLAIM_MODE_COMPACTION))
+ if (!in_reclaim_compaction(sc))
return false;
/* Consider stopping depending on scan and reclaim activity */
@@ -2076,7 +1817,7 @@
/*
* This is a basic per-zone page freer. Used by both kswapd and direct reclaim.
*/
-static void shrink_mem_cgroup_zone(int priority, struct mem_cgroup_zone *mz,
+static void shrink_mem_cgroup_zone(struct mem_cgroup_zone *mz,
struct scan_control *sc)
{
unsigned long nr[NR_LRU_LISTS];
@@ -2089,7 +1830,7 @@
restart:
nr_reclaimed = 0;
nr_scanned = sc->nr_scanned;
- get_scan_count(mz, sc, nr, priority);
+ get_scan_count(mz, sc, nr);
blk_start_plug(&plug);
while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
@@ -2101,7 +1842,7 @@
nr[lru] -= nr_to_scan;
nr_reclaimed += shrink_list(lru, nr_to_scan,
- mz, sc, priority);
+ mz, sc);
}
}
/*
@@ -2112,7 +1853,8 @@
* with multiple processes reclaiming pages, the total
* freeing target can get unreasonably large.
*/
- if (nr_reclaimed >= nr_to_reclaim && priority < DEF_PRIORITY)
+ if (nr_reclaimed >= nr_to_reclaim &&
+ sc->priority < DEF_PRIORITY)
break;
}
blk_finish_plug(&plug);
@@ -2123,23 +1865,23 @@
* rebalance the anon lru active/inactive ratio.
*/
if (inactive_anon_is_low(mz))
- shrink_active_list(SWAP_CLUSTER_MAX, mz, sc, priority, 0);
+ shrink_active_list(SWAP_CLUSTER_MAX, mz,
+ sc, LRU_ACTIVE_ANON);
/* reclaim/compaction might need reclaim to continue */
if (should_continue_reclaim(mz, nr_reclaimed,
- sc->nr_scanned - nr_scanned, sc))
+ sc->nr_scanned - nr_scanned, sc))
goto restart;
throttle_vm_writeout(sc->gfp_mask);
}
-static void shrink_zone(int priority, struct zone *zone,
- struct scan_control *sc)
+static void shrink_zone(struct zone *zone, struct scan_control *sc)
{
struct mem_cgroup *root = sc->target_mem_cgroup;
struct mem_cgroup_reclaim_cookie reclaim = {
.zone = zone,
- .priority = priority,
+ .priority = sc->priority,
};
struct mem_cgroup *memcg;
@@ -2150,7 +1892,7 @@
.zone = zone,
};
- shrink_mem_cgroup_zone(priority, &mz, sc);
+ shrink_mem_cgroup_zone(&mz, sc);
/*
* Limit reclaim has historically picked one memcg and
* scanned it with decreasing priority levels until
@@ -2226,8 +1968,7 @@
* the caller that it should consider retrying the allocation instead of
* further reclaim.
*/
-static bool shrink_zones(int priority, struct zonelist *zonelist,
- struct scan_control *sc)
+static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
{
struct zoneref *z;
struct zone *zone;
@@ -2254,7 +1995,8 @@
if (global_reclaim(sc)) {
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
- if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+ if (zone->all_unreclaimable &&
+ sc->priority != DEF_PRIORITY)
continue; /* Let kswapd poll it */
if (COMPACTION_BUILD) {
/*
@@ -2286,7 +2028,7 @@
/* need some check for avoid more shrink_zone() */
}
- shrink_zone(priority, zone, sc);
+ shrink_zone(zone, sc);
}
return aborted_reclaim;
@@ -2337,7 +2079,6 @@
struct scan_control *sc,
struct shrink_control *shrink)
{
- int priority;
unsigned long total_scanned = 0;
struct reclaim_state *reclaim_state = current->reclaim_state;
struct zoneref *z;
@@ -2350,11 +2091,9 @@
if (global_reclaim(sc))
count_vm_event(ALLOCSTALL);
- for (priority = DEF_PRIORITY; priority >= 0; priority--) {
+ do {
sc->nr_scanned = 0;
- if (!priority)
- disable_swap_token(sc->target_mem_cgroup);
- aborted_reclaim = shrink_zones(priority, zonelist, sc);
+ aborted_reclaim = shrink_zones(zonelist, sc);
/*
* Don't shrink slabs when reclaiming memory from
@@ -2396,7 +2135,7 @@
/* Take a nap, wait for some writeback to complete */
if (!sc->hibernation_mode && sc->nr_scanned &&
- priority < DEF_PRIORITY - 2) {
+ sc->priority < DEF_PRIORITY - 2) {
struct zone *preferred_zone;
first_zones_zonelist(zonelist, gfp_zone(sc->gfp_mask),
@@ -2404,7 +2143,7 @@
&preferred_zone);
wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/10);
}
- }
+ } while (--sc->priority >= 0);
out:
delayacct_freepages_end();
@@ -2442,6 +2181,7 @@
.may_unmap = 1,
.may_swap = 1,
.order = order,
+ .priority = DEF_PRIORITY,
.target_mem_cgroup = NULL,
.nodemask = nodemask,
};
@@ -2474,6 +2214,7 @@
.may_unmap = 1,
.may_swap = !noswap,
.order = 0,
+ .priority = 0,
.target_mem_cgroup = memcg,
};
struct mem_cgroup_zone mz = {
@@ -2484,7 +2225,7 @@
sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
- trace_mm_vmscan_memcg_softlimit_reclaim_begin(0,
+ trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order,
sc.may_writepage,
sc.gfp_mask);
@@ -2495,7 +2236,7 @@
* will pick up pages from other mem cgroup's as well. We hack
* the priority and make it zero.
*/
- shrink_mem_cgroup_zone(0, &mz, &sc);
+ shrink_mem_cgroup_zone(&mz, &sc);
trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
@@ -2516,6 +2257,7 @@
.may_swap = !noswap,
.nr_to_reclaim = SWAP_CLUSTER_MAX,
.order = 0,
+ .priority = DEF_PRIORITY,
.target_mem_cgroup = memcg,
.nodemask = NULL, /* we don't care the placement */
.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
@@ -2546,8 +2288,7 @@
}
#endif
-static void age_active_anon(struct zone *zone, struct scan_control *sc,
- int priority)
+static void age_active_anon(struct zone *zone, struct scan_control *sc)
{
struct mem_cgroup *memcg;
@@ -2563,7 +2304,7 @@
if (inactive_anon_is_low(&mz))
shrink_active_list(SWAP_CLUSTER_MAX, &mz,
- sc, priority, 0);
+ sc, LRU_ACTIVE_ANON);
memcg = mem_cgroup_iter(NULL, memcg, NULL);
} while (memcg);
@@ -2672,7 +2413,6 @@
{
int all_zones_ok;
unsigned long balanced;
- int priority;
int i;
int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */
unsigned long total_scanned;
@@ -2696,18 +2436,15 @@
};
loop_again:
total_scanned = 0;
+ sc.priority = DEF_PRIORITY;
sc.nr_reclaimed = 0;
sc.may_writepage = !laptop_mode;
count_vm_event(PAGEOUTRUN);
- for (priority = DEF_PRIORITY; priority >= 0; priority--) {
+ do {
unsigned long lru_pages = 0;
int has_under_min_watermark_zone = 0;
- /* The swap token gets in the way of swapout... */
- if (!priority)
- disable_swap_token(NULL);
-
all_zones_ok = 1;
balanced = 0;
@@ -2721,14 +2458,15 @@
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+ if (zone->all_unreclaimable &&
+ sc.priority != DEF_PRIORITY)
continue;
/*
* Do some background aging of the anon list, to give
* pages a chance to be referenced before reclaiming.
*/
- age_active_anon(zone, &sc, priority);
+ age_active_anon(zone, &sc);
/*
* If the number of buffer_heads in the machine
@@ -2776,7 +2514,8 @@
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+ if (zone->all_unreclaimable &&
+ sc.priority != DEF_PRIORITY)
continue;
sc.nr_scanned = 0;
@@ -2820,7 +2559,7 @@
!zone_watermark_ok_safe(zone, testorder,
high_wmark_pages(zone) + balance_gap,
end_zone, 0)) {
- shrink_zone(priority, zone, &sc);
+ shrink_zone(zone, &sc);
reclaim_state->reclaimed_slab = 0;
nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages);
@@ -2877,7 +2616,7 @@
* OK, kswapd is getting into trouble. Take a nap, then take
* another pass across the zones.
*/
- if (total_scanned && (priority < DEF_PRIORITY - 2)) {
+ if (total_scanned && (sc.priority < DEF_PRIORITY - 2)) {
if (has_under_min_watermark_zone)
count_vm_event(KSWAPD_SKIP_CONGESTION_WAIT);
else
@@ -2892,7 +2631,7 @@
*/
if (sc.nr_reclaimed >= SWAP_CLUSTER_MAX)
break;
- }
+ } while (--sc.priority >= 0);
out:
/*
@@ -2942,7 +2681,8 @@
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+ if (zone->all_unreclaimable &&
+ sc.priority != DEF_PRIORITY)
continue;
/* Would compaction fail due to lack of free memory? */
@@ -3013,7 +2753,18 @@
* them before going back to sleep.
*/
set_pgdat_percpu_threshold(pgdat, calculate_normal_threshold);
- schedule();
+
+ /*
+ * Compaction records what page blocks it recently failed to
+ * isolate pages from and skips them in the future scanning.
+ * When kswapd is going to sleep, it is reasonable to assume
+ * that pages and compaction may succeed so reset the cache.
+ */
+ reset_isolation_suitable(pgdat);
+
+ if (!kthread_should_stop())
+ schedule();
+
set_pgdat_percpu_threshold(pgdat, calculate_pressure_threshold);
} else {
if (remaining)
@@ -3209,6 +2960,7 @@
.nr_to_reclaim = nr_to_reclaim,
.hibernation_mode = 1,
.order = 0,
+ .priority = DEF_PRIORITY,
};
struct shrink_control shrink = {
.gfp_mask = sc.gfp_mask,
@@ -3386,7 +3138,6 @@
const unsigned long nr_pages = 1 << order;
struct task_struct *p = current;
struct reclaim_state reclaim_state;
- int priority;
struct scan_control sc = {
.may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE),
.may_unmap = !!(zone_reclaim_mode & RECLAIM_SWAP),
@@ -3395,6 +3146,7 @@
SWAP_CLUSTER_MAX),
.gfp_mask = gfp_mask,
.order = order,
+ .priority = ZONE_RECLAIM_PRIORITY,
};
struct shrink_control shrink = {
.gfp_mask = sc.gfp_mask,
@@ -3417,11 +3169,9 @@
* Free memory by calling shrink zone with increasing
* priorities until we have enough memory freed.
*/
- priority = ZONE_RECLAIM_PRIORITY;
do {
- shrink_zone(priority, zone, &sc);
- priority--;
- } while (priority >= 0 && sc.nr_reclaimed < nr_pages);
+ shrink_zone(zone, &sc);
+ } while (sc.nr_reclaimed < nr_pages && --sc.priority >= 0);
}
nr_slab_pages0 = zone_page_state(zone, NR_SLAB_RECLAIMABLE);
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 8e18d6b..959a558 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -761,10 +761,14 @@
"pgrotated",
+#ifdef CONFIG_MIGRATION
+ "pgmigrate_success",
+ "pgmigrate_fail",
+#endif
#ifdef CONFIG_COMPACTION
- "compact_blocks_moved",
- "compact_pages_moved",
- "compact_pagemigrate_failed",
+ "compact_migrate_scanned",
+ "compact_free_scanned",
+ "compact_isolated",
"compact_stall",
"compact_fail",
"compact_success",
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index f3c6ef8..1260e1c 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1382,6 +1382,7 @@
snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+ snd_soc_update_bits(codec, w->reg, 0x1, 0x0);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20100);
@@ -1394,6 +1395,7 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
+ snd_soc_update_bits(codec, w->reg, 0x1, 0x1);
break;
}
return 0;
@@ -1695,9 +1697,6 @@
{"I2S TX1", NULL, "TX_I2S_CLK"},
{"I2S TX2", NULL, "TX_I2S_CLK"},
- {"DEC1 MUX", NULL, "TX CLK"},
- {"DEC2 MUX", NULL, "TX CLK"},
-
{"I2S TX1", NULL, "DEC1 MUX"},
{"I2S TX2", NULL, "DEC2 MUX"},
@@ -2136,8 +2135,6 @@
SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
- 4, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
@@ -2336,10 +2333,11 @@
/* Reduce LINE DAC bias to 70% */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
- /* Disable TX7 internal biasing path which can cause leakage */
+ /* Disable internal biasing path which can cause leakage */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
+ /* Enable pulldown to reduce leakage */
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x83),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
@@ -2350,6 +2348,9 @@
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
+
+ /* Always set TXD_CLK_EN bit to reduce the leakage */
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
};
static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 09f2a51..b31c7c9 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -306,18 +306,18 @@
return 0;
}
- WCD9XXX_BCL_LOCK(&priv->resmgr);
+ codec = priv->codec;
+ mutex_lock(&codec->mutex);
old = spkr_drv_wrnd;
ret = param_set_int(val, kp);
if (ret) {
- WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+ mutex_unlock(&codec->mutex);
return ret;
}
- codec = priv->codec;
dev_dbg(codec->dev, "%s: spkr_drv_wrnd %d -> %d\n",
__func__, old, spkr_drv_wrnd);
- if (old == 0 && spkr_drv_wrnd == 1) {
+ if ((old == -1 || old == 0) && spkr_drv_wrnd == 1) {
WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
WCD9XXX_BANDGAP_AUDIO_MODE);
@@ -332,8 +332,8 @@
snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
0x00);
}
+ mutex_unlock(&codec->mutex);
- WCD9XXX_BCL_UNLOCK(&priv->resmgr);
return 0;
}
@@ -1701,7 +1701,6 @@
struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
- WCD9XXX_BCL_LOCK(&tapan->resmgr);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
tapan->spkr_pa_widget_on = true;
@@ -1712,7 +1711,6 @@
snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
break;
}
- WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
return 0;
}
@@ -4537,7 +4535,6 @@
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
tapan = snd_soc_codec_get_drvdata(codec);
mutex_lock(&codec->mutex);
- WCD9XXX_BCL_LOCK(&tapan->resmgr);
if (codec->reg_def_copy) {
pr_debug("%s: Update ASOC cache", __func__);
@@ -4546,7 +4543,6 @@
codec->reg_size, GFP_KERNEL);
if (!codec->reg_cache) {
pr_err("%s: Cache update failed!\n", __func__);
- WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
mutex_unlock(&codec->mutex);
return -ENOMEM;
}
@@ -4555,7 +4551,6 @@
wcd9xxx_resmgr_post_ssr(&tapan->resmgr);
if (spkr_drv_wrnd == 1)
snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
- WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
tapan_update_reg_defaults(codec);
tapan_update_reg_mclk_rate(wcd9xxx);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 9d52592..516ac4f 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -604,18 +604,17 @@
return 0;
}
- WCD9XXX_BCL_LOCK(&priv->resmgr);
+ codec = priv->codec;
+ mutex_lock(&codec->mutex);
old = spkr_drv_wrnd;
ret = param_set_int(val, kp);
if (ret) {
- WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+ mutex_unlock(&codec->mutex);
return ret;
}
- WCD9XXX_BCL_UNLOCK(&priv->resmgr);
pr_debug("%s: spkr_drv_wrnd %d -> %d\n", __func__, old, spkr_drv_wrnd);
- codec = priv->codec;
- if (old == 0 && spkr_drv_wrnd == 1) {
+ if ((old == -1 || old == 0) && spkr_drv_wrnd == 1) {
WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
WCD9XXX_BANDGAP_AUDIO_MODE);
@@ -630,6 +629,7 @@
snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80,
0x00);
}
+ mutex_unlock(&codec->mutex);
return 0;
}
@@ -2420,7 +2420,6 @@
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
pr_debug("%s: %d %s\n", __func__, event, w->name);
- WCD9XXX_BCL_LOCK(&taiko->resmgr);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
taiko->spkr_pa_widget_on = true;
@@ -2431,7 +2430,6 @@
snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x00);
break;
}
- WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
return 0;
}
@@ -4639,7 +4637,7 @@
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
- .channels_max = 5,
+ .channels_max = 8,
},
.ops = &taiko_dai_ops,
},
@@ -6189,7 +6187,6 @@
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
taiko = snd_soc_codec_get_drvdata(codec);
mutex_lock(&codec->mutex);
- WCD9XXX_BCL_LOCK(&taiko->resmgr);
if (codec->reg_def_copy) {
pr_debug("%s: Update ASOC cache", __func__);
@@ -6201,7 +6198,6 @@
wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
if (spkr_drv_wrnd == 1)
snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
- WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
taiko_update_reg_defaults(codec);
taiko_codec_init_reg(codec);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 84f236e..be11e53 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -209,8 +209,8 @@
int old_clk_rco_users, old_clk_mclk_users;
pr_debug("%s: enter\n", __func__);
- WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ WCD9XXX_BG_CLK_LOCK(resmgr);
old_bg_audio_users = resmgr->bg_audio_users;
old_bg_mbhc_users = resmgr->bg_mbhc_users;
old_clk_rco_users = resmgr->clk_rco_users;
@@ -243,6 +243,7 @@
while (old_clk_rco_users--)
wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_RCO);
}
+ WCD9XXX_BG_CLK_UNLOCK(resmgr);
pr_debug("%s: leave\n", __func__);
}
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index d973c17..171db0a 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1805,7 +1805,7 @@
SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 5,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 192000,
},
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index a39a18b..0a86221 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -711,7 +711,8 @@
static const char *const spk_function[] = {"Off", "On"};
static const char *const slim0_rx_ch_text[] = {"One", "Two"};
static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
- "Five"};
+ "Five", "Six", "Seven",
+ "Eight"};
static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
"Six", "Seven", "Eight"};
static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
@@ -1319,7 +1320,7 @@
static const struct soc_enum msm_snd_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
- SOC_ENUM_SINGLE_EXT(5, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(8, slim0_tx_ch_text),
SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index a076246..4d9632c 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -34,11 +34,19 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+#define EXT_CLASS_D_DIS_DELAY 3000
+#define EXT_CLASS_D_DELAY_DELTA 2000
+
+
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
static int msm_proxy_rx_ch = 2;
static struct snd_soc_jack hs_jack;
+static struct platform_device *spdev;
+static int ext_spk_amp_gpio = -1;
/*
@@ -86,15 +94,69 @@
static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static void msm8x10_enable_ext_spk_power_amp(u32 on);
static const struct snd_soc_dapm_widget msm8x10_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
msm8x10_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SPK("Lineout amp", msm_ext_spkramp_event),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
+static int msm8x10_ext_spk_power_amp_init(void)
+{
+ int ret = 0;
+
+ ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-spk-amp-gpio", 0);
+ if (ext_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_spk_amp_gpio, 0);
+ }
+ return 0;
+}
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s()\n", __func__);
+
+ if (ext_spk_amp_gpio >= 0) {
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ msm8x10_enable_ext_spk_power_amp(1);
+ else
+ msm8x10_enable_ext_spk_power_amp(0);
+ }
+ return 0;
+
+}
+
+static void msm8x10_enable_ext_spk_power_amp(u32 on)
+{
+ if (on) {
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ /*time takes enable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_EN_DELAY,
+ EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ /*time takes disable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_DIS_DELAY,
+ EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external speaker PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
{
@@ -265,10 +327,11 @@
int ret = 0;
pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
-
+ msm8x10_ext_spk_power_amp_init();
snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
ARRAY_SIZE(msm8x10_dapm_widgets));
+ snd_soc_dapm_enable_pin(dapm, "Lineout amp");
snd_soc_dapm_sync(dapm);
ret = snd_soc_jack_new(codec, "Headset Jack",
@@ -686,11 +749,16 @@
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret)
+ goto err;
+
ret = snd_soc_of_parse_audio_routing(card,
"qcom,audio-routing");
if (ret)
goto err;
+ spdev = pdev;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
@@ -708,6 +776,8 @@
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ gpio_free(ext_spk_amp_gpio);
snd_soc_unregister_card(card);
mutex_destroy(&cdc_mclk_mutex);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 4a20af1..687f10d 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -625,20 +625,26 @@
{
int rc = 0;
int avg_vol = 0;
+ int lgain = (volume >> 16) & 0xFFFF;
+ int rgain = volume & 0xFFFF;
if (compressed_audio.prtd && compressed_audio.prtd->audio_client) {
- if (compressed_audio.prtd->channel_mode > 2) {
- avg_vol = (((volume >> 16) & 0xFFFF) +
- (volume & 0xFFFF)) / 2;
- rc = q6asm_set_volume(
- compressed_audio.prtd->audio_client, avg_vol);
- } else {
+ pr_debug("%s: channels %d volume 0x%x\n", __func__,
+ compressed_audio.prtd->channel_mode, volume);
+ if ((compressed_audio.prtd->channel_mode <= 2) &&
+ (lgain != rgain)) {
+ pr_debug("%s: call q6asm_set_lrgain\n", __func__);
rc = q6asm_set_lrgain(
compressed_audio.prtd->audio_client,
- (volume >> 16) & 0xFFFF, volume & 0xFFFF);
+ lgain, rgain);
+ } else {
+ avg_vol = (lgain + rgain)/2;
+ pr_debug("%s: call q6asm_set_volume\n", __func__);
+ rc = q6asm_set_volume(
+ compressed_audio.prtd->audio_client, avg_vol);
}
if (rc < 0) {
pr_err("%s: Send Volume command failed rc=%d\n",
- __func__, rc);
+ __func__, rc);
}
}
compressed_audio.volume = volume;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 77f3a07..11f9e72 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -42,12 +42,6 @@
struct snd_pcm *pcm;
};
-struct snd_msm_volume {
- struct msm_audio *prtd;
- unsigned volume;
-};
-static struct snd_msm_volume pcm_audio = {NULL, 0x2000};
-
#define PLAYBACK_MIN_NUM_PERIODS 2
#define PLAYBACK_MAX_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 12288
@@ -390,7 +384,6 @@
prtd->dsp_cnt = 0;
prtd->set_channel_map = false;
runtime->private_data = prtd;
- pcm_audio.prtd = prtd;
return 0;
}
@@ -479,7 +472,6 @@
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
- pcm_audio.prtd = NULL;
q6asm_audio_client_free(prtd->audio_client);
}
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
@@ -760,30 +752,71 @@
.mmap = msm_pcm_mmap,
};
-static int pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
- char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
pr_debug("%s", __func__);
- for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
- channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
- if (pcm_audio.prtd) {
- pcm_audio.prtd->set_channel_map = true;
- memcpy(pcm_audio.prtd->channel_map, channel_mapping,
- PCM_FORMAT_MAX_NUM_CHANNEL);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ if (!substream->runtime)
+ return 0;
+
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ prtd->set_channel_map = true;
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ prtd->channel_map[i] =
+ (char)(ucontrol->value.integer.value[i]);
}
return 0;
}
+static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s", __func__);
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+ if (!substream->runtime)
+ return 0; /* no channels set */
+
+ prtd = substream->runtime->private_data;
+
+ if (prtd && prtd->set_channel_map == true) {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] =
+ (int)prtd->channel_map[i];
+ } else {
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = 0;
+ }
+
+ return 0;
+}
+
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm *pcm = rtd->pcm;
struct snd_pcm_chmap *chmap_info;
struct snd_kcontrol *kctl;
- char device_num[3];
+ char device_num[12];
int i, ret = 0;
if (!card->dev->coherent_dma_mask)
@@ -791,8 +824,9 @@
pr_debug("%s, Channel map cntrl add\n", __func__);
ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- NULL, PCM_FORMAT_MAX_NUM_CHANNEL, 0,
- &chmap_info);
+ snd_pcm_std_chmaps,
+ PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+ &chmap_info);
if (ret < 0)
return ret;
kctl = chmap_info->kctl;
@@ -802,7 +836,8 @@
strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
pr_debug("%s, Overwriting channel map control name to: %s",
__func__, kctl->id.name);
- kctl->put = pcm_chmap_ctl_put;
+ kctl->put = msm_pcm_chmap_ctl_put;
+ kctl->get = msm_pcm_chmap_ctl_get;
return ret;
}