Merge changes into msm-3.4
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/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-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 282257c..ff7b03d 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -47,6 +47,8 @@
bits 20-25 PARAMETER_OVERRIDE_D
- qcom,skip-charger-detection: If present then charger detection using BC1.2
is not supported and attached host should always be assumed as SDP.
+- USB3_GDSC-supply : phandle to the globally distributed switch controller
+ regulator node to the USB controller.
Sub nodes:
- Sub node for "DWC3- USB3 controller".
@@ -66,6 +68,7 @@
HSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_3p3-supply = <&pm8941_l24>;
vbus_dwc3-supply = <&pm8941_mvs1>;
+ USB3_GDSC-supply = <&gdsc_usb30>;
qcom,dwc-usb3-msm-dbm-eps = <4>
qcom,vdd-voltage-level = <1 5 7>;
qcom,dwc-hsphy-init = <0x00D195A4>;
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/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/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.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b14a406..825c659 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>;
@@ -260,11 +266,12 @@
qcom,dp-manual-pullup;
qcom,msm-bus,name = "usb";
- qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-cases = <3>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
<87 512 0 0>,
- <87 512 60000 960000>;
+ <87 512 60000 960000>,
+ <87 512 6000 6000>;
};
android_usb@fe8050c8 {
@@ -714,6 +721,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-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/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-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/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.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 616995f..dda32ce 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -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/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/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 07f7ed9..010bc10 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -384,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 34c0905..7225ec5 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -427,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/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 17db01e..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
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.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-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 574c979..a8d6420 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"
@@ -38,6 +39,9 @@
CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("core_clk", USB_HS_SYSTEM_CLK, "msm_otg", OFF),
+ CLK_DUMMY("iface_clk", USB_HS_AHB_CLK, "msm_otg", OFF),
+ CLK_DUMMY("xo", CXO_OTG_CLK, "msm_otg", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -50,6 +54,8 @@
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
"msm_sdcc.2", NULL),
+ OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
+ "msm_otg", NULL),
{},
};
@@ -95,6 +101,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 2a4617d..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),
},
};
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index eb9a627..b1b9397 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3013,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 */
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
index e66764f..bea82d5 100644
--- a/arch/arm/mach-msm/clock-generic.c
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -266,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)
@@ -299,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;
}
@@ -307,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);
}
@@ -315,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;
@@ -389,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/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/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_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/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 32589f1..5a69ea3 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2228,6 +2228,7 @@
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/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index 8d96bd8..a8fed52 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -439,12 +439,12 @@
/* Wait for the response */
if (!timeout_ms) {
- rc = wait_event_interruptible(txn_handle->wait_q,
- (txn_handle->resp_received ||
- handle->handle_reset ||
- (txn_handle->send_stat < 0)));
+ 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,
+ rc = wait_event_timeout(txn_handle->wait_q,
(txn_handle->resp_received ||
handle->handle_reset ||
(txn_handle->send_stat < 0)),
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/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 146dc0b..be32e82 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -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/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/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/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 44c9c29..ed266dc 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -258,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 e62dac9..5c454f1 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2370,7 +2370,8 @@
entries[actual_count++] = entry;
/* If we exceed the breakeven point, flush the entire cache */
- if (op_size >= kgsl_driver.full_cache_threshold &&
+ if (kgsl_driver.full_cache_threshold != 0 &&
+ op_size >= kgsl_driver.full_cache_threshold &&
param->op == KGSL_GPUMEM_CACHE_FLUSH) {
full_flush = true;
break;
@@ -2429,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
@@ -2440,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_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/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/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/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/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/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/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_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_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_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index b1e2d93..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,
@@ -1382,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/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a5f586b..2600001 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -182,6 +182,7 @@
struct regulator *hsusb_vddcx;
struct regulator *ssusb_1p8;
struct regulator *ssusb_vddcx;
+ struct regulator *dwc3_gdsc;
/* VBUS regulator if no OTG and running in host only mode */
struct regulator *vbus_otg;
@@ -1260,6 +1261,37 @@
return rc < 0 ? rc : 0;
}
+/*
+ * Config Global Distributed Switch Controller (GDSC)
+ * to support controller power collapse
+ */
+static int dwc3_msm_config_gdsc(struct dwc3_msm *msm, int on)
+{
+ int ret = 0;
+
+ if (IS_ERR(msm->dwc3_gdsc))
+ return 0;
+
+ if (!msm->dwc3_gdsc) {
+ msm->dwc3_gdsc = devm_regulator_get(msm->dev,
+ "USB3_GDSC");
+ if (IS_ERR(msm->dwc3_gdsc))
+ return 0;
+ }
+
+ if (on) {
+ ret = regulator_enable(msm->dwc3_gdsc);
+ if (ret) {
+ dev_err(msm->dev, "unable to enable usb3 gdsc\n");
+ return ret;
+ }
+ } else {
+ regulator_disable(msm->dwc3_gdsc);
+ }
+
+ return 0;
+}
+
static int dwc3_msm_link_clk_reset(bool assert)
{
int ret = 0;
@@ -1729,6 +1761,11 @@
/* make sure above writes are completed before turning off clocks */
wmb();
+
+ /* remove vote for controller power collapse */
+ if (!host_bus_suspend)
+ dwc3_msm_config_gdsc(mdwc, 0);
+
if (!host_bus_suspend || !host_ss_active) {
clk_disable_unprepare(mdwc->core_clk);
mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
@@ -1809,6 +1846,10 @@
mdwc->lpm_flags &= ~MDWC3_TCXO_SHUTDOWN;
}
+ /* add vote for controller power collapse */
+ if (!host_bus_suspend)
+ dwc3_msm_config_gdsc(mdwc, 1);
+
if (!host_bus_suspend)
clk_prepare_enable(mdwc->utmi_clk);
@@ -2495,11 +2536,18 @@
INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
init_completion(&msm->ext_chg_wait);
+ ret = dwc3_msm_config_gdsc(msm, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to configure usb3 gdsc\n");
+ return ret;
+ }
+
msm->xo_clk = clk_get(&pdev->dev, "xo");
if (IS_ERR(msm->xo_clk)) {
dev_err(&pdev->dev, "%s unable to get TCXO buffer handle\n",
__func__);
- return PTR_ERR(msm->xo_clk);
+ ret = PTR_ERR(msm->xo_clk);
+ goto disable_dwc3_gdsc;
}
ret = clk_prepare_enable(msm->xo_clk);
@@ -2906,6 +2954,8 @@
clk_disable_unprepare(msm->xo_clk);
put_xo:
clk_put(msm->xo_clk);
+disable_dwc3_gdsc:
+ dwc3_msm_config_gdsc(msm, 0);
return ret;
}
@@ -2953,6 +3003,8 @@
clk_disable_unprepare(msm->xo_clk);
clk_put(msm->xo_clk);
+ dwc3_msm_config_gdsc(msm, 0);
+
return 0;
}
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-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 c0b2771..72c3c7d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -87,6 +87,11 @@
MODULE_PARM_DESC(lpm_disconnect_thresh,
"Delay before entering LPM on USB disconnect");
+static bool floated_charger_enable;
+module_param(floated_charger_enable , bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(floated_charger_enable,
+ "Whether to enable floated charger");
+
static DECLARE_COMPLETION(pmic_vbus_init);
static struct msm_otg *the_msm_otg;
static bool debug_aca_enabled;
@@ -880,6 +885,7 @@
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
+ bool floated_charger;
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
u32 portsc;
@@ -898,6 +904,7 @@
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
prop_charger = motg->chg_type == USB_PROPRIETARY_CHARGER;
+ floated_charger = motg->chg_type == USB_FLOATED_CHARGER;
/*
* Abort suspend when,
@@ -906,7 +913,8 @@
*/
if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
- !dcp && !prop_charger) || test_bit(A_BUS_REQ, &motg->inputs)) {
+ !dcp && !prop_charger && !floated_charger) ||
+ test_bit(A_BUS_REQ, &motg->inputs)) {
enable_irq(motg->irq);
return -EBUSY;
}
@@ -2211,6 +2219,7 @@
case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
+ case USB_FLOATED_CHARGER: return "USB_FLOATED_CHARGER";
default: return "INVALID_CHARGER";
}
}
@@ -2224,6 +2233,7 @@
struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
struct usb_phy *phy = &motg->phy;
bool is_dcd = false, tmout, vout, is_aca;
+ static bool dcd;
u32 line_state, dm_vlgc;
unsigned long delay;
@@ -2268,6 +2278,10 @@
motg->dcd_time += MSM_CHG_DCD_POLL_TIME;
tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT;
if (is_dcd || tmout) {
+ if (is_dcd)
+ dcd = true;
+ else
+ dcd = false;
msm_chg_disable_dcd(motg);
msm_chg_enable_primary_det(motg);
delay = MSM_CHG_PRIMARY_DET_TIME;
@@ -2306,6 +2320,8 @@
if (line_state) /* DP > VLGC or/and DM > VLGC */
motg->chg_type = USB_PROPRIETARY_CHARGER;
+ else if (!dcd && floated_charger_enable)
+ motg->chg_type = USB_FLOATED_CHARGER;
else
motg->chg_type = USB_SDP_CHARGER;
@@ -2482,6 +2498,12 @@
pm_runtime_put_noidle(otg->phy->dev);
pm_runtime_suspend(otg->phy->dev);
break;
+ case USB_FLOATED_CHARGER:
+ msm_otg_notify_charger(motg,
+ IDEV_CHG_MAX);
+ pm_runtime_put_noidle(otg->phy->dev);
+ pm_runtime_suspend(otg->phy->dev);
+ break;
case USB_ACA_B_CHARGER:
msm_otg_notify_charger(motg,
IDEV_ACA_CHG_MAX);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index aecb19d..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;
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 60b8b2e..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)
{
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 52224e2..7cae18c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -430,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);
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_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 75b6056..4dd9dcb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -3329,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/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/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/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index dc477dd..2f18351 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -165,6 +165,7 @@
USB_ACA_C_CHARGER,
USB_ACA_DOCK_CHARGER,
USB_PROPRIETARY_CHARGER,
+ USB_FLOATED_CHARGER,
};
/**
@@ -457,6 +458,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/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/mm/page_alloc.c b/mm/page_alloc.c
index 5148c1a..9cc2f45 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6093,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/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;
}