Merge "arm/dt: msm8226: Add helper regulator for vdd_buck of audio codec"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index d07eba6..3947f75 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -28,11 +28,21 @@
core can be used for freq control.
- qcom,core-limit-temp: Threshold temperature to start shutting down cores
in degC
-- qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
+- qcom,core-temp-hysteresis: Degrees C below which the cores will be brought
online in sequence.
- qcom,core-control-mask: The cpu mask that will be used to determine if a
core can be controlled or not. A mask of 0 indicates
the feature is disabled.
+- qcom,hotplug-temp: Threshold temperature to start shutting down cores
+ in degC. This will be used when polling based
+ core control is disabled. The difference between hotplug-temp
+ and core-limit-temp is that core-limit-temp is used during
+ early boot prior to thermal_sys being available for hotplug.
+- qcom,hotplug-temp-hysteresis: Degrees C below which thermal will not force the
+ cores to be offlined. Cores can be brought online if needed.
+- qcpm,cpu-sensors: List of type names in thermal zone device struct which maps
+ to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
+ cpus there are.
- qcom,vdd-restriction-temp: When temperature is below this threshold, will
enable vdd restriction which will set higher voltage on
key voltage rails, in degC.
@@ -81,8 +91,12 @@
qcom,freq-step = <2>;
qcom,freq-control-mask = <0xf>
qcom,core-limit-temp = <90>;
- qcom,core-temp-hysterisis = <10>;
+ qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <7>;
+ qcom,hotplug-temp = <110>;
+ qcom,hotplug-temp-hysteresis = <20>;
+ qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+ "tsens_tz_sensor7", "tsens_tz_sensor8";
qcom,pmic-sw-mode-temp = <90>;
qcom,pmic-sw-mode-temp-hysteresis = <80>;
qcom,pmic-sw-mode-regs = "vdd-dig";
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
new file mode 100644
index 0000000..3e223e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -0,0 +1,74 @@
+Goodix GT9xx series touch controller
+
+Required properties:
+
+ - compatible : Should be "goodix,gt9xx"
+ - reg : I2C slave address of the device.
+ - interrupt-parent : Parent of interrupt.
+ - interrupts : Configuration of touch panel controller interrupt
+ GPIO.
+ - goodix,family-id : Family identification of the controller.
+ - interrupt-gpios : Interrupt gpio which is to provide interrupts to
+ host, same as "interrupts" node.
+ - reset-gpios : Reset gpio to control the reset of chip.
+ - goodix,display-coords : Display coordinates in pixels. It is a four
+ tuple consisting of min x, min y, max x and
+ max y values.
+
+Optional properties:
+
+ - avdd-supply : Power supply needed to power up the device, this is
+ for fixed voltage external regulator.
+ - vdd-supply : Power supply needed to power up the device, when use
+ external regulator, do not add this property.
+ - vcc-i2c-supply : Power source required to power up i2c bus.
+ GT9xx series can provide 1.8V from internal
+ LDO, add this properties base on hardware
+ design.
+ - goodix,panel-coords : Panel coordinates for the chip in pixels.
+ It is a four tuple consisting of min x,
+ min y, max x and max y values.
+ - goodix,i2c-pull-up : To specify pull up is required.
+ - goodix,no-force-update : To specify force update is allowed.
+ - goodix,button-map : Button map of key codes. The number of key codes
+ depend on panel.
+ - goodix,cfg-data : Touchpanel controller configuration data, ask vendor
+ to provide that. Default configuration will be
+ used if this property is not present.
+
+Example:
+i2c@f9927000 {
+ goodix@5d {
+ compatible = "goodix,gt9xx";
+ reg = <0x5d>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ reset-gpios = <&msmgpio 16 0x00>;
+ interrupt-gpios = <&msmgpio 17 0x00>;
+ avdd-supply = <&tp_power>;
+ goodix,panel-coords = <0 0 720 1200>;
+ goodix,display-coords = <0 0 720 1080>;
+ goodix,button-map= <158 102 139>;
+ goodix,family-id = <0x0>;
+ goodix,cfg-data = [
+ 41 D0 02 00 05 0A 05 01 01 08
+ 12 58 50 41 03 05 00 00 00 00
+ 00 00 00 00 00 00 00 8C 2E 0E
+ 28 24 73 13 00 00 00 83 03 1D
+ 40 02 00 00 00 03 64 32 00 00
+ 00 1A 38 94 C0 02 00 00 00 04
+ 9E 1C 00 8D 20 00 7A 26 00 6D
+ 2C 00 60 34 00 60 10 38 68 00
+ F0 50 35 FF FF 27 00 00 00 00
+ 00 01 1B 14 0C 14 00 00 01 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 02 04 06 08 0A 0C 0E 10
+ 12 14 16 18 1A 1C FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF
+ FF FF 00 02 04 06 08 0A 0C 0F
+ 10 12 13 14 16 18 1C 1D 1E 1F
+ 20 21 22 24 26 28 29 2A FF FF
+ FF FF FF FF FF FF FF 22 22 22
+ 22 22 22 FF 07 01];
+ };
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
index f02f35e..dd8eb15 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vfe.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
@@ -8,9 +8,13 @@
- reg : offset and length of the register set for the device
for the vfe operating in compatible mode.
- reg-names : should specify relevant names to each reg property defined.
+ - "vfe" - Required.
+ - "vfe_vbif" - Optional for "vfe32". Required for "vfe40".
+ - "tcsr" - Optional for "vfe32". Required for "vfe40".
- interrupts : should contain the vfe interrupt.
- interrupt-names : should specify relevant names to each interrupts
property defined.
+ - "vfe" - Required.
- vdd-supply: phandle to GDSC regulator controlling VFE core.
Example:
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 4a5e58c..a696746 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -81,6 +81,11 @@
- qcom,resume-soc Capacity in percent at which charging should resume
when a fully charged battery drops below this level.
- qcom,chg-vadc Corresponding VADC device's phandle.
+- qcom,pmic-revid The phandle to the revid node of the pmic on which charger
+ peripheral is present. This property is a must on PMIC chips
+ that exhibit inaccuracies in battery current readings. This
+ phandle is used to check the version of the PMIC and apply
+ necessary software workarounds.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
@@ -205,6 +210,7 @@
qcom,btc-disabled = <0>;
qcom,chg-vadc = <&pm8941_vadc>;
qcom,chg-adc_tm = <&pm8941_adc_tm>;
+ qcom,pmic-revid = <&pm8941_revid>;
qcom,chgr@1000 {
reg = <0x1000 0x100>;
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index b93dc4d..7ca741c 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -126,6 +126,7 @@
Required properties :
- compatible : should be "qcom,hsic-smsc-hub"
+- smsc,model-id : should be either <3503> or <4604> depending on hub model
- smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
in Documentation/devicetree/bindings/gpio/gpio.txt.
Required "gpio-name" is "reset" and optionally - "refclk", "int".
@@ -137,6 +138,7 @@
Example SMSC HSIC HUB :
hsic_hub {
compatible = "qcom,hsic-smsc-hub";
+ smsc,model-id = <4604>;
ranges;
smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 527c50c..8827983 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -19,6 +19,7 @@
focaltech Focaltech systems
fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+goodix Goodix. Ltd.
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
hp Hewlett Packard
ibm International Business Machines (IBM)
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index acd0bb9..46f5f22 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -62,6 +62,7 @@
hsic_hub {
compatible = "qcom,hsic-smsc-hub";
+ smsc,model-id = <4604>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
@@ -604,7 +605,7 @@
};
qcom,dc-chgpth@1400 {
- status = "ok";
+ status = "disabled";
};
qcom,boost@1500 {
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
new file mode 100644
index 0000000..e44e943
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
@@ -0,0 +1,105 @@
+/* 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.
+ */
+
+qcom,qrd-4v2-1800mah-data {
+ qcom,fcc-mah = <1800>;
+ qcom,default-rbatt-mohm = <146>;
+ qcom,rbatt-capacitive-mohm = <0>;
+ qcom,flat-ocv-threshold-uv = <3800000>;
+ qcom,max-voltage-uv = <4200000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-id-kohm = <47>;
+
+ qcom,rbatt-sf-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <904 234 100 85 80>,
+ <905 234 100 85 80>,
+ <934 244 102 86 81>,
+ <928 254 105 87 82>,
+ <933 268 109 89 84>,
+ <924 280 114 91 85>,
+ <913 283 123 96 88>,
+ <916 267 135 103 91>,
+ <930 252 137 110 95>,
+ <954 247 117 106 95>,
+ <990 247 103 88 85>,
+ <1036 253 104 86 84>,
+ <1101 264 108 89 85>,
+ <1211 286 112 93 88>,
+ <1366 340 120 95 87>,
+ <1601 394 128 95 87>,
+ <2178 402 128 97 89>,
+ <5419 423 126 97 89>,
+ <10789 528 128 97 91>,
+ <13463 589 132 100 91>,
+ <17695 678 137 102 92>,
+ <23046 814 145 104 93>,
+ <30725 1019 153 106 93>,
+ <41382 1359 156 106 93>,
+ <56311 1959 165 108 95>,
+ <77209 3523 189 117 99>,
+ <104609 6039 235 127 105>,
+ <138858 9711 352 141 112>,
+ <165825 15373 1069 246 226>;
+ };
+
+ qcom,fcc-temp-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-data = <1859 1868 1873 1861 1859>;
+ };
+
+ qcom,pc-temp-ocv-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <4178 4176 4174 4169 4163>,
+ <4090 4100 4105 4101 4099>,
+ <4029 4049 4053 4050 4048>,
+ <3973 3998 4006 4004 4002>,
+ <3932 3959 3965 3962 3960>,
+ <3891 3920 3928 3925 3922>,
+ <3855 3882 3894 3891 3889>,
+ <3825 3844 3862 3862 3859>,
+ <3803 3813 3829 3834 3831>,
+ <3788 3792 3797 3802 3800>,
+ <3777 3780 3778 3776 3773>,
+ <3764 3775 3771 3767 3763>,
+ <3749 3769 3766 3763 3757>,
+ <3725 3756 3758 3755 3750>,
+ <3687 3727 3736 3735 3729>,
+ <3631 3675 3698 3698 3691>,
+ <3571 3607 3637 3642 3637>,
+ <3514 3548 3568 3572 3570>,
+ <3458 3506 3519 3522 3522>,
+ <3444 3498 3511 3516 3515>,
+ <3430 3489 3503 3509 3508>,
+ <3413 3477 3493 3500 3500>,
+ <3395 3461 3478 3488 3486>,
+ <3373 3433 3446 3463 3456>,
+ <3346 3394 3397 3418 3410>,
+ <3307 3341 3334 3361 3352>,
+ <3251 3270 3254 3287 3277>,
+ <3160 3167 3152 3183 3172>,
+ <3000 3000 3000 3000 3000>;
+ };
+};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
index befc29c..f3f8c63 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,dsi_v2_hx8379a_wvga_video {
compatible = "qcom,dsi-panel-v2";
label = "HX8379A WVGA video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
index c2c64da..b598d6c 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,dsi_v2_otm8018b_fwvga_video {
compatible = "qcom,dsi-panel-v2";
label = "OTM8018B FWVGA video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
index f57a7bd..fd8d218 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-/ {
- qcom,dsi_v2_truly_wvga_video {
+&soc {
+ qcom,dsi_v2_truly_wvga_cmd {
compatible = "qcom,dsi-panel-v2";
label = "Truly WVGA command mode dsi panel";
qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
@@ -65,43 +65,81 @@
b0 04
29 01 00 00 00 03
b3 02 00
+ 29 01 00 00 00 03
+ b6 51 83
+ 29 01 00 00 00 05
+ b7 00 80 15 25
+ 29 01 00 00 00 14
+ b8 00 07 07 ff c8 c8 01 18 10 10
+ 37 5a 87 de ff 00 00 00 00
+ 29 01 00 00 00 05
+ b9 00 00 00 00
23 01 00 00 00 02
bd 00
29 01 00 00 00 03
- c0 18 66
+ c0 02 43
29 01 00 00 00 10
- c1 23 31 99 21 20 00 30 28 0c 0c
+ c1 43 31 99 21 20 00 10 28 0c 0c
00 00 00 21 01
29 01 00 00 00 07
- c2 00 06 06 01 03 00
+ c2 28 06 06 01 03 00
+ 29 01 00 00 00 04
+ c3 40 00 03
+ 29 01 00 00 00 03
+ 6f 03 00
+ 29 01 00 00 00 03
+ c4 00 01
+ 29 01 00 00 00 03
+ c6 00 00
+ 29 01 00 00 00 06
+ c7 11 8d a0 f5 27
29 01 00 00 00 19
- c8 04 10 18 20 2e 46 3c 28 1f 18
- 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ c8 01 0a 12 1c 2b 45 3f 29 17 13
+ 0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
29 01 00 00 00 19
- c9 04 10 18 20 2e 46 3c 28 1f 18
- 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ c9 01 0a 12 1c 2b 45 3f 29 17 13
+ 0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
29 01 00 00 00 19
- ca 04 10 18 20 2e 46 3c 28 1f 18
- 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ ca 01 0a 12 1c 2b 45 3f 29 17 13
+ 0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
29 01 00 00 00 11
- d0 29 03 ce a6 00 43 20 10 01 00
+ d0 99 03 ce a6 00 43 20 10 01 00
01 01 00 03 01 00
29 01 00 00 00 08
d1 18 0C 23 03 75 02 50
23 01 00 00 00 02
- d3 11
+ d3 33
29 01 00 00 00 03
d5 2a 2a
+ 29 01 00 00 00 02
+ d6 28
+ 29 01 00 00 00 10
+ d7 01 00 aa c0 2a 2c 22 12 71 0a 12 00 a0
+ 00 03
+ 29 01 00 00 00 09
+ d8 44 44 22 44 21 46 42 40
+ 29 01 00 00 00 04
+ d9 cf 2d 51
+ 29 01 00 00 00 02
+ da 01
29 01 00 00 00 03
- de 01 51
+ de 01 4f
+ 29 01 00 00 00 07
+ e1 00 00 00 00 00 00
23 01 00 00 00 02
- e6 51
+ e6 4f
+ 29 01 00 00 00 06
+ f3 06 00 00 24 00
+ 29 01 00 00 00 02
+ f8 00
23 01 00 00 00 02
fa 03
- 23 01 00 00 64 02
- d6 28
- 15 01 00 00 00 02
- 36 41
+ 29 01 00 00 00 04
+ fb 00 00 00
+ 29 01 00 00 00 06
+ fc 00 00 00 00 00
+ 29 01 00 00 00 05
+ fd 00 00 70 00
39 01 00 00 00 05
2a 00 00 01 df
39 01 00 00 00 05
@@ -111,10 +149,12 @@
39 01 00 00 00 03
44 00 50
15 01 00 00 00 02
+ 36 41
+ 15 01 00 00 00 02
3a 77
05 01 00 00 7D 02
11 00
- 05 01 00 00 14 02
+ 05 01 00 00 3c 02
29 00
];
qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
index 8be8d71..538f2d8 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,dsi_v2_truly_wvga_video {
compatible = "qcom,dsi-panel-v2";
label = "Truly WVGA video mode dsi panel";
@@ -61,41 +61,81 @@
b0 04
29 01 00 00 00 03
b3 02 00
+ 29 01 00 00 00 03
+ b6 51 83
+ 29 01 00 00 00 05
+ b7 00 80 15 25
+ 29 01 00 00 00 14
+ b8 00 07 07 ff c8 c8 01 18 10 10
+ 37 5a 87 de ff 00 00 00 00
+ 29 01 00 00 00 05
+ b9 00 00 00 00
23 01 00 00 00 02
bd 00
29 01 00 00 00 03
- c0 18 66
+ c0 02 43
29 01 00 00 00 10
- c1 23 31 99 21 20 00 30 28 0c 0c
+ c1 43 31 99 21 20 00 10 28 0c 0c
00 00 00 21 01
29 01 00 00 00 07
- c2 00 06 06 01 03 00
+ c2 28 06 06 01 03 00
+ 29 01 00 00 00 04
+ c3 40 00 03
+ 29 01 00 00 00 03
+ 6f 03 00
+ 29 01 00 00 00 03
+ c4 00 01
+ 29 01 00 00 00 03
+ c6 00 00
+ 29 01 00 00 00 06
+ c7 11 8d a0 f5 27
29 01 00 00 00 19
- c8 04 10 18 20 2e 46 3c 28 1f 18
- 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ c8 01 0a 12 1c 2b 45 3f 29 17 13
+ 0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
29 01 00 00 00 19
- c9 04 10 18 20 2e 46 3c 28 1f 18
- 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ c9 01 0a 12 1c 2b 45 3f 29 17 13
+ 0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
29 01 00 00 00 19
- ca 04 10 18 20 2e 46 3c 28 1f 18
- 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ ca 01 0a 12 1c 2b 45 3f 29 17 13
+ 0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
29 01 00 00 00 11
- d0 29 03 ce a6 00 43 20 10 01 00
+ d0 99 03 ce a6 00 43 20 10 01 00
01 01 00 03 01 00
29 01 00 00 00 08
d1 18 0C 23 03 75 02 50
23 01 00 00 00 02
- d3 11
+ d3 33
29 01 00 00 00 03
d5 2a 2a
+ 29 01 00 00 00 02
+ d6 28
+ 29 01 00 00 00 10
+ d7 01 00 aa c0 2a 2c 22 12 71 0a 12 00 a0
+ 00 03
+ 29 01 00 00 00 09
+ d8 44 44 22 44 21 46 42 40
+ 29 01 00 00 00 04
+ d9 cf 2d 51
+ 29 01 00 00 00 02
+ da 01
29 01 00 00 00 03
- de 01 51
+ de 01 4f
+ 29 01 00 00 00 07
+ e1 00 00 00 00 00 00
23 01 00 00 00 02
- e6 51
+ e6 4f
+ 29 01 00 00 00 06
+ f3 06 00 00 24 00
+ 29 01 00 00 00 02
+ f8 00
23 01 00 00 00 02
fa 03
- 23 01 00 00 64 02
- d6 28
+ 29 01 00 00 00 04
+ fb 00 00 00
+ 29 01 00 00 00 06
+ fc 00 00 00 00 00
+ 29 01 00 00 00 05
+ fd 00 00 70 00
39 01 00 00 00 05
2a 00 00 01 df
39 01 00 00 00 05
@@ -110,11 +150,15 @@
3a 77
05 01 00 00 7D 02
11 00
- 05 01 00 00 14 02
+ 05 01 00 00 3c 02
29 00
];
qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
- 05 01 00 00 78 02 10 00];
+ 05 01 00 00 78 02 10 00
+ 23 01 00 00 10 02
+ b0 04
+ 23 01 00 00 20 02
+ b1 01];
qcom,off-cmds-dsi-state = "DSI_LP_MODE";
};
};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 2aea0a5..1820dc7 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -218,6 +218,7 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,vadc-poll-eoc;
chan@8 {
label = "die_temp";
@@ -263,6 +264,7 @@
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
qcom,iadc-vadc = <&pm8110_vadc>;
+ qcom,iadc-poll-eoc;
chan@0 {
label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 51b3f2f..2c5e57f 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,7 +22,7 @@
#address-cells = <1>;
#size-cells = <1>;
- qcom,revid@100 {
+ pm8226_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
};
@@ -85,6 +85,7 @@
qcom,tchg-mins = <150>;
qcom,chg-vadc = <&pm8226_vadc>;
qcom,chg-adc_tm = <&pm8226_adc_tm>;
+ qcom,pmic-revid = <&pm8226_revid>;
qcom,ibatmax-warm-ma = <350>;
qcom,warm-bat-decidegc = <450>;
qcom,warm-bat-mv = <4100>;
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index a2d80ec..43bd0c9 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -238,5 +238,28 @@
reg = <0x2b00 0x100>;
};
};
+
+ krait_regulator_pmic: qcom,krait-regulator-pmic@2000 {
+ spmi-dev-container;
+ compatible = "qcom,krait-regulator-pmic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,ctl@2000 {
+ status = "disabled";
+ reg = <0x2000 0x100>;
+ };
+
+ qcom,ps@2100 {
+ status = "disabled";
+ reg = <0x2100 0x100>;
+ };
+
+ qcom,freq@2200 {
+ status = "disabled";
+ reg = <0x2200 0x100>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index 808f0f6..c070443 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -264,6 +264,7 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,vadc-poll-eoc;
chan@8 {
label = "die_temp";
@@ -813,5 +814,28 @@
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
+
+ krait_regulator_pmic: qcom,krait-regulator-pmic@2900 {
+ spmi-dev-container;
+ compatible = "qcom,krait-regulator-pmic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,ctl@2900 {
+ reg = <0x2900 0x100>;
+ status = "disabled";
+ };
+
+ qcom,ps@2a00 {
+ reg = <0x2a00 0x100>;
+ status = "disabled";
+ };
+
+ qcom,freq@2b00 {
+ reg = <0x2b00 0x100>;
+ status = "disabled";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index 617d738..23ee20d 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -74,8 +74,9 @@
cell-index = <0>;
compatible = "qcom,vfe40";
reg = <0xfda10000 0x1000>,
- <0xfda40000 0x200>;
- reg-names = "vfe", "vfe_vbif";
+ <0xfda40000 0x200>,
+ <0xfd4a8000 0x4>;
+ reg-names = "vfe", "vfe_vbif", "tcsr";
interrupts = <0 57 0>;
interrupt-names = "vfe";
vdd-supply = <&gdsc_vfe>;
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index 9574b7d..30c3209 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -55,18 +55,12 @@
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0x314000>;
};
+
qcom,ion-heap@23 { /* OTHER PIL HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <23>;
qcom,heap-align = <0x1000>;
- qcom,memory-fixed = <0x06400000 0x2000000>;
- };
- qcom,ion-heap@26 { /* MODEM PIL HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <26>;
- qcom,heap-align = <0x1000>;
- qcom,memory-fixed = <0x08400000 0x4E00000>;
-
+ qcom,memory-fixed = <0x0dc00000 0x1900000>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index a10b499..7d7d949 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -16,7 +16,6 @@
&soc {
serial@f991f000 {
status = "ok";
- qcom,cont-splash-enabled;
};
i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index 3e0e4e4..d73fb93 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -55,6 +55,52 @@
qcom,cdc-vdd-spkr-gpios;
qcom,cdc-us-euro-gpios;
};
+
+ tp_power: regulator-tp {
+ compatible = "regulator-fixed";
+ regulator-name = "tp_power";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ gpio = <&msmgpio 15 0>;
+ startup-delay-us = <20000>;
+ enable-active-high;
+ };
+
+ i2c@f9927000 {
+ goodix@5d {
+ compatible = "goodix,gt9xx";
+ reg = <0x5d>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ reset-gpios = <&msmgpio 16 0x00>;
+ interrupt-gpios = <&msmgpio 17 0x00>;
+ avdd-supply = <&tp_power>;
+ goodix,panel-coords = <0 0 720 1200>;
+ goodix,display-coords = <0 0 720 1080>;
+ goodix,button-map= <158 102 139>;
+ goodix,family-id = <0x0>;
+ goodix,cfg-data = [
+ 41 D0 02 00 05 0A 05 01 01 08
+ 12 58 50 41 03 05 00 00 00 00
+ 00 00 00 00 00 00 00 8C 2E 0E
+ 28 24 73 13 00 00 00 83 03 1D
+ 40 02 00 00 00 03 64 32 00 00
+ 00 1A 38 94 C0 02 00 00 00 04
+ 9E 1C 00 8D 20 00 7A 26 00 6D
+ 2C 00 60 34 00 60 10 38 68 00
+ F0 50 35 FF FF 27 00 00 00 00
+ 00 01 1B 14 0C 14 00 00 01 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 02 04 06 08 0A 0C 0E 10
+ 12 14 16 18 1A 1C FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF
+ FF FF 00 02 04 06 08 0A 0C 0F
+ 10 12 13 14 16 18 1C 1D 1E 1F
+ 20 21 22 24 26 28 29 2A FF FF
+ FF FF FF FF FF FF FF 22 22 22
+ 22 22 22 FF 07 01];
+ };
+ };
};
&spmi_bus {
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index 0a3148b..9e98681 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -31,3 +31,7 @@
qcom,cont-splash-enabled;
};
};
+
+&pm8226_bms {
+ qcom,use-external-rsense;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index 0a4657d..320cea1 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -56,6 +56,52 @@
qcom,cdc-vdd-spkr-gpios;
qcom,cdc-us-euro-gpios;
};
+
+ tp_power: regulator-tp {
+ compatible = "regulator-fixed";
+ regulator-name = "tp_power";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ gpio = <&msmgpio 15 0>;
+ startup-delay-us = <20000>;
+ enable-active-high;
+ };
+
+ i2c@f9927000 {
+ goodix@5d {
+ compatible = "goodix,gt9xx";
+ reg = <0x5d>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ reset-gpios = <&msmgpio 16 0x00>;
+ interrupt-gpios = <&msmgpio 17 0x00>;
+ avdd-supply = <&tp_power>;
+ goodix,panel-coords = <0 0 720 1200>;
+ goodix,display-coords = <0 0 720 1080>;
+ goodix,button-map= <158 102 139>;
+ goodix,family-id = <0x0>;
+ goodix,cfg-data = [
+ 41 D0 02 00 05 0A 05 01 01 08
+ 12 58 50 41 03 05 00 00 00 00
+ 00 00 00 00 00 00 00 8C 2E 0E
+ 28 24 73 13 00 00 00 83 03 1D
+ 40 02 00 00 00 03 64 32 00 00
+ 00 1A 38 94 C0 02 00 00 00 04
+ 9E 1C 00 8D 20 00 7A 26 00 6D
+ 2C 00 60 34 00 60 10 38 68 00
+ F0 50 35 FF FF 27 00 00 00 00
+ 00 01 1B 14 0C 14 00 00 01 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 02 04 06 08 0A 0C 0E 10
+ 12 14 16 18 1A 1C FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF
+ FF FF 00 02 04 06 08 0A 0C 0F
+ 10 12 13 14 16 18 1C 1D 1E 1F
+ 20 21 22 24 26 28 29 2A FF FF
+ FF FF FF FF FF FF FF 22 22 22
+ 22 22 22 FF 07 01];
+ };
+ };
};
&spmi_bus {
@@ -114,3 +160,7 @@
qcom,fast-avg-setup = <0>;
};
};
+
+&pm8226_iadc {
+ qcom,rsense = <10000000>;
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index afdd78e..aeb29d7 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -1034,9 +1034,11 @@
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
};
- qcom,msm-mem-hole {
+ memory_hole: qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
- qcom,memblock-remove = <0x6400000 0x9b00000>; /* Address and Size of Hole */
+ qcom,memblock-remove = <0x08400000 0x4000000
+ 0x0d200000 0x2300000
+ 0x0fa00000 0x500000>; /* Address and Size of Hole */
};
tsens: tsens@fc4a8000 {
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index cef04ef..6b72e66 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -952,6 +952,7 @@
cell-id = <2048>;
label = "fab_mmss_noc";
qcom,masterp = <1>;
+ qcom,gateway;
qcom,qport = <1>;
qcom,buswidth = <8>;
qcom,ws = <10000>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msm8610-cdp.dts
rename to arch/arm/boot/dts/msm8610-cdp.dtsi
index f3470c2..bfccb78 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -10,19 +10,6 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
- model = "Qualcomm MSM 8610 CDP";
- compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
- qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
- <163 1 0>, <164 1 0>, <166 1 0>;
-};
-
&soc {
serial@f991e000 {
status = "ok";
@@ -52,7 +39,7 @@
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
- 1D 02 00 0A 06 0D 00 00
+ 1D 03 00 1E 07 0D 00 00
/* Object 7, Instance = 0 */
20 08 32
/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
/* Object 9, Instance = 0 */
83 00 00 13 0B 00 20 32 01 03
00 32 05 30 0A 05 0A 00 70 03
- FC 01 00 36 2F D8 00 00 40 00
+ FC 01 04 2F F8 DC 00 00 40 00
00 0A 00 00 02
/* Object 18, Instance = 0 */
00 00
@@ -143,6 +130,10 @@
"AMIC1", "MIC BIAS External",
"AMIC2", "MIC BIAS Internal2";
};
+
+ qcom,dsi_v2_truly_wvga_video {
+ qcom,cont-splash-enabled;
+ };
};
&i2c_cdc {
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 2041bf6..98a99a7 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc326000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msm8610-mtp.dts
rename to arch/arm/boot/dts/msm8610-mtp.dtsi
index 0d4c174..349c8f7 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -10,19 +10,6 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
- model = "Qualcomm MSM 8610 MTP";
- compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
- qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
- <163 8 0>, <164 8 0>, <166 8 0>;
-};
-
&soc {
serial@f991e000 {
status = "ok";
@@ -52,7 +39,7 @@
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
- 1D 02 00 0A 06 0D 00 00
+ 1D 03 00 1E 07 0D 00 00
/* Object 7, Instance = 0 */
20 08 32
/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
/* Object 9, Instance = 0 */
83 00 00 13 0B 00 20 32 01 03
00 32 05 30 0A 05 0A 00 70 03
- FC 01 00 36 2F D8 00 00 40 00
+ FC 01 04 2F F8 DC 00 00 40 00
00 0A 00 00 02
/* Object 18, Instance = 0 */
00 00
@@ -181,6 +168,10 @@
"AMIC1", "MIC BIAS External",
"AMIC2", "MIC BIAS Internal2";
};
+
+ qcom,dsi_v2_truly_wvga_video {
+ qcom,cont-splash-enabled;
+ };
};
&i2c_cdc {
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index d31a65c..beeeed3 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -24,7 +24,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
- qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
};
@@ -41,7 +41,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
- qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
};
@@ -58,7 +58,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 06 26 30 0f];
};
@@ -75,7 +75,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
- qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
};
@@ -208,45 +208,43 @@
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 1>,
- <4 4 >,
- <5 5 >,
- <6 9 >,
- <7 13>,
- <8 17>,
- <9 21>,
- <10 27>,
- <11 29>,
- <12 31>,
- <13 33>,
- <14 35>,
- <15 37>,
- <16 38>,
- <17 39>,
- <18 41>,
- <19 46>,
- <20 48>,
- <21 49>,
- <22 50>,
- <23 51>,
- <24 52>,
- <25 54>,
- <26 62>,
- <27 63>,
- <28 64>,
- <29 65>,
- <30 66>,
- <31 67>,
- <32 68>,
- <33 69>,
- <34 71>,
- <35 72>,
- <36 106>,
- <37 107>,
- <38 108>,
- <39 109>,
- <40 110>,
- <54 111>,
- <55 113>;
+ <4 5 >,
+ <5 9 >,
+ <6 14>,
+ <7 15>,
+ <8 32>,
+ <9 33>,
+ <10 34>,
+ <11 35>,
+ <12 41>,
+ <13 42>,
+ <14 72>,
+ <15 73>,
+ <16 74>,
+ <17 75>,
+ <18 76>,
+ <19 77>,
+ <20 78>,
+ <21 79>,
+ <22 80>,
+ <23 81>,
+ <24 82>,
+ <25 83>,
+ <26 84>,
+ <27 85>,
+ <28 87>,
+ <29 90>,
+ <30 91>,
+ <31 92>,
+ <32 93>,
+ <33 94>,
+ <34 95>,
+ <35 96>,
+ <36 97>,
+ <37 98>,
+ <38 99>,
+ <39 100>,
+ <40 101>;
};
qcom,pm-8x60@fe805664 {
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index bd1705f..d9de889 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -26,8 +26,6 @@
* };
*/
-/include/ "msm8610.dtsi"
-
&soc {
i2c@f9923000{
focaltech@38{
@@ -344,3 +342,10 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&pm8110_vadc {
+ chan@30 {
+ label = "batt_therm";
+ qcom,scale-function = <6>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-v1-cdp.dts b/arch/arm/boot/dts/msm8610-v1-cdp.dts
new file mode 100644
index 0000000..ba0851f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1-cdp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v1.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610 CDP";
+ compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+ qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
+ <163 1 0>, <164 1 0>, <166 1 0>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v1-mtp.dts b/arch/arm/boot/dts/msm8610-v1-mtp.dts
new file mode 100644
index 0000000..010903f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1-mtp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v1.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610 MTP";
+ compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+ qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
+ <163 8 0>, <164 8 0>, <166 8 0>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
similarity index 92%
rename from arch/arm/boot/dts/msm8610-qrd-skuaa.dts
rename to arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
index aeaf8ca..5abe5c0 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
@@ -12,6 +12,7 @@
/dts-v1/;
+/include/ "msm8610-v1.dtsi"
/include/ "msm8610-qrd.dtsi"
/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
/include/ "msm8610-qrd-camera-sensor.dtsi"
@@ -45,3 +46,10 @@
status = "ok";
qcom,batt-type = <5>;
};
+
+&pm8110_vadc {
+ chan@30 {
+ label = "batt_therm";
+ qcom,scale-function = <7>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
similarity index 83%
rename from arch/arm/boot/dts/msm8610-qrd-skuab.dts
rename to arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
index 947a312..b4559ff 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
@@ -12,6 +12,7 @@
/dts-v1/;
+/include/ "msm8610-v1.dtsi"
/include/ "msm8610-qrd.dtsi"
/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
/include/ "msm8612-qrd-camera-sensor.dtsi"
@@ -80,7 +81,30 @@
};
};
+ usb@f9a55000 {
+ qcom,hsusb-otg-phy-init-seq =
+ <0x44 0x80 0x6a 0x81 0x34 0x82 0x23 0x83 0xffffffff>;
+ };
+
qcom,dsi_v2_otm8018b_fwvga_video {
status = "ok";
};
};
+
+/ {
+ qrd_batterydata: qcom,battery-data {
+ qcom,rpull-up-kohm = <100>;
+ qcom,vref-batt-therm = <1800000>;
+
+ /include/ "batterydata-qrd-4v2-1800mah.dtsi"
+ };
+};
+
+&pm8110_bms {
+ status = "ok";
+ qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+ qcom,battery-data = <&qrd_batterydata>;
+};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1.dtsi
similarity index 70%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1.dtsi
index 607ba8c..5052b96 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1.dtsi
@@ -8,11 +8,12 @@
* 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 "adreno.h"
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8610.dtsi file.
+ */
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610.dtsi"
diff --git a/arch/arm/boot/dts/msm8610-v2-cdp.dts b/arch/arm/boot/dts/msm8610-v2-cdp.dts
new file mode 100644
index 0000000..51ef7a2
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-cdp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v2.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 CDP";
+ compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+ qcom,msm-id = <147 1 0x10001>, <165 1 0x10001>, <161 1 0x10001>, <162 1 0x10001>,
+ <163 1 0x10001>, <164 1 0x10001>, <166 1 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
new file mode 100644
index 0000000..e1c9bb8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v2.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 MTP";
+ compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+ qcom,msm-id = <147 8 0x10001>, <165 8 0x10001>, <161 8 0x10001>, <162 8 0x10001>,
+ <163 8 0x10001>, <164 8 0x10001>, <166 8 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
new file mode 100644
index 0000000..6ad8cb5
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd.dtsi"
+/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
+/include/ "msm8610-qrd-camera-sensor.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 QRD";
+ compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+ qcom,board-id = <11 1>, <11 0>;
+ qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
+ <163 0x10001>, <164 0x10001>, <166 0x10001>;
+};
+
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
similarity index 61%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
index 607ba8c..225be06 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
@@ -8,11 +8,17 @@
* 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 "adreno.h"
+/dts-v1/;
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 QRD";
+ compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+ qcom,board-id = <11 3>;
+ qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
+ <163 0x10001>, <164 0x10001>, <166 0x10001>;
+};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v2.dtsi
similarity index 70%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v2.dtsi
index 607ba8c..5052b96 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v2.dtsi
@@ -8,11 +8,12 @@
* 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 "adreno.h"
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8610.dtsi file.
+ */
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610.dtsi"
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index c6104bf..efa68b9 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -472,6 +472,7 @@
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 2 0>;
qcom,scl-gpio = <&msmgpio 3 0>;
+ qcom,master-id = <86>;
};
i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
@@ -484,6 +485,8 @@
interrupt-names = "qup_err_intr";
interrupts = <0 99 0>;
qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,master-id = <86>;
};
i2c: i2c@f9928000 { /* BLSP1 QUP6 */
@@ -499,6 +502,7 @@
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 16 0>;
qcom,scl-gpio = <&msmgpio 17 0>;
+ qcom,master-id = <86>;
};
i2c@f9925000 { /* BLSP-1 QUP-3 */
@@ -511,6 +515,10 @@
interrupt-names = "qup_err_intr";
interrupts = <0 97 0>;
qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 10 0>;
+ qcom,scl-gpio = <&msmgpio 11 0>;
+ qcom,master-id = <86>;
};
spi_4: spi@f9926000 { /* BLSP1 QUP4 */
@@ -929,10 +937,16 @@
};
&gdsc_vfe {
+ qcom,clock-names = "core_clk", "iface_clk", "bus_clk";
+ qcom,skip-logic-collapse;
+ qcom,retain-periph;
+ qcom,retain-mem;
status = "ok";
};
&gdsc_oxili_cx {
+ qcom,clock-names = "core_clk", "iface_clk", "mem_clk";
+ qcom,skip-logic-collapse;
status = "ok";
};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8926-qrd-skug.dts
similarity index 69%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8926-qrd-skug.dts
index 607ba8c..557e0c8 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -8,11 +8,15 @@
* 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 "adreno.h"
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-qrd.dtsi"
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/ {
+ model = "Qualcomm MSM 8926 QRD SKUG";
+ compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
+ qcom,board-id = <11 5>;
+ qcom,msm-id = <200 0>;
+};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 013da90a..9159ba2 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -64,9 +64,9 @@
&apc_vreg_corner {
qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
- qcom,pvs-corner-ceiling-slow = <1160000 1160000 1280000>;
- qcom,pvs-corner-ceiling-nom = <980000 1080000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+ qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
qcom,cpr-step-quotient = <30>;
qcom,cpr-up-threshold = <0>;
qcom,cpr-down-threshold = <5>;
@@ -77,3 +77,12 @@
qcom,sensors = <6>;
qcom,slope = <2901 2846 3038 2955 2901 2846>;
};
+
+&msmgpio {
+ ngpio = <120>;
+};
+
+&memory_hole {
+ qcom,memblock-remove = <0x08000000 0x7500000
+ 0x0fa00000 0x500000>; /* Address and size of the hole */
+};
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 8e5b58c..dd30820 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -107,8 +107,9 @@
cell-index = <0>;
compatible = "qcom,vfe40";
reg = <0xfda10000 0x1000>,
- <0xfda40000 0x200>;
- reg-names = "vfe", "vfe_vbif";
+ <0xfda40000 0x200>,
+ <0xfd4a8000 0x4>;
+ reg-names = "vfe", "vfe_vbif", "tcsr";
interrupts = <0 57 0>;
interrupt-names = "vfe";
vdd-supply = <&gdsc_vfe>;
@@ -118,8 +119,9 @@
cell-index = <1>;
compatible = "qcom,vfe40";
reg = <0xfda14000 0x1000>,
- <0xfda40000 0x200>;
- reg-names = "vfe", "vfe_vbif";
+ <0xfda40000 0x200>,
+ <0xfd4a8000 0x4>;
+ reg-names = "vfe", "vfe_vbif", "tcsr";
interrupts = <0 58 0>;
interrupt-names = "vfe";
vdd-supply = <&gdsc_vfe>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 63f6d59..455ed2d 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -55,5 +55,12 @@
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0x614000>;
};
+
+ qcom,ion-heap@23 { /* OTHER PIL HEAP */
+ compatible = "qcom,msm-ion-reserve";
+ reg = <23>;
+ qcom,heap-align = <0x1000>;
+ qcom,memory-fixed = <0x05d00000 0x1e00000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index f90599a..1803f91 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -375,6 +375,7 @@
hsic_hub {
compatible = "qcom,hsic-smsc-hub";
+ smsc,model-id = <3503>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 86a61cd..249c963 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -165,3 +165,19 @@
qcom,retain-mem;
qcom,retain-periph;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2000 {
+ status = "ok";
+ };
+
+ qcom,ps@2100 {
+ status = "ok";
+ };
+
+ qcom,freq@2200 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 9d5e50b..af4030f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -168,3 +168,19 @@
&tspp {
vdd_cx-supply = <&pm8841_s2_corner>;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2000 {
+ status = "ok";
+ };
+
+ qcom,ps@2100 {
+ status = "ok";
+ };
+
+ qcom,freq@2200 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c8e3d96..bcea24e 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1504,6 +1504,10 @@
qcom,core-limit-temp = <80>;
qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <0xe>;
+ qcom,hotplug-temp = <110>;
+ qcom,hotplug-temp-hysteresis = <20>;
+ qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+ "tsens_tz_sensor7", "tsens_tz_sensor8";
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
qcom,pmic-sw-mode-temp = <85>;
@@ -1540,7 +1544,7 @@
memory_hole: qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
- qcom,memblock-remove = <0x7b00000 0x8400000>; /* Address and Size of Hole */
+ qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
};
uart7: uart@f995d000 { /*BLSP #2, UART #7 */
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-ab.dtsi
index 88687bd..5809069 100644
--- a/arch/arm/boot/dts/msm8974pro-ab.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ab.dtsi
@@ -39,3 +39,19 @@
&tspp {
vdd_cx-supply = <&pm8841_s2_corner>;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2000 {
+ status = "ok";
+ };
+
+ qcom,ps@2100 {
+ status = "ok";
+ };
+
+ qcom,freq@2200 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
index 250afd2..debf7fb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
@@ -62,10 +62,6 @@
vbus_dwc3-supply = <&pm8941_mvs1>;
};
- qcom,mdss_dsi_toshiba_720p_video {
- qcom,rst-gpio = <&pma8084_gpios 20 0>;
- };
-
gpio_keys {
camera_snapshot {
gpios = <&pma8084_gpios 3 0x1>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-ac.dtsi
index 032c256..4c55169 100644
--- a/arch/arm/boot/dts/msm8974pro-ac.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac.dtsi
@@ -52,6 +52,7 @@
vdd-supply = <&pma8084_l22>;
vddio-supply = <&pma8084_l12>;
vdda-supply = <&pma8084_l2>;
+ qcom,platform-reset-gpio = <&pma8084_gpios 20 0>;
};
qcom,mdss_dsi@fd922e00 {
@@ -188,3 +189,19 @@
&tspp {
vdd_cx-supply = <&pma8084_s2_corner>;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2900 {
+ status = "ok";
+ };
+
+ qcom,ps@2a00 {
+ status = "ok";
+ };
+
+ qcom,freq@2b00 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
new file mode 100644
index 0000000..31bff88
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -0,0 +1,340 @@
+/* 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 {
+ qcom,spm@f9089000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9089000 0x1000>;
+ qcom,core-id = <0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f9099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9099000 0x1000>;
+ qcom,core-id = <1>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f90a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90a9000 0x1000>;
+ qcom,core-id = <2>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f90b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90b9000 0x1000>;
+ qcom,core-id = <3>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9012000 0x1000>;
+ qcom,core-id = <0xffff>; /* L2/APCS SAW */
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-pmic-data0 = <0x02030080>;
+ qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,vctl-timeout-us = <50>;
+ qcom,vctl-port = <0x0>;
+ qcom,phase-port = <0x1>;
+ qcom,pfm-port = <0x2>;
+ qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
+ qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+ 50 02 32 50 0f];
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_retention";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-level@0 {
+ reg = <0x0>;
+ qcom,mode = "wfi";
+ qcom,l2 = "l2_cache_retention";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <715>;
+ qcom,energy-overhead = <17700>;
+ qcom,time-overhead = <2>;
+ };
+
+ qcom,lpm-level@1 {
+ reg = <0x1>;
+ qcom,mode = "retention";
+ qcom,l2 = "l2_cache_retention";
+ qcom,latency-us = <35>;
+ qcom,ss-power = <542>;
+ qcom,energy-overhead = <34920>;
+ qcom,time-overhead = <40>;
+ };
+
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
+ qcom,mode = "standalone_pc";
+ qcom,l2 = "l2_cache_retention";
+ qcom,latency-us = <300>;
+ qcom,ss-power = <476>;
+ qcom,energy-overhead = <225300>;
+ qcom,time-overhead = <350>;
+ };
+
+ qcom,lpm-level@3 {
+ reg = <0x3>;
+ qcom,mode = "pc";
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,gpio-detectable;
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <163>;
+ qcom,energy-overhead = <1577736>;
+ qcom,time-overhead = <5067>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = "pc";
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
+ };
+ };
+
+ qcom,pm-boot {
+ compatible = "qcom,pm-boot";
+ qcom,mode = "tz";
+ };
+
+ qcom,mpm@fc4281d0 {
+ compatible = "qcom,mpm-v2";
+ reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+ <0xf9011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg-names = "vmpm", "ipc";
+ interrupts = <0 171 1>;
+
+ qcom,ipc-bit-offset = <1>;
+
+ qcom,gic-parent = <&intc>;
+ qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+ <47 165>, /* usb30_hs_phy_irq */
+ <50 172>, /* usb1_hs_async_wakeup_irq */
+ <53 104>, /* mdss_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 56>, /* modem_watchdog */
+ <0xff 57>, /* mss_to_apps_irq(0) */
+ <0xff 58>, /* mss_to_apps_irq(1) */
+ <0xff 59>, /* mss_to_apps_irq(2) */
+ <0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 61>, /* mss_a2_bam_irq */
+ <0xff 70>, /* iommu_pmon_nonsecure_irq */
+ <0xff 97>, /* iommu_nonsecure_irq */
+ <0xff 105>, /* iommu_pmon_nonsecure_irq */
+ <0xff 173>, /* o_wcss_apss_smd_hi */
+ <0xff 174>, /* o_wcss_apss_smd_med */
+ <0xff 175>, /* o_wcss_apss_smd_low */
+ <0xff 176>, /* o_wcss_apss_smsm_irq */
+ <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+ <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+ <0xff 179>, /* o_wcss_apss_asic_intr */
+
+ <0xff 181>, /* wcnss watchdog */
+ <0xff 188>, /* lpass_irq_out_apcs(0) */
+ <0xff 189>, /* lpass_irq_out_apcs(1) */
+ <0xff 190>, /* lpass_irq_out_apcs(2) */
+ <0xff 191>, /* lpass_irq_out_apcs(3) */
+ <0xff 192>, /* lpass_irq_out_apcs(4) */
+ <0xff 193>, /* lpass_irq_out_apcs(5) */
+ <0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 195>, /* lpass_irq_out_apcs(7) */
+ <0xff 196>, /* lpass_irq_out_apcs(8) */
+ <0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 200>, /* rpm_ipc(4) */
+ <0xff 201>, /* rpm_ipc(5) */
+ <0xff 202>, /* rpm_ipc(6) */
+ <0xff 203>, /* rpm_ipc(7) */
+ <0xff 204>, /* rpm_ipc(24) */
+ <0xff 205>, /* rpm_ipc(25) */
+ <0xff 206>, /* rpm_ipc(26) */
+ <0xff 207>, /* rpm_ipc(27) */
+ <0xff 211>, /* usb_dwc3_otg */
+ <0xff 240>; /* summary_irq_kpss */
+
+ qcom,gpio-parent = <&msmgpio>;
+ qcom,gpio-map = <3 102>,
+ <4 1 >,
+ <5 5 >,
+ <6 9 >,
+ <7 18>,
+ <8 20>,
+ <9 24>,
+ <10 27>,
+ <11 28>,
+ <12 34>,
+ <13 35>,
+ <14 37>,
+ <15 42>,
+ <16 44>,
+ <17 46>,
+ <18 50>,
+ <19 54>,
+ <20 59>,
+ <21 61>,
+ <22 62>,
+ <23 64>,
+ <24 65>,
+ <25 66>,
+ <26 67>,
+ <27 68>,
+ <28 71>,
+ <29 72>,
+ <30 73>,
+ <31 74>,
+ <32 75>,
+ <33 77>,
+ <34 79>,
+ <35 80>,
+ <36 82>,
+ <37 86>,
+ <38 92>,
+ <39 93>,
+ <40 95>,
+ <41 144>;
+ };
+
+ qcom,pm-8x60@fe805664 {
+ compatible = "qcom,pm-8x60";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xfe805664 0x40>;
+ qcom,pc-mode = "tz_l2_int";
+ qcom,use-sync-timer;
+ qcom,cpus-as-clocks;
+
+ qcom,pm-snoc-client {
+ compatible = "qcom,pm-snoc-client";
+ qcom,msm-bus,name = "ocimem_snoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <54 585 0 0>,
+ <54 585 0 800000>;
+ };
+ };
+
+ qcom,cpu-sleep-status@f9088008{
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x100>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+
+ qcom,rpm-log@fc19dc00 {
+ compatible = "qcom,rpm-log";
+ reg = <0xfc19dc00 0x4000>;
+ qcom,rpm-addr-phys = <0xfc000000>;
+ qcom,offset-version = <4>;
+ qcom,offset-page-buffer-addr = <36>;
+ qcom,offset-log-len = <40>;
+ qcom,offset-log-len-mask = <44>;
+ qcom,offset-page-indices = <56>;
+ };
+
+ qcom,rpm-stats@fc19dba0 {
+ compatible = "qcom,rpm-stats";
+ reg = <0xfc19dba0 0x1000>;
+ reg-names = "phys_addr_base";
+ qcom,sleep-stats-version = <2>;
+ };
+
+ qcom,rpm-rbcpr-stats@fc000000 {
+ compatible = "qcom,rpmrbcpr-stats";
+ reg = <0xfc000000 0x1a0000>;
+ qcom,start-offset = <0x190010>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index e7c6a48..7914a6a 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -19,7 +19,7 @@
/include/ "msm8974.dtsi"
/include/ "msm8974-v2-iommu.dtsi"
/include/ "msm8974-v2-iommu-domains.dtsi"
-/include/ "msm8974-v2-pm.dtsi"
+/include/ "msm8974pro-pm.dtsi"
/include/ "msm8974pro-ion.dtsi"
&soc {
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 31d133a..47b425c 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -1,6 +1,5 @@
# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
@@ -72,6 +71,7 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -425,3 +425,5 @@
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 24ac0d8..97c3664 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -1,6 +1,5 @@
# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
@@ -73,6 +72,7 @@
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_XPU_ERR_FATAL=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -476,3 +476,5 @@
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index b9d37b8..b8dc0d7b 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -69,10 +69,9 @@
CONFIG_MSM_OCMEM_NONSECURE=y
CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_SENSORS_ADSP=y
-CONFIG_MSM_RTB=y
-CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index a5f0704..dd4274a 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -1,6 +1,5 @@
# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
@@ -71,6 +70,7 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index a70b300..32b5b26 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -555,13 +555,15 @@
static DEFINE_RAW_SPINLOCK(stop_lock);
+static struct pt_regs __percpu regs_before_stop;
/*
* ipi_cpu_stop - handle IPI from smp_send_stop()
*/
-static void ipi_cpu_stop(unsigned int cpu)
+static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs)
{
if (system_state == SYSTEM_BOOTING ||
system_state == SYSTEM_RUNNING) {
+ per_cpu(regs_before_stop, cpu) = *regs;
raw_spin_lock(&stop_lock);
printk(KERN_CRIT "CPU%u: stopping\n", cpu);
dump_stack();
@@ -676,7 +678,7 @@
case IPI_CPU_STOP:
irq_enter();
- ipi_cpu_stop(cpu);
+ ipi_cpu_stop(cpu, regs);
irq_exit();
break;
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index ae59e5a..0bf55ae 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -93,6 +93,9 @@
_text = .;
HEAD_TEXT
}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+ . = ALIGN(1<<SECTION_SHIFT);
+#endif
.text : { /* Real text segment */
_stext = .; /* Text and read-only data */
@@ -115,10 +118,10 @@
*(.got) /* Global offset table */
ARM_CPU_KEEP(PROC_INFO)
}
+
#ifdef CONFIG_STRICT_MEMORY_RWX
. = ALIGN(1<<SECTION_SHIFT);
#endif
-
RO_DATA(PAGE_SIZE)
#ifdef CONFIG_ARM_UNWIND
@@ -156,6 +159,9 @@
.init.proc.info : {
ARM_CPU_DISCARD(PROC_INFO)
}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+ . = ALIGN(1<<SECTION_SHIFT);
+#endif
.init.arch.info : {
__arch_info_begin = .;
*(.arch.info.init)
@@ -190,10 +196,6 @@
INIT_RAM_FS
}
#ifndef CONFIG_XIP_KERNEL
-#ifdef CONFIG_STRICT_MEMORY_RWX
- . = ALIGN(1<<SECTION_SHIFT);
-#endif
- __init_data = .;
.exit.data : {
ARM_EXIT_KEEP(EXIT_DATA)
}
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e4a647f..6078901 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -296,7 +296,7 @@
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
obj-$(CONFIG_ARCH_APQ8084) += gdsc.o
-obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o
+obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o krait-regulator-pmic.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 9296515..910264e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -109,6 +109,7 @@
dtb-$(CONFIG_ARCH_MSM8226) += msm8926-cdp.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8926-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd-skug.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-skuf.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-skuf.dtb
dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-xpm.dtb
@@ -133,12 +134,16 @@
# MSM8610
zreladdr-$(CONFIG_ARCH_MSM8610) := 0x00008000
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-rumi.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-sim.dtb
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-qrd-skuaa.dtb
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-qrd-skuab.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-qrd-skuaa.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-qrd-skuab.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-qrd-skuaa.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-qrd-skuab.dtb
# MSMSAMARIUM
zreladdr-$(CONFIG_ARCH_MSMSAMARIUM) := 0x00008000
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 78a73c4..4ea5654 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -230,6 +230,184 @@
},
};
+static struct gpiomux_setting gpio_nc_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting goodix_ldo_en_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_ldo_en_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting goodix_reset_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_reset_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_qrd_blsp_configs[] __initdata = {
+ {
+ .gpio = 2, /* NC */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+ },
+ },
+ {
+ .gpio = 3, /* NC */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+ },
+ },
+ {
+ .gpio = 4, /* NC */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+ },
+ },
+ {
+ .gpio = 14, /* NC */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm_qrd_goodix_configs[] __initdata = {
+ {
+ .gpio = 15, /* LDO EN */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &goodix_ldo_en_act_cfg,
+ [GPIOMUX_SUSPENDED] = &goodix_ldo_en_sus_cfg,
+ },
+ },
+ {
+ .gpio = 16, /* RESET */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &goodix_reset_act_cfg,
+ [GPIOMUX_SUSPENDED] = &goodix_reset_sus_cfg,
+ },
+ },
+ {
+ .gpio = 17, /* INT */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &goodix_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &goodix_int_sus_cfg,
+ },
+ },
+ {
+ .gpio = 18, /* BLSP1 QUP5 I2C_SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 19, /* BLSP1 QUP5 I2C_SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+};
+
+static struct gpiomux_setting nfc_ldo_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_ldo_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_regc_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_regc_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_wake_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_wake_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_qrd_nfc_configs[] __initdata = {
+ { /* NFC LDO EN */
+ .gpio = 0,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &nfc_ldo_act_cfg,
+ [GPIOMUX_SUSPENDED] = &nfc_ldo_sus_cfg,
+ },
+ },
+ { /* NFC REGC*/
+ .gpio = 1,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &nfc_regc_act_cfg,
+ [GPIOMUX_SUSPENDED] = &nfc_regc_sus_cfg,
+ },
+ },
+ { /* NFC WAKE */
+ .gpio = 5,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &nfc_wake_act_cfg,
+ [GPIOMUX_SUSPENDED] = &nfc_wake_sus_cfg,
+ },
+ },
+ { /* NFC */
+ .gpio = 10, /* BLSP1 QUP3 I2C_DAT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ { /* NFC */
+ .gpio = 11, /* BLSP1 QUP3 I2C_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+};
+
static struct gpiomux_setting sd_card_det_active_config = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -571,13 +749,28 @@
msm_gpiomux_install(msm_keypad_configs,
ARRAY_SIZE(msm_keypad_configs));
- msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+ if (of_board_is_qrd())
+ msm_gpiomux_install(msm_qrd_blsp_configs,
+ ARRAY_SIZE(msm_qrd_blsp_configs));
+ else
+ msm_gpiomux_install(msm_blsp_configs,
+ ARRAY_SIZE(msm_blsp_configs));
+
msm_gpiomux_install(wcnss_5wire_interface,
ARRAY_SIZE(wcnss_5wire_interface));
msm_gpiomux_install(&sd_card_det, 1);
- msm_gpiomux_install(msm_synaptics_configs,
- ARRAY_SIZE(msm_synaptics_configs));
+ if (of_board_is_qrd())
+ msm_gpiomux_install(msm_qrd_goodix_configs,
+ ARRAY_SIZE(msm_qrd_goodix_configs));
+ else
+ msm_gpiomux_install(msm_synaptics_configs,
+ ARRAY_SIZE(msm_synaptics_configs));
+
+ if (of_board_is_qrd())
+ msm_gpiomux_install(msm_qrd_nfc_configs,
+ ARRAY_SIZE(msm_qrd_nfc_configs));
+
msm_gpiomux_install_nowrite(msm_lcd_configs,
ARRAY_SIZE(msm_lcd_configs));
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 37567ed..f234712 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -75,7 +75,7 @@
#include <linux/mfd/wcd9xxx/pdata.h>
#endif
-#include <linux/smsc3503.h>
+#include <linux/smsc_hub.h>
#include <linux/msm_ion.h>
#include <mach/ion.h>
#include <mach/mdm2.h>
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 4fb3f43..f8c206b 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -240,6 +240,7 @@
#define GFX3D_CMD_RCGR 0x4000
#define OXILI_GFX3D_CBCR 0x4028
#define OXILI_GFX3D_BCR 0x4030
+#define GMEM_GFX3D_BCR 0x4040
#define OXILI_AHB_BCR 0x4044
#define OXILI_AHB_CBCR 0x403C
#define AHB_CMD_RCGR 0x5000
@@ -507,6 +508,7 @@
static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
@@ -2146,6 +2148,7 @@
static struct branch_clk csi_vfe_clk = {
.cbcr_reg = CSI_VFE_CBCR,
+ .bcr_reg = CSI_VFE_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2216,6 +2219,7 @@
static struct branch_clk gmem_gfx3d_clk = {
.cbcr_reg = GMEM_GFX3D_CBCR,
+ .bcr_reg = GMEM_GFX3D_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2357,6 +2361,7 @@
static struct branch_clk oxili_ahb_clk = {
.cbcr_reg = OXILI_AHB_CBCR,
+ .bcr_reg = OXILI_AHB_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2368,6 +2373,7 @@
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
+ .bcr_reg = OXILI_GFX3D_BCR,
.has_sibling = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2380,6 +2386,7 @@
static struct branch_clk vfe_clk = {
.cbcr_reg = VFE_CBCR,
+ .bcr_reg = VFE_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2392,6 +2399,7 @@
static struct branch_clk vfe_ahb_clk = {
.cbcr_reg = VFE_AHB_CBCR,
+ .bcr_reg = VFE_AHB_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2403,6 +2411,7 @@
static struct branch_clk vfe_axi_clk = {
.cbcr_reg = VFE_AXI_CBCR,
+ .bcr_reg = VFE_AXI_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
/* FIXME: Remove this once simulation is fixed. */
@@ -2767,7 +2776,7 @@
CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991e000.serial"),
CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
-
+ CLK_LOOKUP("bus_clk", pnoc_keepalive_a_clk.c, ""),
CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
@@ -3132,6 +3141,14 @@
CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd404000.qcom,qcrypto"),
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd404000.qcom,qcrypto"),
+
+ /* GDSC clocks */
+ CLK_LOOKUP("core_clk", vfe_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("iface_clk", vfe_ahb_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("bus_clk", vfe_axi_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
+ CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fd8c4034.qcom,gdsc"),
+ CLK_LOOKUP("mem_clk", gmem_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
};
static struct clk_lookup msm_clocks_8610_rumi[] = {
@@ -3229,8 +3246,11 @@
* to remain on whenever CPUs aren't power collapsed.
*/
clk_prepare_enable(&gcc_xo_a_clk_src.c);
-
-
+ /*
+ * Hold an active set vote for the PNOC AHB source. Sleep set vote is 0.
+ */
+ clk_set_rate(&pnoc_keepalive_a_clk.c, 19200000);
+ clk_prepare_enable(&pnoc_keepalive_a_clk.c);
/* Set rates for single-rate clocks. */
clk_set_rate(&usb_hs_system_clk_src.c,
usb_hs_system_clk_src.freq_tbl[0].freq_hz);
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index b7852fe..4488869 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -549,19 +549,21 @@
u32 cbcr_val;
unsigned long irq_flags;
struct branch_clk *branch = to_branch_clk(c);
- int ret = 0;
+ int delay_us = 0, ret = 0;
spin_lock_irqsave(&local_clock_reg_lock, irq_flags);
cbcr_val = readl_relaxed(CBCR_REG(branch));
switch (flags) {
case CLKFLAG_RETAIN_PERIPH:
cbcr_val |= BIT(13);
+ delay_us = 1;
break;
case CLKFLAG_NORETAIN_PERIPH:
cbcr_val &= ~BIT(13);
break;
case CLKFLAG_RETAIN_MEM:
cbcr_val |= BIT(14);
+ delay_us = 1;
break;
case CLKFLAG_NORETAIN_MEM:
cbcr_val &= ~BIT(14);
@@ -570,17 +572,11 @@
ret = -EINVAL;
}
writel_relaxed(cbcr_val, CBCR_REG(branch));
- /*
- * 8974v2.2 has a requirement that writes to set bits 13 and 14 are
- * separated by at least 2 bus cycles. Cover one of these cycles by
- * performing an extra write here. The other cycle is covered by the
- * read-modify-write design of this function.
- */
- writel_relaxed(cbcr_val, CBCR_REG(branch));
- spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
-
- /* Make sure write is issued before returning. */
+ /* Make sure power is enabled before returning. */
mb();
+ udelay(delay_us);
+
+ spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
return ret;
}
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 774548c..ea4865d 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -111,6 +111,13 @@
uint32_t regval;
int i, ret = 0;
+ for (i = sc->clock_count-1; i >= 0; i--) {
+ if (sc->toggle_mem)
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ if (sc->toggle_periph)
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
+
if (sc->toggle_logic) {
regval = readl_relaxed(sc->gdscr);
regval |= SW_COLLAPSE_MASK;
@@ -123,18 +130,11 @@
dev_err(&rdev->dev, "%s disable timed out\n",
sc->rdesc.name);
} else {
- for (i = 0; i < sc->clock_count; i++)
+ for (i = sc->clock_count-1; i >= 0; i--)
clk_reset(sc->clocks[i], CLK_RESET_ASSERT);
sc->resets_asserted = true;
}
- for (i = 0; i < sc->clock_count; i++) {
- if (sc->toggle_mem)
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
- if (sc->toggle_periph)
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
- }
-
return ret;
}
@@ -225,20 +225,9 @@
retain_mem = of_property_read_bool(pdev->dev.of_node,
"qcom,retain-mem");
+ sc->toggle_mem = !retain_mem;
retain_periph = of_property_read_bool(pdev->dev.of_node,
"qcom,retain-periph");
- for (i = 0; i < sc->clock_count; i++) {
- if (retain_mem || (regval & PWR_ON_MASK))
- clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
- else
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
-
- if (retain_periph || (regval & PWR_ON_MASK))
- clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
- else
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
- }
- sc->toggle_mem = !retain_mem;
sc->toggle_periph = !retain_periph;
sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
"qcom,skip-logic-collapse");
@@ -255,6 +244,18 @@
}
}
+ for (i = 0; i < sc->clock_count; i++) {
+ if (retain_mem || (regval & PWR_ON_MASK))
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ else
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+
+ if (retain_periph || (regval & PWR_ON_MASK))
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ else
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
+
sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
pdev->dev.of_node);
if (IS_ERR(sc->rdev)) {
diff --git a/arch/arm/mach-msm/krait-regulator-pmic.c b/arch/arm/mach-msm/krait-regulator-pmic.c
new file mode 100644
index 0000000..5081e7b
--- /dev/null
+++ b/arch/arm/mach-msm/krait-regulator-pmic.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "PMIC PDN %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/spmi.h>
+#include <linux/delay.h>
+
+#define KRAIT_REG_PMIC_DEV_NAME "qcom,krait-regulator-pmic"
+
+#define REG_DIG_MAJOR 0x01
+#define REG_DIG_MINOR 0x00
+
+#define REG_PERPH_TYPE 0x04
+#define CTRL_TYPE_VAL 0x1C
+#define PS_TYPE_VAL 0x1C
+#define FREQ_TYPE_VAL 0x1D
+
+#define REG_PERPH_SUBTYPE 0x05
+#define CTRL_SUBTYPE_VAL 0x08
+#define PS_SUBTYPE_VAL 0x01
+#define FREQ_SUBTYPE_VAL 0x19
+
+#define REG_V_CTL1 0x40
+#define V_CTL1_VAL 0x00
+
+#define REG_MODE_CTL 0x45
+#define NPM_MODE_BIT BIT(7)
+#define AUTO_MODE_BIT BIT(6)
+
+#define REG_EN_CTL 0x46
+#define EN_BIT BIT(7)
+
+#define REG_PD_CTL 0x48
+#define PD_CTL_VAL 0x08
+
+#define REG_MULTIPHASE_CTL 0x51
+#define MULTIPHASE_EN_BIT BIT(7)
+
+#define REG_PHASE_CTL 0x52
+#define BALANCE_EN_BIT BIT(7)
+
+#define REG_VS_CTL 0x61
+#define VS_CTL_VAL 0x85
+
+#define REG_GANG_CTL2 0xC1
+#define GANG_EN_BIT BIT(7)
+
+#define REG_PWM_CL 0x60
+
+struct krait_vreg_pmic_chip {
+ struct spmi_device *spmi;
+ u16 ctrl_base;
+ u16 ps_base;
+ u16 freq_base;
+ u8 ctrl_dig_major;
+ u8 ctrl_dig_minor;
+};
+
+static struct krait_vreg_pmic_chip *the_chip;
+
+static struct of_device_id krait_vreg_pmic_match_table[] = {
+ { .compatible = KRAIT_REG_PMIC_DEV_NAME },
+ {}
+};
+
+static int read_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+ int rc;
+
+ rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, addr, val, 1);
+ if (rc) {
+ pr_err("SPMI read failed [%d,0x%04x] rc=%d\n",
+ spmi->sid, addr, rc);
+ return rc;
+ }
+ return 0;
+}
+
+static int write_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+ int rc;
+
+ rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, val, 1);
+ if (rc) {
+ pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
+ spmi->sid, addr, *val, rc);
+ return rc;
+ }
+ return 0;
+}
+
+#define ISTEP_MA 500
+#define IOFFSET_MA 1000
+#define OVERSHOOT_DIG_MAJOR 1
+#define OVERSHOOT_DIG_MINOR 1
+static bool v_overshoot_fixed(void)
+{
+ if (the_chip->ctrl_dig_major > OVERSHOOT_DIG_MAJOR
+ || (the_chip->ctrl_dig_major == OVERSHOOT_DIG_MAJOR
+ && the_chip->ctrl_dig_minor > OVERSHOOT_DIG_MINOR)) {
+ pr_debug("fixed in h/w\n");
+ return true;
+ }
+ return false;
+}
+
+/**
+ * krait_pmic_is_ready - function to check if the driver is initialized
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: true if this driver has initialized, false otherwise
+ */
+bool krait_pmic_is_ready(void)
+{
+ if (the_chip == NULL) {
+ pr_debug("kait_regulator_pmic not ready yet\n");
+ return false;
+ }
+ return true;
+}
+EXPORT_SYMBOL(krait_pmic_is_ready);
+
+#define I_PFM_MA 2000
+
+/**
+ * krait_pmic_post_pfm_entry - workarounds after entering pfm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pfm_entry(void)
+{
+ u8 setpoint;
+ int rc;
+
+ if (the_chip == NULL) {
+ pr_debug("kait_regulator_pmic not ready yet\n");
+ return -ENXIO;
+ }
+
+ if (v_overshoot_fixed())
+ return 0;
+
+ setpoint = (I_PFM_MA - IOFFSET_MA) / ISTEP_MA;
+ rc = write_byte(the_chip->spmi,
+ the_chip->ps_base + REG_PWM_CL, &setpoint);
+ pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+ the_chip->spmi->sid,
+ the_chip->ps_base + REG_PWM_CL, rc);
+ return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pfm_entry);
+
+#define I_PWM_MA 3500
+/**
+ * krait_pmic_post_pwm_entry - workarounds after entering pwm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pwm_entry(void)
+{
+ u8 setpoint;
+ int rc;
+
+ if (the_chip == NULL) {
+ pr_debug("kait_regulator_pmic not ready yet\n");
+ return -ENXIO;
+ }
+
+ if (v_overshoot_fixed())
+ return 0;
+
+ udelay(50);
+ setpoint = (I_PWM_MA - IOFFSET_MA) / ISTEP_MA;
+
+ rc = write_byte(the_chip->spmi,
+ the_chip->ps_base + REG_PWM_CL, &setpoint);
+ pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+ the_chip->spmi->sid,
+ the_chip->ps_base + REG_PWM_CL, rc);
+ return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pwm_entry);
+
+#define READ_BYTE(chip, addr, val, rc) \
+do { \
+ rc = read_byte(chip->spmi, (addr), &val); \
+ if (rc) \
+ pr_err("register read failed rc=%d\n", rc); \
+} while (0)
+
+#define GANGED_VREG_COUNT 4
+static int gang_configuration_check(struct krait_vreg_pmic_chip *chip)
+{
+ u8 val;
+ int rc;
+ int i;
+
+ return 0;
+
+ READ_BYTE(chip, chip->ctrl_base + REG_V_CTL1, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(val != V_CTL1_VAL);
+
+ READ_BYTE(chip, chip->ctrl_base + REG_MODE_CTL, val, rc);
+ if (rc)
+ return rc;
+ /* The Auto mode should be off */
+ BUG_ON(val & AUTO_MODE_BIT);
+ /* The NPM mode should be on */
+ BUG_ON(!(val & NPM_MODE_BIT));
+
+ READ_BYTE(chip, chip->ctrl_base + REG_EN_CTL, val, rc);
+ if (rc)
+ return rc;
+ /* The en bit should be set */
+ BUG_ON(val & EN_BIT);
+
+ READ_BYTE(chip, chip->ctrl_base + REG_PD_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(val != PD_CTL_VAL);
+
+ READ_BYTE(chip, chip->ctrl_base + REG_MULTIPHASE_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(!(val & MULTIPHASE_EN_BIT));
+
+ READ_BYTE(chip, chip->ctrl_base + REG_PHASE_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(!(val & BALANCE_EN_BIT));
+
+ READ_BYTE(chip, chip->ctrl_base + REG_VS_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(val != VS_CTL_VAL);
+
+ for (i = 0; i < GANGED_VREG_COUNT; i++) {
+ READ_BYTE(chip,
+ chip->ctrl_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+ if (rc)
+ return rc;
+
+ if (!(val & GANG_EN_BIT)) {
+ pr_err("buck = %d, ctrl gang not enabled\n", i);
+ BUG();
+ }
+ }
+
+ for (i = 0; i < GANGED_VREG_COUNT; i++) {
+ READ_BYTE(chip,
+ chip->ps_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+ if (rc)
+ return rc;
+
+ if (!(val & GANG_EN_BIT)) {
+ pr_err("buck = %d, ps gang not enabled\n", i);
+ BUG();
+ }
+ }
+
+ for (i = 0; i < GANGED_VREG_COUNT; i++) {
+ READ_BYTE(chip,
+ chip->freq_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+ if (rc)
+ return rc;
+
+ if (!(val & GANG_EN_BIT)) {
+ pr_err("buck = %d, freq gang not enabled\n", i);
+ BUG();
+ }
+ }
+ return 0;
+}
+
+static int __devinit krait_vreg_pmic_probe(struct spmi_device *spmi)
+{
+ u8 type, subtype;
+ int rc;
+ struct krait_vreg_pmic_chip *chip;
+ struct spmi_resource *spmi_resource;
+ struct resource *resource;
+
+ chip = devm_kzalloc(&spmi->dev, sizeof *chip, GFP_KERNEL);
+ if (chip == NULL) {
+ pr_err("kzalloc() failed.\n");
+ return -ENOMEM;
+ }
+
+ chip->spmi = spmi;
+
+ spmi_for_each_container_dev(spmi_resource, spmi) {
+ if (!spmi_resource) {
+ pr_err("spmi resource absent\n");
+ return -ENXIO;
+ }
+
+ resource = spmi_get_resource(spmi, spmi_resource,
+ IORESOURCE_MEM, 0);
+ if (!(resource && resource->start)) {
+ pr_err("node %s IO resource absent!\n",
+ spmi->dev.of_node->full_name);
+ return -ENXIO;
+ }
+
+ rc = read_byte(chip->spmi,
+ resource->start + REG_PERPH_TYPE,
+ &type);
+ if (rc) {
+ pr_err("Peripheral type read failed rc=%d\n", rc);
+ return -ENXIO;
+ }
+
+ rc = read_byte(chip->spmi,
+ resource->start + REG_PERPH_SUBTYPE,
+ &subtype);
+ if (rc) {
+ pr_err("Peripheral subtype read failed rc=%d\n", rc);
+ return -ENXIO;
+ }
+
+ if (type == CTRL_TYPE_VAL && subtype == CTRL_SUBTYPE_VAL)
+ chip->ctrl_base = resource->start;
+ else if (type == PS_TYPE_VAL && subtype == PS_SUBTYPE_VAL)
+ chip->ps_base = resource->start;
+ else if (type == FREQ_TYPE_VAL && subtype == FREQ_SUBTYPE_VAL)
+ chip->freq_base = resource->start;
+ }
+
+ if (chip->ctrl_base == 0) {
+ pr_err("ctrl base address missing\n");
+ return -ENXIO;
+ }
+
+ if (chip->ps_base == 0) {
+ pr_err("ps base address missing\n");
+ return -ENXIO;
+ }
+
+ if (chip->freq_base == 0) {
+ pr_err("freq base address missing\n");
+ return -ENXIO;
+ }
+
+ READ_BYTE(chip, chip->ctrl_base + REG_DIG_MAJOR,
+ chip->ctrl_dig_major, rc);
+ if (rc)
+ return rc;
+
+ READ_BYTE(chip, chip->ctrl_base + REG_DIG_MINOR,
+ chip->ctrl_dig_minor, rc);
+ if (rc)
+ return rc;
+
+ gang_configuration_check(chip);
+
+ the_chip = chip;
+ return 0;
+}
+
+static struct spmi_driver qpnp_revid_driver = {
+ .probe = krait_vreg_pmic_probe,
+ .driver = {
+ .name = KRAIT_REG_PMIC_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = krait_vreg_pmic_match_table,
+ },
+};
+
+static int __init qpnp_revid_init(void)
+{
+ return spmi_driver_register(&qpnp_revid_driver);
+}
+
+static void __exit qpnp_revid_exit(void)
+{
+ return spmi_driver_unregister(&qpnp_revid_driver);
+}
+
+module_init(qpnp_revid_init);
+module_exit(qpnp_revid_exit);
+
+MODULE_DESCRIPTION("KRAIT REGULATOR PMIC DRIVER");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/mach-msm/krait-regulator-pmic.h
similarity index 70%
rename from drivers/gpu/msm/adreno_trace.c
rename to arch/arm/mach-msm/krait-regulator-pmic.h
index 607ba8c..06ca3ea 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/mach-msm/krait-regulator-pmic.h
@@ -8,11 +8,11 @@
* 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 "adreno.h"
-
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+#ifndef __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+#define __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+bool krait_pmic_is_ready(void);
+int krait_pmic_post_pfm_entry(void);
+int krait_pmic_post_pwm_entry(void);
+#endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 9c5f197..4b2259e 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -29,7 +29,9 @@
#include <linux/regulator/krait-regulator.h>
#include <linux/debugfs.h>
#include <linux/syscore_ops.h>
+#include <linux/cpu.h>
#include <mach/msm_iomap.h>
+#include "krait-regulator-pmic.h"
#include "spm.h"
#include "pm.h"
@@ -222,8 +224,9 @@
int cpu_num;
int coeff1;
int coeff2;
- bool online;
+ bool reg_en;
int online_at_probe;
+ bool force_bhs;
};
DEFINE_PER_CPU(struct krait_power_vreg *, krait_vregs);
@@ -372,7 +375,7 @@
phase_scaling_factor = pvreg->efuse_phase_scaling_factor;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
+ if (!kvreg->reg_en)
continue;
if (kvreg->mode == LDO_MODE) {
@@ -414,7 +417,7 @@
struct krait_power_vreg *kvreg;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (kvreg->online)
+ if (kvreg->reg_en)
online_total++;
}
return online_total;
@@ -427,7 +430,7 @@
struct pmic_gang_vreg *pvreg = from->pvreg;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
+ if (!kvreg->reg_en)
continue;
load_total += kvreg->load;
}
@@ -474,16 +477,18 @@
}
/* First check if the coeff is low for PFM mode */
- if (load_total <= pvreg->pfm_threshold && n_online == 1) {
+ if (load_total <= pvreg->pfm_threshold
+ && n_online == 1
+ && krait_pmic_is_ready()) {
if (!pvreg->pfm_mode) {
rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
if (rc) {
pr_err("%s PFM en failed load_t %d rc = %d\n",
from->name, load_total, rc);
return rc;
- } else {
- pvreg->pfm_mode = true;
}
+ krait_pmic_post_pfm_entry();
+ pvreg->pfm_mode = true;
}
return rc;
}
@@ -495,10 +500,10 @@
pr_err("%s PFM exit failed load %d rc = %d\n",
from->name, coeff_total, rc);
return rc;
- } else {
- pvreg->pfm_mode = false;
- udelay(PWM_SETTLING_TIME_US);
}
+ pvreg->pfm_mode = false;
+ krait_pmic_post_pwm_entry();
+ udelay(PWM_SETTLING_TIME_US);
}
/* calculate phases */
@@ -565,7 +570,7 @@
mutex_lock(&pvreg->krait_power_vregs_lock);
kvreg->load = load_uA;
- if (!kvreg->online) {
+ if (!kvreg->reg_en) {
mutex_unlock(&pvreg->krait_power_vregs_lock);
return kvreg->mode;
}
@@ -588,10 +593,10 @@
return kvreg->mode;
}
-static int switch_to_using_hs(struct krait_power_vreg *kvreg)
+static void __switch_to_using_bhs(void *info)
{
- if (kvreg->mode == HS_MODE)
- return 0;
+ struct krait_power_vreg *kvreg = info;
+
/* enable bhs */
if (version > KPSS_VERSION_2P0) {
krait_masked_write(kvreg, APC_PWR_GATE_MODE,
@@ -645,21 +650,18 @@
kvreg->mode = HS_MODE;
pr_debug("%s using BHS\n", kvreg->name);
- return 0;
}
-static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+static void __switch_to_using_ldo(void *info)
{
- if (kvreg->mode == LDO_MODE
- && get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
- return 0;
+ struct krait_power_vreg *kvreg = info;
/*
* if the krait is in ldo mode and a voltage change is requested on the
* ldo switch to using hs before changing ldo voltage
*/
if (kvreg->mode == LDO_MODE)
- switch_to_using_hs(kvreg);
+ __switch_to_using_bhs(kvreg);
set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
if (version > KPSS_VERSION_2P0) {
@@ -698,7 +700,25 @@
kvreg->mode = LDO_MODE;
pr_debug("%s using LDO\n", kvreg->name);
- return 0;
+}
+
+static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+{
+ if (kvreg->mode == LDO_MODE
+ && get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
+ return 0;
+
+ return smp_call_function_single(kvreg->cpu_num,
+ __switch_to_using_ldo, kvreg, 1);
+}
+
+static int switch_to_using_bhs(struct krait_power_vreg *kvreg)
+{
+ if (kvreg->mode == HS_MODE)
+ return 0;
+
+ return smp_call_function_single(kvreg->cpu_num,
+ __switch_to_using_bhs, kvreg, 1);
}
static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV)
@@ -750,6 +770,41 @@
return rc;
}
+static int configure_ldo_or_hs_one(struct krait_power_vreg *kvreg, int vmax)
+{
+ int rc;
+
+ if (!kvreg->reg_en)
+ return 0;
+
+ if (kvreg->force_bhs)
+ /*
+ * The cpu is in transitory phase where it is being
+ * prepared to be offlined or onlined and is being
+ * forced to run on BHS during that time
+ */
+ return 0;
+
+ if (kvreg->uV <= kvreg->ldo_threshold_uV
+ && kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
+ <= vmax) {
+ rc = switch_to_using_ldo(kvreg);
+ if (rc < 0) {
+ pr_err("could not switch %s to ldo rc = %d\n",
+ kvreg->name, rc);
+ return rc;
+ }
+ } else {
+ rc = switch_to_using_bhs(kvreg);
+ if (rc < 0) {
+ pr_err("could not switch %s to hs rc = %d\n",
+ kvreg->name, rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
static int configure_ldo_or_hs_all(struct krait_power_vreg *from, int vmax)
{
struct pmic_gang_vreg *pvreg = from->pvreg;
@@ -757,27 +812,12 @@
int rc = 0;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
- continue;
- if (kvreg->uV <= kvreg->ldo_threshold_uV
- && kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
- <= vmax) {
- rc = switch_to_using_ldo(kvreg);
- if (rc < 0) {
- pr_err("could not switch %s to ldo rc = %d\n",
- kvreg->name, rc);
- return rc;
- }
- } else {
- rc = switch_to_using_hs(kvreg);
- if (rc < 0) {
- pr_err("could not switch %s to hs rc = %d\n",
- kvreg->name, rc);
- return rc;
- }
+ rc = configure_ldo_or_hs_one(kvreg, vmax);
+ if (rc) {
+ pr_err("could not switch %s\n", kvreg->name);
+ break;
}
}
-
return rc;
}
@@ -856,7 +896,7 @@
struct krait_power_vreg *kvreg;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
+ if (!kvreg->reg_en)
continue;
v = kvreg->uV;
@@ -896,7 +936,7 @@
rc = krait_voltage_decrease(kvreg, vmax);
if (rc < 0) {
- dev_err(&rdev->dev, "%s failed to set %duV from %duV rc = %d\n",
+ pr_err("%s failed to set %duV from %duV rc = %d\n",
kvreg->name, requested_uV, orig_krait_uV, rc);
}
@@ -927,7 +967,7 @@
}
mutex_lock(&pvreg->krait_power_vregs_lock);
- if (!kvreg->online) {
+ if (!kvreg->reg_en) {
kvreg->uV = min_uV;
mutex_unlock(&pvreg->krait_power_vregs_lock);
return 0;
@@ -943,7 +983,7 @@
{
struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
- return kvreg->online;
+ return kvreg->reg_en;
}
static int krait_power_enable(struct regulator_dev *rdev)
@@ -953,8 +993,9 @@
int rc;
mutex_lock(&pvreg->krait_power_vregs_lock);
+ pr_debug("enable %s\n", kvreg->name);
__krait_power_mdd_enable(kvreg, true);
- kvreg->online = true;
+ kvreg->reg_en = true;
rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
if (rc < 0)
goto en_err;
@@ -975,7 +1016,8 @@
int rc;
mutex_lock(&pvreg->krait_power_vregs_lock);
- kvreg->online = false;
+ pr_debug("disable %s\n", kvreg->name);
+ kvreg->reg_en = false;
rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
if (rc < 0)
@@ -999,6 +1041,69 @@
.is_enabled = krait_power_is_enabled,
};
+static int krait_regulator_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (int)hcpu;
+ struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu);
+ struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+
+ pr_debug("start state=0x%02x, cpu=%d is_online=%d\n",
+ (int)action, cpu, cpu_online(cpu));
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_UP_PREPARE:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = true;
+ /*
+ * cpu is offline at this point, force bhs on which ever cpu
+ * this callback is running on
+ */
+ pr_debug("%s force BHS locally\n", kvreg->name);
+ __switch_to_using_bhs(kvreg);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_ONLINE:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = false;
+ /*
+ * switch the cpu to proper bhs/ldo, the cpu is online at this
+ * point. The gang voltage and mode votes for the cpu were
+ * submitted in CPU_UP_PREPARE phase
+ */
+ configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ case CPU_DOWN_PREPARE:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = true;
+ /*
+ * switch the cpu to run on bhs using smp function calls. Note
+ * that the cpu is online at this point.
+ */
+ pr_debug("%s force BHS remotely\n", kvreg->name);
+ switch_to_using_bhs(kvreg);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ case CPU_DOWN_FAILED:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = false;
+ configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ default:
+ break;
+ }
+
+ pr_debug("done state=0x%02x, cpu=%d is_online=%d\n",
+ (int)action, cpu, cpu_online(cpu));
+ return NOTIFY_OK;
+}
+
+static struct notifier_block krait_cpu_notifier = {
+ .notifier_call = krait_regulator_cpu_callback,
+};
+
static struct dentry *dent;
static int get_retention_dbg_uV(void *data, u64 *val)
{
@@ -1481,11 +1586,14 @@
KRAIT_REGULATOR_DRIVER_NAME, rc);
return rc;
}
+
+ register_hotcpu_notifier(&krait_cpu_notifier);
return platform_driver_register(&krait_pdn_driver);
}
static void __exit krait_power_exit(void)
{
+ unregister_hotcpu_notifier(&krait_cpu_notifier);
platform_driver_unregister(&krait_power_driver);
platform_driver_unregister(&krait_pdn_driver);
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_id.c b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
index 7e9883f..25a749a 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_id.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
@@ -35,16 +35,22 @@
if (!fabreg->info[i].gateway) {
fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
if (fabreg->info[i].id < SLAVE_ID_KEY) {
- WARN(fabreg->info[i].id >= MSM_BUS_MASTER_LAST,
- "id %d exceeds array size!\n",
- fabreg->info[i].id);
+ if (fabreg->info[i].id >= MSM_BUS_MASTER_LAST) {
+ WARN(1, "id %d exceeds array size!\n",
+ fabreg->info[i].id);
+ continue;
+ }
+
master_iids[fabreg->info[i].id] =
fabreg->info[i].priv_id;
} else {
- WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
- (MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY),
- "id %d exceeds array size!\n",
- fabreg->info[i].id);
+ if ((fabreg->info[i].id - SLAVE_ID_KEY) >=
+ (MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY)) {
+ WARN(1, "id %d exceeds array size!\n",
+ fabreg->info[i].id);
+ continue;
+ }
+
slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
= fabreg->info[i].priv_id;
}
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 86e8963..a5593bf 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -23,15 +23,16 @@
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
#include <mach/scm.h>
#include <mach/msm_cache_dump.h>
-#include <mach/memory.h>
#include <mach/msm_iomap.h>
#include <mach/msm_memory_dump.h>
#define L2_DUMP_OFFSET 0x14
-static unsigned long msm_cache_dump_addr;
+static dma_addr_t msm_cache_dump_addr;
+static void *msm_cache_dump_vaddr;
/*
* These should not actually be dereferenced. There's no
@@ -76,7 +77,6 @@
unsigned long buf;
unsigned long size;
} l1_cache_data;
- void *temp;
u32 l1_size, l2_size;
unsigned long total_size;
@@ -102,19 +102,20 @@
};
total_size = l1_size + l2_size;
- msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
+ msm_cache_dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev,
+ total_size, &msm_cache_dump_addr,
+ GFP_KERNEL);
- if (!msm_cache_dump_addr) {
+ if (!msm_cache_dump_vaddr) {
pr_err("%s: Could not get memory for cache dumping\n",
__func__);
return -ENOMEM;
}
- temp = ioremap(msm_cache_dump_addr, total_size);
- memset(temp, 0xFF, total_size);
+ memset(msm_cache_dump_vaddr, 0xFF, total_size);
/* Clean caches before sending buffer to TZ */
- clean_caches((unsigned long) temp, total_size, msm_cache_dump_addr);
- iounmap(temp);
+ clean_caches((unsigned long) msm_cache_dump_vaddr, total_size,
+ msm_cache_dump_addr);
l1_cache_data.buf = msm_cache_dump_addr;
l1_cache_data.size = l1_size;
@@ -126,8 +127,9 @@
pr_err("%s: could not register L1 buffer ret = %d.\n",
__func__, ret);
- l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
- l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
+ l1_dump = (struct l1_cache_dump *)(uint32_t)msm_cache_dump_addr;
+ l2_dump = (struct l2_cache_dump *)(uint32_t)(msm_cache_dump_addr
+ + l1_size);
#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
l1_cache_data.buf = msm_cache_dump_addr + l1_size;
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
index 65b0d28..8fa73ae 100644
--- a/arch/arm/mach-msm/perf_trace_counters.c
+++ b/arch/arm/mach-msm/perf_trace_counters.c
@@ -106,7 +106,7 @@
dir = debugfs_create_dir("perf_debug_tp", NULL);
if (!dir)
return -ENOMEM;
- file = debugfs_create_file("enabled", 0777, dir,
+ file = debugfs_create_file("enabled", 0660, dir,
&value, &fops_perftp);
if (!file) {
debugfs_remove(dir);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index c85f7a1..37fd650 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -159,6 +159,21 @@
}
EXPORT_SYMBOL(msm_set_restart_mode);
+static bool scm_pmic_arbiter_disable_supported;
+/*
+ * Force the SPMI PMIC arbiter to shutdown so that no more SPMI transactions
+ * are sent from the MSM to the PMIC. This is required in order to avoid an
+ * SPMI lockup on certain PMIC chips if PS_HOLD is lowered in the middle of
+ * an SPMI transaction.
+ */
+static void halt_spmi_pmic_arbiter(void)
+{
+ if (scm_pmic_arbiter_disable_supported) {
+ pr_crit("Calling SCM to disable SPMI PMIC arbiter\n");
+ scm_call_atomic1(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER, 0);
+ }
+}
+
static void __msm_power_off(int lower_pshold)
{
printk(KERN_CRIT "Powering off the SoC\n");
@@ -169,10 +184,12 @@
qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
if (lower_pshold) {
- if (!use_restart_v2())
+ if (!use_restart_v2()) {
__raw_writel(0, PSHOLD_CTL_SU);
- else
+ } else {
+ halt_spmi_pmic_arbiter();
__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
+ }
mdelay(10000);
printk(KERN_ERR "Powering off has failed\n");
@@ -298,6 +315,7 @@
} else {
/* Needed to bypass debug image on some chips */
msm_disable_wdog_debug();
+ halt_spmi_pmic_arbiter();
__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
}
@@ -340,6 +358,9 @@
restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
pm_power_off = msm_power_off;
+ if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0)
+ scm_pmic_arbiter_disable_supported = true;
+
return 0;
}
early_initcall(msm_restart_init);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 6cb04c7..9479492 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -75,6 +75,7 @@
PLATFORM_SUBTYPE_SKUAA = 0x1,
PLATFORM_SUBTYPE_SKUF = 0x2,
PLATFORM_SUBTYPE_SKUAB = 0x3,
+ PLATFORM_SUBTYPE_SKUG = 0x5,
PLATFORM_SUBTYPE_QRD_INVALID,
};
@@ -83,6 +84,7 @@
[PLATFORM_SUBTYPE_SKUAA] = "SKUAA",
[PLATFORM_SUBTYPE_SKUF] = "SKUF",
[PLATFORM_SUBTYPE_SKUAB] = "SKUAB",
+ [PLATFORM_SUBTYPE_SKUG] = "SKUG",
};
enum {
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 34cb153..e82ea2b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -909,6 +909,14 @@
"TCM link");
#endif
+#ifdef CONFIG_STRICT_MEMORY_RWX
+ poison_init_mem((char *)__arch_info_begin,
+ __init_end - (char *)__arch_info_begin);
+ reclaimed_initmem = free_area(__phys_to_pfn(__pa(__arch_info_begin)),
+ __phys_to_pfn(__pa(__init_end)),
+ "init");
+ totalram_pages += reclaimed_initmem;
+#else
poison_init_mem(__init_begin, __init_end - __init_begin);
if (!machine_is_integrator() && !machine_is_cintegrator()) {
reclaimed_initmem = free_area(__phys_to_pfn(__pa(__init_begin)),
@@ -916,6 +924,7 @@
"init");
totalram_pages += reclaimed_initmem;
}
+#endif
}
#ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index c2efc34..e5a60a9 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1379,8 +1379,6 @@
}
EXPORT_SYMBOL(mem_text_write_kernel_word);
-extern char __init_data[];
-
static void __init map_lowmem(void)
{
struct memblock_region *reg;
@@ -1401,7 +1399,7 @@
#ifdef CONFIG_STRICT_MEMORY_RWX
if (start <= __pa(_text) && __pa(_text) < end) {
map.length = SECTION_SIZE;
- map.type = MT_MEMORY;
+ map.type = MT_MEMORY_RW;
create_mapping(&map);
@@ -1421,14 +1419,15 @@
map.pfn = __phys_to_pfn(__pa(__init_begin));
map.virtual = (unsigned long)__init_begin;
- map.length = __init_data - __init_begin;
- map.type = MT_MEMORY;
+ map.length = (char *)__arch_info_begin - __init_begin;
+ map.type = MT_MEMORY_RX;
create_mapping(&map);
- map.pfn = __phys_to_pfn(__pa(__init_data));
- map.virtual = (unsigned long)__init_data;
- map.length = __phys_to_virt(end) - (unsigned int)__init_data;
+ map.pfn = __phys_to_pfn(__pa(__arch_info_begin));
+ map.virtual = (unsigned long)__arch_info_begin;
+ map.length = __phys_to_virt(end) -
+ (unsigned long)__arch_info_begin;
map.type = MT_MEMORY_RW;
} else {
map.length = end - start;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index a779b24..1deee5c 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -459,6 +459,7 @@
if ((read_len + 9) >= USER_SPACE_DATA) {
pr_err("diag: dci: Invalid length while forming dci pkt in %s",
__func__);
+ mutex_unlock(&driver->dci_mutex);
return -EIO;
}
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index a24fc54..aa88b37 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -350,19 +350,21 @@
bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
"i: %3d, cmd_code: %4x, subsys_id: %4x, "
"client: %2d, cmd_code_lo: %4x, "
- "cmd_code_hi: %4x, process_id: %5d\n",
+ "cmd_code_hi: %4x, process_id: %5d %s\n",
i,
driver->table[i].cmd_code,
driver->table[i].subsys_id,
driver->table[i].client_id,
driver->table[i].cmd_code_lo,
driver->table[i].cmd_code_hi,
- driver->table[i].process_id);
+ driver->table[i].process_id,
+ (diag_find_polling_reg(i) ? "<- Polling cmd reg" : ""));
bytes_in_buffer += bytes_written;
/* Check if there is room to add another table entry */
bytes_remaining = buf_size - bytes_in_buffer;
+
if (bytes_remaining < bytes_written)
break;
}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index c91095e..755f0a1 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -19,9 +19,13 @@
#include "diagfwd_cntl.h"
#include "diag_masks.h"
-int diag_event_config;
int diag_event_num_bytes;
+#define DIAG_CTRL_MASK_INVALID 0
+#define DIAG_CTRL_MASK_ALL_DISABLED 1
+#define DIAG_CTRL_MASK_ALL_ENABLED 2
+#define DIAG_CTRL_MASK_VALID 3
+
#define ALL_EQUIP_ID 100
#define ALL_SSID -1
#define MAX_SSID_PER_RANGE 100
@@ -106,6 +110,8 @@
uint8_t *parse_ptr, *ptr = driver->msg_masks;
mutex_lock(&driver->diagchar_mutex);
+ driver->msg_status = rt_mask ? DIAG_CTRL_MASK_ALL_ENABLED :
+ DIAG_CTRL_MASK_ALL_DISABLED;
while (*(uint32_t *)(ptr + 4)) {
first_ssid = *(uint32_t *)ptr;
ptr += 8; /* increment by 8 to skip 'last' */
@@ -131,7 +137,6 @@
uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
mutex_lock(&driver->diagchar_mutex);
-
/* First SSID can be zero : So check that last is non-zero */
while (*(uint32_t *)(ptr + 4)) {
first = *(uint32_t *)ptr;
@@ -177,6 +182,7 @@
} else
pr_alert("diag: Not enough buffer space for MSG_MASK\n");
}
+ driver->msg_status = DIAG_CTRL_MASK_VALID;
mutex_unlock(&driver->diagchar_mutex);
diag_print_mask_table();
}
@@ -186,28 +192,29 @@
uint8_t *ptr = driver->event_masks;
mutex_lock(&driver->diagchar_mutex);
- if (toggle)
+ if (toggle) {
+ driver->event_status = DIAG_CTRL_MASK_ALL_ENABLED;
memset(ptr, 0xFF, EVENT_MASK_SIZE);
- else
+ } else {
+ driver->event_status = DIAG_CTRL_MASK_ALL_DISABLED;
memset(ptr, 0, EVENT_MASK_SIZE);
+ }
mutex_unlock(&driver->diagchar_mutex);
}
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
+static void diag_update_event_mask(uint8_t *buf, int num_bytes)
{
uint8_t *ptr = driver->event_masks;
uint8_t *temp = buf + 2;
mutex_lock(&driver->diagchar_mutex);
- if (!toggle)
- memset(ptr, 0 , EVENT_MASK_SIZE);
- else
- if (CHK_OVERFLOW(ptr, ptr,
- ptr+EVENT_MASK_SIZE, num_bytes))
- memcpy(ptr, temp , num_bytes);
- else
- printk(KERN_CRIT "Not enough buffer space for EVENT_MASK\n");
+ if (CHK_OVERFLOW(ptr, ptr, ptr+EVENT_MASK_SIZE, num_bytes)) {
+ memcpy(ptr, temp, num_bytes);
+ driver->event_status = DIAG_CTRL_MASK_VALID;
+ } else {
+ pr_err("diag: In %s, not enough buffer space\n", __func__);
+ }
mutex_unlock(&driver->diagchar_mutex);
}
@@ -226,6 +233,7 @@
(parse_ptr->num_items + 7)/8);
parse_ptr++;
}
+ driver->log_status = DIAG_CTRL_MASK_ALL_DISABLED;
mutex_unlock(&driver->diagchar_mutex);
}
@@ -282,10 +290,13 @@
}
ptr_data = driver->log_masks + offset;
if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
- + LOG_MASK_SIZE, (num_items+7)/8))
- memcpy(ptr_data, temp , (num_items+7)/8);
- else
+ + LOG_MASK_SIZE, (num_items+7)/8)) {
+ memcpy(ptr_data, temp, (num_items+7)/8);
+ driver->log_status = DIAG_CTRL_MASK_VALID;
+ } else {
pr_err("diag: Not enough buffer space for LOG_MASK\n");
+ driver->log_status = DIAG_CTRL_MASK_INVALID;
+ }
mutex_unlock(&driver->diagchar_mutex);
}
@@ -330,15 +341,36 @@
driver->log_mask->num_items = ptr->num_items;
driver->log_mask->data_len = 11 + size;
driver->log_mask->stream_id = 1; /* 2, if dual stream */
- driver->log_mask->status = 3; /* status for valid mask */
driver->log_mask->equip_id = ptr->equip_id;
- driver->log_mask->log_mask_size = size;
+ driver->log_mask->status = driver->log_status;
+ switch (driver->log_status) {
+ case DIAG_CTRL_MASK_ALL_DISABLED:
+ driver->log_mask->log_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_ALL_ENABLED:
+ driver->log_mask->log_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_VALID:
+ driver->log_mask->log_mask_size = size;
+ break;
+ default:
+ /* Log status is not set or the buffer is corrupted */
+ pr_err("diag: In %s, invalid status %d", __func__,
+ driver->log_status);
+ driver->log_mask->status = DIAG_CTRL_MASK_INVALID;
+ }
+
+ if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return;
+ }
/* send only desired update, NOT ALL */
if (equip_id == ALL_EQUIP_ID || equip_id ==
driver->log_mask->equip_id) {
memcpy(buf, driver->log_mask, header_size);
- memcpy(buf+header_size, driver->log_masks+ptr->index,
- size);
+ if (driver->log_status == DIAG_CTRL_MASK_VALID)
+ memcpy(buf + header_size,
+ driver->log_masks+ptr->index, size);
if (ch) {
while (retry_count < 3) {
wr_size = smd_write(ch, buf,
@@ -380,11 +412,34 @@
driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
driver->event_mask->data_len = 7 + num_bytes;
driver->event_mask->stream_id = 1; /* 2, if dual stream */
- driver->event_mask->status = 3; /* status for valid mask */
- driver->event_mask->event_config = diag_event_config; /* event config */
- driver->event_mask->event_mask_size = num_bytes;
+ driver->event_mask->status = driver->event_status;
+
+ switch (driver->event_status) {
+ case DIAG_CTRL_MASK_ALL_DISABLED:
+ driver->event_mask->event_config = 0;
+ driver->event_mask->event_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_ALL_ENABLED:
+ driver->event_mask->event_config = 1;
+ driver->event_mask->event_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_VALID:
+ driver->event_mask->event_config = 1;
+ driver->event_mask->event_mask_size = num_bytes;
+ memcpy(buf + header_size, driver->event_masks, num_bytes);
+ break;
+ default:
+ /* Event status is not set yet or the buffer is corrupted */
+ pr_err("diag: In %s, invalid status %d", __func__,
+ driver->event_status);
+ driver->event_mask->status = DIAG_CTRL_MASK_INVALID;
+ }
+
+ if (driver->event_mask->status == DIAG_CTRL_MASK_INVALID) {
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return;
+ }
memcpy(buf, driver->event_mask, header_size);
- memcpy(buf+header_size, driver->event_masks, num_bytes);
if (ch) {
while (retry_count < 3) {
wr_size = smd_write(ch, buf, header_size + num_bytes);
@@ -418,44 +473,68 @@
ptr += 4;
actual_last = *(uint32_t *)ptr;
ptr += 4;
- if ((updated_ssid_first >= first && updated_ssid_last <=
- actual_last) || (updated_ssid_first == ALL_SSID)) {
- /* send f3 mask update */
- driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
- driver->msg_mask->msg_mask_size = actual_last -
- first + 1;
- driver->msg_mask->data_len = 11 +
- 4 * (driver->msg_mask->msg_mask_size);
- driver->msg_mask->stream_id = 1; /* 2, if dual stream */
- driver->msg_mask->status = 3; /* status valid mask */
- driver->msg_mask->msg_mode = 0; /* Legcay mode */
- driver->msg_mask->ssid_first = first;
- driver->msg_mask->ssid_last = actual_last;
- memcpy(buf, driver->msg_mask, header_size);
+ if (!((updated_ssid_first >= first && updated_ssid_last <=
+ actual_last) || (updated_ssid_first == ALL_SSID))) {
+ ptr += MAX_SSID_PER_RANGE*4;
+ continue;
+ }
+ /* send f3 mask update */
+ driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+ driver->msg_mask->status = driver->msg_status;
+ switch (driver->msg_status) {
+ case DIAG_CTRL_MASK_ALL_DISABLED:
+ driver->msg_mask->msg_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_ALL_ENABLED:
+ driver->msg_mask->msg_mask_size = 1;
memcpy(buf+header_size, ptr,
4 * (driver->msg_mask->msg_mask_size));
- if (ch) {
- while (retry_count < 3) {
- size = smd_write(ch, buf, header_size +
- 4*(driver->msg_mask->msg_mask_size));
- if (size == -ENOMEM) {
- retry_count++;
- usleep_range(10000, 10100);
- } else
- break;
- }
- if (size != header_size +
- 4*(driver->msg_mask->msg_mask_size))
- pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
- proc, size, (header_size +
- 4*(driver->msg_mask->msg_mask_size)));
- else
- pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
- first, actual_last, proc);
- } else
- pr_err("diag: proc %d, ch invalid msg mask update\n",
- proc);
+ break;
+ case DIAG_CTRL_MASK_VALID:
+ driver->msg_mask->msg_mask_size = actual_last -
+ first + 1;
+ memcpy(buf+header_size, ptr,
+ 4 * (driver->msg_mask->msg_mask_size));
+ break;
+ default:
+ /* Msg status is not set or the buffer is corrupted */
+ pr_err("diag: In %s, invalid status %d", __func__,
+ driver->msg_status);
+ driver->msg_mask->status = DIAG_CTRL_MASK_INVALID;
}
+
+ if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return;
+ }
+ driver->msg_mask->data_len = 11 +
+ 4 * (driver->msg_mask->msg_mask_size);
+ driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+ driver->msg_mask->msg_mode = 0; /* Legcay mode */
+ driver->msg_mask->ssid_first = first;
+ driver->msg_mask->ssid_last = actual_last;
+ memcpy(buf, driver->msg_mask, header_size);
+ if (ch) {
+ while (retry_count < 3) {
+ size = smd_write(ch, buf, header_size +
+ 4*(driver->msg_mask->msg_mask_size));
+ if (size == -ENOMEM) {
+ retry_count++;
+ usleep_range(10000, 10100);
+ } else
+ break;
+ }
+ if (size != header_size +
+ 4*(driver->msg_mask->msg_mask_size))
+ pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
+ proc, size, (header_size +
+ 4*(driver->msg_mask->msg_mask_size)));
+ else
+ pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+ first, actual_last, proc);
+ } else
+ pr_err("diag: proc %d, ch invalid msg mask update\n",
+ proc);
ptr += MAX_SSID_PER_RANGE*4;
}
mutex_unlock(&driver->diag_cntl_mutex);
@@ -706,8 +785,8 @@
#endif
} else if (*buf == 0x82) { /* event mask change */
buf += 4;
- diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
- diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+ diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
+ diag_update_event_mask(buf, diag_event_num_bytes);
diag_update_userspace_clients(EVENT_MASKS_TYPE);
#if defined(CONFIG_DIAG_OVER_USB)
if (chk_apps_only()) {
@@ -729,7 +808,6 @@
}
#endif
} else if (*buf == 0x60) {
- diag_event_config = *(buf+1);
diag_toggle_event_mask(*(buf+1));
diag_update_userspace_clients(EVENT_MASKS_TYPE);
#if defined(CONFIG_DIAG_OVER_USB)
@@ -764,6 +842,10 @@
void diag_masks_init(void)
{
+ driver->event_status = DIAG_CTRL_MASK_INVALID;
+ driver->msg_status = DIAG_CTRL_MASK_INVALID;
+ driver->log_status = DIAG_CTRL_MASK_INVALID;
+
if (driver->event_mask == NULL) {
driver->event_mask = kzalloc(sizeof(
struct diag_ctrl_event_mask), GFP_KERNEL);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7ef1d80..45314d9 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -362,9 +362,12 @@
struct work_struct diag_drain_work;
struct workqueue_struct *diag_cntl_wq;
uint8_t *msg_masks;
+ uint8_t msg_status;
uint8_t *log_masks;
+ uint8_t log_status;
int log_masks_length;
uint8_t *event_masks;
+ uint8_t event_status;
uint8_t log_on_demand_support;
struct diag_master_table *table;
uint8_t *pkt_buf;
@@ -412,5 +415,6 @@
extern uint16_t wrap_count;
void diag_get_timestamp(char *time_str);
+int diag_find_polling_reg(int i);
#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 24d7fac..6cc18da 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -327,17 +327,19 @@
subsys_id = driver->table[i].subsys_id;
cmd_code_lo = driver->table[i].cmd_code_lo;
cmd_code_hi = driver->table[i].cmd_code_hi;
- if (driver->table[i].cmd_code == 0x0C)
- return 1;
- else if (driver->table[i].cmd_code == 0xFF) {
- if (subsys_id == 0x04 && cmd_code_hi == 0x0E &&
- cmd_code_lo == 0x0E)
+
+ if (driver->table[i].cmd_code == 0xFF) {
+ if (subsys_id == 0xFF && cmd_code_hi >= 0x0C &&
+ cmd_code_lo <= 0x0C)
return 1;
- else if (subsys_id == 0x08 && cmd_code_hi == 0x02 &&
- cmd_code_lo == 0x02)
+ if (subsys_id == 0x04 && cmd_code_hi >= 0x0E &&
+ cmd_code_lo <= 0x0E)
return 1;
- else if (subsys_id == 0x32 && cmd_code_hi == 0x03 &&
- cmd_code_lo == 0x03)
+ else if (subsys_id == 0x08 && cmd_code_hi >= 0x02 &&
+ cmd_code_lo <= 0x02)
+ return 1;
+ else if (subsys_id == 0x32 && cmd_code_hi >= 0x03 &&
+ cmd_code_lo <= 0x03)
return 1;
}
return 0;
@@ -356,7 +358,8 @@
}
/* re-scan the registration table */
for (i = 0; i < diag_max_reg; i++) {
- if (diag_find_polling_reg(i) == 1) {
+ if (driver->table[i].process_id != 0 &&
+ diag_find_polling_reg(i) == 1) {
driver->polling_reg_flag = 1;
break;
}
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index c501700..d500c0a 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1451,14 +1451,17 @@
if (!drvdata->byte_cntr_present) {
dev_info(&pdev->dev, "Byte Counter feature absent\n");
- return 0;
+ goto out;
}
drvdata->byte_cntr_irq = platform_get_irq_byname(pdev,
"byte-cntr-irq");
if (drvdata->byte_cntr_irq < 0) {
+ /* Even though this is an error condition, we do not fail
+ * the probe as the byte counter feature is optional
+ */
dev_err(&pdev->dev, "Byte-cntr-irq not specified\n");
- return 0;
+ goto err;
}
ret = devm_request_irq(&pdev->dev, drvdata->byte_cntr_irq,
tmc_etr_byte_cntr_irq,
@@ -1466,7 +1469,7 @@
node_name, drvdata);
if (ret) {
dev_err(&pdev->dev, "Request irq failed\n");
- return ret;
+ goto err;
}
init_waitqueue_head(&drvdata->wq);
node_size += strlen(node_name);
@@ -1477,10 +1480,14 @@
ret = tmc_etr_byte_cntr_dev_register(drvdata);
if (ret) {
dev_err(&pdev->dev, "Byte cntr node not registered\n");
- return ret;
+ goto err;
}
dev_info(&pdev->dev, "Byte Counter feature enabled\n");
return 0;
+err:
+ drvdata->byte_cntr_present = false;
+out:
+ return ret;
}
static void tmc_etr_byte_cntr_exit(struct tmc_drvdata *drvdata)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 418c488..1f60c65 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -346,6 +346,7 @@
dbs_tuners_ins.sampling_rate = new_rate
= max(new_rate, min_sampling_rate);
+ get_online_cpus();
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy;
struct cpu_dbs_info_s *dbs_info;
@@ -380,6 +381,7 @@
}
mutex_unlock(&dbs_info->timer_mutex);
}
+ put_online_cpus();
}
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 0e4b309..c726694 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -564,7 +564,7 @@
creq.qce_cb = qcedev_cipher_req_cb;
creq.areq = (void *)&qcedev_areq->cipher_req;
-
+ creq.flags = 0;
ret = qce_ablk_cipher_req(podev->qce, &creq);
unsupported:
if (ret)
@@ -640,6 +640,7 @@
sreq.size = qcedev_areq->sha_req.sreq.nbytes;
sreq.src = qcedev_areq->sha_req.sreq.src;
sreq.areq = (void *)&qcedev_areq->sha_req;
+ sreq.flags = 0;
ret = qce_process_sha_req(podev->qce, &sreq);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index c98cbba..ae57d6c 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -492,6 +492,7 @@
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
q_alg = container_of(alg, struct qcrypto_alg, cipher_alg);
+ ctx->flags = 0;
/* update context with ptr to cp */
ctx->cp = q_alg->cp;
@@ -517,6 +518,8 @@
/* update context with ptr to cp */
sha_ctx->cp = q_alg->cp;
sha_ctx->sg = NULL;
+ sha_ctx->flags = 0;
+
sha_ctx->tmp_tbuf = kzalloc(SHA_MAX_BLOCK_SIZE +
SHA_MAX_DIGEST_SIZE, GFP_KERNEL);
if (sha_ctx->tmp_tbuf == NULL) {
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index aac183b..118e033 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -22,11 +22,9 @@
msm_adreno-y += \
adreno_ringbuffer.o \
adreno_drawctxt.o \
- adreno_dispatch.o \
adreno_postmortem.o \
adreno_snapshot.o \
adreno_coresight.o \
- adreno_trace.o \
adreno_a2xx.o \
adreno_a2xx_trace.o \
adreno_a2xx_snapshot.o \
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 8875d74..b964620 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -32,7 +32,6 @@
#include "adreno.h"
#include "adreno_pm4types.h"
-#include "adreno_trace.h"
#include "a2xx_reg.h"
#include "a3xx_reg.h"
@@ -114,6 +113,18 @@
.long_ib_detect = 1,
};
+/* This set of registers are used for Hang detection
+ * If the values of these registers are same after
+ * KGSL_TIMEOUT_PART time, GPU hang is reported in
+ * kernel log.
+ * *****ALERT******ALERT********ALERT*************
+ * Order of registers below is important, registers
+ * from LONG_IB_DETECT_REG_INDEX_START to
+ * LONG_IB_DETECT_REG_INDEX_END are used in long ib detection.
+ */
+#define LONG_IB_DETECT_REG_INDEX_START 1
+#define LONG_IB_DETECT_REG_INDEX_END 5
+
unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
/*
@@ -202,6 +213,8 @@
512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
};
+static unsigned int adreno_isidle(struct kgsl_device *device);
+
/**
* adreno_perfcounter_init: Reserve kernel performance counters
* @device: device to configure
@@ -585,9 +598,23 @@
static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
{
+ irqreturn_t result;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- return adreno_dev->gpudev->irq_handler(adreno_dev);
+ result = adreno_dev->gpudev->irq_handler(adreno_dev);
+
+ device->pwrctrl.irq_last = 1;
+ if (device->requested_state == KGSL_STATE_NONE) {
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+ queue_work(device->work_queue, &device->idle_check_ws);
+ }
+
+ /* Reset the time-out in our idle timer */
+ mod_timer_pending(&device->idle_timer,
+ jiffies + device->pwrctrl.interval_timeout);
+ mod_timer_pending(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+ return result;
}
static void adreno_cleanup_pt(struct kgsl_device *device,
@@ -894,7 +921,7 @@
adreno_dev->dev.cff_dump_enable);
}
-static int adreno_iommu_setstate(struct kgsl_device *device,
+static void adreno_iommu_setstate(struct kgsl_device *device,
unsigned int context_id,
uint32_t flags)
{
@@ -907,24 +934,22 @@
struct kgsl_context *context;
struct adreno_context *adreno_ctx = NULL;
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- unsigned int result;
if (adreno_use_default_setstate(adreno_dev)) {
kgsl_mmu_device_setstate(&device->mmu, flags);
- return 0;
+ return;
}
num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
context = kgsl_context_get(device, context_id);
if (context == NULL)
- return -EINVAL;
+ return;
adreno_ctx = ADRENO_CONTEXT(context);
- result = kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER);
-
- if (result)
- goto done;
+ if (kgsl_mmu_enable_clk(&device->mmu,
+ KGSL_IOMMU_CONTEXT_USER))
+ return;
pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
device->mmu.hwpagetable);
@@ -958,24 +983,14 @@
* This returns the per context timestamp but we need to
* use the global timestamp for iommu clock disablement
*/
- result = adreno_ringbuffer_issuecmds(device, adreno_ctx,
- KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+ adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE,
+ &link[0], sizedwords);
- /*
- * On error disable the IOMMU clock right away otherwise turn it off
- * after the command has been retired
- */
- if (result)
- kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
- else
- kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
-
-done:
+ kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
kgsl_context_put(context);
- return result;
}
-static int adreno_gpummu_setstate(struct kgsl_device *device,
+static void adreno_gpummu_setstate(struct kgsl_device *device,
unsigned int context_id,
uint32_t flags)
{
@@ -986,7 +1001,6 @@
unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
struct kgsl_context *context;
struct adreno_context *adreno_ctx = NULL;
- int ret = 0;
/*
* Fix target freeze issue by adding TLB flush for each submit
@@ -1003,8 +1017,7 @@
if (!adreno_use_default_setstate(adreno_dev)) {
context = kgsl_context_get(device, context_id);
if (context == NULL)
- return -EINVAL;
-
+ return;
adreno_ctx = ADRENO_CONTEXT(context);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
@@ -1079,7 +1092,7 @@
sizedwords += 2;
}
- ret = adreno_ringbuffer_issuecmds(device, adreno_ctx,
+ adreno_ringbuffer_issuecmds(device, adreno_ctx,
KGSL_CMD_FLAGS_PMODE,
&link[0], sizedwords);
@@ -1087,11 +1100,9 @@
} else {
kgsl_mmu_device_setstate(&device->mmu, flags);
}
-
- return ret;
}
-static int adreno_setstate(struct kgsl_device *device,
+static void adreno_setstate(struct kgsl_device *device,
unsigned int context_id,
uint32_t flags)
{
@@ -1100,8 +1111,6 @@
return adreno_gpummu_setstate(device, context_id, flags);
else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
return adreno_iommu_setstate(device, context_id, flags);
-
- return 0;
}
static unsigned int
@@ -1577,10 +1586,6 @@
if (status)
goto error_close_rb;
- status = adreno_dispatcher_init(adreno_dev);
- if (status)
- goto error_close_device;
-
adreno_debugfs_init(device);
adreno_profile_init(device);
@@ -1596,8 +1601,6 @@
return 0;
-error_close_device:
- kgsl_device_platform_remove(device);
error_close_rb:
adreno_ringbuffer_close(&adreno_dev->ringbuffer);
error:
@@ -1620,7 +1623,6 @@
kgsl_pwrscale_detach_policy(device);
kgsl_pwrscale_close(device);
- adreno_dispatcher_close(adreno_dev);
adreno_ringbuffer_close(&adreno_dev->ringbuffer);
kgsl_device_platform_remove(device);
@@ -1632,7 +1634,8 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
- kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ if (KGSL_STATE_DUMP_AND_FT != device->state)
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
/* Power up the device */
kgsl_pwrctrl_enable(device);
@@ -1702,15 +1705,13 @@
kgsl_cffdump_open(device);
- kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ if (KGSL_STATE_DUMP_AND_FT != device->state)
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
regulator_left_on = (regulator_is_enabled(device->pwrctrl.gpu_reg) ||
(device->pwrctrl.gpu_cx &&
regulator_is_enabled(device->pwrctrl.gpu_cx)));
- /* Clear any GPU faults that might have been left over */
- adreno_set_gpu_fault(adreno_dev, 0);
-
/* Power up the device */
kgsl_pwrctrl_enable(device);
@@ -1756,10 +1757,10 @@
if (status)
goto error_irq_off;
- adreno_perfcounter_start(adreno_dev);
+ mod_timer(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
- /* Start the dispatcher */
- adreno_dispatcher_start(adreno_dev);
+ adreno_perfcounter_start(adreno_dev);
device->reset_counter++;
@@ -1790,7 +1791,6 @@
adreno_dev->drawctxt_active = NULL;
- adreno_dispatcher_stop(adreno_dev);
adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
kgsl_mmu_stop(&device->mmu);
@@ -1798,6 +1798,7 @@
device->ftbl->irqctrl(device, 0);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
del_timer_sync(&device->idle_timer);
+ del_timer_sync(&device->hang_timer);
adreno_ocmem_gmem_free(adreno_dev);
@@ -1809,48 +1810,918 @@
return 0;
}
-/**
- * adreno_reset() - Helper function to reset the GPU
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Try to reset the GPU to recover from a fault. First, try to do a low latency
- * soft reset. If the soft reset fails for some reason, then bring out the big
- * guns and toggle the footswitch.
+/*
+ * Set the reset status of all contexts to
+ * INNOCENT_CONTEXT_RESET_EXT except for the bad context
+ * since thats the guilty party, if fault tolerance failed then
+ * mark all as guilty
*/
-int adreno_reset(struct kgsl_device *device)
+
+static int _mark_context_status(int id, void *ptr, void *data)
+{
+ unsigned int ft_status = *((unsigned int *) data);
+ struct kgsl_context *context = ptr;
+ struct adreno_context *adreno_context = ADRENO_CONTEXT(context);
+
+ if (ft_status) {
+ context->reset_status =
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+ } else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
+ context->reset_status) {
+ if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG |
+ CTXT_FLAGS_GPU_HANG_FT))
+ context->reset_status =
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ else
+ context->reset_status =
+ KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
+ }
+
+ return 0;
+}
+
+static void adreno_mark_context_status(struct kgsl_device *device,
+ int ft_status)
+{
+ /* Mark the status for all the contexts in the device */
+
+ read_lock(&device->context_lock);
+ idr_for_each(&device->context_idr, _mark_context_status, &ft_status);
+ read_unlock(&device->context_lock);
+}
+
+/*
+ * For hung contexts set the current memstore value to the most recent issued
+ * timestamp - this resets the status and lets the system continue on
+ */
+
+static int _set_max_ts(int id, void *ptr, void *data)
+{
+ struct kgsl_device *device = data;
+ struct kgsl_context *context = ptr;
+ struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
+
+ if (drawctxt && drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(context->id,
+ soptimestamp), drawctxt->timestamp);
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(context->id,
+ eoptimestamp), drawctxt->timestamp);
+ }
+
+ return 0;
+}
+
+static void adreno_set_max_ts_for_bad_ctxs(struct kgsl_device *device)
+{
+ read_lock(&device->context_lock);
+ idr_for_each(&device->context_idr, _set_max_ts, device);
+ read_unlock(&device->context_lock);
+}
+
+static void adreno_destroy_ft_data(struct adreno_ft_data *ft_data)
+{
+ vfree(ft_data->rb_buffer);
+ vfree(ft_data->bad_rb_buffer);
+ vfree(ft_data->good_rb_buffer);
+}
+
+static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
+ unsigned int *ptr,
+ bool inc)
+{
+ int status = -EINVAL;
+ unsigned int val1;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int start_ptr = *ptr;
+
+ while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
+ if (inc)
+ start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
+ size);
+ else
+ start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
+ size);
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
+ /* Ensure above read is finished before next read */
+ rmb();
+ if (KGSL_CMD_IDENTIFIER == val1) {
+ if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
+ start_ptr = adreno_ringbuffer_dec_wrapped(
+ start_ptr, size);
+ *ptr = start_ptr;
+ status = 0;
+ break;
+ }
+ }
+ return status;
+}
+
+static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
+ unsigned int *rb_rptr,
+ unsigned int global_eop,
+ bool inc)
+{
+ int status = -EINVAL;
+ unsigned int temp_rb_rptr = *rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[3];
+ int i = 0;
+ bool check = false;
+
+ if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
+ return status;
+
+ do {
+ /*
+ * when decrementing we need to decrement first and
+ * then read make sure we cover all the data
+ */
+ if (!inc)
+ temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+ temp_rb_rptr, size);
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
+ temp_rb_rptr);
+ /* Ensure above read is finished before next read */
+ rmb();
+
+ if (check && ((inc && val[i] == global_eop) ||
+ (!inc && (val[i] ==
+ cp_type3_packet(CP_MEM_WRITE, 2) ||
+ val[i] == CACHE_FLUSH_TS)))) {
+ /* decrement i, i.e i = (i - 1 + 3) % 3 if
+ * we are going forward, else increment i */
+ i = (i + 2) % 3;
+ if (val[i] == rb->device->memstore.gpuaddr +
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)) {
+ int j = ((i + 2) % 3);
+ if ((inc && (val[j] == CACHE_FLUSH_TS ||
+ val[j] == cp_type3_packet(
+ CP_MEM_WRITE, 2))) ||
+ (!inc && val[j] == global_eop)) {
+ /* Found the global eop */
+ status = 0;
+ break;
+ }
+ }
+ /* if no match found then increment i again
+ * since we decremented before matching */
+ i = (i + 1) % 3;
+ }
+ if (inc)
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
+ temp_rb_rptr, size);
+
+ i = (i + 1) % 3;
+ if (2 == i)
+ check = true;
+ } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
+ /* temp_rb_rptr points to the command stream after global eop,
+ * move backward till the start of command sequence */
+ if (!status) {
+ status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
+ if (!status) {
+ *rb_rptr = temp_rb_rptr;
+ KGSL_FT_INFO(rb->device,
+ "Offset of cmd sequence after eop timestamp: 0x%x\n",
+ temp_rb_rptr / sizeof(unsigned int));
+ }
+ }
+ if (status)
+ KGSL_FT_ERR(rb->device,
+ "Failed to find the command sequence after eop timestamp %x\n",
+ global_eop);
+ return status;
+}
+
+static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
+ unsigned int *rb_rptr,
+ unsigned int ib1)
+{
+ int status = -EINVAL;
+ unsigned int temp_rb_rptr = *rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[2];
+ int i = 0;
+ bool check = false;
+ bool ctx_switch = false;
+
+ while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+ /* Ensure above read is finished before next read */
+ rmb();
+
+ if (check && val[i] == ib1) {
+ /* decrement i, i.e i = (i - 1 + 2) % 2 */
+ i = (i + 1) % 2;
+ if (adreno_cmd_is_ib(val[i])) {
+ /* go till start of command sequence */
+ status = _find_start_of_cmd_seq(rb,
+ &temp_rb_rptr, false);
+
+ KGSL_FT_INFO(rb->device,
+ "Found the hanging IB at offset 0x%x\n",
+ temp_rb_rptr / sizeof(unsigned int));
+ break;
+ }
+ /* if no match the increment i since we decremented
+ * before checking */
+ i = (i + 1) % 2;
+ }
+ /* Make sure you do not encounter a context switch twice, we can
+ * encounter it once for the bad context as the start of search
+ * can point to the context switch */
+ if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+ if (ctx_switch) {
+ KGSL_FT_ERR(rb->device,
+ "Context switch encountered before bad "
+ "IB found\n");
+ break;
+ }
+ ctx_switch = true;
+ }
+ i = (i + 1) % 2;
+ if (1 == i)
+ check = true;
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+ size);
+ }
+ if (!status)
+ *rb_rptr = temp_rb_rptr;
+ return status;
+}
+
+static void adreno_setup_ft_data(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
{
int ret = 0;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_context *context;
+ struct adreno_context *adreno_context;
+ unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
- /* Try soft reset first */
- if (adreno_soft_reset(device) != 0) {
+ memset(ft_data, 0, sizeof(*ft_data));
+ ft_data->start_of_replay_cmds = 0xFFFFFFFF;
+ ft_data->replay_for_snapshot = 0xFFFFFFFF;
+
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ft_data->ib1);
+
+ kgsl_sharedmem_readl(&device->memstore, &ft_data->context_id,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ current_context));
+
+ kgsl_sharedmem_readl(&device->memstore,
+ &ft_data->global_eop,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
+
+ /* Ensure context id and global eop ts read complete */
+ rmb();
+
+ ft_data->rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!ft_data->rb_buffer) {
+ KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+ rb->buffer_desc.size);
+ return;
+ }
+
+ ft_data->bad_rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!ft_data->bad_rb_buffer) {
+ KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+ rb->buffer_desc.size);
+ return;
+ }
+
+ ft_data->good_rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!ft_data->good_rb_buffer) {
+ KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+ rb->buffer_desc.size);
+ return;
+ }
+ ft_data->status = 0;
+
+ /* find the start of bad command sequence in rb */
+ context = kgsl_context_get(device, ft_data->context_id);
+
+ ft_data->ft_policy = adreno_dev->ft_policy;
+
+ if (!ft_data->ft_policy)
+ ft_data->ft_policy = KGSL_FT_DEFAULT_POLICY;
+
+ /* Look for the command stream that is right after the global eop */
+ ret = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
+ ft_data->global_eop + 1, false);
+ if (ret) {
+ ft_data->ft_policy |= KGSL_FT_TEMP_DISABLE;
+ goto done;
+ } else {
+ ft_data->start_of_replay_cmds = rb_rptr;
+ ft_data->ft_policy &= ~KGSL_FT_TEMP_DISABLE;
+ }
+
+ if (context) {
+ adreno_context = ADRENO_CONTEXT(context);
+ if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
+ if (ft_data->ib1) {
+ ret = _find_hanging_ib_sequence(rb,
+ &rb_rptr, ft_data->ib1);
+ if (ret) {
+ KGSL_FT_ERR(device,
+ "Start not found for replay IB seq\n");
+ goto done;
+ }
+ ft_data->start_of_replay_cmds = rb_rptr;
+ ft_data->replay_for_snapshot = rb_rptr;
+ }
+ }
+ }
+
+done:
+ kgsl_context_put(context);
+}
+
+static int
+_adreno_check_long_ib(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ unsigned int curr_global_ts = 0;
+
+ /* check if the global ts is still the same */
+ kgsl_sharedmem_readl(&device->memstore,
+ &curr_global_ts,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
+ /* Ensure above read is finished before long ib check */
+ rmb();
+
+ /* Mark long ib as handled */
+ adreno_dev->long_ib = 0;
+
+ if (curr_global_ts == adreno_dev->long_ib_ts) {
+ KGSL_FT_ERR(device,
+ "IB ran too long, invalidate ctxt\n");
+ return 1;
+ } else {
+ /* Do nothing GPU has gone ahead */
+ KGSL_FT_INFO(device, "false long ib detection return\n");
+ return 0;
+ }
+}
+
+/**
+ * adreno_soft_reset() - Do a soft reset of the GPU hardware
+ * @device: KGSL device to soft reset
+ *
+ * "soft reset" the GPU hardware - this is a fast path GPU reset
+ * The GPU hardware is reset but we never pull power so we can skip
+ * a lot of the standard adreno_stop/adreno_start sequence
+ */
+int adreno_soft_reset(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ int ret;
+
+ /* If the jump table index is 0 soft reset is not supported */
+ if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
+ dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
+ return -EINVAL;
+ }
+
+ if (adreno_dev->drawctxt_active)
+ kgsl_context_put(&adreno_dev->drawctxt_active->base);
+
+ adreno_dev->drawctxt_active = NULL;
+
+ /* Stop the ringbuffer */
+ adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
+
+ /* Delete the idle timer */
+ del_timer_sync(&device->idle_timer);
+
+ /* Make sure we are totally awake */
+ kgsl_pwrctrl_enable(device);
+
+ /* Reset the GPU */
+ adreno_dev->gpudev->soft_reset(adreno_dev);
+
+ /* Reinitialize the GPU */
+ adreno_dev->gpudev->start(adreno_dev);
+
+ /* Enable IRQ */
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+ device->ftbl->irqctrl(device, 1);
+
+ /*
+ * Restart the ringbuffer - we can go down the warm start path because
+ * power was never yanked
+ */
+ ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+ if (ret)
+ return ret;
+
+ device->reset_counter++;
+
+ return 0;
+}
+
+static int
+_adreno_ft_restart_device(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ /* If device soft reset fails try hard reset */
+ if (adreno_soft_reset(device))
KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
+ else
+ /* Soft reset is successful */
+ goto reset_done;
- /* If it failed, then pull the power */
- ret = adreno_stop(device);
- if (ret)
- return ret;
+ /* restart device */
+ if (adreno_stop(device)) {
+ KGSL_FT_ERR(device, "Device stop failed\n");
+ return 1;
+ }
- ret = adreno_start(device);
+ if (adreno_init(device)) {
+ KGSL_FT_ERR(device, "Device init failed\n");
+ return 1;
+ }
- if (ret)
- return ret;
+ if (adreno_start(device)) {
+ KGSL_FT_ERR(device, "Device start failed\n");
+ return 1;
+ }
+
+reset_done:
+ if (context)
+ kgsl_mmu_setstate(&device->mmu, context->pagetable,
+ KGSL_MEMSTORE_GLOBAL);
+
+ /* If iommu is used then we need to make sure that the iommu clocks
+ * are on since there could be commands in pipeline that touch iommu */
+ if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
+ if (kgsl_mmu_enable_clk(&device->mmu,
+ KGSL_IOMMU_CONTEXT_USER))
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline void
+_adreno_debug_ft_info(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
+{
+
+ /*
+ * Dumping rb is a very useful tool to debug FT.
+ * It will tell us if we are extracting the rb correctly
+ * NOP'ing the right IB, skipping the EOF correctly etc.
+ */
+ if (device->ft_log >= 7) {
+
+ /* Print fault tolerance data here */
+ KGSL_FT_INFO(device, "Temp RB buffer size 0x%X\n",
+ ft_data->rb_size);
+ adreno_dump_rb(device, ft_data->rb_buffer,
+ ft_data->rb_size<<2, 0, ft_data->rb_size);
+
+ KGSL_FT_INFO(device, "Bad RB buffer size 0x%X\n",
+ ft_data->bad_rb_size);
+ adreno_dump_rb(device, ft_data->bad_rb_buffer,
+ ft_data->bad_rb_size<<2, 0, ft_data->bad_rb_size);
+
+ KGSL_FT_INFO(device, "Good RB buffer size 0x%X\n",
+ ft_data->good_rb_size);
+ adreno_dump_rb(device, ft_data->good_rb_buffer,
+ ft_data->good_rb_size<<2, 0, ft_data->good_rb_size);
+
+ }
+}
+
+static int
+_adreno_ft_resubmit_rb(struct kgsl_device *device,
+ struct adreno_ringbuffer *rb,
+ struct kgsl_context *context,
+ struct adreno_ft_data *ft_data,
+ unsigned int *buff, unsigned int size)
+{
+ unsigned int ret = 0;
+ unsigned int retry_num = 0;
+
+ _adreno_debug_ft_info(device, ft_data);
+
+ do {
+ ret = _adreno_ft_restart_device(device, context);
+ if (ret == 0)
+ break;
+ /*
+ * If device restart fails sleep for 20ms before
+ * attempting restart. This allows GPU HW to settle
+ * and improve the chances of next restart to be
+ * successful.
+ */
+ msleep(20);
+ KGSL_FT_ERR(device, "Retry device restart %d\n", retry_num);
+ retry_num++;
+ } while (retry_num < 4);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "Device restart failed\n");
+ BUG_ON(1);
+ goto done;
+ }
+
+ if (size) {
+
+ /* submit commands and wait for them to pass */
+ adreno_ringbuffer_restore(rb, buff, size);
+
+ ret = adreno_idle(device);
+ }
+
+done:
+ return ret;
+}
+
+
+static int
+_adreno_ft(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
+{
+ int ret = 0, i;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_context *context;
+ struct adreno_context *adreno_context = NULL;
+ struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
+ unsigned int long_ib = 0;
+ static int no_context_ft;
+ struct kgsl_mmu *mmu = &device->mmu;
+
+ context = kgsl_context_get(device, ft_data->context_id);
+
+ if (context == NULL) {
+ KGSL_FT_ERR(device, "Last context unknown id:%d\n",
+ ft_data->context_id);
+ if (no_context_ft) {
+ /*
+ * If 2 consecutive no context ft occurred then
+ * just reset GPU
+ */
+ no_context_ft = 0;
+ goto play_good_cmds;
+ }
+ } else {
+ no_context_ft = 0;
+ adreno_context = ADRENO_CONTEXT(context);
+ adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+ /*
+ * set the invalid ts flag to 0 for this context since we have
+ * detected a hang for it
+ */
+ context->wait_on_invalid_ts = false;
+
+ if (!(adreno_context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) {
+ ft_data->status = 1;
+ KGSL_FT_ERR(device, "Fault tolerance not supported\n");
+ goto play_good_cmds;
+ }
+
+ /*
+ * This flag will be set by userspace for contexts
+ * that do not want to be fault tolerant (ex: OPENCL)
+ */
+ if (adreno_context->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE) {
+ ft_data->status = 1;
+ KGSL_FT_ERR(device,
+ "No FT set for this context play good cmds\n");
+ goto play_good_cmds;
+ }
+
+ }
+
+ /* Check if we detected a long running IB, if false return */
+ if ((adreno_context) && (adreno_dev->long_ib)) {
+ long_ib = _adreno_check_long_ib(device);
+ if (!long_ib) {
+ adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG;
+ return 0;
+ }
}
/*
- * If active_cnt is non-zero then the system was active before
- * going into a reset - put it back in that state
+ * Extract valid contents from rb which can still be executed after
+ * hang
*/
+ adreno_ringbuffer_extract(rb, ft_data);
- if (atomic_read(&device->active_cnt))
- kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ /* If long IB detected do not attempt replay of bad cmds */
+ if (long_ib) {
+ ft_data->status = 1;
+ _adreno_debug_ft_info(device, ft_data);
+ goto play_good_cmds;
+ }
- /* Set the page table back to the default page table */
- kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
- KGSL_MEMSTORE_GLOBAL);
+ if ((ft_data->ft_policy & KGSL_FT_DISABLE) ||
+ (ft_data->ft_policy & KGSL_FT_TEMP_DISABLE)) {
+ KGSL_FT_ERR(device, "NO FT policy play only good cmds\n");
+ ft_data->status = 1;
+ goto play_good_cmds;
+ }
+ /* Do not try to replay if hang is due to a pagefault */
+ if (context && test_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv)) {
+ /* Resume MMU */
+ mmu->mmu_ops->mmu_pagefault_resume(mmu);
+ if ((ft_data->context_id == context->id) &&
+ (ft_data->global_eop == context->pagefault_ts)) {
+ ft_data->ft_policy &= ~KGSL_FT_REPLAY;
+ KGSL_FT_ERR(device, "MMU fault skipping replay\n");
+ }
+ clear_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv);
+ }
+
+ if (ft_data->ft_policy & KGSL_FT_REPLAY) {
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "Replay status: 1\n");
+ ft_data->status = 1;
+ } else
+ goto play_good_cmds;
+ }
+
+ if (ft_data->ft_policy & KGSL_FT_SKIPIB) {
+ for (i = 0; i < ft_data->bad_rb_size; i++) {
+ if ((ft_data->bad_rb_buffer[i] ==
+ CP_HDR_INDIRECT_BUFFER_PFD) &&
+ (ft_data->bad_rb_buffer[i+1] == ft_data->ib1)) {
+
+ ft_data->bad_rb_buffer[i] = cp_nop_packet(2);
+ ft_data->bad_rb_buffer[i+1] =
+ KGSL_NOP_IB_IDENTIFIER;
+ ft_data->bad_rb_buffer[i+2] =
+ KGSL_NOP_IB_IDENTIFIER;
+ break;
+ }
+ }
+
+ if ((i == (ft_data->bad_rb_size)) || (!ft_data->ib1)) {
+ KGSL_FT_ERR(device, "Bad IB to NOP not found\n");
+ ft_data->status = 1;
+ goto play_good_cmds;
+ }
+
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "NOP faulty IB status: 1\n");
+ ft_data->status = 1;
+ } else {
+ ft_data->status = 0;
+ goto play_good_cmds;
+ }
+ }
+
+ if (ft_data->ft_policy & KGSL_FT_SKIPFRAME) {
+ for (i = 0; i < ft_data->bad_rb_size; i++) {
+ if (ft_data->bad_rb_buffer[i] ==
+ KGSL_END_OF_FRAME_IDENTIFIER) {
+ ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+ break;
+ }
+ }
+
+ /* EOF not found in RB, discard till EOF in
+ next IB submission */
+ if (adreno_context && (i == ft_data->bad_rb_size)) {
+ adreno_context->flags |= CTXT_FLAGS_SKIP_EOF;
+ KGSL_FT_INFO(device,
+ "EOF not found in RB, skip next issueib till EOF\n");
+ ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+ }
+
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "Skip EOF status: 1\n");
+ ft_data->status = 1;
+ } else {
+ ft_data->status = 0;
+ goto play_good_cmds;
+ }
+ }
+
+play_good_cmds:
+
+ if (ft_data->status)
+ KGSL_FT_ERR(device, "Bad context commands failed\n");
+ else {
+ KGSL_FT_INFO(device, "Bad context commands success\n");
+
+ if (adreno_context) {
+ adreno_context->flags = (adreno_context->flags &
+ ~CTXT_FLAGS_GPU_HANG) | CTXT_FLAGS_GPU_HANG_FT;
+ }
+
+ if (last_active_ctx)
+ _kgsl_context_get(&last_active_ctx->base);
+
+ adreno_dev->drawctxt_active = last_active_ctx;
+ }
+
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->good_rb_buffer, ft_data->good_rb_size);
+
+ if (ret) {
+ /*
+ * If we fail here we can try to invalidate another
+ * context and try fault tolerance again, although
+ * we will only try ft with no context once to avoid
+ * going into continuous loop of trying ft with no context
+ */
+ if (!context)
+ no_context_ft = 1;
+ ret = -EAGAIN;
+ KGSL_FT_ERR(device, "Playing good commands unsuccessful\n");
+ goto done;
+ } else
+ KGSL_FT_INFO(device, "Playing good commands successful\n");
+
+ /* ringbuffer now has data from the last valid context id,
+ * so restore the active_ctx to the last valid context */
+ if (ft_data->last_valid_ctx_id) {
+ struct kgsl_context *last_ctx = kgsl_context_get(device,
+ ft_data->last_valid_ctx_id);
+
+ adreno_dev->drawctxt_active = ADRENO_CONTEXT(last_ctx);
+ }
+
+done:
+ /* Turn off iommu clocks */
+ if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+ kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
+ kgsl_context_put(context);
return ret;
}
+static int
+adreno_ft(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
+{
+ int ret = 0;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+
+ /*
+ * If GPU FT is turned off do not run FT.
+ * If GPU stall detection is suspected to be false,
+ * we can use this option to confirm stall detection.
+ */
+ if (ft_data->ft_policy & KGSL_FT_OFF) {
+ KGSL_FT_ERR(device, "GPU FT turned off\n");
+ return 0;
+ }
+
+ KGSL_FT_INFO(device,
+ "Start Parameters: IB1: 0x%X, "
+ "Bad context_id: %u, global_eop: 0x%x\n",
+ ft_data->ib1, ft_data->context_id, ft_data->global_eop);
+
+ KGSL_FT_INFO(device, "Last issued global timestamp: %x\n",
+ rb->global_ts);
+
+ /* We may need to replay commands multiple times based on whether
+ * multiple contexts hang the GPU */
+ while (true) {
+
+ ret = _adreno_ft(device, ft_data);
+
+ if (-EAGAIN == ret) {
+ /* setup new fault tolerance parameters and retry, this
+ * means more than 1 contexts are causing hang */
+ adreno_destroy_ft_data(ft_data);
+ adreno_setup_ft_data(device, ft_data);
+ KGSL_FT_INFO(device,
+ "Retry. Parameters: "
+ "IB1: 0x%X, Bad context_id: %u, global_eop: 0x%x\n",
+ ft_data->ib1, ft_data->context_id,
+ ft_data->global_eop);
+ } else {
+ break;
+ }
+ }
+
+ if (ret)
+ goto done;
+
+ /* Restore correct states after fault tolerance */
+ if (adreno_dev->drawctxt_active)
+ device->mmu.hwpagetable =
+ adreno_dev->drawctxt_active->base.pagetable;
+ else
+ device->mmu.hwpagetable = device->mmu.defaultpagetable;
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp), rb->global_ts);
+
+ /* switch to NULL ctxt */
+ if (adreno_dev->drawctxt_active != NULL)
+ adreno_drawctxt_switch(adreno_dev, NULL, 0);
+
+done:
+ adreno_set_max_ts_for_bad_ctxs(device);
+ adreno_mark_context_status(device, ret);
+ KGSL_FT_ERR(device, "policy 0x%X status 0x%x\n",
+ ft_data->ft_policy, ret);
+ return ret;
+}
+
+int
+adreno_dump_and_exec_ft(struct kgsl_device *device)
+{
+ int result = -ETIMEDOUT;
+ struct adreno_ft_data ft_data;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ unsigned int curr_pwrlevel;
+
+ if (device->state == KGSL_STATE_HUNG)
+ goto done;
+ if (device->state == KGSL_STATE_DUMP_AND_FT) {
+ mutex_unlock(&device->mutex);
+ wait_for_completion(&device->ft_gate);
+ mutex_lock(&device->mutex);
+ if (device->state != KGSL_STATE_HUNG)
+ result = 0;
+ } else {
+ /*
+ * While fault tolerance is happening we do not want the
+ * idle_timer to fire and attempt to change any device state
+ */
+ del_timer_sync(&device->idle_timer);
+
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_FT);
+ INIT_COMPLETION(device->ft_gate);
+ /* Detected a hang */
+
+ kgsl_cffdump_hang(device);
+ /* Run fault tolerance at max power level */
+ curr_pwrlevel = pwr->active_pwrlevel;
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
+
+ /* Get the fault tolerance data as soon as hang is detected */
+ adreno_setup_ft_data(device, &ft_data);
+
+ /*
+ * If long ib is detected, do not attempt postmortem or
+ * snapshot, if GPU is still executing commands
+ * we will get errors
+ */
+ if (!adreno_dev->long_ib) {
+ /*
+ * Trigger an automatic dump of the state to
+ * the console
+ */
+ kgsl_postmortem_dump(device, 0);
+
+ /*
+ * Make a GPU snapshot. For now, do it after the
+ * PM dump so we can at least be sure the PM dump
+ * will work as it always has
+ */
+ kgsl_device_snapshot(device, 1);
+ }
+
+ result = adreno_ft(device, &ft_data);
+ adreno_destroy_ft_data(&ft_data);
+
+ /* restore power level */
+ kgsl_pwrctrl_pwrlevel_change(device, curr_pwrlevel);
+
+ if (result) {
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
+ } else {
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ mod_timer(&device->hang_timer,
+ (jiffies +
+ msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+ }
+ complete_all(&device->ft_gate);
+ }
+done:
+ return result;
+}
+EXPORT_SYMBOL(adreno_dump_and_exec_ft);
+
/**
* _ft_sysfs_store() - Common routine to write to FT sysfs files
* @buf: value to write
@@ -2248,185 +3119,140 @@
return status;
}
-/**
- * adreno_hw_isidle() - Check if the GPU core is idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Return true if the RBBM status register for the GPU type indicates that the
- * hardware is idle
- */
-static bool adreno_hw_isidle(struct kgsl_device *device)
-{
- unsigned int reg_rbbm_status;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
- /* Don't consider ourselves idle if there is an IRQ pending */
- if (adreno_dev->gpudev->irq_pending(adreno_dev))
- return false;
-
- adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
- ®_rbbm_status);
-
- if (adreno_is_a2xx(adreno_dev)) {
- if (reg_rbbm_status == 0x110)
- return true;
- } else if (adreno_is_a3xx(adreno_dev)) {
- if (!(reg_rbbm_status & 0x80000000))
- return true;
- }
-
- return false;
-}
-
-/**
- * adreno_soft_reset() - Do a soft reset of the GPU hardware
- * @device: KGSL device to soft reset
- *
- * "soft reset" the GPU hardware - this is a fast path GPU reset
- * The GPU hardware is reset but we never pull power so we can skip
- * a lot of the standard adreno_stop/adreno_start sequence
- */
-int adreno_soft_reset(struct kgsl_device *device)
+static int adreno_ringbuffer_drain(struct kgsl_device *device,
+ unsigned int *regs)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- int ret;
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ unsigned long wait = jiffies;
+ unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+ unsigned int rptr;
- if (!adreno_dev->gpudev->soft_reset) {
- dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
- return -EINVAL;
- }
+ do {
+ /*
+ * Wait is "jiffies" first time in the loop to start
+ * GPU stall detection immediately.
+ */
+ if (time_after(jiffies, wait)) {
+ /* Check to see if the core is hung */
+ if (adreno_ft_detect(device, regs))
+ return -ETIMEDOUT;
- if (adreno_dev->drawctxt_active)
- kgsl_context_put(&adreno_dev->drawctxt_active->base);
-
- adreno_dev->drawctxt_active = NULL;
-
- /* Stop the ringbuffer */
- adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
-
- if (kgsl_pwrctrl_isenabled(device))
- device->ftbl->irqctrl(device, 0);
-
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
- adreno_set_gpu_fault(adreno_dev, 0);
-
- /* Delete the idle timer */
- del_timer_sync(&device->idle_timer);
-
- /* Make sure we are totally awake */
- kgsl_pwrctrl_enable(device);
-
- /* Reset the GPU */
- adreno_dev->gpudev->soft_reset(adreno_dev);
-
- /* Reinitialize the GPU */
- adreno_dev->gpudev->start(adreno_dev);
-
- /* Enable IRQ */
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
- device->ftbl->irqctrl(device, 1);
-
- /*
- * If we have offsets for the jump tables we can try to do a warm start,
- * otherwise do a full ringbuffer restart
- */
-
- if (adreno_dev->pm4_jt_idx)
- ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
- else
- ret = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
-
- if (ret)
- return ret;
-
- device->reset_counter++;
+ wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+ }
+ rptr = adreno_get_rptr(rb);
+ if (time_after(jiffies, timeout)) {
+ KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
+ rptr, rb->wptr);
+ return -ETIMEDOUT;
+ }
+ } while (rptr != rb->wptr);
return 0;
}
-/*
- * adreno_isidle() - return true if the GPU hardware is idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Return true if the GPU hardware is idle and there are no commands pending in
- * the ringbuffer
- */
-bool adreno_isidle(struct kgsl_device *device)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int rptr;
-
- if (!kgsl_pwrctrl_isenabled(device))
- return true;
-
- rptr = adreno_get_rptr(&adreno_dev->ringbuffer);
-
- if (rptr == adreno_dev->ringbuffer.wptr)
- return adreno_hw_isidle(device);
-
- return false;
-}
-
-/**
- * adreno_idle() - wait for the GPU hardware to go idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Wait up to ADRENO_IDLE_TIMEOUT milliseconds for the GPU hardware to go quiet.
- */
-
+/* Caller must hold the device mutex. */
int adreno_idle(struct kgsl_device *device)
{
+ unsigned long wait_time;
+ unsigned long wait_time_part;
+ unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned long wait = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
- /*
- * Make sure the device mutex is held so the dispatcher can't send any
- * more commands to the hardware
- */
+ memset(prev_reg_val, 0, sizeof(prev_reg_val));
- BUG_ON(!mutex_is_locked(&device->mutex));
+ kgsl_cffdump_regpoll(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
+ 0x00000000, 0x80000000);
- if (adreno_is_a3xx(adreno_dev))
- kgsl_cffdump_regpoll(device,
- adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
- 0x00000000, 0x80000000);
- else
- kgsl_cffdump_regpoll(device,
- adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
- 0x110, 0x110);
+retry:
+ /* First, wait for the ringbuffer to drain */
+ if (adreno_ringbuffer_drain(device, prev_reg_val))
+ goto err;
- while (time_before(jiffies, wait)) {
- /*
- * If we fault, stop waiting and return an error. The dispatcher
- * will clean up the fault from the work queue, but we need to
- * make sure we don't block it by waiting for an idle that
- * will never come.
- */
+ /* now, wait for the GPU to finish its operations */
+ wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+ wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
- if (adreno_gpu_fault(adreno_dev) != 0)
- return -EDEADLK;
-
+ while (time_before(jiffies, wait_time)) {
if (adreno_isidle(device))
return 0;
+
+ /* Dont wait for timeout, detect hang faster. */
+ if (time_after(jiffies, wait_time_part)) {
+ wait_time_part = jiffies +
+ msecs_to_jiffies(KGSL_TIMEOUT_PART);
+ if ((adreno_ft_detect(device, prev_reg_val)))
+ goto err;
+ }
+
}
+err:
+ KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
+ if (KGSL_STATE_DUMP_AND_FT != device->state &&
+ !adreno_dump_and_exec_ft(device)) {
+ wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+ goto retry;
+ }
return -ETIMEDOUT;
}
/**
- * adreno_drain() - Drain the dispatch queue
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Tell the dispatcher to pause - this has the effect of draining the inflight
- * command batches
+ * is_adreno_rbbm_status_idle - Check if GPU core is idle by probing
+ * rbbm_status register
+ * @device - Pointer to the GPU device whose idle status is to be
+ * checked
+ * @returns - Returns whether the core is idle (based on rbbm_status)
+ * false if the core is active, true if the core is idle
*/
-static int adreno_drain(struct kgsl_device *device)
+static bool is_adreno_rbbm_status_idle(struct kgsl_device *device)
{
+ unsigned int reg_rbbm_status;
+ bool status = false;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- adreno_dispatcher_pause(adreno_dev);
- return 0;
+ /* Is the core idle? */
+ adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
+ ®_rbbm_status);
+
+ if (adreno_is_a2xx(adreno_dev)) {
+ if (reg_rbbm_status == 0x110)
+ status = true;
+ } else {
+ if (!(reg_rbbm_status & 0x80000000))
+ status = true;
+ }
+ return status;
+}
+
+static unsigned int adreno_isidle(struct kgsl_device *device)
+{
+ int status = false;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+
+ /* If the device isn't active, don't force it on. */
+ if (kgsl_pwrctrl_isenabled(device)) {
+ /* Is the ring buffer is empty? */
+ unsigned int rptr = adreno_get_rptr(rb);
+ if (rptr == rb->wptr) {
+ /*
+ * Are there interrupts pending? If so then pretend we
+ * are not idle - this avoids the possiblity that we go
+ * to a lower power state without handling interrupts
+ * first.
+ */
+
+ if (!adreno_dev->gpudev->irq_pending(adreno_dev)) {
+ /* Is the core idle? */
+ status = is_adreno_rbbm_status_idle(device);
+ }
+ }
+ } else {
+ status = true;
+ }
+ return status;
}
/* Caller must hold the device mutex. */
@@ -2597,6 +3423,342 @@
__raw_writel(value, reg);
}
+static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
+{
+ unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
+
+ if (k_ctxt != NULL) {
+ struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
+ if (kgsl_context_detached(k_ctxt))
+ context_id = KGSL_CONTEXT_INVALID;
+ else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+ context_id = k_ctxt->id;
+ }
+
+ return context_id;
+}
+
+static unsigned int adreno_check_hw_ts(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
+{
+ int status = 0;
+ unsigned int ref_ts, enableflag;
+ unsigned int context_id = _get_context_id(context);
+
+ /*
+ * If the context ID is invalid, we are in a race with
+ * the context being destroyed by userspace so bail.
+ */
+ if (context_id == KGSL_CONTEXT_INVALID) {
+ KGSL_DRV_WARN(device, "context was detached");
+ return -EINVAL;
+ }
+
+ status = kgsl_check_timestamp(device, context, timestamp);
+ if (status)
+ return status;
+
+ kgsl_sharedmem_readl(&device->memstore, &enableflag,
+ KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
+ /*
+ * Barrier is needed here to make sure the read from memstore
+ * has posted
+ */
+
+ mb();
+
+ if (enableflag) {
+ kgsl_sharedmem_readl(&device->memstore, &ref_ts,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts));
+
+ /* Make sure the memstore read has posted */
+ mb();
+ if (timestamp_cmp(ref_ts, timestamp) >= 0) {
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts), timestamp);
+ /* Make sure the memstore write is posted */
+ wmb();
+ }
+ } else {
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts), timestamp);
+ enableflag = 1;
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ts_cmp_enable), enableflag);
+
+ /* Make sure the memstore write gets posted */
+ wmb();
+
+ /*
+ * submit a dummy packet so that even if all
+ * commands upto timestamp get executed we will still
+ * get an interrupt
+ */
+
+ if (context && device->state != KGSL_STATE_SLUMBER) {
+ adreno_ringbuffer_issuecmds(device,
+ ADRENO_CONTEXT(context),
+ KGSL_CMD_FLAGS_GET_INT, NULL, 0);
+ }
+ }
+
+ return 0;
+}
+
+/* Return 1 if the event timestmp has already passed, 0 if it was marked */
+static int adreno_next_event(struct kgsl_device *device,
+ struct kgsl_event *event)
+{
+ return adreno_check_hw_ts(device, event->context, event->timestamp);
+}
+
+static int adreno_check_interrupt_timestamp(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
+{
+ int status;
+
+ mutex_lock(&device->mutex);
+ status = adreno_check_hw_ts(device, context, timestamp);
+ mutex_unlock(&device->mutex);
+
+ return status;
+}
+
+/*
+ wait_event_interruptible_timeout checks for the exit condition before
+ placing a process in wait q. For conditional interrupts we expect the
+ process to already be in its wait q when its exit condition checking
+ function is called.
+*/
+#define kgsl_wait_event_interruptible_timeout(wq, condition, timeout, io)\
+({ \
+ long __ret = timeout; \
+ if (io) \
+ __wait_io_event_interruptible_timeout(wq, condition, __ret);\
+ else \
+ __wait_event_interruptible_timeout(wq, condition, __ret);\
+ __ret; \
+})
+
+
+
+unsigned int adreno_ft_detect(struct kgsl_device *device,
+ unsigned int *prev_reg_val)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ unsigned int curr_reg_val[FT_DETECT_REGS_COUNT];
+ unsigned int fast_hang_detected = 1;
+ unsigned int long_ib_detected = 1;
+ unsigned int i;
+ static unsigned long next_hang_detect_time;
+ static unsigned int prev_global_ts;
+ unsigned int curr_global_ts = 0;
+ unsigned int curr_context_id = 0;
+ static struct adreno_context *curr_context;
+ static struct kgsl_context *context;
+ static char pid_name[TASK_COMM_LEN] = "unknown";
+
+ if (!adreno_dev->fast_hang_detect)
+ fast_hang_detected = 0;
+
+ if (!adreno_dev->long_ib_detect)
+ long_ib_detected = 0;
+
+ if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED))
+ return 0;
+
+ if (is_adreno_rbbm_status_idle(device) &&
+ (kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED)
+ == rb->global_ts)) {
+
+ /*
+ * On A2XX if the RPTR != WPTR and the device is idle, then
+ * the last write to WPTR probably failed to latch so write it
+ * again
+ */
+
+ if (adreno_is_a2xx(adreno_dev)) {
+ unsigned int rptr;
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
+ &rptr);
+ if (rptr != adreno_dev->ringbuffer.wptr)
+ adreno_writereg(adreno_dev,
+ ADRENO_REG_CP_RB_WPTR,
+ adreno_dev->ringbuffer.wptr);
+ }
+
+ return 0;
+ }
+
+ /*
+ * Time interval between hang detection should be KGSL_TIMEOUT_PART
+ * or more, if next hang detection is requested < KGSL_TIMEOUT_PART
+ * from the last time do nothing.
+ */
+ if ((next_hang_detect_time) &&
+ (time_before(jiffies, next_hang_detect_time)))
+ return 0;
+ else
+ next_hang_detect_time = (jiffies +
+ msecs_to_jiffies(KGSL_TIMEOUT_PART-1));
+
+ /* Read the current Hang detect reg values here */
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+ if (ft_detect_regs[i] == 0)
+ continue;
+ kgsl_regread(device, ft_detect_regs[i],
+ &curr_reg_val[i]);
+ }
+
+ /* Read the current global timestamp here */
+ kgsl_sharedmem_readl(&device->memstore,
+ &curr_global_ts,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
+ /* Make sure the memstore read has posted */
+ mb();
+
+ if (curr_global_ts == prev_global_ts) {
+
+ /* If we don't already have a good context, get it. */
+ if (kgsl_context_detached(context)) {
+ kgsl_context_put(context);
+ context = NULL;
+ curr_context = NULL;
+ strlcpy(pid_name, "unknown", sizeof(pid_name));
+
+ kgsl_sharedmem_readl(&device->memstore,
+ &curr_context_id,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ current_context));
+ /* Make sure the memstore read has posted */
+ mb();
+
+ context = kgsl_context_get(device, curr_context_id);
+ if (context != NULL) {
+ struct task_struct *task;
+ curr_context = ADRENO_CONTEXT(context);
+ curr_context->ib_gpu_time_used = 0;
+ task = find_task_by_vpid(context->pid);
+ if (task)
+ get_task_comm(pid_name, task);
+ } else {
+ KGSL_DRV_ERR(device,
+ "Fault tolerance no context found\n");
+ }
+ }
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+ if (curr_reg_val[i] != prev_reg_val[i]) {
+ fast_hang_detected = 0;
+
+ /* Check for long IB here */
+ if ((i >=
+ LONG_IB_DETECT_REG_INDEX_START)
+ &&
+ (i <=
+ LONG_IB_DETECT_REG_INDEX_END))
+ long_ib_detected = 0;
+ }
+ }
+
+ if (fast_hang_detected) {
+ KGSL_FT_ERR(device,
+ "Proc %s, ctxt_id %d ts %d triggered fault tolerance"
+ " on global ts %d\n",
+ pid_name, context ? context->id : 0,
+ (kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED) + 1),
+ curr_global_ts + 1);
+ return 1;
+ }
+
+ if (curr_context != NULL) {
+
+ curr_context->ib_gpu_time_used += KGSL_TIMEOUT_PART;
+ KGSL_FT_INFO(device,
+ "Proc %s used GPU Time %d ms on timestamp 0x%X\n",
+ pid_name, curr_context->ib_gpu_time_used,
+ curr_global_ts+1);
+
+ if ((long_ib_detected) &&
+ (!(curr_context->flags &
+ CTXT_FLAGS_NO_FAULT_TOLERANCE))) {
+ curr_context->ib_gpu_time_used +=
+ KGSL_TIMEOUT_PART;
+ if (curr_context->ib_gpu_time_used >
+ KGSL_TIMEOUT_LONG_IB_DETECTION) {
+ if (adreno_dev->long_ib_ts !=
+ curr_global_ts) {
+ KGSL_FT_ERR(device,
+ "Proc %s, ctxt_id %d ts %d"
+ "used GPU for %d ms long ib "
+ "detected on global ts %d\n",
+ pid_name, context->id,
+ (kgsl_readtimestamp(device,
+ context,
+ KGSL_TIMESTAMP_RETIRED)+1),
+ curr_context->ib_gpu_time_used,
+ curr_global_ts+1);
+ adreno_dev->long_ib = 1;
+ adreno_dev->long_ib_ts =
+ curr_global_ts;
+ curr_context->ib_gpu_time_used =
+ 0;
+ return 1;
+ }
+ }
+ }
+ }
+ } else {
+ /* GPU is moving forward */
+ prev_global_ts = curr_global_ts;
+ kgsl_context_put(context);
+ context = NULL;
+ curr_context = NULL;
+ strlcpy(pid_name, "unknown", sizeof(pid_name));
+ adreno_dev->long_ib = 0;
+ adreno_dev->long_ib_ts = 0;
+ }
+
+
+ /* If hangs are not detected copy the current reg values
+ * to previous values and return no hang */
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
+ prev_reg_val[i] = curr_reg_val[i];
+ return 0;
+}
+
+static int _check_pending_timestamp(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ unsigned int context_id = _get_context_id(context);
+ unsigned int ts_issued;
+
+ if (context_id == KGSL_CONTEXT_INVALID)
+ return -EINVAL;
+
+ ts_issued = adreno_context_timestamp(context, &adreno_dev->ringbuffer);
+
+ if (timestamp_cmp(timestamp, ts_issued) <= 0)
+ return 0;
+
+ if (context && !context->wait_on_invalid_ts) {
+ KGSL_DRV_ERR(device, "Cannot wait for invalid ts <%d:0x%x>, last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id, ts_issued);
+
+ /* Only print this message once */
+ context->wait_on_invalid_ts = true;
+ }
+
+ return -EINVAL;
+}
+
/**
* adreno_waittimestamp - sleep while waiting for the specified timestamp
* @device - pointer to a KGSL device structure
@@ -2604,35 +3766,147 @@
* @timestamp - GPU timestamp to wait for
* @msecs - amount of time to wait (in milliseconds)
*
- * Wait up to 'msecs' milliseconds for the specified timestamp to expire.
+ * Wait 'msecs' milliseconds for the specified timestamp to expire. Wake up
+ * every KGSL_TIMEOUT_PART milliseconds to check for a device hang and process
+ * one if it happened. Otherwise, spend most of our time in an interruptible
+ * wait for the timestamp interrupt to be processed. This function must be
+ * called with the mutex already held.
*/
static int adreno_waittimestamp(struct kgsl_device *device,
- struct kgsl_context *context,
- unsigned int timestamp,
- unsigned int msecs)
+ struct kgsl_context *context,
+ unsigned int timestamp,
+ unsigned int msecs)
{
- int ret;
- struct adreno_context *drawctxt;
+ static unsigned int io_cnt;
+ struct adreno_context *adreno_ctx = context ? ADRENO_CONTEXT(context) :
+ NULL;
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ unsigned int context_id = _get_context_id(context);
+ unsigned int time_elapsed = 0;
+ unsigned int wait;
+ int ts_compare = 1;
+ int io, ret = -ETIMEDOUT;
- if (context == NULL) {
- /* If they are doing then complain once */
- dev_WARN_ONCE(device->dev, 1,
- "IOCTL_KGSL_DEVICE_WAITTIMESTAMP is deprecated\n");
+ if (context_id == KGSL_CONTEXT_INVALID) {
+ KGSL_DRV_WARN(device, "context was detached");
return -EINVAL;
}
- /* Return -EINVAL if the context has been detached */
- if (kgsl_context_detached(context))
- return -EINVAL;
+ /*
+ * Check to see if the requested timestamp is "newer" then the last
+ * timestamp issued. If it is complain once and return error. Only
+ * print the message once per context so that badly behaving
+ * applications don't spam the logs
+ */
- ret = adreno_drawctxt_wait(ADRENO_DEVICE(device), context,
- timestamp, msecs_to_jiffies(msecs));
+ if (adreno_ctx && !(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+ if (_check_pending_timestamp(device, context, timestamp))
+ return -EINVAL;
- /* If the context got invalidated then return a specific error */
- drawctxt = ADRENO_CONTEXT(context);
+ /* Reset the invalid timestamp flag on a valid wait */
+ context->wait_on_invalid_ts = false;
+ }
- if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
- ret = -EDEADLK;
+ /*
+ * On the first time through the loop only wait 100ms.
+ * this gives enough time for the engine to start moving and oddly
+ * provides better hang detection results than just going the full
+ * KGSL_TIMEOUT_PART right off the bat. The exception to this rule
+ * is if msecs happens to be < 100ms then just use 20ms or the msecs,
+ * whichever is larger because anything less than 20 is unreliable
+ */
+
+ if (msecs == 0 || msecs >= 100)
+ wait = 100;
+ else
+ wait = (msecs > 20) ? msecs : 20;
+
+ do {
+ long status;
+
+ /*
+ * if the timestamp happens while we're not
+ * waiting, there's a chance that an interrupt
+ * will not be generated and thus the timestamp
+ * work needs to be queued.
+ */
+
+ if (kgsl_check_timestamp(device, context, timestamp)) {
+ queue_work(device->work_queue, &device->ts_expired_ws);
+ ret = 0;
+ break;
+ }
+
+ /*
+ * For proper power accounting sometimes we need to call
+ * io_wait_interruptible_timeout and sometimes we need to call
+ * plain old wait_interruptible_timeout. We call the regular
+ * timeout N times out of 100, where N is a number specified by
+ * the current power level
+ */
+
+ io_cnt = (io_cnt + 1) % 100;
+ io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
+ ? 0 : 1;
+
+ mutex_unlock(&device->mutex);
+
+ /* Wait for a timestamp event */
+ status = kgsl_wait_event_interruptible_timeout(
+ device->wait_queue,
+ adreno_check_interrupt_timestamp(device, context,
+ timestamp), msecs_to_jiffies(wait), io);
+
+ mutex_lock(&device->mutex);
+
+ /*
+ * If status is non zero then either the condition was satisfied
+ * or there was an error. In either event, this is the end of
+ * the line for us
+ */
+
+ if (status != 0) {
+ ret = (status > 0) ? 0 : (int) status;
+ break;
+ }
+ time_elapsed += wait;
+
+ /* If user specified timestamps are being used, wait at least
+ * KGSL_SYNCOBJ_SERVER_TIMEOUT msecs for the user driver to
+ * issue a IB for a timestamp before checking to see if the
+ * current timestamp we are waiting for is valid or not
+ */
+
+ if (ts_compare && (adreno_ctx &&
+ (adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS))) {
+ if (time_elapsed > KGSL_SYNCOBJ_SERVER_TIMEOUT) {
+ ret = _check_pending_timestamp(device, context,
+ timestamp);
+ if (ret)
+ break;
+
+ /* Don't do this check again */
+ ts_compare = 0;
+
+ /*
+ * Reset the invalid timestamp flag on a valid
+ * wait
+ */
+ context->wait_on_invalid_ts = false;
+ }
+ }
+
+ /*
+ * We want to wait the floor of KGSL_TIMEOUT_PART
+ * and (msecs - time_elapsed).
+ */
+
+ if (KGSL_TIMEOUT_PART < (msecs - time_elapsed))
+ wait = KGSL_TIMEOUT_PART;
+ else
+ wait = (msecs - time_elapsed);
+
+ } while (!msecs || time_elapsed < msecs);
return ret;
}
@@ -2641,13 +3915,13 @@
struct kgsl_context *context, enum kgsl_timestamp_type type)
{
unsigned int timestamp = 0;
- unsigned int id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
+ unsigned int context_id = _get_context_id(context);
/*
- * If the context is detached we are in a race with
+ * If the context ID is invalid, we are in a race with
* the context being destroyed by userspace so bail.
*/
- if (context && kgsl_context_detached(context)) {
+ if (context_id == KGSL_CONTEXT_INVALID) {
KGSL_DRV_WARN(device, "context was detached");
return timestamp;
}
@@ -2661,11 +3935,11 @@
}
case KGSL_TIMESTAMP_CONSUMED:
kgsl_sharedmem_readl(&device->memstore, ×tamp,
- KGSL_MEMSTORE_OFFSET(id, soptimestamp));
+ KGSL_MEMSTORE_OFFSET(context_id, soptimestamp));
break;
case KGSL_TIMESTAMP_RETIRED:
kgsl_sharedmem_readl(&device->memstore, ×tamp,
- KGSL_MEMSTORE_OFFSET(id, eoptimestamp));
+ KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp));
break;
}
@@ -2825,7 +4099,6 @@
.gpuid = adreno_gpuid,
.snapshot = adreno_snapshot,
.irq_handler = adreno_irq_handler,
- .drain = adreno_drain,
/* Optional functions */
.setstate = adreno_setstate,
.drawctxt_create = adreno_drawctxt_create,
@@ -2833,7 +4106,7 @@
.drawctxt_destroy = adreno_drawctxt_destroy,
.setproperty = adreno_setproperty,
.postmortem_dump = adreno_dump,
- .drawctxt_sched = adreno_drawctxt_sched,
+ .next_event = adreno_next_event,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 3a19a17..72f15e7 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -35,11 +35,12 @@
#define ADRENO_CHIPID_PATCH(_id) ((_id) & 0xFF)
/* Flags to control command packet settings */
-#define KGSL_CMD_FLAGS_NONE 0
-#define KGSL_CMD_FLAGS_PMODE BIT(0)
-#define KGSL_CMD_FLAGS_INTERNAL_ISSUE BIT(1)
-#define KGSL_CMD_FLAGS_WFI BIT(2)
-#define KGSL_CMD_FLAGS_PROFILE BIT(3)
+#define KGSL_CMD_FLAGS_NONE 0x00000000
+#define KGSL_CMD_FLAGS_PMODE 0x00000001
+#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
+#define KGSL_CMD_FLAGS_GET_INT 0x00000004
+#define KGSL_CMD_FLAGS_PROFILE 0x00000008
+#define KGSL_CMD_FLAGS_EOF 0x00000100
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
@@ -95,51 +96,6 @@
TRACE_BUS_CTL,
};
-#define ADRENO_SOFT_FAULT 1
-#define ADRENO_HARD_FAULT 2
-#define ADRENO_TIMEOUT_FAULT 3
-
-/*
- * Maximum size of the dispatcher ringbuffer - the actual inflight size will be
- * smaller then this but this size will allow for a larger range of inflight
- * sizes that can be chosen at runtime
- */
-
-#define ADRENO_DISPATCH_CMDQUEUE_SIZE 128
-
-/**
- * struct adreno_dispatcher - container for the adreno GPU dispatcher
- * @mutex: Mutex to protect the structure
- * @state: Current state of the dispatcher (active or paused)
- * @timer: Timer to monitor the progress of the command batches
- * @inflight: Number of command batch operations pending in the ringbuffer
- * @fault: Non-zero if a fault was detected.
- * @pending: Priority list of contexts waiting to submit command batches
- * @plist_lock: Spin lock to protect the pending queue
- * @cmdqueue: Queue of command batches currently flight
- * @head: pointer to the head of of the cmdqueue. This is the oldest pending
- * operation
- * @tail: pointer to the tail of the cmdqueue. This is the most recently
- * submitted operation
- * @work: work_struct to put the dispatcher in a work queue
- * @kobj: kobject for the dispatcher directory in the device sysfs node
- */
-struct adreno_dispatcher {
- struct mutex mutex;
- unsigned int state;
- struct timer_list timer;
- struct timer_list fault_timer;
- unsigned int inflight;
- atomic_t fault;
- struct plist_head pending;
- spinlock_t plist_lock;
- struct kgsl_cmdbatch *cmdqueue[ADRENO_DISPATCH_CMDQUEUE_SIZE];
- unsigned int head;
- unsigned int tail;
- struct work_struct work;
- struct kobject kobj;
-};
-
struct adreno_gpudev;
struct adreno_device {
@@ -180,7 +136,6 @@
unsigned int ocmem_base;
unsigned int gpu_cycles;
struct adreno_profile profile;
- struct adreno_dispatcher dispatcher;
};
#define PERFCOUNTER_FLAG_NONE 0x0
@@ -311,9 +266,9 @@
/* GPU specific function hooks */
int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
- int (*ctxt_save)(struct adreno_device *, struct adreno_context *);
- int (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
- int (*ctxt_draw_workaround)(struct adreno_device *,
+ void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
+ void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
+ void (*ctxt_draw_workaround)(struct adreno_device *,
struct adreno_context *);
irqreturn_t (*irq_handler)(struct adreno_device *);
void (*irq_control)(struct adreno_device *, int);
@@ -336,6 +291,46 @@
void (*postmortem_dump)(struct adreno_device *adreno_dev);
};
+/*
+ * struct adreno_ft_data - Structure that contains all information to
+ * perform gpu fault tolerance
+ * @ib1 - IB1 that the GPU was executing when hang happened
+ * @context_id - Context which caused the hang
+ * @global_eop - eoptimestamp at time of hang
+ * @rb_buffer - Buffer that holds the commands from good contexts
+ * @rb_size - Number of valid dwords in rb_buffer
+ * @bad_rb_buffer - Buffer that holds commands from the hanging context
+ * bad_rb_size - Number of valid dwords in bad_rb_buffer
+ * @good_rb_buffer - Buffer that holds commands from good contexts
+ * good_rb_size - Number of valid dwords in good_rb_buffer
+ * @last_valid_ctx_id - The last context from which commands were placed in
+ * ringbuffer before the GPU hung
+ * @step - Current fault tolerance step being executed
+ * @err_code - Fault tolerance error code
+ * @fault - Indicates whether the hang was caused due to a pagefault
+ * @start_of_replay_cmds - Offset in ringbuffer from where commands can be
+ * replayed during fault tolerance
+ * @replay_for_snapshot - Offset in ringbuffer where IB's can be saved for
+ * replaying with snapshot
+ */
+struct adreno_ft_data {
+ unsigned int ib1;
+ unsigned int context_id;
+ unsigned int global_eop;
+ unsigned int *rb_buffer;
+ unsigned int rb_size;
+ unsigned int *bad_rb_buffer;
+ unsigned int bad_rb_size;
+ unsigned int *good_rb_buffer;
+ unsigned int good_rb_size;
+ unsigned int last_valid_ctx_id;
+ unsigned int status;
+ unsigned int ft_policy;
+ unsigned int err_code;
+ unsigned int start_of_replay_cmds;
+ unsigned int replay_for_snapshot;
+};
+
#define FT_DETECT_REGS_COUNT 12
struct log_field {
@@ -344,16 +339,13 @@
};
/* Fault Tolerance policy flags */
-#define KGSL_FT_OFF 0
-#define KGSL_FT_REPLAY 1
-#define KGSL_FT_SKIPIB 2
-#define KGSL_FT_SKIPFRAME 3
-#define KGSL_FT_DISABLE 4
-#define KGSL_FT_TEMP_DISABLE 5
-#define KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB))
-
-/* This internal bit is used to skip the PM dump on replayed command batches */
-#define KGSL_FT_SKIP_PMDUMP 31
+#define KGSL_FT_OFF BIT(0)
+#define KGSL_FT_REPLAY BIT(1)
+#define KGSL_FT_SKIPIB BIT(2)
+#define KGSL_FT_SKIPFRAME BIT(3)
+#define KGSL_FT_DISABLE BIT(4)
+#define KGSL_FT_TEMP_DISABLE BIT(5)
+#define KGSL_FT_DEFAULT_POLICY (KGSL_FT_REPLAY + KGSL_FT_SKIPIB)
/* Pagefault policy flags */
#define KGSL_FT_PAGEFAULT_INT_ENABLE BIT(0)
@@ -363,14 +355,6 @@
#define KGSL_FT_PAGEFAULT_DEFAULT_POLICY (KGSL_FT_PAGEFAULT_INT_ENABLE + \
KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
-#define ADRENO_FT_TYPES \
- { BIT(KGSL_FT_OFF), "off" }, \
- { BIT(KGSL_FT_REPLAY), "replay" }, \
- { BIT(KGSL_FT_SKIPIB), "skipib" }, \
- { BIT(KGSL_FT_SKIPFRAME), "skipframe" }, \
- { BIT(KGSL_FT_DISABLE), "disable" }, \
- { BIT(KGSL_FT_TEMP_DISABLE), "temp" }
-
extern struct adreno_gpudev adreno_a2xx_gpudev;
extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -400,7 +384,6 @@
int adreno_coresight_init(struct platform_device *pdev);
int adreno_idle(struct kgsl_device *device);
-bool adreno_isidle(struct kgsl_device *device);
void adreno_shadermem_regread(struct kgsl_device *device,
unsigned int offsetwords,
@@ -427,23 +410,13 @@
void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
int hang);
-void adreno_dispatcher_start(struct adreno_device *adreno_dev);
-int adreno_dispatcher_init(struct adreno_device *adreno_dev);
-void adreno_dispatcher_close(struct adreno_device *adreno_dev);
-int adreno_dispatcher_idle(struct adreno_device *adreno_dev,
- unsigned int timeout);
-void adreno_dispatcher_irq_fault(struct kgsl_device *device);
-void adreno_dispatcher_stop(struct adreno_device *adreno_dev);
+int adreno_dump_and_exec_ft(struct kgsl_device *device);
-int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
- struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch,
- uint32_t *timestamp);
+void adreno_dump_rb(struct kgsl_device *device, const void *buf,
+ size_t len, int start, int size);
-void adreno_dispatcher_schedule(struct kgsl_device *device);
-void adreno_dispatcher_pause(struct adreno_device *adreno_dev);
-void adreno_dispatcher_queue_context(struct kgsl_device *device,
- struct adreno_context *drawctxt);
-int adreno_reset(struct kgsl_device *device);
+unsigned int adreno_ft_detect(struct kgsl_device *device,
+ unsigned int *prev_reg_val);
int adreno_ft_init_sysfs(struct kgsl_device *device);
void adreno_ft_uninit_sysfs(struct kgsl_device *device);
@@ -560,7 +533,9 @@
{
if (k_ctxt) {
struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
- return a_ctxt->timestamp;
+
+ if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+ return a_ctxt->timestamp;
}
return rb->global_ts;
}
@@ -759,31 +734,4 @@
return ADRENO_REG_REGISTER_MAX;
return adreno_dev->gpudev->reg_offsets->offsets[offset_name];
}
-
-/**
- * adreno_gpu_fault() - Return the current state of the GPU
- * @adreno_dev: A ponter to the adreno_device to query
- *
- * Return 0 if there is no fault or positive with the last type of fault that
- * occurred
- */
-static inline unsigned int adreno_gpu_fault(struct adreno_device *adreno_dev)
-{
- smp_rmb();
- return atomic_read(&adreno_dev->dispatcher.fault);
-}
-
-/**
- * adreno_set_gpu_fault() - Set the current fault status of the GPU
- * @adreno_dev: A pointer to the adreno_device to set
- * @state: fault state to set
- *
- */
-static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev,
- int state)
-{
- atomic_set(&adreno_dev->dispatcher.fault, state);
- smp_wmb();
-}
-
#endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index cce4f91..3d72c5c 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1451,7 +1451,7 @@
return ret;
}
-static int a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
@@ -1468,7 +1468,7 @@
ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW)
adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
else
- return 0;
+ return;
/*
* Issue an empty draw call to avoid possible hangs due to
* repeated idles without intervening draw calls.
@@ -1499,46 +1499,41 @@
| adreno_dev->pix_shader_start;
}
- return adreno_ringbuffer_issuecmds(device, context,
- KGSL_CMD_FLAGS_PMODE, &cmd[0], cmds - cmd);
+ adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_PMODE,
+ &cmd[0], cmds - cmd);
}
-static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
- int ret;
if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
- return 0;
+ return;
- if (context->state == ADRENO_CONTEXT_STATE_INVALID)
- return 0;
+ if (context->flags & CTXT_FLAGS_GPU_HANG)
+ KGSL_CTXT_WARN(device,
+ "Current active context has caused gpu hang\n");
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->reg_save[1],
context->reg_save[2] << 2, true);
/* save registers and constants. */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->reg_save, 3);
- if (ret)
- return ret;
-
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_save[1],
context->shader_save[2] << 2, true);
/* save shader partitioning and instructions. */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_PMODE,
context->shader_save, 3);
- if (ret)
- return ret;
kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_fixup[1],
@@ -1547,13 +1542,10 @@
* fixup shader partitioning parameter for
* SET_SHADER_BASES.
*/
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->shader_fixup, 3);
- if (ret)
- return ret;
-
context->flags |= CTXT_FLAGS_SHADER_RESTORE;
}
}
@@ -1566,41 +1558,32 @@
/* save gmem.
* (note: changes shader. shader must already be saved.)
*/
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.gmem_save, 3);
- if (ret)
- return ret;
-
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
/* Restore TP0_CHICKEN */
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
-
- if (ret)
- return ret;
}
adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
} else if (adreno_is_a2xx(adreno_dev))
- return a2xx_drawctxt_draw_workaround(adreno_dev, context);
-
- return 0;
+ a2xx_drawctxt_draw_workaround(adreno_dev, context);
}
-static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
unsigned int cmds[5];
- int ret = 0;
if (context == NULL) {
/* No context - set the default pagetable and thats it */
@@ -1615,7 +1598,7 @@
: KGSL_CONTEXT_INVALID;
kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
id);
- return 0;
+ return;
}
cmds[0] = cp_nop_packet(1);
@@ -1624,11 +1607,8 @@
cmds[3] = device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->base.id;
- ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
+ adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
cmds, 5);
- if (ret)
- return ret;
-
kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
context->base.id);
@@ -1641,11 +1621,9 @@
context->context_gmem_shadow.gmem_restore[2] << 2,
true);
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.gmem_restore, 3);
- if (ret)
- return ret;
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
kgsl_cffdump_syncmem(context->base.device,
@@ -1654,11 +1632,9 @@
context->chicken_restore[2] << 2, true);
/* Restore TP0_CHICKEN */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
- if (ret)
- return ret;
}
context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
@@ -1670,10 +1646,8 @@
context->reg_restore[2] << 2, true);
/* restore registers and constants. */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE, context->reg_restore, 3);
- if (ret)
- return ret;
/* restore shader instructions & partitioning. */
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
@@ -1682,22 +1656,18 @@
context->shader_restore[1],
context->shader_restore[2] << 2, true);
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->shader_restore, 3);
- if (ret)
- return ret;
}
}
if (adreno_is_a20x(adreno_dev)) {
cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
cmds[1] = context->bin_base_offset;
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE, cmds, 2);
}
-
- return ret;
}
/*
@@ -1764,14 +1734,13 @@
if (!status) {
if (master_status & MASTER_INT_SIGNAL__CP_INT_STAT) {
- /*
- * This indicates that we could not read CP_INT_STAT.
- * As a precaution schedule the dispatcher to check
- * things out. Since we did not ack any interrupts this
- * interrupt will be generated again
- */
+ /* This indicates that we could not read CP_INT_STAT.
+ * As a precaution just wake up processes so
+ * they can check their timestamps. Since, we
+ * did not ack any interrupts this interrupt will
+ * be generated again */
KGSL_DRV_WARN(device, "Unable to read CP_INT_STATUS\n");
- adreno_dispatcher_schedule(device);
+ wake_up_interruptible_all(&device->wait_queue);
} else
KGSL_DRV_WARN(device, "Spurious interrput detected\n");
return;
@@ -1797,7 +1766,7 @@
if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
queue_work(device->work_queue, &device->ts_expired_ws);
- adreno_dispatcher_schedule(device);
+ wake_up_interruptible_all(&device->wait_queue);
}
}
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index c4f81fa..d96965c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2382,38 +2382,32 @@
return ret;
}
-static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
+static void a3xx_drawctxt_save(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
- int ret;
if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
- return 0;
+ return;
- if (context->state == ADRENO_CONTEXT_STATE_INVALID)
- return 0;
+ if (context->flags & CTXT_FLAGS_GPU_HANG)
+ KGSL_CTXT_WARN(device,
+ "Current active context has caused gpu hang\n");
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
/* Fixup self modifying IBs for save operations */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE, context->save_fixup, 3);
- if (ret)
- return ret;
/* save registers and constants. */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->regconstant_save, 3);
- if (ret)
- return ret;
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
/* Save shader instructions */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_PMODE, context->shader_save, 3);
- if (ret)
- return ret;
context->flags |= CTXT_FLAGS_SHADER_RESTORE;
}
@@ -2431,25 +2425,19 @@
context->context_gmem_shadow.gmem_save[1],
context->context_gmem_shadow.gmem_save[2] << 2, true);
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.
gmem_save, 3);
- if (ret)
- return ret;
-
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
}
-
- return 0;
}
-static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
+static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
unsigned int cmds[5];
- int ret = 0;
if (context == NULL) {
/* No context - set the default pagetable and thats it */
@@ -2464,7 +2452,7 @@
: KGSL_CONTEXT_INVALID;
kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
id);
- return 0;
+ return;
}
cmds[0] = cp_nop_packet(1);
@@ -2473,11 +2461,8 @@
cmds[3] = device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->base.id;
- ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
+ adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
cmds, 5);
- if (ret)
- return ret;
-
kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
context->base.id);
@@ -2493,47 +2478,36 @@
context->context_gmem_shadow.gmem_restore[2] << 2,
true);
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.
gmem_restore, 3);
- if (ret)
- return ret;
context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
}
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE, context->reg_restore, 3);
- if (ret)
- return ret;
/* Fixup self modifying IBs for restore operations */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->restore_fixup, 3);
- if (ret)
- return ret;
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->constant_restore, 3);
- if (ret)
- return ret;
if (context->flags & CTXT_FLAGS_SHADER_RESTORE)
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->shader_restore, 3);
- if (ret)
- return ret;
+
/* Restore HLSQ_CONTROL_0 register */
- ret = adreno_ringbuffer_issuecmds(device, context,
+ adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->hlsqcontrol_restore, 3);
}
-
- return ret;
}
static int a3xx_rb_init(struct adreno_device *adreno_dev,
@@ -2596,7 +2570,7 @@
/* Clear the error */
kgsl_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
- goto done;
+ return;
}
case A3XX_INT_RBBM_REG_TIMEOUT:
err = "RBBM: AHB register timeout";
@@ -2637,23 +2611,21 @@
case A3XX_INT_UCHE_OOB_ACCESS:
err = "UCHE: Out of bounds access";
break;
- default:
- return;
}
+
KGSL_DRV_CRIT(device, "%s\n", err);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-done:
- /* Trigger a fault in the dispatcher - this will effect a restart */
- adreno_dispatcher_irq_fault(device);
}
static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
{
struct kgsl_device *device = &adreno_dev->dev;
+ /* Wake up everybody waiting for the interrupt */
+ wake_up_interruptible_all(&device->wait_queue);
+
+ /* Schedule work to free mem and issue ibs */
queue_work(device->work_queue, &device->ts_expired_ws);
- adreno_dispatcher_schedule(device);
}
/**
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
deleted file mode 100644
index 4d3172b..0000000
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/jiffies.h>
-#include <linux/err.h>
-
-#include "kgsl.h"
-#include "adreno.h"
-#include "adreno_ringbuffer.h"
-#include "adreno_trace.h"
-
-#define ADRENO_DISPATCHER_ACTIVE 0
-#define ADRENO_DISPATCHER_PAUSE 1
-
-#define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s))
-
-/* Number of commands that can be queued in a context before it sleeps */
-static unsigned int _context_cmdqueue_size = 50;
-
-/* Number of milliseconds to wait for the context queue to clear */
-static unsigned int _context_queue_wait = 10000;
-
-/* Number of command batches sent at a time from a single context */
-static unsigned int _context_cmdbatch_burst = 5;
-
-/* Number of command batches inflight in the ringbuffer at any time */
-static unsigned int _dispatcher_inflight = 15;
-
-/* Command batch timeout (in milliseconds) */
-static unsigned int _cmdbatch_timeout = 2000;
-
-/* Interval for reading and comparing fault detection registers */
-static unsigned int _fault_timer_interval = 50;
-
-/* Local array for the current set of fault detect registers */
-static unsigned int fault_detect_regs[FT_DETECT_REGS_COUNT];
-
-/* The last retired global timestamp read during fault detect */
-static unsigned int fault_detect_ts;
-
-/**
- * fault_detect_read() - Read the set of fault detect registers
- * @device: Pointer to the KGSL device struct
- *
- * Read the set of fault detect registers and store them in the local array.
- * This is for the initial values that are compared later with
- * fault_detect_read_compare
- */
-static void fault_detect_read(struct kgsl_device *device)
-{
- int i;
-
- fault_detect_ts = kgsl_readtimestamp(device, NULL,
- KGSL_TIMESTAMP_RETIRED);
-
- for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
- if (ft_detect_regs[i] == 0)
- continue;
- kgsl_regread(device, ft_detect_regs[i],
- &fault_detect_regs[i]);
- }
-}
-
-/*
- * Check to see if the device is idle and that the global timestamp is up to
- * date
- */
-static inline bool _isidle(struct kgsl_device *device)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int ts;
-
- ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
-
- if (adreno_isidle(device) == true &&
- (ts >= adreno_dev->ringbuffer.global_ts))
- return true;
-
- return false;
-}
-
-/**
- * fault_detect_read_compare() - Read the fault detect registers and compare
- * them to the current value
- * @device: Pointer to the KGSL device struct
- *
- * Read the set of fault detect registers and compare them to the current set
- * of registers. Return 1 if any of the register values changed
- */
-static int fault_detect_read_compare(struct kgsl_device *device)
-{
- int i, ret = 0;
- unsigned int ts;
-
- /* Check to see if the device is idle - if so report no hang */
- if (_isidle(device) == true)
- ret = 1;
-
- for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
- unsigned int val;
-
- if (ft_detect_regs[i] == 0)
- continue;
- kgsl_regread(device, ft_detect_regs[i], &val);
- if (val != fault_detect_regs[i])
- ret = 1;
- fault_detect_regs[i] = val;
- }
-
- ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
- if (ts != fault_detect_ts)
- ret = 1;
-
- fault_detect_ts = ts;
-
- return ret;
-}
-
-/**
- * adreno_dispatcher_get_cmdbatch() - Get a new command from a context queue
- * @drawctxt: Pointer to the adreno draw context
- *
- * Dequeue a new command batch from the context list
- */
-static inline struct kgsl_cmdbatch *adreno_dispatcher_get_cmdbatch(
- struct adreno_context *drawctxt)
-{
- struct kgsl_cmdbatch *cmdbatch = NULL;
-
- mutex_lock(&drawctxt->mutex);
- if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
- cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
- /*
- * Don't dequeue a cmdbatch that is still waiting for other
- * events
- */
- if (kgsl_cmdbatch_sync_pending(cmdbatch)) {
- cmdbatch = ERR_PTR(-EAGAIN);
- goto done;
- }
-
- drawctxt->cmdqueue_head =
- CMDQUEUE_NEXT(drawctxt->cmdqueue_head,
- ADRENO_CONTEXT_CMDQUEUE_SIZE);
- drawctxt->queued--;
- }
-
-done:
- mutex_unlock(&drawctxt->mutex);
-
- return cmdbatch;
-}
-
-/**
- * adreno_dispatcher_requeue_cmdbatch() - Put a command back on the context
- * queue
- * @drawctxt: Pointer to the adreno draw context
- * @cmdbatch: Pointer to the KGSL cmdbatch to requeue
- *
- * Failure to submit a command to the ringbuffer isn't the fault of the command
- * being submitted so if a failure happens, push it back on the head of the the
- * context queue to be reconsidered again
- */
-static inline void adreno_dispatcher_requeue_cmdbatch(
- struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch)
-{
- unsigned int prev;
- mutex_lock(&drawctxt->mutex);
-
- if (kgsl_context_detached(&drawctxt->base) ||
- drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
- mutex_unlock(&drawctxt->mutex);
- return;
- }
-
- prev = drawctxt->cmdqueue_head - 1;
-
- if (prev < 0)
- prev = ADRENO_CONTEXT_CMDQUEUE_SIZE - 1;
-
- /*
- * The maximum queue size always needs to be one less then the size of
- * the ringbuffer queue so there is "room" to put the cmdbatch back in
- */
-
- BUG_ON(prev == drawctxt->cmdqueue_tail);
-
- drawctxt->cmdqueue[prev] = cmdbatch;
- drawctxt->queued++;
-
- /* Reset the command queue head to reflect the newly requeued change */
- drawctxt->cmdqueue_head = prev;
- mutex_unlock(&drawctxt->mutex);
-}
-
-/**
- * dispatcher_queue_context() - Queue a context in the dispatcher pending list
- * @dispatcher: Pointer to the adreno dispatcher struct
- * @drawctxt: Pointer to the adreno draw context
- *
- * Add a context to the dispatcher pending list.
- */
-static void dispatcher_queue_context(struct adreno_device *adreno_dev,
- struct adreno_context *drawctxt)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- spin_lock(&dispatcher->plist_lock);
-
- if (plist_node_empty(&drawctxt->pending)) {
- /* Get a reference to the context while it sits on the list */
- _kgsl_context_get(&drawctxt->base);
- trace_dispatch_queue_context(drawctxt);
- plist_add(&drawctxt->pending, &dispatcher->pending);
- }
-
- spin_unlock(&dispatcher->plist_lock);
-}
-
-/**
- * sendcmd() - Send a command batch to the GPU hardware
- * @dispatcher: Pointer to the adreno dispatcher struct
- * @cmdbatch: Pointer to the KGSL cmdbatch being sent
- *
- * Send a KGSL command batch to the GPU hardware
- */
-static int sendcmd(struct adreno_device *adreno_dev,
- struct kgsl_cmdbatch *cmdbatch)
-{
- struct kgsl_device *device = &adreno_dev->dev;
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- int ret;
-
- dispatcher->inflight++;
-
- mutex_lock(&device->mutex);
-
- if (dispatcher->inflight == 1) {
- /* Time to make the donuts. Turn on the GPU */
- ret = kgsl_active_count_get(device);
- if (ret) {
- dispatcher->inflight--;
- mutex_unlock(&device->mutex);
- return ret;
- }
- }
-
- ret = adreno_ringbuffer_submitcmd(adreno_dev, cmdbatch);
-
- /*
- * On the first command, if the submission was successful, then read the
- * fault registers. If it failed then turn off the GPU. Sad face.
- */
-
- if (dispatcher->inflight == 1) {
- if (ret == 0)
- fault_detect_read(device);
- else
- kgsl_active_count_put(device);
- }
-
- mutex_unlock(&device->mutex);
-
- if (ret) {
- dispatcher->inflight--;
- KGSL_DRV_ERR(device,
- "Unable to submit command to the ringbuffer\n");
- return ret;
- }
-
- trace_adreno_cmdbatch_submitted(cmdbatch, dispatcher->inflight);
-
- dispatcher->cmdqueue[dispatcher->tail] = cmdbatch;
- dispatcher->tail = (dispatcher->tail + 1) %
- ADRENO_DISPATCH_CMDQUEUE_SIZE;
-
- /*
- * If this is the first command in the pipe then the GPU will
- * immediately start executing it so we can start the expiry timeout on
- * the command batch here. Subsequent command batches will have their
- * timer started when the previous command batch is retired
- */
- if (dispatcher->inflight == 1) {
- cmdbatch->expires = jiffies +
- msecs_to_jiffies(_cmdbatch_timeout);
- mod_timer(&dispatcher->timer, cmdbatch->expires);
-
- /* Start the fault detection timer */
- if (adreno_dev->fast_hang_detect)
- mod_timer(&dispatcher->fault_timer,
- jiffies +
- msecs_to_jiffies(_fault_timer_interval));
- }
-
- return 0;
-}
-
-/**
- * dispatcher_context_sendcmds() - Send commands from a context to the GPU
- * @adreno_dev: Pointer to the adreno device struct
- * @drawctxt: Pointer to the adreno context to dispatch commands from
- *
- * Dequeue and send a burst of commands from the specified context to the GPU
- */
-static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev,
- struct adreno_context *drawctxt)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- int count = 0;
- int requeued = 0;
-
- /*
- * Each context can send a specific number of command batches per cycle
- */
- while ((count < _context_cmdbatch_burst) &&
- (dispatcher->inflight < _dispatcher_inflight)) {
- int ret;
- struct kgsl_cmdbatch *cmdbatch;
-
- if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
- break;
-
- if (adreno_gpu_fault(adreno_dev) != 0)
- break;
-
- cmdbatch = adreno_dispatcher_get_cmdbatch(drawctxt);
-
- if (cmdbatch == NULL)
- break;
-
- /*
- * adreno_context_get_cmdbatch returns -EAGAIN if the current
- * cmdbatch has pending sync points so no more to do here.
- * When the sync points are satisfied then the context will get
- * reqeueued
- */
-
- if (IS_ERR(cmdbatch) && PTR_ERR(cmdbatch) == -EAGAIN) {
- requeued = 1;
- break;
- }
-
- /*
- * If this is a synchronization submission then there are no
- * commands to submit. Discard it and get the next item from
- * the queue. Decrement count so this packet doesn't count
- * against the burst for the context
- */
-
- if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
- kgsl_cmdbatch_destroy(cmdbatch);
- continue;
- }
-
- ret = sendcmd(adreno_dev, cmdbatch);
-
- /*
- * There are various reasons why we can't submit a command (no
- * memory for the commands, full ringbuffer, etc) but none of
- * these are actually the current command's fault. Requeue it
- * back on the context and let it come back around again if
- * conditions improve
- */
- if (ret) {
- adreno_dispatcher_requeue_cmdbatch(drawctxt, cmdbatch);
- requeued = 1;
- break;
- }
- count++;
- }
-
- /*
- * If the context successfully submitted commands, then
- * unconditionally put it back on the queue to be considered the
- * next time around. This might seem a little wasteful but it is
- * reasonable to think that a busy context will stay busy.
- */
-
- if (count || requeued) {
- dispatcher_queue_context(adreno_dev, drawctxt);
-
- /*
- * If we submitted something there will be room in the
- * context queue so ping the context wait queue on the
- * chance that the context is snoozing
- */
-
- wake_up_interruptible_all(&drawctxt->wq);
- }
-
- /* Return the number of command batches processed */
- if (count > 0)
- return count;
-
- /*
- * If we didn't process anything because of a stall or an error
- * return -1 so the issuecmds loop knows that we shouldn't
- * keep trying to process it
- */
-
- return requeued ? -1 : 0;
-}
-
-static void plist_move(struct plist_head *old, struct plist_head *new)
-{
- plist_head_init(new);
- list_splice_tail(&old->node_list, &new->node_list);
- plist_head_init(old);
-}
-
-/**
- * _adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
- * @adreno_dev: Pointer to the adreno device struct
- *
- * Issue as many commands as possible (up to inflight) from the pending contexts
- * This function assumes the dispatcher mutex has been locked.
- */
-static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct plist_head tmp;
- struct adreno_context *drawctxt, *next;
-
- /* Leave early if the dispatcher isn't in a happy state */
- if ((dispatcher->state != ADRENO_DISPATCHER_ACTIVE) ||
- adreno_gpu_fault(adreno_dev) != 0)
- return 0;
-
- /* Copy the current context list to a temporary list */
- spin_lock(&dispatcher->plist_lock);
- plist_move(&dispatcher->pending, &tmp);
- spin_unlock(&dispatcher->plist_lock);
-
- /* Try to fill the ringbuffer as much as possible */
- while (dispatcher->inflight < _dispatcher_inflight) {
-
- /* Stop doing things if the dispatcher is paused or faulted */
- if ((dispatcher->state != ADRENO_DISPATCHER_ACTIVE) ||
- adreno_gpu_fault(adreno_dev) != 0)
- break;
-
- if (plist_head_empty(&tmp))
- break;
-
- /* Get the next entry on the list */
- drawctxt = plist_first_entry(&tmp, struct adreno_context,
- pending);
-
- /* Remove it from the list */
- plist_del(&drawctxt->pending, &tmp);
-
- if (kgsl_context_detached(&drawctxt->base) ||
- drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
- kgsl_context_put(&drawctxt->base);
- continue;
- }
-
- dispatcher_context_sendcmds(adreno_dev, drawctxt);
- kgsl_context_put(&drawctxt->base);
- }
-
- /* Requeue any remaining contexts for the next go around */
-
- spin_lock(&dispatcher->plist_lock);
-
- plist_for_each_entry_safe(drawctxt, next, &tmp, pending) {
- int prio = drawctxt->pending.prio;
-
- /* Reset the context node */
- plist_node_init(&drawctxt->pending, prio);
-
- /* And put it back in the master list */
- plist_add(&drawctxt->pending, &dispatcher->pending);
- }
-
- spin_unlock(&dispatcher->plist_lock);
-
- return 0;
-}
-
-/**
- * adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
- * @adreno_dev: Pointer to the adreno device struct
- *
- * Lock the dispatcher and call _adreno_dispatcher_issueibcmds
- */
-int adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- int ret;
-
- mutex_lock(&dispatcher->mutex);
- ret = _adreno_dispatcher_issuecmds(adreno_dev);
- mutex_unlock(&dispatcher->mutex);
-
- return ret;
-}
-
-static int _check_context_queue(struct adreno_context *drawctxt)
-{
- int ret;
-
- mutex_lock(&drawctxt->mutex);
-
- /*
- * Wake up if there is room in the context or if the whole thing got
- * invalidated while we were asleep
- */
-
- if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
- ret = 1;
- else
- ret = drawctxt->queued < _context_cmdqueue_size ? 1 : 0;
-
- mutex_unlock(&drawctxt->mutex);
-
- return ret;
-}
-
-/**
- * get_timestamp() - Return the next timestamp for the context
- * @drawctxt - Pointer to an adreno draw context struct
- * @cmdbatch - Pointer to a command batch
- * @timestamp - Pointer to a timestamp value possibly passed from the user
- *
- * Assign a timestamp based on the settings of the draw context and the command
- * batch.
- */
-static int get_timestamp(struct adreno_context *drawctxt,
- struct kgsl_cmdbatch *cmdbatch, unsigned int *timestamp)
-{
- /* Synchronization commands don't get a timestamp */
- if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
- *timestamp = 0;
- return 0;
- }
-
- if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
- /*
- * User specified timestamps need to be greater than the last
- * issued timestamp in the context
- */
- if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0)
- return -ERANGE;
-
- drawctxt->timestamp = *timestamp;
- } else
- drawctxt->timestamp++;
-
- *timestamp = drawctxt->timestamp;
- return 0;
-}
-
-/**
- * adreno_dispactcher_queue_cmd() - Queue a new command in the context
- * @adreno_dev: Pointer to the adreno device struct
- * @drawctxt: Pointer to the adreno draw context
- * @cmdbatch: Pointer to the command batch being submitted
- * @timestamp: Pointer to the requested timestamp
- *
- * Queue a command in the context - if there isn't any room in the queue, then
- * block until there is
- */
-int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
- struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch,
- uint32_t *timestamp)
-{
- int ret;
-
- mutex_lock(&drawctxt->mutex);
-
- if (drawctxt->flags & CTXT_FLAGS_BEING_DESTROYED) {
- mutex_unlock(&drawctxt->mutex);
- return -EINVAL;
- }
-
- /*
- * After skipping to the end of the frame we need to force the preamble
- * to run (if it exists) regardless of the context state.
- */
-
- if (drawctxt->flags & CTXT_FLAGS_FORCE_PREAMBLE) {
- set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv);
- drawctxt->flags &= ~CTXT_FLAGS_FORCE_PREAMBLE;
- }
-
- /*
- * If we are waiting for the end of frame and it hasn't appeared yet,
- * then mark the command batch as skipped. It will still progress
- * through the pipeline but it won't actually send any commands
- */
-
- if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
- set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv);
-
- /*
- * If this command batch represents the EOF then clear the way
- * for the dispatcher to continue submitting
- */
-
- if (cmdbatch->flags & KGSL_CONTEXT_END_OF_FRAME) {
- drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
-
- /*
- * Force the preamble on the next command to ensure that
- * the state is correct
- */
-
- drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
- }
- }
-
- /* Wait for room in the context queue */
-
- while (drawctxt->queued >= _context_cmdqueue_size) {
- trace_adreno_drawctxt_sleep(drawctxt);
- mutex_unlock(&drawctxt->mutex);
-
- ret = wait_event_interruptible_timeout(drawctxt->wq,
- _check_context_queue(drawctxt),
- msecs_to_jiffies(_context_queue_wait));
-
- mutex_lock(&drawctxt->mutex);
- trace_adreno_drawctxt_wake(drawctxt);
-
- if (ret <= 0) {
- mutex_unlock(&drawctxt->mutex);
- return (ret == 0) ? -ETIMEDOUT : (int) ret;
- }
-
- /*
- * Account for the possiblity that the context got invalidated
- * while we were sleeping
- */
-
- if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
- mutex_unlock(&drawctxt->mutex);
- return -EDEADLK;
- }
- }
-
- ret = get_timestamp(drawctxt, cmdbatch, timestamp);
- if (ret) {
- mutex_unlock(&drawctxt->mutex);
- return ret;
- }
-
- cmdbatch->timestamp = *timestamp;
-
- /*
- * Set the fault tolerance policy for the command batch - assuming the
- * context hsn't disabled FT use the current device policy
- */
-
- if (drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
- set_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy);
- else
- cmdbatch->fault_policy = adreno_dev->ft_policy;
-
- /* Put the command into the queue */
- drawctxt->cmdqueue[drawctxt->cmdqueue_tail] = cmdbatch;
- drawctxt->cmdqueue_tail = (drawctxt->cmdqueue_tail + 1) %
- ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
- drawctxt->queued++;
- trace_adreno_cmdbatch_queued(cmdbatch, drawctxt->queued);
-
-
- mutex_unlock(&drawctxt->mutex);
-
- /* Add the context to the dispatcher pending list */
- dispatcher_queue_context(adreno_dev, drawctxt);
-
- /*
- * Only issue commands if inflight is less than burst -this prevents us
- * from sitting around waiting for the mutex on a busy system - the work
- * loop will schedule it for us. Inflight is mutex protected but the
- * worse that can happen is that it will go to 0 after we check and if
- * it goes to 0 it is because the work loop decremented it and the work
- * queue will try to schedule new commands anyway.
- */
-
- if (adreno_dev->dispatcher.inflight < _context_cmdbatch_burst)
- adreno_dispatcher_issuecmds(adreno_dev);
-
- return 0;
-}
-
-/*
- * If an IB inside of the command batch has a gpuaddr that matches the base
- * passed in then zero the size which effectively skips it when it is submitted
- * in the ringbuffer.
- */
-static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base)
-{
- int i;
-
- for (i = 0; i < cmdbatch->ibcount; i++) {
- if (cmdbatch->ibdesc[i].gpuaddr == base) {
- cmdbatch->ibdesc[i].sizedwords = 0;
- return;
- }
- }
-}
-
-static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch,
- struct kgsl_cmdbatch **replay, int count)
-{
- struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context);
- int skip = 1;
- int i;
-
- for (i = 0; i < count; i++) {
-
- /*
- * Only operate on command batches that belong to the
- * faulting context
- */
-
- if (replay[i]->context->id != cmdbatch->context->id)
- continue;
-
- /*
- * Skip all the command batches in this context until
- * the EOF flag is seen. If the EOF flag is seen then
- * force the preamble for the next command.
- */
-
- if (skip) {
- set_bit(CMDBATCH_FLAG_SKIP, &replay[i]->priv);
-
- if (replay[i]->flags & KGSL_CONTEXT_END_OF_FRAME)
- skip = 0;
- } else {
- set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
- return;
- }
- }
-
- /*
- * If the EOF flag hasn't been seen yet then set the flag in the
- * drawctxt to keep looking for it
- */
-
- if (skip && drawctxt)
- drawctxt->flags |= CTXT_FLAGS_SKIP_EOF;
-
- /*
- * If we did see the EOF flag then force the preamble on for the
- * next command issued on this context
- */
-
- if (!skip && drawctxt)
- drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
-}
-
-static void remove_invalidated_cmdbatches(struct kgsl_device *device,
- struct kgsl_cmdbatch **replay, int count)
-{
- int i;
-
- for (i = 0; i < count; i++) {
- struct kgsl_cmdbatch *cmd = replay[i];
- struct adreno_context *drawctxt;
-
- if (cmd == NULL)
- continue;
-
- drawctxt = ADRENO_CONTEXT(cmd->context);
-
- if (kgsl_context_detached(cmd->context) ||
- drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
- replay[i] = NULL;
-
- mutex_lock(&device->mutex);
- kgsl_cancel_events_timestamp(device, cmd->context,
- cmd->timestamp);
- mutex_unlock(&device->mutex);
-
- kgsl_cmdbatch_destroy(cmd);
- }
- }
-}
-
-static char _pidname[TASK_COMM_LEN];
-
-static inline const char *_kgsl_context_comm(struct kgsl_context *context)
-{
- struct task_struct *task = NULL;
-
- if (context)
- task = find_task_by_vpid(context->pid);
-
- if (task)
- get_task_comm(_pidname, task);
- else
- snprintf(_pidname, TASK_COMM_LEN, "unknown");
-
- return _pidname;
-}
-
-#define pr_fault(_d, _c, fmt, args...) \
- dev_err((_d)->dev, "%s[%d]: " fmt, \
- _kgsl_context_comm((_c)->context), \
- (_c)->context->pid, ##args)
-
-
-static void adreno_fault_header(struct kgsl_device *device,
- struct kgsl_cmdbatch *cmdbatch)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int status, base, rptr, wptr, ib1base, ib2base, ib1sz, ib2sz;
-
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
- &status);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_BASE),
- &base);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_RPTR),
- &rptr);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_WPTR),
- &wptr);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
- &ib1base);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
- &ib1sz);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
- &ib2base);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
- &ib2sz);
-
- trace_adreno_gpu_fault(cmdbatch->context->id, cmdbatch->timestamp,
- status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
-
- pr_fault(device, cmdbatch,
- "gpu fault ctx %d ts %d status %8.8X rb %4.4x/%4.4x ib1 %8.8x/%4.4x ib2 %8.8x/%4.4x\n",
- cmdbatch->context->id, cmdbatch->timestamp, status,
- rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
-}
-
-static int dispatcher_do_fault(struct kgsl_device *device)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- unsigned int ptr;
- unsigned int reg, base;
- struct kgsl_cmdbatch **replay = NULL;
- struct kgsl_cmdbatch *cmdbatch;
- int ret, i, count = 0;
- int fault, first = 0;
- bool pagefault = false;
- BUG_ON(dispatcher->inflight == 0);
-
- fault = atomic_xchg(&dispatcher->fault, 0);
- if (fault == 0)
- return 0;
-
- /* Turn off all the timers */
- del_timer_sync(&dispatcher->timer);
- del_timer_sync(&dispatcher->fault_timer);
-
- mutex_lock(&device->mutex);
-
- cmdbatch = dispatcher->cmdqueue[dispatcher->head];
-
- trace_adreno_cmdbatch_fault(cmdbatch, fault);
-
- /*
- * If the fault was due to a timeout then stop the CP to ensure we don't
- * get activity while we are trying to dump the state of the system
- */
-
- if (fault == ADRENO_TIMEOUT_FAULT) {
- adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, ®);
- reg |= (1 << 27) | (1 << 28);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
-
- /* Skip the PM dump for a timeout because it confuses people */
- set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
- }
-
- adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &base);
-
- /*
- * Dump the postmortem and snapshot information if this is the first
- * detected fault for the oldest active command batch
- */
-
- if (!test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) {
- adreno_fault_header(device, cmdbatch);
-
- if (device->pm_dump_enable)
- kgsl_postmortem_dump(device, 0);
-
- kgsl_device_snapshot(device, 1);
- }
-
- mutex_unlock(&device->mutex);
-
- /* Allocate memory to store the inflight commands */
- replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL);
-
- if (replay == NULL) {
- unsigned int ptr = dispatcher->head;
-
- while (ptr != dispatcher->tail) {
- struct kgsl_context *context =
- dispatcher->cmdqueue[ptr]->context;
-
- adreno_drawctxt_invalidate(device, context);
- kgsl_cmdbatch_destroy(dispatcher->cmdqueue[ptr]);
-
- ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
- }
-
- /*
- * Set the replay count to zero - this will ensure that the
- * hardware gets reset but nothing else goes played
- */
-
- count = 0;
- goto replay;
- }
-
- /* Copy the inflight command batches into the temporary storage */
- ptr = dispatcher->head;
-
- while (ptr != dispatcher->tail) {
- replay[count++] = dispatcher->cmdqueue[ptr];
- ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
- }
-
- /*
- * For the purposes of replay, we assume that the oldest command batch
- * that hasn't retired a timestamp is "hung".
- */
-
- cmdbatch = replay[0];
-
- /*
- * If FT is disabled for this cmdbatch invalidate immediately
- */
-
- if (test_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy) ||
- test_bit(KGSL_FT_TEMP_DISABLE, &cmdbatch->fault_policy)) {
- pr_fault(device, cmdbatch, "gpu skipped ctx %d ts %d\n",
- cmdbatch->context->id, cmdbatch->timestamp);
-
- adreno_drawctxt_invalidate(device, cmdbatch->context);
- }
-
- /*
- * Set a flag so we don't print another PM dump if the cmdbatch fails
- * again on replay
- */
-
- set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
-
- /*
- * A hardware fault generally means something was deterministically
- * wrong with the command batch - no point in trying to replay it
- * Clear the replay bit and move on to the next policy level
- */
-
- if (fault == ADRENO_HARD_FAULT)
- clear_bit(KGSL_FT_REPLAY, &(cmdbatch->fault_policy));
-
- /*
- * A timeout fault means the IB timed out - clear the policy and
- * invalidate - this will clear the FT_SKIP_PMDUMP bit but that is okay
- * because we won't see this cmdbatch again
- */
-
- if (fault == ADRENO_TIMEOUT_FAULT)
- bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG);
-
- /*
- * If the context had a GPU page fault then it is likely it would fault
- * again if replayed
- */
-
- if (test_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv)) {
- /* we'll need to resume the mmu later... */
- pagefault = true;
- clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy);
- clear_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv);
- }
-
- /*
- * Execute the fault tolerance policy. Each command batch stores the
- * current fault policy that was set when it was queued.
- * As the options are tried in descending priority
- * (REPLAY -> SKIPIBS -> SKIPFRAME -> NOTHING) the bits are cleared
- * from the cmdbatch policy so the next thing can be tried if the
- * change comes around again
- */
-
- /* Replay the hanging command batch again */
- if (test_and_clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy)) {
- trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_REPLAY));
- set_bit(KGSL_FT_REPLAY, &cmdbatch->fault_recovery);
- goto replay;
- }
-
- /*
- * Skip the last IB1 that was played but replay everything else.
- * Note that the last IB1 might not be in the "hung" command batch
- * because the CP may have caused a page-fault while it was prefetching
- * the next IB1/IB2. walk all outstanding commands and zap the
- * supposedly bad IB1 where ever it lurks.
- */
-
- if (test_and_clear_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_policy)) {
- trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPIB));
- set_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_recovery);
-
- for (i = 0; i < count; i++) {
- if (replay[i] != NULL)
- cmdbatch_skip_ib(replay[i], base);
- }
-
- goto replay;
- }
-
- if (test_and_clear_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_policy)) {
- trace_adreno_cmdbatch_recovery(cmdbatch,
- BIT(KGSL_FT_SKIPFRAME));
- set_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_recovery);
-
- /*
- * Skip all the pending command batches for this context until
- * the EOF frame is seen
- */
- cmdbatch_skip_frame(cmdbatch, replay, count);
- goto replay;
- }
-
- /* If we get here then all the policies failed */
-
- pr_fault(device, cmdbatch, "gpu failed ctx %d ts %d\n",
- cmdbatch->context->id, cmdbatch->timestamp);
-
- /* Invalidate the context */
- adreno_drawctxt_invalidate(device, cmdbatch->context);
-
-
-replay:
- /* Reset the dispatcher queue */
- dispatcher->inflight = 0;
- dispatcher->head = dispatcher->tail = 0;
-
- /* Reset the GPU */
- mutex_lock(&device->mutex);
-
- /* resume the MMU if it is stalled */
- if (pagefault && device->mmu.mmu_ops->mmu_pagefault_resume != NULL)
- device->mmu.mmu_ops->mmu_pagefault_resume(&device->mmu);
-
- ret = adreno_reset(device);
- mutex_unlock(&device->mutex);
-
- /* If adreno_reset() fails then what hope do we have for the future? */
- BUG_ON(ret);
-
- /* Remove any pending command batches that have been invalidated */
- remove_invalidated_cmdbatches(device, replay, count);
-
- /* Replay the pending command buffers */
- for (i = 0; i < count; i++) {
-
- int ret;
-
- if (replay[i] == NULL)
- continue;
-
- /*
- * Force the preamble on the first command (if applicable) to
- * avoid any strange stage issues
- */
-
- if (first == 0) {
- set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
- first = 1;
- }
-
- /*
- * Force each command batch to wait for idle - this avoids weird
- * CP parse issues
- */
-
- set_bit(CMDBATCH_FLAG_WFI, &replay[i]->priv);
-
- ret = sendcmd(adreno_dev, replay[i]);
-
- /*
- * If sending the command fails, then try to recover by
- * invalidating the context
- */
-
- if (ret) {
- pr_fault(device, replay[i],
- "gpu reset failed ctx %d ts %d\n",
- replay[i]->context->id, replay[i]->timestamp);
-
- adreno_drawctxt_invalidate(device, replay[i]->context);
- remove_invalidated_cmdbatches(device, &replay[i],
- count - i);
- }
- }
-
- mutex_lock(&device->mutex);
- kgsl_active_count_put(device);
- mutex_unlock(&device->mutex);
-
- kfree(replay);
-
- return 1;
-}
-
-static inline int cmdbatch_consumed(struct kgsl_cmdbatch *cmdbatch,
- unsigned int consumed, unsigned int retired)
-{
- return ((timestamp_cmp(cmdbatch->timestamp, consumed) >= 0) &&
- (timestamp_cmp(retired, cmdbatch->timestamp) < 0));
-}
-
-static void _print_recovery(struct kgsl_device *device,
- struct kgsl_cmdbatch *cmdbatch)
-{
- static struct {
- unsigned int mask;
- const char *str;
- } flags[] = { ADRENO_FT_TYPES };
-
- int i, nr = find_first_bit(&cmdbatch->fault_recovery, BITS_PER_LONG);
- char *result = "unknown";
-
- for (i = 0; i < ARRAY_SIZE(flags); i++) {
- if (flags[i].mask == BIT(nr)) {
- result = (char *) flags[i].str;
- break;
- }
- }
-
- pr_fault(device, cmdbatch,
- "gpu %s ctx %d ts %d policy %lX\n",
- result, cmdbatch->context->id, cmdbatch->timestamp,
- cmdbatch->fault_recovery);
-}
-
-/**
- * adreno_dispatcher_work() - Master work handler for the dispatcher
- * @work: Pointer to the work struct for the current work queue
- *
- * Process expired commands and send new ones.
- */
-static void adreno_dispatcher_work(struct work_struct *work)
-{
- struct adreno_dispatcher *dispatcher =
- container_of(work, struct adreno_dispatcher, work);
- struct adreno_device *adreno_dev =
- container_of(dispatcher, struct adreno_device, dispatcher);
- struct kgsl_device *device = &adreno_dev->dev;
- int count = 0;
-
- mutex_lock(&dispatcher->mutex);
-
- while (dispatcher->head != dispatcher->tail) {
- uint32_t consumed, retired = 0;
- struct kgsl_cmdbatch *cmdbatch =
- dispatcher->cmdqueue[dispatcher->head];
- struct adreno_context *drawctxt;
- BUG_ON(cmdbatch == NULL);
-
- drawctxt = ADRENO_CONTEXT(cmdbatch->context);
-
- /*
- * First try to expire the timestamp. This happens if the
- * context is valid and the timestamp expired normally or if the
- * context was destroyed before the command batch was finished
- * in the GPU. Either way retire the command batch advance the
- * pointers and continue processing the queue
- */
-
- if (!kgsl_context_detached(cmdbatch->context))
- retired = kgsl_readtimestamp(device, cmdbatch->context,
- KGSL_TIMESTAMP_RETIRED);
-
- if (kgsl_context_detached(cmdbatch->context) ||
- (timestamp_cmp(cmdbatch->timestamp, retired) <= 0)) {
-
- /*
- * If the cmdbatch in question had faulted announce its
- * successful completion to the world
- */
-
- if (cmdbatch->fault_recovery != 0)
- _print_recovery(device, cmdbatch);
-
- trace_adreno_cmdbatch_retired(cmdbatch,
- dispatcher->inflight - 1);
-
- /* Reduce the number of inflight command batches */
- dispatcher->inflight--;
-
- /* Zero the old entry*/
- dispatcher->cmdqueue[dispatcher->head] = NULL;
-
- /* Advance the buffer head */
- dispatcher->head = CMDQUEUE_NEXT(dispatcher->head,
- ADRENO_DISPATCH_CMDQUEUE_SIZE);
-
- /* Destroy the retired command batch */
- kgsl_cmdbatch_destroy(cmdbatch);
-
- /* Update the expire time for the next command batch */
-
- if (dispatcher->inflight > 0) {
- cmdbatch =
- dispatcher->cmdqueue[dispatcher->head];
- cmdbatch->expires = jiffies +
- msecs_to_jiffies(_cmdbatch_timeout);
- }
-
- count++;
- continue;
- }
-
- /*
- * If we got a fault from the interrupt handler, this command
- * is to blame. Invalidate it, reset and replay
- */
-
- if (dispatcher_do_fault(device))
- goto done;
-
- /* Get the last consumed timestamp */
- consumed = kgsl_readtimestamp(device, cmdbatch->context,
- KGSL_TIMESTAMP_CONSUMED);
-
- /*
- * Break here if fault detection is disabled for the context or
- * if the long running IB detection is disaled device wide
- * Long running command buffers will be allowed to run to
- * completion - but badly behaving command buffers (infinite
- * shaders etc) can end up running forever.
- */
-
- if (!adreno_dev->long_ib_detect ||
- drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
- break;
-
- /*
- * The last line of defense is to check if the command batch has
- * timed out. If we get this far but the timeout hasn't expired
- * yet then the GPU is still ticking away
- */
-
- if (time_is_after_jiffies(cmdbatch->expires))
- break;
-
- /* Boom goes the dynamite */
-
- pr_fault(device, cmdbatch,
- "gpu timeout ctx %d ts %d\n",
- cmdbatch->context->id, cmdbatch->timestamp);
-
- adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT);
-
- dispatcher_do_fault(device);
- break;
- }
-
- /*
- * Decrement the active count to 0 - this will allow the system to go
- * into suspend even if there are queued command batches
- */
-
- if (count && dispatcher->inflight == 0) {
- mutex_lock(&device->mutex);
- kgsl_active_count_put(device);
- mutex_unlock(&device->mutex);
- }
-
- /* Dispatch new commands if we have the room */
- if (dispatcher->inflight < _dispatcher_inflight)
- _adreno_dispatcher_issuecmds(adreno_dev);
-
-done:
- /* Either update the timer for the next command batch or disable it */
- if (dispatcher->inflight) {
- struct kgsl_cmdbatch *cmdbatch
- = dispatcher->cmdqueue[dispatcher->head];
-
- /* Update the timeout timer for the next command batch */
- mod_timer(&dispatcher->timer, cmdbatch->expires);
- } else {
- del_timer_sync(&dispatcher->timer);
- del_timer_sync(&dispatcher->fault_timer);
- }
-
- /* Before leaving update the pwrscale information */
- mutex_lock(&device->mutex);
- kgsl_pwrscale_idle(device);
- mutex_unlock(&device->mutex);
-
- mutex_unlock(&dispatcher->mutex);
-}
-
-void adreno_dispatcher_schedule(struct kgsl_device *device)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- queue_work(device->work_queue, &dispatcher->work);
-}
-
-/**
- * adreno_dispatcher_queue_context() - schedule a drawctxt in the dispatcher
- * device: pointer to the KGSL device
- * drawctxt: pointer to the drawctxt to schedule
- *
- * Put a draw context on the dispatcher pending queue and schedule the
- * dispatcher. This is used to reschedule changes that might have been blocked
- * for sync points or other concerns
- */
-void adreno_dispatcher_queue_context(struct kgsl_device *device,
- struct adreno_context *drawctxt)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
- dispatcher_queue_context(adreno_dev, drawctxt);
- adreno_dispatcher_schedule(device);
-}
-
-/*
- * This is called on a regular basis while command batches are inflight. Fault
- * detection registers are read and compared to the existing values - if they
- * changed then the GPU is still running. If they are the same between
- * subsequent calls then the GPU may have faulted
- */
-
-void adreno_dispatcher_fault_timer(unsigned long data)
-{
- struct adreno_device *adreno_dev = (struct adreno_device *) data;
- struct kgsl_device *device = &adreno_dev->dev;
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- /* Leave if the user decided to turn off fast hang detection */
- if (adreno_dev->fast_hang_detect == 0)
- return;
-
- if (adreno_gpu_fault(adreno_dev)) {
- adreno_dispatcher_schedule(device);
- return;
- }
-
- /*
- * Read the fault registers - if it returns 0 then they haven't changed
- * so mark the dispatcher as faulted and schedule the work loop.
- */
-
- if (!fault_detect_read_compare(device)) {
- adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT);
- adreno_dispatcher_schedule(device);
- } else {
- mod_timer(&dispatcher->fault_timer,
- jiffies + msecs_to_jiffies(_fault_timer_interval));
- }
-}
-
-/*
- * This is called when the timer expires - it either means the GPU is hung or
- * the IB is taking too long to execute
- */
-void adreno_dispatcher_timer(unsigned long data)
-{
- struct adreno_device *adreno_dev = (struct adreno_device *) data;
- struct kgsl_device *device = &adreno_dev->dev;
-
- adreno_dispatcher_schedule(device);
-}
-/**
- * adreno_dispatcher_irq_fault() - Trigger a fault in the dispatcher
- * @device: Pointer to the KGSL device
- *
- * Called from an interrupt context this will trigger a fault in the
- * dispatcher for the oldest pending command batch
- */
-void adreno_dispatcher_irq_fault(struct kgsl_device *device)
-{
- adreno_set_gpu_fault(ADRENO_DEVICE(device), ADRENO_HARD_FAULT);
- adreno_dispatcher_schedule(device);
-}
-
-/**
- * adreno_dispatcher_pause() - stop the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Pause the dispather so it doesn't accept any new commands
- */
-void adreno_dispatcher_pause(struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- /*
- * This will probably get called while holding other mutexes so don't
- * take the dispatcher mutex. The biggest penalty is that another
- * command might be submitted while we are in here but thats okay
- * because whoever is waiting for the drain will just have another
- * command batch to wait for
- */
-
- dispatcher->state = ADRENO_DISPATCHER_PAUSE;
-}
-
-/**
- * adreno_dispatcher_start() - activate the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Set the disaptcher active and start the loop once to get things going
- */
-void adreno_dispatcher_start(struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- dispatcher->state = ADRENO_DISPATCHER_ACTIVE;
-
- /* Schedule the work loop to get things going */
- adreno_dispatcher_schedule(&adreno_dev->dev);
-}
-
-/**
- * adreno_dispatcher_stop() - stop the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Stop the dispatcher and close all the timers
- */
-void adreno_dispatcher_stop(struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- del_timer_sync(&dispatcher->timer);
- del_timer_sync(&dispatcher->fault_timer);
-
- dispatcher->state = ADRENO_DISPATCHER_PAUSE;
-}
-
-/**
- * adreno_dispatcher_close() - close the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Close the dispatcher and free all the oustanding commands and memory
- */
-void adreno_dispatcher_close(struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- mutex_lock(&dispatcher->mutex);
- del_timer_sync(&dispatcher->timer);
- del_timer_sync(&dispatcher->fault_timer);
-
- while (dispatcher->head != dispatcher->tail) {
- kgsl_cmdbatch_destroy(dispatcher->cmdqueue[dispatcher->head]);
- dispatcher->head = (dispatcher->head + 1)
- % ADRENO_DISPATCH_CMDQUEUE_SIZE;
- }
-
- mutex_unlock(&dispatcher->mutex);
-
- kobject_put(&dispatcher->kobj);
-}
-
-struct dispatcher_attribute {
- struct attribute attr;
- ssize_t (*show)(struct adreno_dispatcher *,
- struct dispatcher_attribute *, char *);
- ssize_t (*store)(struct adreno_dispatcher *,
- struct dispatcher_attribute *, const char *buf,
- size_t count);
- unsigned int max;
- unsigned int *value;
-};
-
-#define DISPATCHER_UINT_ATTR(_name, _mode, _max, _value) \
- struct dispatcher_attribute dispatcher_attr_##_name = { \
- .attr = { .name = __stringify(_name), .mode = _mode }, \
- .show = _show_uint, \
- .store = _store_uint, \
- .max = _max, \
- .value = &(_value), \
- }
-
-#define to_dispatcher_attr(_a) \
- container_of((_a), struct dispatcher_attribute, attr)
-#define to_dispatcher(k) container_of(k, struct adreno_dispatcher, kobj)
-
-static ssize_t _store_uint(struct adreno_dispatcher *dispatcher,
- struct dispatcher_attribute *attr,
- const char *buf, size_t size)
-{
- unsigned long val;
- int ret = kstrtoul(buf, 0, &val);
-
- if (ret)
- return ret;
-
- if (!val || (attr->max && (val > attr->max)))
- return -EINVAL;
-
- *((unsigned int *) attr->value) = val;
- return size;
-}
-
-static ssize_t _show_uint(struct adreno_dispatcher *dispatcher,
- struct dispatcher_attribute *attr,
- char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n",
- *((unsigned int *) attr->value));
-}
-
-static DISPATCHER_UINT_ATTR(inflight, 0644, ADRENO_DISPATCH_CMDQUEUE_SIZE,
- _dispatcher_inflight);
-/*
- * Our code that "puts back" a command from the context is much cleaner
- * if we are sure that there will always be enough room in the
- * ringbuffer so restrict the maximum size of the context queue to
- * ADRENO_CONTEXT_CMDQUEUE_SIZE - 1
- */
-static DISPATCHER_UINT_ATTR(context_cmdqueue_size, 0644,
- ADRENO_CONTEXT_CMDQUEUE_SIZE - 1, _context_cmdqueue_size);
-static DISPATCHER_UINT_ATTR(context_burst_count, 0644, 0,
- _context_cmdbatch_burst);
-static DISPATCHER_UINT_ATTR(cmdbatch_timeout, 0644, 0, _cmdbatch_timeout);
-static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait);
-static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0,
- _fault_timer_interval);
-
-static struct attribute *dispatcher_attrs[] = {
- &dispatcher_attr_inflight.attr,
- &dispatcher_attr_context_cmdqueue_size.attr,
- &dispatcher_attr_context_burst_count.attr,
- &dispatcher_attr_cmdbatch_timeout.attr,
- &dispatcher_attr_context_queue_wait.attr,
- &dispatcher_attr_fault_detect_interval.attr,
- NULL,
-};
-
-static ssize_t dispatcher_sysfs_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct adreno_dispatcher *dispatcher = to_dispatcher(kobj);
- struct dispatcher_attribute *pattr = to_dispatcher_attr(attr);
- ssize_t ret = -EIO;
-
- if (pattr->show)
- ret = pattr->show(dispatcher, pattr, buf);
-
- return ret;
-}
-
-static ssize_t dispatcher_sysfs_store(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- struct adreno_dispatcher *dispatcher = to_dispatcher(kobj);
- struct dispatcher_attribute *pattr = to_dispatcher_attr(attr);
- ssize_t ret = -EIO;
-
- if (pattr->store)
- ret = pattr->store(dispatcher, pattr, buf, count);
-
- return ret;
-}
-
-static void dispatcher_sysfs_release(struct kobject *kobj)
-{
-}
-
-static const struct sysfs_ops dispatcher_sysfs_ops = {
- .show = dispatcher_sysfs_show,
- .store = dispatcher_sysfs_store
-};
-
-static struct kobj_type ktype_dispatcher = {
- .sysfs_ops = &dispatcher_sysfs_ops,
- .default_attrs = dispatcher_attrs,
- .release = dispatcher_sysfs_release
-};
-
-/**
- * adreno_dispatcher_init() - Initialize the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Initialize the dispatcher
- */
-int adreno_dispatcher_init(struct adreno_device *adreno_dev)
-{
- struct kgsl_device *device = &adreno_dev->dev;
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- int ret;
-
- memset(dispatcher, 0, sizeof(*dispatcher));
-
- mutex_init(&dispatcher->mutex);
-
- setup_timer(&dispatcher->timer, adreno_dispatcher_timer,
- (unsigned long) adreno_dev);
-
- setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer,
- (unsigned long) adreno_dev);
-
- INIT_WORK(&dispatcher->work, adreno_dispatcher_work);
-
- plist_head_init(&dispatcher->pending);
- spin_lock_init(&dispatcher->plist_lock);
-
- dispatcher->state = ADRENO_DISPATCHER_ACTIVE;
-
- ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher,
- &device->dev->kobj, "dispatch");
-
- return ret;
-}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 907d41f..0af4c12e 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -13,12 +13,10 @@
#include <linux/slab.h>
#include <linux/msm_kgsl.h>
-#include <linux/sched.h>
#include "kgsl.h"
#include "kgsl_sharedmem.h"
#include "adreno.h"
-#include "adreno_trace.h"
#define KGSL_INIT_REFTIMESTAMP 0x7FFFFFFF
@@ -134,247 +132,6 @@
*incmd = cmd;
}
-static void wait_callback(struct kgsl_device *device, void *priv, u32 id,
- u32 timestamp, u32 type)
-{
- struct adreno_context *drawctxt = priv;
- wake_up_interruptible_all(&drawctxt->waiting);
-}
-
-#define adreno_wait_event_interruptible_timeout(wq, condition, timeout, io) \
-({ \
- long __ret = timeout; \
- if (io) \
- __wait_io_event_interruptible_timeout(wq, condition, __ret); \
- else \
- __wait_event_interruptible_timeout(wq, condition, __ret); \
- __ret; \
-})
-
-#define adreno_wait_event_interruptible(wq, condition, io) \
-({ \
- long __ret; \
- if (io) \
- __wait_io_event_interruptible(wq, condition, __ret); \
- else \
- __wait_event_interruptible(wq, condition, __ret); \
- __ret; \
-})
-
-static int _check_context_timestamp(struct kgsl_device *device,
- struct adreno_context *drawctxt, unsigned int timestamp)
-{
- int ret = 0;
-
- /* Bail if the drawctxt has been invalidated or destroyed */
- if (kgsl_context_detached(&drawctxt->base) ||
- drawctxt->state != ADRENO_CONTEXT_STATE_ACTIVE)
- return 1;
-
- mutex_lock(&device->mutex);
- ret = kgsl_check_timestamp(device, &drawctxt->base, timestamp);
- mutex_unlock(&device->mutex);
-
- return ret;
-}
-
-/**
- * adreno_drawctxt_wait() - sleep until a timestamp expires
- * @adreno_dev: pointer to the adreno_device struct
- * @drawctxt: Pointer to the draw context to sleep for
- * @timetamp: Timestamp to wait on
- * @timeout: Number of jiffies to wait (0 for infinite)
- *
- * Register an event to wait for a timestamp on a context and sleep until it
- * has past. Returns < 0 on error, -ETIMEDOUT if the timeout expires or 0
- * on success
- */
-int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
- struct kgsl_context *context,
- uint32_t timestamp, unsigned int timeout)
-{
- static unsigned int io_cnt;
- struct kgsl_device *device = &adreno_dev->dev;
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
- int ret, io;
-
- if (kgsl_context_detached(context))
- return -EINVAL;
-
- if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
- return -EDEADLK;
-
- /* Needs to hold the device mutex */
- BUG_ON(!mutex_is_locked(&device->mutex));
-
- trace_adreno_drawctxt_wait_start(context->id, timestamp);
-
- ret = kgsl_add_event(device, context->id, timestamp,
- wait_callback, drawctxt, NULL);
- if (ret)
- goto done;
-
- /*
- * For proper power accounting sometimes we need to call
- * io_wait_interruptible_timeout and sometimes we need to call
- * plain old wait_interruptible_timeout. We call the regular
- * timeout N times out of 100, where N is a number specified by
- * the current power level
- */
-
- io_cnt = (io_cnt + 1) % 100;
- io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
- ? 0 : 1;
-
- mutex_unlock(&device->mutex);
-
- if (timeout) {
- ret = (int) adreno_wait_event_interruptible_timeout(
- drawctxt->waiting,
- _check_context_timestamp(device, drawctxt, timestamp),
- msecs_to_jiffies(timeout), io);
-
- if (ret == 0)
- ret = -ETIMEDOUT;
- else if (ret > 0)
- ret = 0;
- } else {
- ret = (int) adreno_wait_event_interruptible(drawctxt->waiting,
- _check_context_timestamp(device, drawctxt, timestamp),
- io);
- }
-
- mutex_lock(&device->mutex);
-
- /* -EDEADLK if the context was invalidated while we were waiting */
- if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
- ret = -EDEADLK;
-
-
- /* Return -EINVAL if the context was detached while we were waiting */
- if (kgsl_context_detached(context))
- ret = -EINVAL;
-
-done:
- trace_adreno_drawctxt_wait_done(context->id, timestamp, ret);
- return ret;
-}
-
-static void global_wait_callback(struct kgsl_device *device, void *priv, u32 id,
- u32 timestamp, u32 type)
-{
- struct adreno_context *drawctxt = priv;
-
- wake_up_interruptible_all(&drawctxt->waiting);
- kgsl_context_put(&drawctxt->base);
-}
-
-static int _check_global_timestamp(struct kgsl_device *device,
- unsigned int timestamp)
-{
- int ret;
-
- mutex_lock(&device->mutex);
- ret = kgsl_check_timestamp(device, NULL, timestamp);
- mutex_unlock(&device->mutex);
-
- return ret;
-}
-
-int adreno_drawctxt_wait_global(struct adreno_device *adreno_dev,
- struct kgsl_context *context,
- uint32_t timestamp, unsigned int timeout)
-{
- struct kgsl_device *device = &adreno_dev->dev;
- struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
- int ret;
-
- /* Needs to hold the device mutex */
- BUG_ON(!mutex_is_locked(&device->mutex));
-
- _kgsl_context_get(context);
-
- trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp);
-
- ret = kgsl_add_event(device, KGSL_MEMSTORE_GLOBAL, timestamp,
- global_wait_callback, drawctxt, NULL);
- if (ret) {
- kgsl_context_put(context);
- goto done;
- }
-
- mutex_unlock(&device->mutex);
-
- if (timeout) {
- ret = (int) wait_event_interruptible_timeout(drawctxt->waiting,
- _check_global_timestamp(device, timestamp),
- msecs_to_jiffies(timeout));
-
- if (ret == 0)
- ret = -ETIMEDOUT;
- else if (ret > 0)
- ret = 0;
- } else {
- ret = (int) wait_event_interruptible(drawctxt->waiting,
- _check_global_timestamp(device, timestamp));
- }
-
- mutex_lock(&device->mutex);
-
- if (ret)
- kgsl_cancel_events_timestamp(device, NULL, timestamp);
-
-done:
- trace_adreno_drawctxt_wait_done(KGSL_MEMSTORE_GLOBAL, timestamp, ret);
- return ret;
-}
-
-/**
- * adreno_drawctxt_invalidate() - Invalidate an adreno draw context
- * @device: Pointer to the KGSL device structure for the GPU
- * @context: Pointer to the KGSL context structure
- *
- * Invalidate the context and remove all queued commands and cancel any pending
- * waiters
- */
-void adreno_drawctxt_invalidate(struct kgsl_device *device,
- struct kgsl_context *context)
-{
- struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-
- trace_adreno_drawctxt_invalidate(drawctxt);
-
- drawctxt->state = ADRENO_CONTEXT_STATE_INVALID;
-
- /* Clear the pending queue */
- mutex_lock(&drawctxt->mutex);
-
- while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
- struct kgsl_cmdbatch *cmdbatch =
- drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
- drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
- ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
- mutex_unlock(&drawctxt->mutex);
-
- mutex_lock(&device->mutex);
- kgsl_cancel_events_timestamp(device, context,
- cmdbatch->timestamp);
- mutex_unlock(&device->mutex);
-
- kgsl_cmdbatch_destroy(cmdbatch);
- mutex_lock(&drawctxt->mutex);
- }
-
- mutex_unlock(&drawctxt->mutex);
-
- /* Give the bad news to everybody waiting around */
- wake_up_interruptible_all(&drawctxt->waiting);
- wake_up_interruptible_all(&drawctxt->wq);
-}
-
/**
* adreno_drawctxt_create - create a new adreno draw context
* @dev_priv: the owner of the context
@@ -392,7 +149,6 @@
int ret;
drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
-
if (drawctxt == NULL)
return ERR_PTR(-ENOMEM);
@@ -412,30 +168,22 @@
KGSL_CONTEXT_NO_FAULT_TOLERANCE |
KGSL_CONTEXT_TYPE_MASK);
- /* Always enable per-context timestamps */
- *flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
- drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
-
if (*flags & KGSL_CONTEXT_PREAMBLE)
drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
if (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
- if (*flags & KGSL_CONTEXT_USER_GENERATED_TS)
+ if (*flags & KGSL_CONTEXT_PER_CONTEXT_TS)
+ drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
+
+ if (*flags & KGSL_CONTEXT_USER_GENERATED_TS) {
+ if (!(*flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
+ ret = -EINVAL;
+ goto err;
+ }
drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
-
- mutex_init(&drawctxt->mutex);
- init_waitqueue_head(&drawctxt->wq);
- init_waitqueue_head(&drawctxt->waiting);
-
- /*
- * Set up the plist node for the dispatcher. For now all contexts have
- * the same priority, but later the priority will be set at create time
- * by the user
- */
-
- plist_node_init(&drawctxt->pending, ADRENO_CONTEXT_DEFAULT_PRIORITY);
+ }
if (*flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;
@@ -448,6 +196,12 @@
goto err;
kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ref_wait_ts),
+ KGSL_INIT_REFTIMESTAMP);
+ kgsl_sharedmem_writel(device, &device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ts_cmp_enable),
+ 0);
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
0);
kgsl_sharedmem_writel(device, &device->memstore,
@@ -461,39 +215,22 @@
}
/**
- * adreno_drawctxt_sched() - Schedule a previously blocked context
- * @device: pointer to a KGSL device
- * @drawctxt: drawctxt to rechedule
- *
- * This function is called by the core when it knows that a previously blocked
- * context has been unblocked. The default adreno response is to reschedule the
- * context on the dispatcher
- */
-void adreno_drawctxt_sched(struct kgsl_device *device,
- struct kgsl_context *context)
-{
- adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context));
-}
-
-/**
* adreno_drawctxt_detach(): detach a context from the GPU
* @context: Generic KGSL context container for the context
*
*/
-int adreno_drawctxt_detach(struct kgsl_context *context)
+void adreno_drawctxt_detach(struct kgsl_context *context)
{
struct kgsl_device *device;
struct adreno_device *adreno_dev;
struct adreno_context *drawctxt;
- int ret;
if (context == NULL)
- return 0;
+ return;
device = context->device;
adreno_dev = ADRENO_DEVICE(device);
drawctxt = ADRENO_CONTEXT(context);
-
/* deactivate context */
if (adreno_dev->drawctxt_active == drawctxt) {
/* no need to save GMEM or shader, the context is
@@ -509,39 +246,13 @@
adreno_drawctxt_switch(adreno_dev, NULL, 0);
}
- mutex_lock(&drawctxt->mutex);
-
- while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
- struct kgsl_cmdbatch *cmdbatch =
- drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
- drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
- ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
- mutex_unlock(&drawctxt->mutex);
-
- /*
- * Don't hold the drawctxt mutex while the cmdbatch is being
- * destroyed because the cmdbatch destroy takes the device
- * mutex and the world falls in on itself
- */
-
- kgsl_cmdbatch_destroy(cmdbatch);
- mutex_lock(&drawctxt->mutex);
- }
-
- mutex_unlock(&drawctxt->mutex);
-
- /* Wait for the last global timestamp to pass before continuing */
- ret = adreno_drawctxt_wait_global(adreno_dev, context,
- drawctxt->internal_timestamp, 10 * 1000);
+ if (device->state != KGSL_STATE_HUNG)
+ adreno_idle(device);
adreno_profile_process_results(device);
kgsl_sharedmem_free(&drawctxt->gpustate);
kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
-
- return ret;
}
@@ -585,12 +296,11 @@
* Switch the current draw context
*/
-int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
+void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt,
unsigned int flags)
{
struct kgsl_device *device = &adreno_dev->dev;
- int ret = 0;
if (drawctxt) {
if (flags & KGSL_CONTEXT_SAVE_GMEM)
@@ -606,24 +316,18 @@
if (adreno_dev->drawctxt_active == drawctxt) {
if (adreno_dev->gpudev->ctxt_draw_workaround &&
adreno_is_a225(adreno_dev))
- ret = adreno_dev->gpudev->ctxt_draw_workaround(
+ adreno_dev->gpudev->ctxt_draw_workaround(
adreno_dev, drawctxt);
- return ret;
+ return;
}
- trace_adreno_drawctxt_switch(adreno_dev->drawctxt_active,
- drawctxt, flags);
+ KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
+ adreno_dev->drawctxt_active ?
+ adreno_dev->drawctxt_active->base.id : 0,
+ drawctxt ? drawctxt->base.id : 0, flags);
/* Save the old context */
- ret = adreno_dev->gpudev->ctxt_save(adreno_dev,
- adreno_dev->drawctxt_active);
-
- if (ret) {
- KGSL_DRV_ERR(device,
- "Error in GPU context %d save: %d\n",
- adreno_dev->drawctxt_active->base.id, ret);
- return ret;
- }
+ adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
/* Put the old instance of the active drawctxt */
if (adreno_dev->drawctxt_active) {
@@ -636,14 +340,6 @@
_kgsl_context_get(&drawctxt->base);
/* Set the new context */
- ret = adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
- if (ret) {
- KGSL_DRV_ERR(device,
- "Error in GPU context %d restore: %d\n",
- drawctxt->base.id, ret);
- return ret;
- }
-
+ adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
adreno_dev->drawctxt_active = drawctxt;
- return 0;
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 5c12676..3088099 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -54,8 +54,6 @@
#define CTXT_FLAGS_SKIP_EOF BIT(15)
/* Context no fault tolerance */
#define CTXT_FLAGS_NO_FAULT_TOLERANCE BIT(16)
-/* Force the preamble for the next submission */
-#define CTXT_FLAGS_FORCE_PREAMBLE BIT(17)
/* Symbolic table for the adreno draw context type */
#define ADRENO_DRAWCTXT_TYPES \
@@ -71,13 +69,6 @@
const char *str;
};
-#define ADRENO_CONTEXT_CMDQUEUE_SIZE 128
-
-#define ADRENO_CONTEXT_DEFAULT_PRIORITY 1
-
-#define ADRENO_CONTEXT_STATE_ACTIVE 0
-#define ADRENO_CONTEXT_STATE_INVALID 1
-
struct kgsl_device;
struct adreno_device;
struct kgsl_device_private;
@@ -108,58 +99,18 @@
struct kgsl_memdesc quad_vertices_restore;
};
-/**
- * struct adreno_context - Adreno GPU draw context
- * @id: Unique integer ID of the context
- * @timestamp: Last issued context-specific timestamp
- * @internal_timestamp: Global timestamp of the last issued command
- * @state: Current state of the context
- * @flags: Bitfield controlling behavior of the context
- * @type: Context type (GL, CL, RS)
- * @mutex: Mutex to protect the cmdqueue
- * @pagetable: Pointer to the GPU pagetable for the context
- * @gpustate: Pointer to the GPU scratch memory for context save/restore
- * @reg_restore: Command buffer for restoring context registers
- * @shader_save: Command buffer for saving shaders
- * @shader_restore: Command buffer to restore shaders
- * @context_gmem_shadow: GMEM shadow structure for save/restore
- * @reg_save: A2XX command buffer to save context registers
- * @shader_fixup: A2XX command buffer to "fix" shaders on restore
- * @chicken_restore: A2XX command buffer to "fix" register restore
- * @bin_base_offset: Saved value of the A2XX BIN_BASE_OFFSET register
- * @regconstant_save: A3XX command buffer to save some registers
- * @constant_retore: A3XX command buffer to restore some registers
- * @hslqcontrol_restore: A3XX command buffer to restore HSLSQ registers
- * @save_fixup: A3XX command buffer to "fix" register save
- * @restore_fixup: A3XX cmmand buffer to restore register save fixes
- * @shader_load_commands: A3XX GPU memory descriptor for shader load IB
- * @shader_save_commands: A3XX GPU memory descriptor for shader save IB
- * @constantr_save_commands: A3XX GPU memory descriptor for constant save IB
- * @constant_load_commands: A3XX GPU memory descriptor for constant load IB
- * @cond_execs: A3XX GPU memory descriptor for conditional exec IB
- * @hlsq_restore_commands: A3XX GPU memory descriptor for HLSQ restore IB
- * @cmdqueue: Queue of command batches waiting to be dispatched for this context
- * @cmdqueue_head: Head of the cmdqueue queue
- * @cmdqueue_tail: Tail of the cmdqueue queue
- * @pending: Priority list node for the dispatcher list of pending contexts
- * @wq: Workqueue structure for contexts to sleep pending room in the queue
- * @waiting: Workqueue structure for contexts waiting for a timestamp or event
- * @queued: Number of commands queued in the cmdqueue
- */
struct adreno_context {
struct kgsl_context base;
unsigned int ib_gpu_time_used;
unsigned int timestamp;
- unsigned int internal_timestamp;
- int state;
uint32_t flags;
unsigned int type;
- struct mutex mutex;
struct kgsl_memdesc gpustate;
unsigned int reg_restore[3];
unsigned int shader_save[3];
unsigned int shader_restore[3];
+ /* Information of the GMEM shadow that is created in context create */
struct gmem_shadow_t context_gmem_shadow;
/* A2XX specific items */
@@ -180,44 +131,23 @@
struct kgsl_memdesc constant_load_commands[3];
struct kgsl_memdesc cond_execs[4];
struct kgsl_memdesc hlsqcontrol_restore_commands[1];
-
- /* Dispatcher */
- struct kgsl_cmdbatch *cmdqueue[ADRENO_CONTEXT_CMDQUEUE_SIZE];
- int cmdqueue_head;
- int cmdqueue_tail;
-
- struct plist_node pending;
- wait_queue_head_t wq;
- wait_queue_head_t waiting;
-
- int queued;
};
struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
uint32_t *flags);
-int adreno_drawctxt_detach(struct kgsl_context *context);
+void adreno_drawctxt_detach(struct kgsl_context *context);
void adreno_drawctxt_destroy(struct kgsl_context *context);
-void adreno_drawctxt_sched(struct kgsl_device *device,
- struct kgsl_context *context);
-
-int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
+void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt,
unsigned int flags);
void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device,
struct kgsl_context *context,
unsigned int offset);
-int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
- struct kgsl_context *context,
- uint32_t timestamp, unsigned int timeout);
-
-void adreno_drawctxt_invalidate(struct kgsl_device *device,
- struct kgsl_context *context);
-
/* GPU context switch helper functions */
void build_quad_vtxbuff(struct adreno_context *drawctxt,
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 8fb2830..32dbd51 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -22,7 +22,6 @@
#include "adreno_ringbuffer.h"
#include "kgsl_cffdump.h"
#include "kgsl_pwrctrl.h"
-#include "adreno_trace.h"
#include "a2xx_reg.h"
#include "a3xx_reg.h"
@@ -396,8 +395,8 @@
int adreno_dump(struct kgsl_device *device, int manual)
{
- unsigned int cp_ib1_base;
- unsigned int cp_ib2_base;
+ unsigned int cp_ib1_base, cp_ib1_bufsz;
+ unsigned int cp_ib2_base, cp_ib2_bufsz;
phys_addr_t pt_base, cur_pt_base;
unsigned int cp_rb_base, cp_rb_ctrl, rb_count;
unsigned int cp_rb_wptr, cp_rb_rptr;
@@ -410,6 +409,7 @@
unsigned int ts_processed = 0xdeaddead;
struct kgsl_context *context;
unsigned int context_id;
+ unsigned int rbbm_status;
static struct ib_list ib_list;
@@ -419,10 +419,16 @@
mb();
- msm_clk_dump_debug_info();
+ if (device->pm_dump_enable) {
+ msm_clk_dump_debug_info();
- if (adreno_dev->gpudev->postmortem_dump)
- adreno_dev->gpudev->postmortem_dump(adreno_dev);
+ if (adreno_dev->gpudev->postmortem_dump)
+ adreno_dev->gpudev->postmortem_dump(adreno_dev);
+ }
+
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
+ &rbbm_status);
pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
cur_pt_base = pt_base;
@@ -444,8 +450,26 @@
adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
&cp_ib1_base);
kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
+ &cp_ib1_bufsz);
+ kgsl_regread(device,
adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
&cp_ib2_base);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
+ &cp_ib2_bufsz);
+
+ /* If postmortem dump is not enabled, dump minimal set and return */
+ if (!device->pm_dump_enable) {
+
+ KGSL_LOG_DUMP(device,
+ "STATUS %08X | IB1:%08X/%08X | IB2: %08X/%08X"
+ " | RPTR: %04X | WPTR: %04X\n",
+ rbbm_status, cp_ib1_base, cp_ib1_bufsz, cp_ib2_base,
+ cp_ib2_bufsz, cp_rb_rptr, cp_rb_wptr);
+
+ return 0;
+ }
kgsl_sharedmem_readl(&device->memstore,
(unsigned int *) &context_id,
@@ -620,9 +644,5 @@
error_vfree:
vfree(rb_copy);
end:
- /* Restart the dispatcher after a manually triggered dump */
- if (manual)
- adreno_dispatcher_start(adreno_dev);
-
return result;
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1ad90fd..b8cf21f 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -67,8 +67,11 @@
unsigned long wait_time;
unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
unsigned long wait_time_part;
+ unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
unsigned int rptr;
+ memset(prev_reg_val, 0, sizeof(prev_reg_val));
+
/* if wptr ahead, fill the remaining with NOPs */
if (wptr_ahead) {
/* -1 for header */
@@ -102,13 +105,43 @@
if (freecmds == 0 || freecmds > numcmds)
break;
+ /* Dont wait for timeout, detect hang faster.
+ */
+ if (time_after(jiffies, wait_time_part)) {
+ wait_time_part = jiffies +
+ msecs_to_jiffies(KGSL_TIMEOUT_PART);
+ if ((adreno_ft_detect(rb->device,
+ prev_reg_val))){
+ KGSL_DRV_ERR(rb->device,
+ "Hang detected while waiting for freespace in"
+ "ringbuffer rptr: 0x%x, wptr: 0x%x\n",
+ rptr, rb->wptr);
+ goto err;
+ }
+ }
+
if (time_after(jiffies, wait_time)) {
KGSL_DRV_ERR(rb->device,
"Timed out while waiting for freespace in ringbuffer "
"rptr: 0x%x, wptr: 0x%x\n", rptr, rb->wptr);
- return -ETIMEDOUT;
+ goto err;
}
+ continue;
+
+err:
+ if (!adreno_dump_and_exec_ft(rb->device)) {
+ if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
+ KGSL_CTXT_WARN(rb->device,
+ "Context %p caused a gpu hang. Will not accept commands for context %d\n",
+ context, context->base.id);
+ return -EDEADLK;
+ }
+ wait_time = jiffies + wait_timeout;
+ } else {
+ /* GPU is hung and fault tolerance failed */
+ BUG();
+ }
}
return 0;
}
@@ -147,8 +180,7 @@
if (!ret) {
ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
rb->wptr += numcmds;
- } else
- ptr = ERR_PTR(ret);
+ }
return ptr;
}
@@ -315,6 +347,7 @@
int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
{
int status;
+ /*cp_rb_cntl_u cp_rb_cntl; */
union reg_cp_rb_cntl cp_rb_cntl;
unsigned int rb_cntl;
struct kgsl_device *device = rb->device;
@@ -535,17 +568,18 @@
static int
adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
- struct adreno_context *drawctxt,
+ struct adreno_context *context,
unsigned int flags, unsigned int *cmds,
- int sizedwords, uint32_t timestamp)
+ int sizedwords)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
unsigned int *ringcmds;
unsigned int total_sizedwords = sizedwords;
unsigned int i;
unsigned int rcmd_gpu;
- unsigned int context_id;
+ unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
unsigned int gpuaddr = rb->device->memstore.gpuaddr;
+ unsigned int timestamp;
bool profile_ready;
/*
@@ -560,19 +594,15 @@
adreno_profile_assignments_ready(&adreno_dev->profile) &&
!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE);
- /* The global timestamp always needs to be incremented */
- rb->global_ts++;
-
- /* If this is a internal IB, use the global timestamp for it */
- if (!drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
- timestamp = rb->global_ts;
- context_id = KGSL_MEMSTORE_GLOBAL;
- } else {
- context_id = drawctxt->base.id;
- }
-
- if (drawctxt)
- drawctxt->internal_timestamp = rb->global_ts;
+ /*
+ * if the context was not created with per context timestamp
+ * support, we must use the global timestamp since issueibcmds
+ * will be returning that one, or if an internal issue then
+ * use global timestamp.
+ */
+ if ((context && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) &&
+ !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
+ context_id = context->base.id;
/* reserve space to temporarily turn off protected mode
* error checking if needed
@@ -583,8 +613,13 @@
/* internal ib command identifier for the ringbuffer */
total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0;
- /* Add two dwords for the CP_INTERRUPT */
- total_sizedwords += drawctxt ? 2 : 0;
+ /* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
+ total_sizedwords += context ? 13 : 0;
+
+ if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+ (flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+ KGSL_CMD_FLAGS_GET_INT)))
+ total_sizedwords += 2;
if (adreno_is_a3xx(adreno_dev))
total_sizedwords += 7;
@@ -592,31 +627,25 @@
if (adreno_is_a2xx(adreno_dev))
total_sizedwords += 2; /* CP_WAIT_FOR_IDLE */
+ total_sizedwords += 2; /* scratchpad ts for fault tolerance */
total_sizedwords += 3; /* sop timestamp */
total_sizedwords += 4; /* eop timestamp */
- if (adreno_is_a20x(adreno_dev))
- total_sizedwords += 2; /* CACHE_FLUSH */
-
- if (drawctxt) {
+ if (KGSL_MEMSTORE_GLOBAL != context_id)
total_sizedwords += 3; /* global timestamp without cache
* flush for non-zero context */
- }
if (adreno_is_a20x(adreno_dev))
total_sizedwords += 2; /* CACHE_FLUSH */
- if (flags & KGSL_CMD_FLAGS_WFI)
- total_sizedwords += 2; /* WFI */
+ if (flags & KGSL_CMD_FLAGS_EOF)
+ total_sizedwords += 2;
if (profile_ready)
total_sizedwords += 6; /* space for pre_ib and post_ib */
- ringcmds = adreno_ringbuffer_allocspace(rb, drawctxt, total_sizedwords);
-
- if (IS_ERR(ringcmds))
- return PTR_ERR(ringcmds);
- if (ringcmds == NULL)
+ ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords);
+ if (!ringcmds)
return -ENOSPC;
rcmd_gpu = rb->buffer_desc.gpuaddr
@@ -633,9 +662,24 @@
/* Add any IB required for profiling if it is enabled */
if (profile_ready)
- adreno_profile_preib_processing(rb->device, drawctxt->base.id,
+ adreno_profile_preib_processing(rb->device, context->base.id,
&flags, &ringcmds, &rcmd_gpu);
+ /* always increment the global timestamp. once. */
+ rb->global_ts++;
+
+ if (KGSL_MEMSTORE_GLOBAL != context_id)
+ timestamp = context->timestamp;
+ else
+ timestamp = rb->global_ts;
+
+ /* scratchpad ts for fault tolerance */
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type0_packet(adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_TIMESTAMP), 1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ rb->global_ts);
+
/* start-of-pipeline timestamp */
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
@@ -705,7 +749,7 @@
KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
- if (drawctxt) {
+ if (KGSL_MEMSTORE_GLOBAL != context_id) {
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
@@ -721,13 +765,56 @@
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, CACHE_FLUSH);
}
- if (drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
+ if (context) {
+ /* Conditional execution based on memory values */
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_COND_EXEC, 4));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
+ KGSL_MEMSTORE_OFFSET(
+ context_id, ts_cmp_enable)) >> 2);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
+ KGSL_MEMSTORE_OFFSET(
+ context_id, ref_wait_ts)) >> 2);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
+ /* # of conditional command DWORDs */
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 8);
+
+ /* Clear the ts_cmp_enable for the context */
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_MEM_WRITE, 2));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
+ KGSL_MEMSTORE_OFFSET(
+ context_id, ts_cmp_enable));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
+
+ /* Clear the ts_cmp_enable for the global timestamp */
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_MEM_WRITE, 2));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
+ KGSL_MEMSTORE_OFFSET(
+ KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
+
+ /* Trigger the interrupt */
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_INTERRUPT, 1));
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
CP_INT_CNTL__RB_INT_MASK);
}
+ /*
+ * If per context timestamps are enabled and any of the kgsl
+ * internal commands want INT to be generated trigger the INT
+ */
+ if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+ (flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+ KGSL_CMD_FLAGS_GET_INT))) {
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_INTERRUPT, 1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ CP_INT_CNTL__RB_INT_MASK);
+ }
+
if (adreno_is_a3xx(adreno_dev)) {
/* Dummy set-constant to trigger context rollover */
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
@@ -737,10 +824,10 @@
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
}
- if (flags & KGSL_CMD_FLAGS_WFI) {
+ if (flags & KGSL_CMD_FLAGS_EOF) {
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
- cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
- GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00000000);
+ KGSL_END_OF_FRAME_IDENTIFIER);
}
adreno_ringbuffer_submit(rb);
@@ -758,10 +845,14 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ if (device->state & KGSL_STATE_HUNG)
+ return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
+ KGSL_TIMESTAMP_RETIRED);
+
flags |= KGSL_CMD_FLAGS_INTERNAL_ISSUE;
return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds,
- sizedwords, 0);
+ sizedwords);
}
static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
@@ -954,90 +1045,39 @@
return ret;
}
-/**
- * _ringbuffer_verify_ib() - parse an IB and verify that it is correct
- * @dev_priv: Pointer to the process struct
- * @ibdesc: Pointer to the IB descriptor
- *
- * This function only gets called if debugging is enabled - it walks the IB and
- * does additional level parsing and verification above and beyond what KGSL
- * core does
- */
-static inline bool _ringbuffer_verify_ib(struct kgsl_device_private *dev_priv,
- struct kgsl_ibdesc *ibdesc)
-{
- struct kgsl_device *device = dev_priv->device;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
- /* Check that the size of the IBs is under the allowable limit */
- if (ibdesc->sizedwords == 0 || ibdesc->sizedwords > 0xFFFFF) {
- KGSL_DRV_ERR(device, "Invalid IB size 0x%X\n",
- ibdesc->sizedwords);
- return false;
- }
-
- if (unlikely(adreno_dev->ib_check_level >= 1) &&
- !_parse_ibs(dev_priv, ibdesc->gpuaddr, ibdesc->sizedwords)) {
- KGSL_DRV_ERR(device, "Could not verify the IBs\n");
- return false;
- }
-
- return true;
-}
-
int
adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
struct kgsl_context *context,
- struct kgsl_cmdbatch *cmdbatch,
- uint32_t *timestamp)
+ struct kgsl_ibdesc *ibdesc,
+ unsigned int numibs,
+ uint32_t *timestamp,
+ unsigned int flags)
{
struct kgsl_device *device = dev_priv->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
- int i, ret;
-
- if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
- return -EDEADLK;
-
- /* Verify the IBs before they get queued */
-
- for (i = 0; i < cmdbatch->ibcount; i++) {
- if (!_ringbuffer_verify_ib(dev_priv, &cmdbatch->ibdesc[i]))
- return -EINVAL;
- }
-
- /* Queue the command in the ringbuffer */
- ret = adreno_dispatcher_queue_cmd(adreno_dev, drawctxt, cmdbatch,
- timestamp);
-
- if (ret)
- KGSL_DRV_ERR(device,
- "adreno_dispatcher_queue_cmd returned %d\n", ret);
-
- return ret;
-}
-
-/* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */
-int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
- struct kgsl_cmdbatch *cmdbatch)
-{
- struct kgsl_device *device = &adreno_dev->dev;
- struct kgsl_ibdesc *ibdesc;
- unsigned int numibs;
- unsigned int *link;
+ unsigned int *link = 0;
unsigned int *cmds;
unsigned int i;
- struct kgsl_context *context;
- struct adreno_context *drawctxt;
+ struct adreno_context *drawctxt = NULL;
unsigned int start_index = 0;
- int flags = KGSL_CMD_FLAGS_NONE;
int ret;
- context = cmdbatch->context;
+ if (device->state & KGSL_STATE_HUNG) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
+ context == NULL || ibdesc == 0 || numibs == 0) {
+ ret = -EINVAL;
+ goto done;
+ }
drawctxt = ADRENO_CONTEXT(context);
- ibdesc = cmdbatch->ibdesc;
- numibs = cmdbatch->ibcount;
+ if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
+ ret = -EDEADLK;
+ goto done;
+ }
/* process any profiling results that are available into the log_buf */
adreno_profile_process_results(device);
@@ -1046,21 +1086,17 @@
commands are stored in the first node of the IB chain. We can skip that
if a context switch hasn't occured */
- if ((drawctxt->flags & CTXT_FLAGS_PREAMBLE) &&
- !test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) &&
- (adreno_dev->drawctxt_active == drawctxt))
+ if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
+ adreno_dev->drawctxt_active == drawctxt)
start_index = 1;
- /*
- * In skip mode don't issue the draw IBs but keep all the other
- * accoutrements of a submision (including the interrupt) to keep
- * the accounting sane. Set start_index and numibs to 0 to just
- * generate the start and end markers and skip everything else
- */
-
- if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) {
- start_index = 0;
- numibs = 0;
+ if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
+ if (flags & KGSL_CMD_FLAGS_EOF)
+ drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
+ if (start_index)
+ numibs = 1;
+ else
+ numibs = 0;
}
cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
@@ -1081,17 +1117,19 @@
*cmds++ = ibdesc[0].sizedwords;
}
for (i = start_index; i < numibs; i++) {
+ if (unlikely(adreno_dev->ib_check_level >= 1 &&
+ !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
+ ibdesc[i].sizedwords))) {
+ ret = -EINVAL;
+ goto done;
+ }
- /*
- * Skip 0 sized IBs - these are presumed to have been removed
- * from consideration by the FT policy
- */
+ if (ibdesc[i].sizedwords == 0) {
+ ret = -EINVAL;
+ goto done;
+ }
- if (ibdesc[i].sizedwords == 0)
- *cmds++ = cp_nop_packet(2);
- else
- *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
-
+ *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
*cmds++ = ibdesc[i].gpuaddr;
*cmds++ = ibdesc[i].sizedwords;
}
@@ -1099,47 +1137,253 @@
*cmds++ = cp_nop_packet(1);
*cmds++ = KGSL_END_OF_IB_IDENTIFIER;
- ret = kgsl_setstate(&device->mmu, context->id,
+ kgsl_setstate(&device->mmu, context->id,
kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
device->id));
- if (ret)
- goto done;
+ adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
- ret = adreno_drawctxt_switch(adreno_dev, drawctxt, cmdbatch->flags);
-
- /*
- * In the unlikely event of an error in the drawctxt switch,
- * treat it like a hang
- */
- if (ret)
- goto done;
-
- if (test_bit(CMDBATCH_FLAG_WFI, &cmdbatch->priv))
- flags = KGSL_CMD_FLAGS_WFI;
+ if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
+ if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
+ KGSL_DRV_ERR(device,
+ "Invalid user generated ts <%d:0x%x>, "
+ "less than last issued ts <%d:0x%x>\n",
+ context->id, *timestamp, context->id,
+ drawctxt->timestamp);
+ return -ERANGE;
+ }
+ drawctxt->timestamp = *timestamp;
+ } else
+ drawctxt->timestamp++;
ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
- flags,
- &link[0], (cmds - link),
- cmdbatch->timestamp);
-
-#ifdef CONFIG_MSM_KGSL_CFF_DUMP
+ (flags & KGSL_CMD_FLAGS_EOF),
+ &link[0], (cmds - link));
if (ret)
goto done;
+
+ if (drawctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+ *timestamp = drawctxt->timestamp;
+ else
+ *timestamp = adreno_dev->ringbuffer.global_ts;
+
+#ifdef CONFIG_MSM_KGSL_CFF_DUMP
/*
* insert wait for idle after every IB1
* this is conservative but works reliably and is ok
* even for performance simulations
*/
- ret = adreno_idle(device);
+ adreno_idle(device);
#endif
+ /*
+ * If context hung and recovered then return error so that the
+ * application may handle it
+ */
+ if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_FT) {
+ drawctxt->flags &= ~CTXT_FLAGS_GPU_HANG_FT;
+ ret = -EPROTO;
+ } else
+ ret = 0;
+
done:
- kgsl_trace_issueibcmds(device, context->id, cmdbatch,
- cmdbatch->timestamp, cmdbatch->flags, ret,
- drawctxt->type);
+ device->pwrctrl.irq_last = 0;
+ kgsl_trace_issueibcmds(device, context ? context->id : 0, ibdesc,
+ numibs, *timestamp, flags, ret,
+ drawctxt ? drawctxt->type : 0);
kfree(link);
return ret;
}
+
+static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
+ unsigned int rb_rptr)
+{
+ unsigned int temp_rb_rptr = rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[2];
+ int i = 0;
+ bool check = false;
+ bool cmd_start = false;
+
+ /* Go till the start of the ib sequence and turn on preamble */
+ while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+ if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
+ /* decrement i */
+ i = (i + 1) % 2;
+ if (val[i] == cp_nop_packet(4)) {
+ temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+ temp_rb_rptr, size);
+ kgsl_sharedmem_writel(rb->device,
+ &rb->buffer_desc,
+ temp_rb_rptr, cp_nop_packet(1));
+ }
+ KGSL_FT_INFO(rb->device,
+ "Turned preamble on at offset 0x%x\n",
+ temp_rb_rptr / 4);
+ break;
+ }
+ /* If you reach beginning of next command sequence then exit
+ * First command encountered is the current one so don't break
+ * on that. */
+ if (KGSL_CMD_IDENTIFIER == val[i]) {
+ if (cmd_start)
+ break;
+ cmd_start = true;
+ }
+
+ i = (i + 1) % 2;
+ if (1 == i)
+ check = true;
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+ size);
+ }
+}
+
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+ struct adreno_ft_data *ft_data)
+{
+ struct kgsl_device *device = rb->device;
+ unsigned int rb_rptr = ft_data->start_of_replay_cmds;
+ unsigned int good_rb_idx = 0, bad_rb_idx = 0, temp_rb_idx = 0;
+ unsigned int last_good_cmd_end_idx = 0, last_bad_cmd_end_idx = 0;
+ unsigned int cmd_start_idx = 0;
+ unsigned int val1 = 0;
+ int copy_rb_contents = 0;
+ unsigned int temp_rb_rptr;
+ struct kgsl_context *k_ctxt;
+ struct adreno_context *a_ctxt;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int *temp_rb_buffer = ft_data->rb_buffer;
+ int *rb_size = &ft_data->rb_size;
+ unsigned int *bad_rb_buffer = ft_data->bad_rb_buffer;
+ int *bad_rb_size = &ft_data->bad_rb_size;
+ unsigned int *good_rb_buffer = ft_data->good_rb_buffer;
+ int *good_rb_size = &ft_data->good_rb_size;
+
+ /*
+ * If the start index from where commands need to be copied is invalid
+ * then no need to save off any commands
+ */
+ if (0xFFFFFFFF == ft_data->start_of_replay_cmds)
+ return;
+
+ k_ctxt = kgsl_context_get(device, ft_data->context_id);
+
+ if (k_ctxt) {
+ a_ctxt = ADRENO_CONTEXT(k_ctxt);
+ if (a_ctxt->flags & CTXT_FLAGS_PREAMBLE)
+ _turn_preamble_on_for_ib_seq(rb, rb_rptr);
+ kgsl_context_put(k_ctxt);
+ }
+ k_ctxt = NULL;
+
+ /* Walk the rb from the context switch. Omit any commands
+ * for an invalid context. */
+ while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
+
+ if (KGSL_CMD_IDENTIFIER == val1) {
+ /* Start is the NOP dword that comes before
+ * KGSL_CMD_IDENTIFIER */
+ cmd_start_idx = temp_rb_idx - 1;
+ if ((copy_rb_contents) && (good_rb_idx))
+ last_good_cmd_end_idx = good_rb_idx - 1;
+ if ((!copy_rb_contents) && (bad_rb_idx))
+ last_bad_cmd_end_idx = bad_rb_idx - 1;
+ }
+
+ /* check for context switch indicator */
+ if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+ unsigned int temp_idx, val2;
+ /* increment by 3 to get to the context_id */
+ temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
+ size;
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
+ temp_rb_rptr);
+
+ /* if context switches to a context that did not cause
+ * hang then start saving the rb contents as those
+ * commands can be executed */
+ k_ctxt = kgsl_context_get(rb->device, val2);
+
+ if (k_ctxt) {
+ a_ctxt = ADRENO_CONTEXT(k_ctxt);
+
+ /* If we are changing to a good context and were not
+ * copying commands then copy over commands to the good
+ * context */
+ if (!copy_rb_contents && ((k_ctxt &&
+ !(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
+ !k_ctxt)) {
+ for (temp_idx = cmd_start_idx;
+ temp_idx < temp_rb_idx;
+ temp_idx++)
+ good_rb_buffer[good_rb_idx++] =
+ temp_rb_buffer[temp_idx];
+ ft_data->last_valid_ctx_id = val2;
+ copy_rb_contents = 1;
+ /* remove the good commands from bad buffer */
+ bad_rb_idx = last_bad_cmd_end_idx;
+ } else if (copy_rb_contents && k_ctxt &&
+ (a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
+
+ /* If we are changing back to a bad context
+ * from good ctxt and were not copying commands
+ * to bad ctxt then copy over commands to
+ * the bad context */
+ for (temp_idx = cmd_start_idx;
+ temp_idx < temp_rb_idx;
+ temp_idx++)
+ bad_rb_buffer[bad_rb_idx++] =
+ temp_rb_buffer[temp_idx];
+ /* If we are changing to bad context then
+ * remove the dwords we copied for this
+ * sequence from the good buffer */
+ good_rb_idx = last_good_cmd_end_idx;
+ copy_rb_contents = 0;
+ }
+ }
+ kgsl_context_put(k_ctxt);
+ }
+
+ if (copy_rb_contents)
+ good_rb_buffer[good_rb_idx++] = val1;
+ else
+ bad_rb_buffer[bad_rb_idx++] = val1;
+
+ /* Copy both good and bad commands to temp buffer */
+ temp_rb_buffer[temp_rb_idx++] = val1;
+
+ rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
+ }
+ *good_rb_size = good_rb_idx;
+ *bad_rb_size = bad_rb_idx;
+ *rb_size = temp_rb_idx;
+}
+
+void
+adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
+ int num_rb_contents)
+{
+ int i;
+ unsigned int *ringcmds;
+ unsigned int rcmd_gpu;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
+
+ if (!num_rb_contents)
+ return;
+
+ if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_RPTR, 0);
+ BUG_ON(num_rb_contents > rb->buffer_desc.size);
+ }
+ ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
+ rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
+ for (i = 0; i < num_rb_contents; i++)
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, rb_buff[i]);
+ rb->wptr += num_rb_contents;
+ adreno_ringbuffer_submit(rb);
+}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 3aa0101..9634e32 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -27,6 +27,7 @@
struct kgsl_device;
struct kgsl_device_private;
+struct adreno_ft_data;
#define GSL_RB_MEMPTRS_SCRATCH_COUNT 8
struct kgsl_rbmemptrs {
@@ -98,11 +99,10 @@
int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
struct kgsl_context *context,
- struct kgsl_cmdbatch *cmdbatch,
- uint32_t *timestamp);
-
-int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
- struct kgsl_cmdbatch *cmdbatch);
+ struct kgsl_ibdesc *ibdesc,
+ unsigned int numibs,
+ uint32_t *timestamp,
+ unsigned int flags);
int adreno_ringbuffer_init(struct kgsl_device *device);
@@ -124,6 +124,13 @@
void kgsl_cp_intrcallback(struct kgsl_device *device);
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+ struct adreno_ft_data *ft_data);
+
+void
+adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
+ int num_rb_contents);
+
unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
struct adreno_context *context,
unsigned int numcmds);
diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h
deleted file mode 100644
index 6079b61..0000000
--- a/drivers/gpu/msm/adreno_trace.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/* 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.
- *
- */
-
-#if !defined(_ADRENO_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _ADRENO_TRACE_H
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM kgsl
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE adreno_trace
-
-#include <linux/tracepoint.h>
-
-TRACE_EVENT(adreno_cmdbatch_queued,
- TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int queued),
- TP_ARGS(cmdbatch, queued),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- __field(unsigned int, timestamp)
- __field(unsigned int, queued)
- __field(unsigned int, flags)
- ),
- TP_fast_assign(
- __entry->id = cmdbatch->context->id;
- __entry->timestamp = cmdbatch->timestamp;
- __entry->queued = queued;
- __entry->flags = cmdbatch->flags;
- ),
- TP_printk(
- "ctx=%u ts=%u queued=%u flags=%s",
- __entry->id, __entry->timestamp, __entry->queued,
- __entry->flags ? __print_flags(__entry->flags, "|",
- { KGSL_CONTEXT_SYNC, "SYNC" },
- { KGSL_CONTEXT_END_OF_FRAME, "EOF" })
- : "none"
- )
-);
-
-DECLARE_EVENT_CLASS(adreno_cmdbatch_template,
- TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
- TP_ARGS(cmdbatch, inflight),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- __field(unsigned int, timestamp)
- __field(unsigned int, inflight)
- ),
- TP_fast_assign(
- __entry->id = cmdbatch->context->id;
- __entry->timestamp = cmdbatch->timestamp;
- __entry->inflight = inflight;
- ),
- TP_printk(
- "ctx=%u ts=%u inflight=%u",
- __entry->id, __entry->timestamp,
- __entry->inflight
- )
-);
-
-DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_submitted,
- TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
- TP_ARGS(cmdbatch, inflight)
-);
-
-TRACE_EVENT(adreno_cmdbatch_retired,
- TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
- TP_ARGS(cmdbatch, inflight),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- __field(unsigned int, timestamp)
- __field(unsigned int, inflight)
- __field(unsigned int, recovery)
- ),
- TP_fast_assign(
- __entry->id = cmdbatch->context->id;
- __entry->timestamp = cmdbatch->timestamp;
- __entry->inflight = inflight;
- __entry->recovery = cmdbatch->fault_recovery;
- ),
- TP_printk(
- "ctx=%u ts=%u inflight=%u recovery=%s",
- __entry->id, __entry->timestamp,
- __entry->inflight,
- __entry->recovery ?
- __print_flags(__entry->recovery, "|",
- ADRENO_FT_TYPES) : "none"
- )
-);
-
-TRACE_EVENT(adreno_cmdbatch_fault,
- TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int fault),
- TP_ARGS(cmdbatch, fault),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- __field(unsigned int, timestamp)
- __field(unsigned int, fault)
- ),
- TP_fast_assign(
- __entry->id = cmdbatch->context->id;
- __entry->timestamp = cmdbatch->timestamp;
- __entry->fault = fault;
- ),
- TP_printk(
- "ctx=%u ts=%u type=%s",
- __entry->id, __entry->timestamp,
- __print_symbolic(__entry->fault,
- { 0, "none" },
- { ADRENO_SOFT_FAULT, "soft" },
- { ADRENO_HARD_FAULT, "hard" },
- { ADRENO_TIMEOUT_FAULT, "timeout" })
- )
-);
-
-TRACE_EVENT(adreno_cmdbatch_recovery,
- TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int action),
- TP_ARGS(cmdbatch, action),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- __field(unsigned int, timestamp)
- __field(unsigned int, action)
- ),
- TP_fast_assign(
- __entry->id = cmdbatch->context->id;
- __entry->timestamp = cmdbatch->timestamp;
- __entry->action = action;
- ),
- TP_printk(
- "ctx=%u ts=%u action=%s",
- __entry->id, __entry->timestamp,
- __print_symbolic(__entry->action, ADRENO_FT_TYPES)
- )
-);
-
-DECLARE_EVENT_CLASS(adreno_drawctxt_template,
- TP_PROTO(struct adreno_context *drawctxt),
- TP_ARGS(drawctxt),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- ),
- TP_fast_assign(
- __entry->id = drawctxt->base.id;
- ),
- TP_printk("ctx=%u", __entry->id)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_sleep,
- TP_PROTO(struct adreno_context *drawctxt),
- TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_wake,
- TP_PROTO(struct adreno_context *drawctxt),
- TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, dispatch_queue_context,
- TP_PROTO(struct adreno_context *drawctxt),
- TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_invalidate,
- TP_PROTO(struct adreno_context *drawctxt),
- TP_ARGS(drawctxt)
-);
-
-TRACE_EVENT(adreno_drawctxt_wait_start,
- TP_PROTO(unsigned int id, unsigned int ts),
- TP_ARGS(id, ts),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- __field(unsigned int, ts)
- ),
- TP_fast_assign(
- __entry->id = id;
- __entry->ts = ts;
- ),
- TP_printk(
- "ctx=%u ts=%u",
- __entry->id, __entry->ts
- )
-);
-
-TRACE_EVENT(adreno_drawctxt_wait_done,
- TP_PROTO(unsigned int id, unsigned int ts, int status),
- TP_ARGS(id, ts, status),
- TP_STRUCT__entry(
- __field(unsigned int, id)
- __field(unsigned int, ts)
- __field(int, status)
- ),
- TP_fast_assign(
- __entry->id = id;
- __entry->ts = ts;
- __entry->status = status;
- ),
- TP_printk(
- "ctx=%u ts=%u status=%d",
- __entry->id, __entry->ts, __entry->status
- )
-);
-
-TRACE_EVENT(adreno_drawctxt_switch,
- TP_PROTO(struct adreno_context *oldctx,
- struct adreno_context *newctx,
- unsigned int flags),
- TP_ARGS(oldctx, newctx, flags),
- TP_STRUCT__entry(
- __field(unsigned int, oldctx)
- __field(unsigned int, newctx)
- __field(unsigned int, flags)
- ),
- TP_fast_assign(
- __entry->oldctx = oldctx ? oldctx->base.id : 0;
- __entry->newctx = newctx ? newctx->base.id : 0;
- ),
- TP_printk(
- "oldctx=%u newctx=%u flags=%X",
- __entry->oldctx, __entry->newctx, flags
- )
-);
-
-TRACE_EVENT(adreno_gpu_fault,
- TP_PROTO(unsigned int ctx, unsigned int ts,
- unsigned int status, unsigned int rptr, unsigned int wptr,
- unsigned int ib1base, unsigned int ib1size,
- unsigned int ib2base, unsigned int ib2size),
- TP_ARGS(ctx, ts, status, rptr, wptr, ib1base, ib1size, ib2base,
- ib2size),
- TP_STRUCT__entry(
- __field(unsigned int, ctx)
- __field(unsigned int, ts)
- __field(unsigned int, status)
- __field(unsigned int, rptr)
- __field(unsigned int, wptr)
- __field(unsigned int, ib1base)
- __field(unsigned int, ib1size)
- __field(unsigned int, ib2base)
- __field(unsigned int, ib2size)
- ),
- TP_fast_assign(
- __entry->ctx = ctx;
- __entry->ts = ts;
- __entry->status = status;
- __entry->rptr = rptr;
- __entry->wptr = wptr;
- __entry->ib1base = ib1base;
- __entry->ib1size = ib1size;
- __entry->ib2base = ib2base;
- __entry->ib2size = ib2size;
- ),
- TP_printk("ctx=%d ts=%d status=%X RB=%X/%X IB1=%X/%X IB2=%X/%X",
- __entry->ctx, __entry->ts, __entry->status, __entry->wptr,
- __entry->rptr, __entry->ib1base, __entry->ib1size,
- __entry->ib2base, __entry->ib2size)
-);
-
-#endif /* _ADRENO_TRACE_H */
-
-/* This part must be outside protection */
-#include <trace/define_trace.h>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 35a03de..2781a34 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -14,7 +14,6 @@
#include <linux/fb.h>
#include <linux/file.h>
#include <linux/fs.h>
-#include <linux/list.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
@@ -63,10 +62,59 @@
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
/**
+ * kgsl_hang_check() - Check for GPU hang
+ * data: KGSL device structure
+ *
+ * This function is called every KGSL_TIMEOUT_PART time when
+ * GPU is active to check for hang. If a hang is detected we
+ * trigger fault tolerance.
+ */
+void kgsl_hang_check(struct work_struct *work)
+{
+ struct kgsl_device *device = container_of(work, struct kgsl_device,
+ hang_check_ws);
+ static unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
+
+ mutex_lock(&device->mutex);
+
+ if (device->state == KGSL_STATE_ACTIVE) {
+
+ /* Check to see if the GPU is hung */
+ if (adreno_ft_detect(device, prev_reg_val))
+ adreno_dump_and_exec_ft(device);
+
+ mod_timer(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+ }
+
+ mutex_unlock(&device->mutex);
+}
+
+/**
+ * hang_timer() - Hang timer function
+ * data: KGSL device structure
+ *
+ * This function is called when hang timer expires, in this
+ * function we check if GPU is in active state and queue the
+ * work on device workqueue to check for the hang. We restart
+ * the timer after KGSL_TIMEOUT_PART time.
+ */
+void hang_timer(unsigned long data)
+{
+ struct kgsl_device *device = (struct kgsl_device *) data;
+
+ if (device->state == KGSL_STATE_ACTIVE) {
+ /* Have work run in a non-interrupt context. */
+ queue_work(device->work_queue, &device->hang_check_ws);
+ }
+}
+
+/**
* kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
* device: KGSL device
* id: ID of the context submitting the command
- * cmdbatch: Pointer to kgsl_cmdbatch describing these commands
+ * ibdesc: Pointer to the list of IB descriptors
+ * numib: Number of IBs in the list
* timestamp: Timestamp assigned to the command batch
* flags: Flags sent by the user
* result: Result of the submission attempt
@@ -76,11 +124,11 @@
* GPU specific modules.
*/
void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
- struct kgsl_cmdbatch *cmdbatch,
+ struct kgsl_ibdesc *ibdesc, int numibs,
unsigned int timestamp, unsigned int flags,
int result, unsigned int type)
{
- trace_kgsl_issueibcmds(device, id, cmdbatch,
+ trace_kgsl_issueibcmds(device, id, ibdesc, numibs,
timestamp, flags, result, type);
}
EXPORT_SYMBOL(kgsl_trace_issueibcmds);
@@ -482,8 +530,8 @@
EXPORT_SYMBOL(kgsl_context_init);
/**
- * kgsl_context_detach() - Release the "master" context reference
- * @context: The context that will be detached
+ * kgsl_context_detach - Release the "master" context reference
+ * @context - The context that will be detached
*
* This is called when a context becomes unusable, because userspace
* has requested for it to be destroyed. The context itself may
@@ -492,12 +540,14 @@
* detached by checking the KGSL_CONTEXT_DETACHED bit in
* context->priv.
*/
-int kgsl_context_detach(struct kgsl_context *context)
+void
+kgsl_context_detach(struct kgsl_context *context)
{
- int ret;
-
+ struct kgsl_device *device;
if (context == NULL)
- return -EINVAL;
+ return;
+
+ device = context->device;
/*
* Mark the context as detached to keep others from using
@@ -505,22 +555,19 @@
* we don't try to detach twice.
*/
if (test_and_set_bit(KGSL_CONTEXT_DETACHED, &context->priv))
- return -EINVAL;
+ return;
- trace_kgsl_context_detach(context->device, context);
+ trace_kgsl_context_detach(device, context);
- ret = context->device->ftbl->drawctxt_detach(context);
-
+ device->ftbl->drawctxt_detach(context);
/*
* Cancel events after the device-specific context is
* detached, to avoid possibly freeing memory while
* it is still in use by the GPU.
*/
- kgsl_context_cancel_events(context->device, context);
+ kgsl_context_cancel_events(device, context);
kgsl_context_put(context);
-
- return ret;
}
void
@@ -532,8 +579,6 @@
trace_kgsl_context_destroy(device, context);
- BUG_ON(!kgsl_context_detached(context));
-
write_lock(&device->context_lock);
if (context->id != KGSL_CONTEXT_INVALID) {
idr_remove(&device->context_idr, context->id);
@@ -604,11 +649,10 @@
policy_saved = device->pwrscale.policy;
device->pwrscale.policy = NULL;
kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
-
- /* Tell the device to drain the submission queue */
- device->ftbl->drain(device);
-
- /* Wait for the active count to hit zero */
+ /*
+ * Make sure no user process is waiting for a timestamp
+ * before supending.
+ */
kgsl_active_count_wait(device, 0);
/*
@@ -619,10 +663,13 @@
/* Don't let the timer wake us during suspended sleep. */
del_timer_sync(&device->idle_timer);
+ del_timer_sync(&device->hang_timer);
switch (device->state) {
case KGSL_STATE_INIT:
break;
case KGSL_STATE_ACTIVE:
+ /* Wait for the device to become idle */
+ device->ftbl->idle(device);
case KGSL_STATE_NAP:
case KGSL_STATE_SLEEP:
/* make sure power is on to stop the device */
@@ -948,16 +995,8 @@
if (context == NULL)
break;
- if (context->dev_priv == dev_priv) {
- /*
- * Hold a reference to the context in case somebody
- * tries to put it while we are detaching
- */
-
- _kgsl_context_get(context);
+ if (context->dev_priv == dev_priv)
kgsl_context_detach(context);
- kgsl_context_put(context);
- }
next = next + 1;
}
@@ -971,7 +1010,6 @@
result = kgsl_close_device(device);
mutex_unlock(&device->mutex);
-
kfree(dev_priv);
kgsl_put_process_private(device, private);
@@ -1004,6 +1042,7 @@
* Make sure the gates are open, so they don't block until
* we start suspend or FT.
*/
+ complete_all(&device->ft_gate);
complete_all(&device->hwaccess_gate);
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
kgsl_active_count_put(device);
@@ -1399,610 +1438,93 @@
return result;
}
-/*
- * KGSL command batch management
- * A command batch is a single submission from userland. The cmdbatch
- * encapsulates everything about the submission : command buffers, flags and
- * sync points.
- *
- * Sync points are events that need to expire before the
- * cmdbatch can be queued to the hardware. For each sync point a
- * kgsl_cmdbatch_sync_event struct is created and added to a list in the
- * cmdbatch. There can be multiple types of events both internal ones (GPU
- * events) and external triggers. As the events expire the struct is deleted
- * from the list. The GPU will submit the command batch as soon as the list
- * goes empty indicating that all the sync points have been met.
- */
-
-/**
- * struct kgsl_cmdbatch_sync_event
- * @type: Syncpoint type
- * @node: Local list node for the cmdbatch sync point list
- * @cmdbatch: Pointer to the cmdbatch that owns the sync event
- * @context: Pointer to the KGSL context that owns the cmdbatch
- * @timestamp: Pending timestamp for the event
- * @handle: Pointer to a sync fence handle
- * @device: Pointer to the KGSL device
- * @lock: Spin lock to protect the sync event list
- */
-struct kgsl_cmdbatch_sync_event {
- int type;
- struct list_head node;
- struct kgsl_cmdbatch *cmdbatch;
- struct kgsl_context *context;
- unsigned int timestamp;
- struct kgsl_sync_fence_waiter *handle;
- struct kgsl_device *device;
- spinlock_t lock;
-};
-
-/**
- * kgsl_cmdbatch_destroy_object() - Destroy a cmdbatch object
- * @kref: Pointer to the kref structure for this object
- *
- * Actually destroy a command batch object. Called from kgsl_cmdbatch_put
- */
-void kgsl_cmdbatch_destroy_object(struct kref *kref)
-{
- struct kgsl_cmdbatch *cmdbatch = container_of(kref,
- struct kgsl_cmdbatch, refcount);
-
- kgsl_context_put(cmdbatch->context);
- kfree(cmdbatch->ibdesc);
-
- kfree(cmdbatch);
-}
-EXPORT_SYMBOL(kgsl_cmdbatch_destroy_object);
-
-/*
- * a generic function to retire a pending sync event and (possibly)
- * kick the dispatcher
- */
-static void kgsl_cmdbatch_sync_expire(struct kgsl_device *device,
- struct kgsl_cmdbatch_sync_event *event)
-{
- int sched = 0;
-
- spin_lock(&event->cmdbatch->lock);
- list_del(&event->node);
- sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
- spin_unlock(&event->cmdbatch->lock);
-
- /*
- * if this is the last event in the list then tell
- * the GPU device that the cmdbatch can be submitted
- */
-
- if (sched && device->ftbl->drawctxt_sched)
- device->ftbl->drawctxt_sched(device, event->cmdbatch->context);
-}
-
-
-/*
- * This function is called by the GPU event when the sync event timestamp
- * expires
- */
-static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, void *priv,
- u32 id, u32 timestamp, u32 type)
-{
- struct kgsl_cmdbatch_sync_event *event = priv;
-
- kgsl_cmdbatch_sync_expire(device, event);
-
- kgsl_context_put(event->context);
- kgsl_cmdbatch_put(event->cmdbatch);
-
- kfree(event);
-}
-
-/**
- * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure
- * @cmdbatch: Pointer to the command batch object to destroy
- *
- * Start the process of destroying a command batch. Cancel any pending events
- * and decrement the refcount.
- */
-void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
-{
- struct kgsl_cmdbatch_sync_event *event, *tmp;
-
- spin_lock(&cmdbatch->lock);
-
- /* Delete any pending sync points for this command batch */
- list_for_each_entry_safe(event, tmp, &cmdbatch->synclist, node) {
-
- if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) {
- /* Cancel the event if it still exists */
- kgsl_cancel_event(cmdbatch->device, event->context,
- event->timestamp, kgsl_cmdbatch_sync_func,
- event);
- } else if (event->type == KGSL_CMD_SYNCPOINT_TYPE_FENCE) {
- if (kgsl_sync_fence_async_cancel(event->handle)) {
- list_del(&event->node);
- kfree(event);
- kgsl_cmdbatch_put(cmdbatch);
- }
- }
- }
-
- spin_unlock(&cmdbatch->lock);
- kgsl_cmdbatch_put(cmdbatch);
-}
-EXPORT_SYMBOL(kgsl_cmdbatch_destroy);
-
-/*
- * A callback that gets registered with kgsl_sync_fence_async_wait and is fired
- * when a fence is expired
- */
-static void kgsl_cmdbatch_sync_fence_func(void *priv)
-{
- struct kgsl_cmdbatch_sync_event *event = priv;
-
- spin_lock(&event->lock);
- kgsl_cmdbatch_sync_expire(event->device, event);
- kgsl_cmdbatch_put(event->cmdbatch);
- spin_unlock(&event->lock);
- kfree(event);
-}
-
-/* kgsl_cmdbatch_add_sync_fence() - Add a new sync fence syncpoint
- * @device: KGSL device
- * @cmdbatch: KGSL cmdbatch to add the sync point to
- * @priv: Private sructure passed by the user
- *
- * Add a new fence sync syncpoint to the cmdbatch.
- */
-static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device,
- struct kgsl_cmdbatch *cmdbatch, void *priv)
-{
- struct kgsl_cmd_syncpoint_fence *sync = priv;
- struct kgsl_cmdbatch_sync_event *event;
-
- event = kzalloc(sizeof(*event), GFP_KERNEL);
-
- if (event == NULL)
- return -ENOMEM;
-
- kref_get(&cmdbatch->refcount);
-
- event->type = KGSL_CMD_SYNCPOINT_TYPE_FENCE;
- event->cmdbatch = cmdbatch;
- event->device = device;
- spin_lock_init(&event->lock);
-
- /*
- * Add it to the list first to account for the possiblity that the
- * callback will happen immediately after the call to
- * kgsl_sync_fence_async_wait
- */
-
- spin_lock(&cmdbatch->lock);
- list_add(&event->node, &cmdbatch->synclist);
- spin_unlock(&cmdbatch->lock);
-
- /*
- * There is a distinct race condition that can occur if the fence
- * callback is fired before the function has a chance to return. The
- * event struct would be freed before we could write event->handle and
- * hilarity ensued. Protect against this by protecting the call to
- * kgsl_sync_fence_async_wait and the kfree in the callback with a lock.
- */
-
- spin_lock(&event->lock);
-
- event->handle = kgsl_sync_fence_async_wait(sync->fd,
- kgsl_cmdbatch_sync_fence_func, event);
-
-
- if (IS_ERR_OR_NULL(event->handle)) {
- int ret = PTR_ERR(event->handle);
-
- spin_lock(&cmdbatch->lock);
- list_del(&event->node);
- spin_unlock(&cmdbatch->lock);
-
- kgsl_cmdbatch_put(cmdbatch);
- spin_unlock(&event->lock);
- kfree(event);
-
- return ret;
- }
-
- spin_unlock(&event->lock);
- return 0;
-}
-
-/* kgsl_cmdbatch_add_sync_timestamp() - Add a new sync point for a cmdbatch
- * @device: KGSL device
- * @cmdbatch: KGSL cmdbatch to add the sync point to
- * @priv: Private sructure passed by the user
- *
- * Add a new sync point timestamp event to the cmdbatch.
- */
-static int kgsl_cmdbatch_add_sync_timestamp(struct kgsl_device *device,
- struct kgsl_cmdbatch *cmdbatch, void *priv)
-{
- struct kgsl_cmd_syncpoint_timestamp *sync = priv;
- struct kgsl_context *context = kgsl_context_get(cmdbatch->device,
- sync->context_id);
- struct kgsl_cmdbatch_sync_event *event;
- int ret = -EINVAL;
-
- if (context == NULL)
- return -EINVAL;
-
- /* Sanity check - you can't create a sync point on your own context */
- if (context == cmdbatch->context) {
- KGSL_DRV_ERR(device,
- "Cannot create a sync point on your own context %d\n",
- context->id);
- goto done;
- }
-
- event = kzalloc(sizeof(*event), GFP_KERNEL);
- if (event == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- kref_get(&cmdbatch->refcount);
-
- event->type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP;
- event->cmdbatch = cmdbatch;
- event->context = context;
- event->timestamp = sync->timestamp;
-
- spin_lock(&cmdbatch->lock);
- list_add(&event->node, &cmdbatch->synclist);
- spin_unlock(&cmdbatch->lock);
-
- mutex_lock(&device->mutex);
- kgsl_active_count_get(device);
- ret = kgsl_add_event(device, context->id, sync->timestamp,
- kgsl_cmdbatch_sync_func, event, NULL);
- kgsl_active_count_put(device);
- mutex_unlock(&device->mutex);
-
- if (ret) {
- spin_lock(&cmdbatch->lock);
- list_del(&event->node);
- spin_unlock(&cmdbatch->lock);
-
- kgsl_cmdbatch_put(cmdbatch);
- kfree(event);
- }
-
-done:
- if (ret)
- kgsl_context_put(context);
-
- return ret;
-}
-
-/**
- * kgsl_cmdbatch_add_sync() - Add a sync point to a command batch
- * @device: Pointer to the KGSL device struct for the GPU
- * @cmdbatch: Pointer to the cmdbatch
- * @sync: Pointer to the user-specified struct defining the syncpoint
- *
- * Create a new sync point in the cmdbatch based on the user specified
- * parameters
- */
-static int kgsl_cmdbatch_add_sync(struct kgsl_device *device,
- struct kgsl_cmdbatch *cmdbatch,
- struct kgsl_cmd_syncpoint *sync)
-{
- void *priv;
- int ret, psize;
- int (*func)(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch,
- void *priv);
-
- switch (sync->type) {
- case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP:
- psize = sizeof(struct kgsl_cmd_syncpoint_timestamp);
- func = kgsl_cmdbatch_add_sync_timestamp;
- break;
- case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
- psize = sizeof(struct kgsl_cmd_syncpoint_fence);
- func = kgsl_cmdbatch_add_sync_fence;
- break;
- default:
- KGSL_DRV_ERR(device, "Invalid sync type 0x%x\n", sync->type);
- return -EINVAL;
- }
-
- if (sync->size != psize) {
- KGSL_DRV_ERR(device, "Invalid sync size %d\n", sync->size);
- return -EINVAL;
- }
-
- priv = kzalloc(sync->size, GFP_KERNEL);
- if (priv == NULL)
- return -ENOMEM;
-
- if (copy_from_user(priv, sync->priv, sync->size)) {
- kfree(priv);
- return -EFAULT;
- }
-
- ret = func(device, cmdbatch, priv);
- kfree(priv);
-
- return ret;
-}
-
-/**
- * kgsl_cmdbatch_create() - Create a new cmdbatch structure
- * @device: Pointer to a KGSL device struct
- * @context: Pointer to a KGSL context struct
- * @numibs: Number of indirect buffers to make room for in the cmdbatch
- *
- * Allocate an new cmdbatch structure and add enough room to store the list of
- * indirect buffers
- */
-static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
- struct kgsl_context *context, unsigned int flags,
- unsigned int numibs)
-{
- struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL);
- if (cmdbatch == NULL)
- return ERR_PTR(-ENOMEM);
-
- if (!(flags & KGSL_CONTEXT_SYNC)) {
- cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs,
- GFP_KERNEL);
- if (cmdbatch->ibdesc == NULL) {
- kfree(cmdbatch);
- return ERR_PTR(-ENOMEM);
- }
- }
-
- kref_init(&cmdbatch->refcount);
- INIT_LIST_HEAD(&cmdbatch->synclist);
- spin_lock_init(&cmdbatch->lock);
-
- cmdbatch->device = device;
- cmdbatch->ibcount = (flags & KGSL_CONTEXT_SYNC) ? 0 : numibs;
- cmdbatch->context = context;
- cmdbatch->flags = flags & ~KGSL_CONTEXT_SUBMIT_IB_LIST;
-
- /*
- * Increase the reference count on the context so it doesn't disappear
- * during the lifetime of this command batch
- */
- _kgsl_context_get(context);
-
- return cmdbatch;
-}
-
-/**
- * _kgsl_cmdbatch_verify() - Perform a quick sanity check on a command batch
- * @device: Pointer to a KGSL instance that owns the command batch
- * @pagetable: Pointer to the pagetable for the current process
- * @cmdbatch: Number of indirect buffers to make room for in the cmdbatch
- *
- * Do a quick sanity test on the list of indirect buffers in a command batch
- * verifying that the size and GPU address
- */
-static bool _kgsl_cmdbatch_verify(struct kgsl_device_private *dev_priv,
- struct kgsl_cmdbatch *cmdbatch)
-{
- int i;
- struct kgsl_process_private *private = dev_priv->process_priv;
-
- for (i = 0; i < cmdbatch->ibcount; i++) {
- if (cmdbatch->ibdesc[i].sizedwords == 0) {
- KGSL_DRV_ERR(dev_priv->device,
- "invalid size ctx %d ib(%d) %X/%X\n",
- cmdbatch->context->id, i,
- cmdbatch->ibdesc[i].gpuaddr,
- cmdbatch->ibdesc[i].sizedwords);
-
- return false;
- }
-
- if (!kgsl_mmu_gpuaddr_in_range(private->pagetable,
- cmdbatch->ibdesc[i].gpuaddr)) {
- KGSL_DRV_ERR(dev_priv->device,
- "Invalid address ctx %d ib(%d) %X/%X\n",
- cmdbatch->context->id, i,
- cmdbatch->ibdesc[i].gpuaddr,
- cmdbatch->ibdesc[i].sizedwords);
-
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * _kgsl_cmdbatch_create_legacy() - Create a cmdbatch from a legacy ioctl struct
- * @device: Pointer to the KGSL device struct for the GPU
- * @context: Pointer to the KGSL context that issued the command batch
- * @param: Pointer to the kgsl_ringbuffer_issueibcmds struct that the user sent
- *
- * Create a command batch from the legacy issueibcmds format.
- */
-static struct kgsl_cmdbatch *_kgsl_cmdbatch_create_legacy(
- struct kgsl_device *device,
- struct kgsl_context *context,
- struct kgsl_ringbuffer_issueibcmds *param)
-{
- struct kgsl_cmdbatch *cmdbatch =
- kgsl_cmdbatch_create(device, context, param->flags, 1);
-
- if (IS_ERR(cmdbatch))
- return cmdbatch;
-
- cmdbatch->ibdesc[0].gpuaddr = param->ibdesc_addr;
- cmdbatch->ibdesc[0].sizedwords = param->numibs;
- cmdbatch->ibcount = 1;
- cmdbatch->flags = param->flags;
-
- return cmdbatch;
-}
-
-/**
- * _kgsl_cmdbatch_create() - Create a cmdbatch from a ioctl struct
- * @device: Pointer to the KGSL device struct for the GPU
- * @context: Pointer to the KGSL context that issued the command batch
- * @flags: Flags passed in from the user command
- * @cmdlist: Pointer to the list of commands from the user
- * @numcmds: Number of commands in the list
- * @synclist: Pointer to the list of syncpoints from the user
- * @numsyncs: Number of syncpoints in the list
- *
- * Create a command batch from the standard issueibcmds format sent by the user.
- */
-static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
- struct kgsl_context *context,
- unsigned int flags,
- unsigned int cmdlist, unsigned int numcmds,
- unsigned int synclist, unsigned int numsyncs)
-{
- struct kgsl_cmdbatch *cmdbatch =
- kgsl_cmdbatch_create(device, context, flags, numcmds);
- int ret = 0;
-
- if (IS_ERR(cmdbatch))
- return cmdbatch;
-
- if (!(flags & KGSL_CONTEXT_SYNC)) {
- if (copy_from_user(cmdbatch->ibdesc, (void __user *) cmdlist,
- sizeof(struct kgsl_ibdesc) * numcmds)) {
- ret = -EFAULT;
- goto done;
- }
- }
-
- if (synclist && numsyncs) {
- struct kgsl_cmd_syncpoint sync;
- void __user *uptr = (void __user *) synclist;
- int i;
-
- for (i = 0; i < numsyncs; i++) {
- memset(&sync, 0, sizeof(sync));
-
- if (copy_from_user(&sync, uptr, sizeof(sync))) {
- ret = -EFAULT;
- break;
- }
-
- ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync);
-
- if (ret)
- break;
-
- uptr += sizeof(sync);
- }
- }
-
-done:
- if (ret) {
- kgsl_cmdbatch_destroy(cmdbatch);
- return ERR_PTR(ret);
- }
-
- return cmdbatch;
-}
-
static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
+ int result = 0;
+ int i = 0;
struct kgsl_ringbuffer_issueibcmds *param = data;
- struct kgsl_device *device = dev_priv->device;
+ struct kgsl_ibdesc *ibdesc;
struct kgsl_context *context;
- struct kgsl_cmdbatch *cmdbatch;
- long result = -EINVAL;
- /* The legacy functions don't support synchronization commands */
- if (param->flags & KGSL_CONTEXT_SYNC)
- return -EINVAL;
-
- /* Get the context */
context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
- if (context == NULL)
+ if (context == NULL) {
+ result = -EINVAL;
goto done;
+ }
if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
+ if (!param->numibs) {
+ result = -EINVAL;
+ goto done;
+ }
+
/*
- * Do a quick sanity check on the number of IBs in the
- * submission
+ * Put a reasonable upper limit on the number of IBs that can be
+ * submitted
*/
- if (param->numibs == 0 || param->numibs > KGSL_MAX_NUMIBS)
+ if (param->numibs > 10000) {
+ result = -EINVAL;
goto done;
+ }
- cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
- param->ibdesc_addr, param->numibs, 0, 0);
- } else
- cmdbatch = _kgsl_cmdbatch_create_legacy(device, context, param);
+ ibdesc = kzalloc(sizeof(struct kgsl_ibdesc) * param->numibs,
+ GFP_KERNEL);
+ if (!ibdesc) {
+ KGSL_MEM_ERR(dev_priv->device,
+ "kzalloc(%d) failed\n",
+ sizeof(struct kgsl_ibdesc) * param->numibs);
+ result = -ENOMEM;
+ goto done;
+ }
- if (IS_ERR(cmdbatch)) {
- result = PTR_ERR(cmdbatch);
- goto done;
+ if (copy_from_user(ibdesc, (void *)param->ibdesc_addr,
+ sizeof(struct kgsl_ibdesc) * param->numibs)) {
+ result = -EFAULT;
+ KGSL_DRV_ERR(dev_priv->device,
+ "copy_from_user failed\n");
+ goto free_ibdesc;
+ }
+ } else {
+ KGSL_DRV_INFO(dev_priv->device,
+ "Using single IB submission mode for ib submission\n");
+ /* If user space driver is still using the old mode of
+ * submitting single ib then we need to support that as well */
+ ibdesc = kzalloc(sizeof(struct kgsl_ibdesc), GFP_KERNEL);
+ if (!ibdesc) {
+ KGSL_MEM_ERR(dev_priv->device,
+ "kzalloc(%d) failed\n",
+ sizeof(struct kgsl_ibdesc));
+ result = -ENOMEM;
+ goto done;
+ }
+ ibdesc[0].gpuaddr = param->ibdesc_addr;
+ ibdesc[0].sizedwords = param->numibs;
+ param->numibs = 1;
}
- /* Run basic sanity checking on the command */
- if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
- goto free_cmdbatch;
+ for (i = 0; i < param->numibs; i++) {
+ struct kgsl_pagetable *pt = dev_priv->process_priv->pagetable;
- result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
- cmdbatch, ¶m->timestamp);
-
-free_cmdbatch:
- if (result)
- kgsl_cmdbatch_destroy(cmdbatch);
-
-done:
- kgsl_context_put(context);
- return result;
-}
-
-static long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
- unsigned int cmd, void *data)
-{
- struct kgsl_submit_commands *param = data;
- struct kgsl_device *device = dev_priv->device;
- struct kgsl_context *context;
- struct kgsl_cmdbatch *cmdbatch;
-
- long result = -EINVAL;
-
- /* The number of IBs are completely ignored for sync commands */
- if (!(param->flags & KGSL_CONTEXT_SYNC)) {
- if (param->numcmds == 0 || param->numcmds > KGSL_MAX_NUMIBS)
- return -EINVAL;
- } else if (param->numcmds != 0) {
- KGSL_DEV_ERR_ONCE(device,
- "Commands specified with the SYNC flag. They will be ignored\n");
+ if (!kgsl_mmu_gpuaddr_in_range(pt, ibdesc[i].gpuaddr)) {
+ result = -ERANGE;
+ KGSL_DRV_ERR(dev_priv->device,
+ "invalid ib base GPU virtual addr %x\n",
+ ibdesc[i].gpuaddr);
+ goto free_ibdesc;
+ }
}
- context = kgsl_context_get_owner(dev_priv, param->context_id);
- if (context == NULL)
- return -EINVAL;
+ result = dev_priv->device->ftbl->issueibcmds(dev_priv,
+ context,
+ ibdesc,
+ param->numibs,
+ ¶m->timestamp,
+ param->flags);
- cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
- (unsigned int) param->cmdlist, param->numcmds,
- (unsigned int) param->synclist, param->numsyncs);
-
- if (IS_ERR(cmdbatch)) {
- result = PTR_ERR(cmdbatch);
- goto done;
- }
-
- /* Run basic sanity checking on the command */
- if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
- goto free_cmdbatch;
-
- result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
- cmdbatch, ¶m->timestamp);
-
-free_cmdbatch:
- if (result)
- kgsl_cmdbatch_destroy(cmdbatch);
-
+free_ibdesc:
+ kfree(ibdesc);
done:
kgsl_context_put(context);
return result;
@@ -2143,11 +1665,14 @@
{
struct kgsl_drawctxt_destroy *param = data;
struct kgsl_context *context;
- long result;
+ long result = -EINVAL;
context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
- result = kgsl_context_detach(context);
+ if (context) {
+ kgsl_context_detach(context);
+ result = 0;
+ }
kgsl_context_put(context);
return result;
@@ -3246,7 +2771,7 @@
} kgsl_ioctl_funcs[] = {
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
kgsl_ioctl_device_getproperty,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
kgsl_ioctl_device_waittimestamp,
KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -3254,9 +2779,8 @@
kgsl_ioctl_device_waittimestamp_ctxtid,
KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
- kgsl_ioctl_rb_issueibcmds, 0),
- KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS,
- kgsl_ioctl_submit_commands, 0),
+ kgsl_ioctl_rb_issueibcmds,
+ KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
kgsl_ioctl_cmdstream_readtimestamp,
KGSL_IOCTL_LOCK),
@@ -3265,13 +2789,13 @@
KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
kgsl_ioctl_cmdstream_freememontimestamp,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
kgsl_ioctl_cmdstream_freememontimestamp_ctxtid,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
kgsl_ioctl_drawctxt_create,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
kgsl_ioctl_drawctxt_destroy,
KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -3291,10 +2815,10 @@
kgsl_ioctl_cff_user_event, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
kgsl_ioctl_timestamp_event,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
kgsl_ioctl_device_setproperty,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
kgsl_ioctl_gpumem_alloc_id, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
@@ -3938,6 +3462,7 @@
setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+ setup_timer(&device->hang_timer, hang_timer, (unsigned long) device);
status = kgsl_create_device_workqueue(device);
if (status)
goto error_pwrctrl_close;
@@ -3997,6 +3522,7 @@
if (device->state == KGSL_STATE_ACTIVE)
kgsl_idle(device);
+
}
if (device->pm_dump_enable) {
@@ -4010,12 +3536,13 @@
pwr->power_flags, pwr->active_pwrlevel);
KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
- pwr->interval_timeout);
+ pwr->interval_timeout);
}
/* Disable the idle timer so we don't get interrupted */
del_timer_sync(&device->idle_timer);
+ del_timer_sync(&device->hang_timer);
/* Force on the clocks */
kgsl_pwrctrl_wake(device);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 2e9d52e..8d390a9 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -78,8 +78,6 @@
#define KGSL_MEMFREE_HIST_SIZE ((int)(PAGE_SIZE * 2))
-#define KGSL_MAX_NUMIBS 100000
-
struct kgsl_memfree_hist_elem {
unsigned int pid;
unsigned int gpuaddr;
@@ -143,7 +141,6 @@
struct kgsl_pagetable;
struct kgsl_memdesc;
-struct kgsl_cmdbatch;
struct kgsl_memdesc_ops {
int (*vmflags)(struct kgsl_memdesc *);
@@ -208,6 +205,7 @@
#define MMU_CONFIG 1
#endif
+void kgsl_hang_check(struct work_struct *work);
void kgsl_mem_entry_destroy(struct kref *kref);
int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
@@ -239,7 +237,7 @@
unsigned int value);
void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
- struct kgsl_cmdbatch *cmdbatch,
+ struct kgsl_ibdesc *ibdesc, int numibs,
unsigned int timestamp, unsigned int flags,
int result, unsigned int type);
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 110264b..9ab8d22 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -123,6 +123,7 @@
KGSL_DEBUGFS_LOG(ctxt_log);
KGSL_DEBUGFS_LOG(mem_log);
KGSL_DEBUGFS_LOG(pwr_log);
+KGSL_DEBUGFS_LOG(ft_log);
static int memfree_hist_print(struct seq_file *s, void *unused)
{
@@ -184,6 +185,7 @@
device->drv_log = KGSL_LOG_LEVEL_DEFAULT;
device->mem_log = KGSL_LOG_LEVEL_DEFAULT;
device->pwr_log = KGSL_LOG_LEVEL_DEFAULT;
+ device->ft_log = KGSL_LOG_LEVEL_DEFAULT;
debugfs_create_file("log_level_cmd", 0644, device->d_debugfs, device,
&cmd_log_fops);
@@ -197,6 +199,8 @@
&pwr_log_fops);
debugfs_create_file("memfree_history", 0444, device->d_debugfs, device,
&memfree_hist_fops);
+ debugfs_create_file("log_level_ft", 0644, device->d_debugfs, device,
+ &ft_log_fops);
/* Create postmortem dump control files */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index cd9c4f7..09a31c9 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -13,7 +13,6 @@
#ifndef __KGSL_DEVICE_H
#define __KGSL_DEVICE_H
-#include <linux/slab.h>
#include <linux/idr.h>
#include <linux/pm_qos.h>
#include <linux/sched.h>
@@ -77,7 +76,6 @@
struct kgsl_context;
struct kgsl_power_stats;
struct kgsl_event;
-struct kgsl_cmdbatch;
struct kgsl_functable {
/* Mandatory functions - these functions must be implemented
@@ -89,7 +87,7 @@
void (*regwrite) (struct kgsl_device *device,
unsigned int offsetwords, unsigned int value);
int (*idle) (struct kgsl_device *device);
- bool (*isidle) (struct kgsl_device *device);
+ unsigned int (*isidle) (struct kgsl_device *device);
int (*suspend_context) (struct kgsl_device *device);
int (*init) (struct kgsl_device *device);
int (*start) (struct kgsl_device *device);
@@ -103,8 +101,9 @@
unsigned int (*readtimestamp) (struct kgsl_device *device,
struct kgsl_context *context, enum kgsl_timestamp_type type);
int (*issueibcmds) (struct kgsl_device_private *dev_priv,
- struct kgsl_context *context, struct kgsl_cmdbatch *cmdbatch,
- uint32_t *timestamps);
+ struct kgsl_context *context, struct kgsl_ibdesc *ibdesc,
+ unsigned int sizedwords, uint32_t *timestamp,
+ unsigned int flags);
int (*setup_pt)(struct kgsl_device *device,
struct kgsl_pagetable *pagetable);
void (*cleanup_pt)(struct kgsl_device *device,
@@ -116,15 +115,14 @@
void * (*snapshot)(struct kgsl_device *device, void *snapshot,
int *remain, int hang);
irqreturn_t (*irq_handler)(struct kgsl_device *device);
- int (*drain)(struct kgsl_device *device);
/* Optional functions - these functions are not mandatory. The
driver will check that the function pointer is not NULL before
calling the hook */
- int (*setstate) (struct kgsl_device *device, unsigned int context_id,
+ void (*setstate) (struct kgsl_device *device, unsigned int context_id,
uint32_t flags);
struct kgsl_context *(*drawctxt_create) (struct kgsl_device_private *,
uint32_t *flags);
- int (*drawctxt_detach) (struct kgsl_context *context);
+ void (*drawctxt_detach) (struct kgsl_context *context);
void (*drawctxt_destroy) (struct kgsl_context *context);
long (*ioctl) (struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
@@ -134,8 +132,6 @@
int (*postmortem_dump) (struct kgsl_device *device, int manual);
int (*next_event)(struct kgsl_device *device,
struct kgsl_event *event);
- void (*drawctxt_sched)(struct kgsl_device *device,
- struct kgsl_context *context);
};
/* MH register values */
@@ -159,56 +155,6 @@
unsigned int created;
};
-/**
- * struct kgsl_cmdbatch - KGSl command descriptor
- * @device: KGSL GPU device that the command was created for
- * @context: KGSL context that created the command
- * @timestamp: Timestamp assigned to the command
- * @flags: flags
- * @priv: Internal flags
- * @fault_policy: Internal policy describing how to handle this command in case
- * of a fault
- * @fault_recovery: recovery actions actually tried for this batch
- * @ibcount: Number of IBs in the command list
- * @ibdesc: Pointer to the list of IBs
- * @expires: Point in time when the cmdbatch is considered to be hung
- * @invalid: non-zero if the dispatcher determines the command and the owning
- * context should be invalidated
- * @refcount: kref structure to maintain the reference count
- * @synclist: List of context/timestamp tuples to wait for before issuing
- *
- * This struture defines an atomic batch of command buffers issued from
- * userspace.
- */
-struct kgsl_cmdbatch {
- struct kgsl_device *device;
- struct kgsl_context *context;
- spinlock_t lock;
- uint32_t timestamp;
- uint32_t flags;
- unsigned long priv;
- unsigned long fault_policy;
- unsigned long fault_recovery;
- uint32_t ibcount;
- struct kgsl_ibdesc *ibdesc;
- unsigned long expires;
- int invalid;
- struct kref refcount;
- struct list_head synclist;
-};
-
-/**
- * enum kgsl_cmdbatch_priv - Internal cmdbatch flags
- * @CMDBATCH_FLAG_SKIP - skip the entire command batch
- * @CMDBATCH_FLAG_FORCE_PREAMBLE - Force the preamble on for the cmdbatch
- * @CMDBATCH_FLAG_WFI - Force wait-for-idle for the submission
- */
-
-enum kgsl_cmdbatch_priv {
- CMDBATCH_FLAG_SKIP = 0,
- CMDBATCH_FLAG_FORCE_PREAMBLE,
- CMDBATCH_FLAG_WFI,
-};
struct kgsl_device {
struct device *dev;
@@ -244,7 +190,9 @@
struct completion hwaccess_gate;
const struct kgsl_functable *ftbl;
struct work_struct idle_check_ws;
+ struct work_struct hang_check_ws;
struct timer_list idle_timer;
+ struct timer_list hang_timer;
struct kgsl_pwrctrl pwrctrl;
int open_count;
@@ -258,6 +206,7 @@
wait_queue_head_t active_cnt_wq;
struct workqueue_struct *work_queue;
struct device *parentdev;
+ struct completion ft_gate;
struct dentry *d_debugfs;
struct idr context_idr;
rwlock_t context_lock;
@@ -284,13 +233,13 @@
int drv_log;
int mem_log;
int pwr_log;
+ int ft_log;
int pm_dump_enable;
struct kgsl_pwrscale pwrscale;
struct kobject pwrscale_kobj;
struct work_struct ts_expired_ws;
struct list_head events;
struct list_head events_pending_list;
- unsigned int events_last_timestamp;
s64 on_time;
/* Postmortem Control switches */
@@ -305,8 +254,11 @@
#define KGSL_DEVICE_COMMON_INIT(_dev) \
.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
+ .ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\
.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
kgsl_idle_check),\
+ .hang_check_ws = __WORK_INITIALIZER((_dev).hang_check_ws,\
+ kgsl_hang_check),\
.ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\
kgsl_process_events),\
.context_idr = IDR_INIT((_dev).context_idr),\
@@ -401,9 +353,6 @@
int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
kgsl_event_func func, void *priv, void *owner);
-void kgsl_cancel_event(struct kgsl_device *device, struct kgsl_context *context,
- unsigned int timestamp, kgsl_event_func func, void *priv);
-
static inline void kgsl_process_add_stats(struct kgsl_process_private *priv,
unsigned int type, size_t size)
{
@@ -491,6 +440,8 @@
return 0;
}
+
+
int kgsl_check_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp);
@@ -646,40 +597,4 @@
{
kgsl_signal_event(device, context, timestamp, KGSL_EVENT_CANCELLED);
}
-
-void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch);
-
-void kgsl_cmdbatch_destroy_object(struct kref *kref);
-
-/**
- * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object
- * @cmdbatch: Pointer to the command batch object
- */
-static inline void kgsl_cmdbatch_put(struct kgsl_cmdbatch *cmdbatch)
-{
- if (cmdbatch)
- kref_put(&cmdbatch->refcount, kgsl_cmdbatch_destroy_object);
-}
-
-/**
- * kgsl_cmdbatch_sync_pending() - return true if the cmdbatch is waiting
- * @cmdbatch: Pointer to the command batch object to check
- *
- * Return non-zero if the specified command batch is still waiting for sync
- * point dependencies to be satisfied
- */
-static inline int kgsl_cmdbatch_sync_pending(struct kgsl_cmdbatch *cmdbatch)
-{
- int ret;
-
- if (cmdbatch == NULL)
- return 0;
-
- spin_lock(&cmdbatch->lock);
- ret = list_empty(&cmdbatch->synclist) ? 0 : 1;
- spin_unlock(&cmdbatch->lock);
-
- return ret;
-}
-
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index c7ac0ad..9e8f6d0 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -48,8 +48,7 @@
{
int id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
- trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created,
- event->func);
+ trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created);
if (event->func)
event->func(device, event->priv, id, timestamp, type);
@@ -236,7 +235,7 @@
*/
if (timestamp_cmp(cur_ts, ts) >= 0) {
- trace_kgsl_fire_event(id, cur_ts, ts, 0, func);
+ trace_kgsl_fire_event(id, cur_ts, ts, 0);
func(device, priv, id, ts, KGSL_EVENT_TIMESTAMP_RETIRED);
kgsl_context_put(context);
@@ -253,7 +252,7 @@
* Increase the active count on the device to avoid going into power
* saving modes while events are pending
*/
- ret = kgsl_active_count_get_light(device);
+ ret = kgsl_active_count_get(device);
if (ret < 0) {
kgsl_context_put(context);
kfree(event);
@@ -267,7 +266,7 @@
event->owner = owner;
event->created = jiffies;
- trace_kgsl_register_event(id, ts, func);
+ trace_kgsl_register_event(id, ts);
/* Add the event to either the owning context or the global list */
@@ -334,11 +333,7 @@
void *priv)
{
struct kgsl_event *event;
- struct list_head *head;
-
- BUG_ON(!mutex_is_locked(&device->mutex));
-
- head = _get_list_head(device, context);
+ struct list_head *head = _get_list_head(device, context);
event = _find_event(device, head, timestamp, func, priv);
@@ -405,19 +400,10 @@
struct kgsl_context *context, *tmp;
uint32_t timestamp;
- /*
- * Bail unless the global timestamp has advanced. We can safely do this
- * outside of the mutex for speed
- */
-
- timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
- if (timestamp == device->events_last_timestamp)
- return;
-
mutex_lock(&device->mutex);
- device->events_last_timestamp = timestamp;
-
+ /* Process expired global events */
+ timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
_retire_events(device, &device->events, timestamp);
_mark_next_event(device, &device->events);
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 2634e4f..68052b1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -482,17 +482,15 @@
return NULL;
}
-static int kgsl_gpummu_default_setstate(struct kgsl_mmu *mmu,
+static void kgsl_gpummu_default_setstate(struct kgsl_mmu *mmu,
uint32_t flags)
{
struct kgsl_gpummu_pt *gpummu_pt;
if (!kgsl_mmu_enabled())
- return 0;
+ return;
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
- int ret = kgsl_idle(mmu->device);
- if (ret)
- return ret;
+ kgsl_idle(mmu->device);
gpummu_pt = mmu->hwpagetable->priv;
kgsl_regwrite(mmu->device, MH_MMU_PT_BASE,
gpummu_pt->base.gpuaddr);
@@ -502,16 +500,12 @@
/* Invalidate all and tc */
kgsl_regwrite(mmu->device, MH_MMU_INVALIDATE, 0x00000003);
}
-
- return 0;
}
-static int kgsl_gpummu_setstate(struct kgsl_mmu *mmu,
+static void kgsl_gpummu_setstate(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable,
unsigned int context_id)
{
- int ret = 0;
-
if (mmu->flags & KGSL_FLAGS_STARTED) {
/* page table not current, then setup mmu to use new
* specified page table
@@ -524,13 +518,10 @@
kgsl_mmu_pt_get_flags(pagetable, mmu->device->id);
/* call device specific set page table */
- ret = kgsl_setstate(mmu, context_id,
- KGSL_MMUFLAGS_TLBFLUSH |
+ kgsl_setstate(mmu, context_id, KGSL_MMUFLAGS_TLBFLUSH |
KGSL_MMUFLAGS_PTUPDATE);
}
}
-
- return ret;
}
static int kgsl_gpummu_init(struct kgsl_mmu *mmu)
@@ -572,7 +563,6 @@
struct kgsl_device *device = mmu->device;
struct kgsl_gpummu_pt *gpummu_pt;
- int ret;
if (mmu->flags & KGSL_FLAGS_STARTED)
return 0;
@@ -584,6 +574,9 @@
/* setup MMU and sub-client behavior */
kgsl_regwrite(device, MH_MMU_CONFIG, mmu->config);
+ /* idle device */
+ kgsl_idle(device);
+
/* enable axi interrupts */
kgsl_regwrite(device, MH_INTERRUPT_MASK,
GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT);
@@ -614,12 +607,10 @@
kgsl_regwrite(mmu->device, MH_MMU_VA_RANGE,
(KGSL_PAGETABLE_BASE |
(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE >> 16)));
+ kgsl_setstate(mmu, KGSL_MEMSTORE_GLOBAL, KGSL_MMUFLAGS_TLBFLUSH);
+ mmu->flags |= KGSL_FLAGS_STARTED;
- ret = kgsl_setstate(mmu, KGSL_MEMSTORE_GLOBAL, KGSL_MMUFLAGS_TLBFLUSH);
- if (!ret)
- mmu->flags |= KGSL_FLAGS_STARTED;
-
- return ret;
+ return 0;
}
static int
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e296784..ecda5a7 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -423,12 +423,8 @@
* the GPU and trigger a snapshot. To stall the transaction return
* EBUSY error.
*/
- if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) {
- /* turn off GPU IRQ so we don't get faults from it too */
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
- adreno_dispatcher_irq_fault(device);
+ if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
ret = -EBUSY;
- }
done:
return ret;
}
@@ -1209,12 +1205,10 @@
return 0;
}
-static int kgsl_iommu_setstate(struct kgsl_mmu *mmu,
+static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable,
unsigned int context_id)
{
- int ret = 0;
-
if (mmu->flags & KGSL_FLAGS_STARTED) {
/* page table not current, then setup mmu to use new
* specified page table
@@ -1225,12 +1219,10 @@
flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
mmu->device->id) |
KGSL_MMUFLAGS_TLBFLUSH;
- ret = kgsl_setstate(mmu, context_id,
+ kgsl_setstate(mmu, context_id,
KGSL_MMUFLAGS_PTUPDATE | flags);
}
}
-
- return ret;
}
/*
@@ -1900,40 +1892,31 @@
* cpu
* Return - void
*/
-static int kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
uint32_t flags)
{
struct kgsl_iommu *iommu = mmu->priv;
int temp;
int i;
- int ret = 0;
phys_addr_t pt_base = kgsl_iommu_get_pt_base_addr(mmu,
mmu->hwpagetable);
phys_addr_t pt_val;
- ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
-
- if (ret) {
+ if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
- return ret;
+ return;
}
/* For v0 SMMU GPU needs to be idle for tlb invalidate as well */
- if (msm_soc_version_supports_iommu_v0()) {
- ret = kgsl_idle(mmu->device);
- if (ret)
- return ret;
- }
+ if (msm_soc_version_supports_iommu_v0())
+ kgsl_idle(mmu->device);
/* Acquire GPU-CPU sync Lock here */
_iommu_lock();
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
- if (!msm_soc_version_supports_iommu_v0()) {
- ret = kgsl_idle(mmu->device);
- if (ret)
- goto unlock;
- }
+ if (!msm_soc_version_supports_iommu_v0())
+ kgsl_idle(mmu->device);
for (i = 0; i < iommu->unit_count; i++) {
/* get the lsb value which should not change when
* changing ttbr0 */
@@ -1994,13 +1977,12 @@
}
}
}
-unlock:
+
/* Release GPU-CPU sync Lock here */
_iommu_unlock();
/* Disable smmu clock */
kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
- return ret;
}
/*
@@ -2057,7 +2039,6 @@
.mmu_pagefault_resume = kgsl_iommu_pagefault_resume,
.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
.mmu_enable_clk = kgsl_iommu_enable_clk,
- .mmu_disable_clk = kgsl_iommu_disable_clk,
.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
.mmu_get_default_ttbr0 = kgsl_iommu_get_default_ttbr0,
.mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index 3a32953..a7832e4 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -103,6 +103,15 @@
#define KGSL_PWR_CRIT(_dev, fmt, args...) \
KGSL_LOG_CRIT(_dev->dev, _dev->pwr_log, fmt, ##args)
+#define KGSL_FT_INFO(_dev, fmt, args...) \
+KGSL_LOG_INFO(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_WARN(_dev, fmt, args...) \
+KGSL_LOG_WARN(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_ERR(_dev, fmt, args...) \
+KGSL_LOG_ERR(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_CRIT(_dev, fmt, args...) \
+KGSL_LOG_CRIT(_dev->dev, _dev->ft_log, fmt, ##args)
+
/* Core error messages - these are for core KGSL functions that have
no device associated with them (such as memory) */
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6635a7c..952019f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -566,7 +566,7 @@
}
EXPORT_SYMBOL(kgsl_mmu_putpagetable);
-int kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
+void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
uint32_t flags)
{
struct kgsl_device *device = mmu->device;
@@ -574,16 +574,14 @@
if (!(flags & (KGSL_MMUFLAGS_TLBFLUSH | KGSL_MMUFLAGS_PTUPDATE))
&& !adreno_is_a2xx(adreno_dev))
- return 0;
+ return;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
- return 0;
+ return;
else if (device->ftbl->setstate)
- return device->ftbl->setstate(device, context_id, flags);
+ device->ftbl->setstate(device, context_id, flags);
else if (mmu->mmu_ops->mmu_device_setstate)
- return mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-
- return 0;
+ mmu->mmu_ops->mmu_device_setstate(mmu, flags);
}
EXPORT_SYMBOL(kgsl_setstate);
@@ -592,6 +590,7 @@
struct kgsl_mh *mh = &device->mh;
/* force mmu off to for now*/
kgsl_regwrite(device, MH_MMU_CONFIG, 0);
+ kgsl_idle(device);
/* define physical memory range accessible by the core */
kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index a30ee3f..faba81e 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -133,10 +133,10 @@
int (*mmu_close) (struct kgsl_mmu *mmu);
int (*mmu_start) (struct kgsl_mmu *mmu);
void (*mmu_stop) (struct kgsl_mmu *mmu);
- int (*mmu_setstate) (struct kgsl_mmu *mmu,
+ void (*mmu_setstate) (struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable,
unsigned int context_id);
- int (*mmu_device_setstate) (struct kgsl_mmu *mmu,
+ void (*mmu_device_setstate) (struct kgsl_mmu *mmu,
uint32_t flags);
void (*mmu_pagefault) (struct kgsl_mmu *mmu);
phys_addr_t (*mmu_get_current_ptbase)
@@ -147,8 +147,6 @@
(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
int (*mmu_enable_clk)
(struct kgsl_mmu *mmu, int ctx_id);
- void (*mmu_disable_clk)
- (struct kgsl_mmu *mmu);
phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id);
@@ -233,7 +231,7 @@
int kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc);
unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
-int kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
+void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
uint32_t flags);
int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
phys_addr_t pt_base);
@@ -262,23 +260,19 @@
return 0;
}
-static inline int kgsl_mmu_setstate(struct kgsl_mmu *mmu,
+static inline void kgsl_mmu_setstate(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable,
unsigned int context_id)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_setstate)
- return mmu->mmu_ops->mmu_setstate(mmu, pagetable, context_id);
-
- return 0;
+ mmu->mmu_ops->mmu_setstate(mmu, pagetable, context_id);
}
-static inline int kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
+static inline void kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
uint32_t flags)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_device_setstate)
- return mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-
- return 0;
+ mmu->mmu_ops->mmu_device_setstate(mmu, flags);
}
static inline void kgsl_mmu_stop(struct kgsl_mmu *mmu)
@@ -326,12 +320,6 @@
return 0;
}
-static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
-{
- if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk)
- mmu->mmu_ops->mmu_disable_clk(mmu);
-}
-
static inline void kgsl_mmu_disable_clk_on_ts(struct kgsl_mmu *mmu,
unsigned int ts, bool ts_valid)
{
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 07131f7..1a95761 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1215,6 +1215,9 @@
} else {
device->pwrctrl.irq_last = 0;
}
+ } else if (device->state & (KGSL_STATE_HUNG |
+ KGSL_STATE_DUMP_AND_FT)) {
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
}
mutex_unlock(&device->mutex);
@@ -1270,6 +1273,7 @@
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
return -EBUSY;
}
+ del_timer_sync(&device->hang_timer);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
@@ -1339,6 +1343,7 @@
case KGSL_STATE_NAP:
case KGSL_STATE_SLEEP:
del_timer_sync(&device->idle_timer);
+ del_timer_sync(&device->hang_timer);
/* make sure power is on to stop the device*/
kgsl_pwrctrl_enable(device);
device->ftbl->suspend_context(device);
@@ -1430,6 +1435,8 @@
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+ mod_timer(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
device->pwrctrl.pm_qos_latency);
case KGSL_STATE_ACTIVE:
@@ -1497,6 +1504,10 @@
return "SLEEP";
case KGSL_STATE_SUSPEND:
return "SUSPEND";
+ case KGSL_STATE_HUNG:
+ return "HUNG";
+ case KGSL_STATE_DUMP_AND_FT:
+ return "DNR";
case KGSL_STATE_SLUMBER:
return "SLUMBER";
default:
@@ -1528,6 +1539,7 @@
(device->state != KGSL_STATE_ACTIVE)) {
mutex_unlock(&device->mutex);
wait_for_completion(&device->hwaccess_gate);
+ wait_for_completion(&device->ft_gate);
mutex_lock(&device->mutex);
/* Stop the idle timer */
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index dc3ad21..b7d7235 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/err.h>
#include <linux/file.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -282,65 +281,3 @@
{
sync_timeline_destroy(context->timeline);
}
-
-static void kgsl_sync_callback(struct sync_fence *fence,
- struct sync_fence_waiter *waiter)
-{
- struct kgsl_sync_fence_waiter *kwaiter =
- (struct kgsl_sync_fence_waiter *) waiter;
- kwaiter->func(kwaiter->priv);
- sync_fence_put(kwaiter->fence);
- kfree(kwaiter);
-}
-
-struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv)
-{
- struct kgsl_sync_fence_waiter *kwaiter;
- struct sync_fence *fence;
- int status;
-
- fence = sync_fence_fdget(fd);
- if (fence == NULL)
- return ERR_PTR(-EINVAL);
-
- /* create the waiter */
- kwaiter = kzalloc(sizeof(*kwaiter), GFP_ATOMIC);
- if (kwaiter == NULL) {
- sync_fence_put(fence);
- return ERR_PTR(-ENOMEM);
- }
- kwaiter->fence = fence;
- kwaiter->priv = priv;
- kwaiter->func = func;
- sync_fence_waiter_init((struct sync_fence_waiter *) kwaiter,
- kgsl_sync_callback);
-
- /* if status then error or signaled */
- status = sync_fence_wait_async(fence,
- (struct sync_fence_waiter *) kwaiter);
- if (status) {
- kfree(kwaiter);
- sync_fence_put(fence);
- if (status < 0)
- kwaiter = ERR_PTR(status);
- else
- kwaiter = NULL;
- }
-
- return kwaiter;
-}
-
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *kwaiter)
-{
- if (kwaiter == NULL)
- return 0;
-
- if (sync_fence_cancel_async(kwaiter->fence,
- (struct sync_fence_waiter *) kwaiter) == 0) {
- sync_fence_put(kwaiter->fence);
- kfree(kwaiter);
- return 1;
- }
- return 0;
-}
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 275eaf0..63adf06 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 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,13 +28,6 @@
unsigned int timestamp;
};
-struct kgsl_sync_fence_waiter {
- struct sync_fence_waiter waiter;
- struct sync_fence *fence;
- void (*func)(void *priv);
- void *priv;
-};
-
#if defined(CONFIG_SYNC)
struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
unsigned int timestamp);
@@ -46,9 +39,6 @@
void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
unsigned int timestamp);
void kgsl_sync_timeline_destroy(struct kgsl_context *context);
-struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv);
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter);
#else
static inline struct sync_pt
*kgsl_sync_pt_create(struct sync_timeline *timeline, unsigned int timestamp)
@@ -82,20 +72,6 @@
static inline void kgsl_sync_timeline_destroy(struct kgsl_context *context)
{
}
-
-static inline struct
-kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv)
-{
- return NULL;
-}
-
-static inline int
-kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter)
-{
- return 1;
-}
-
#endif
#endif /* __KGSL_SYNC_H */
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f39b8b..f16f2b4 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -37,13 +37,14 @@
TP_PROTO(struct kgsl_device *device,
int drawctxt_id,
- struct kgsl_cmdbatch *cmdbatch,
+ struct kgsl_ibdesc *ibdesc,
+ int numibs,
int timestamp,
int flags,
int result,
unsigned int type),
- TP_ARGS(device, drawctxt_id, cmdbatch, timestamp, flags,
+ TP_ARGS(device, drawctxt_id, ibdesc, numibs, timestamp, flags,
result, type),
TP_STRUCT__entry(
@@ -60,8 +61,8 @@
TP_fast_assign(
__assign_str(device_name, device->name);
__entry->drawctxt_id = drawctxt_id;
- __entry->ibdesc_addr = cmdbatch->ibdesc[0].gpuaddr;
- __entry->numibs = cmdbatch->ibcount;
+ __entry->ibdesc_addr = ibdesc[0].gpuaddr;
+ __entry->numibs = numibs;
__entry->timestamp = timestamp;
__entry->flags = flags;
__entry->result = result;
@@ -730,46 +731,42 @@
);
TRACE_EVENT(kgsl_register_event,
- TP_PROTO(unsigned int id, unsigned int timestamp, void *func),
- TP_ARGS(id, timestamp, func),
+ TP_PROTO(unsigned int id, unsigned int timestamp),
+ TP_ARGS(id, timestamp),
TP_STRUCT__entry(
__field(unsigned int, id)
__field(unsigned int, timestamp)
- __field(void *, func)
),
TP_fast_assign(
__entry->id = id;
__entry->timestamp = timestamp;
- __entry->func = func;
),
TP_printk(
- "ctx=%u ts=%u cb=%pF",
- __entry->id, __entry->timestamp, __entry->func)
+ "ctx=%u ts=%u",
+ __entry->id, __entry->timestamp)
);
TRACE_EVENT(kgsl_fire_event,
TP_PROTO(unsigned int id, unsigned int ts,
- unsigned int type, unsigned int age, void *func),
- TP_ARGS(id, ts, type, age, func),
+ unsigned int type, unsigned int age),
+ TP_ARGS(id, ts, type, age),
TP_STRUCT__entry(
__field(unsigned int, id)
__field(unsigned int, ts)
__field(unsigned int, type)
__field(unsigned int, age)
- __field(void *, func)
),
TP_fast_assign(
__entry->id = id;
__entry->ts = ts;
__entry->type = type;
__entry->age = age;
- __entry->func = func;
),
TP_printk(
- "ctx=%u ts=%u type=%s age=%u cb=%pF",
+ "ctx=%u ts=%u type=%s age=%u",
__entry->id, __entry->ts,
__print_symbolic(__entry->type, KGSL_EVENT_TYPES),
- __entry->age, __entry->func)
+ __entry->age)
);
TRACE_EVENT(kgsl_active_count,
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 0af57aa..883417f 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -353,13 +353,7 @@
return ts_diff < Z180_PACKET_COUNT;
}
-/**
- * z180_idle() - Idle the 2D device
- * @device: Pointer to the KGSL device struct for the Z180
- *
- * wait until the z180 submission queue is idle
- */
-int z180_idle(struct kgsl_device *device)
+static int z180_idle(struct kgsl_device *device)
{
int status = 0;
struct z180_device *z180_dev = Z180_DEVICE(device);
@@ -379,8 +373,10 @@
int
z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv,
struct kgsl_context *context,
- struct kgsl_cmdbatch *cmdbatch,
- uint32_t *timestamp)
+ struct kgsl_ibdesc *ibdesc,
+ unsigned int numibs,
+ uint32_t *timestamp,
+ unsigned int ctrl)
{
long result = 0;
unsigned int ofs = PACKETSIZE_STATESTREAM * sizeof(unsigned int);
@@ -393,20 +389,6 @@
struct kgsl_pagetable *pagetable = dev_priv->process_priv->pagetable;
struct z180_device *z180_dev = Z180_DEVICE(device);
unsigned int sizedwords;
- unsigned int numibs;
- struct kgsl_ibdesc *ibdesc;
-
- mutex_lock(&device->mutex);
-
- kgsl_active_count_get(device);
-
- if (cmdbatch == NULL) {
- result = EINVAL;
- goto error;
- }
-
- ibdesc = cmdbatch->ibdesc;
- numibs = cmdbatch->ibcount;
if (device->state & KGSL_STATE_HUNG) {
result = -EINVAL;
@@ -448,7 +430,7 @@
context->id, cmd, sizedwords);
/* context switch */
if ((context->id != (int)z180_dev->ringbuffer.prevctx) ||
- (cmdbatch->flags & KGSL_CONTEXT_CTX_SWITCH)) {
+ (ctrl & KGSL_CONTEXT_CTX_SWITCH)) {
KGSL_CMD_INFO(device, "context switch %d -> %d\n",
context->id, z180_dev->ringbuffer.prevctx);
kgsl_mmu_setstate(&device->mmu, pagetable,
@@ -456,13 +438,10 @@
cnt = PACKETSIZE_STATESTREAM;
ofs = 0;
}
-
- result = kgsl_setstate(&device->mmu,
+ kgsl_setstate(&device->mmu,
KGSL_MEMSTORE_GLOBAL,
kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
device->id));
- if (result < 0)
- goto error;
result = wait_event_interruptible_timeout(device->wait_queue,
room_in_rb(z180_dev),
@@ -503,12 +482,9 @@
z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, cmd);
z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0);
error:
- kgsl_trace_issueibcmds(device, context->id, cmdbatch,
- *timestamp, cmdbatch->flags, result, 0);
- kgsl_active_count_put(device);
-
- mutex_unlock(&device->mutex);
+ kgsl_trace_issueibcmds(device, context->id, ibdesc, numibs,
+ *timestamp, ctrl, result, 0);
return (int)result;
}
@@ -619,12 +595,8 @@
static int z180_stop(struct kgsl_device *device)
{
- int ret;
-
device->ftbl->irqctrl(device, 0);
- ret = z180_idle(device);
- if (ret)
- return ret;
+ z180_idle(device);
del_timer_sync(&device->idle_timer);
@@ -690,7 +662,7 @@
return status;
}
-static bool z180_isidle(struct kgsl_device *device)
+static unsigned int z180_isidle(struct kgsl_device *device)
{
struct z180_device *z180_dev = Z180_DEVICE(device);
@@ -903,7 +875,7 @@
return context;
}
-static int
+static void
z180_drawctxt_detach(struct kgsl_context *context)
{
struct kgsl_device *device;
@@ -917,13 +889,9 @@
if (z180_dev->ringbuffer.prevctx == context->id) {
z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
device->mmu.hwpagetable = device->mmu.defaultpagetable;
-
- /* Ignore the result - we are going down anyway */
kgsl_setstate(&device->mmu, KGSL_MEMSTORE_GLOBAL,
KGSL_MMUFLAGS_PTUPDATE);
}
-
- return 0;
}
static void
@@ -997,7 +965,6 @@
.irqctrl = z180_irqctrl,
.gpuid = z180_gpuid,
.irq_handler = z180_irq_handler,
- .drain = z180_idle, /* drain == idle for the z180 */
/* Optional functions */
.drawctxt_create = z180_drawctxt_create,
.drawctxt_detach = z180_drawctxt_detach,
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index a36e92d..1be0870 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -45,6 +45,5 @@
};
int z180_dump(struct kgsl_device *, int);
-int z180_idle(struct kgsl_device *);
#endif /* __Z180_H */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index bc53c0e..5d929cf 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -58,8 +58,6 @@
unsigned int i;
unsigned int reg_val;
- z180_idle(device);
-
KGSL_LOG_DUMP(device, "Z180 Register Dump\n");
for (i = 0; i < ARRAY_SIZE(regs_to_dump); i++) {
kgsl_regread(device,
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 8b0fcf4..9e0be59 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -131,57 +131,111 @@
};
static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
- {-200, 1672},
- {-180, 1656},
- {-160, 1639},
- {-140, 1620},
- {-120, 1599},
- {-100, 1577},
- {-80, 1553},
- {-60, 1527},
- {-40, 1550},
- {-20, 1471},
- {0, 1440},
- {20, 1408},
- {40, 1374},
- {60, 1339},
- {80, 1303},
- {100, 1266},
- {120, 1228},
- {140, 1190},
- {160, 1150},
- {180, 1111},
- {200, 1071},
- {220, 1032},
- {240, 992},
- {260, 953},
- {280, 915},
- {300, 877},
- {320, 841},
- {340, 805},
- {360, 770},
- {380, 736},
- {400, 704},
- {420, 673},
- {440, 643},
- {460, 614},
- {480, 587},
- {500, 561},
- {520, 536},
- {540, 513},
- {560, 491},
- {580, 470},
- {600, 450},
- {620, 431},
- {640, 414},
- {660, 397},
- {680, 382},
- {700, 367},
- {720, 353},
- {740, 340},
- {760, 328},
- {780, 317},
- {800, 306},
+ {-200, 1540},
+ {-180, 1517},
+ {-160, 1492},
+ {-140, 1467},
+ {-120, 1440},
+ {-100, 1412},
+ {-80, 1383},
+ {-60, 1353},
+ {-40, 1323},
+ {-20, 1292},
+ {0, 1260},
+ {20, 1228},
+ {40, 1196},
+ {60, 1163},
+ {80, 1131},
+ {100, 1098},
+ {120, 1066},
+ {140, 1034},
+ {160, 1002},
+ {180, 971},
+ {200, 941},
+ {220, 911},
+ {240, 882},
+ {260, 854},
+ {280, 826},
+ {300, 800},
+ {320, 774},
+ {340, 749},
+ {360, 726},
+ {380, 703},
+ {400, 681},
+ {420, 660},
+ {440, 640},
+ {460, 621},
+ {480, 602},
+ {500, 585},
+ {520, 568},
+ {540, 552},
+ {560, 537},
+ {580, 523},
+ {600, 510},
+ {620, 497},
+ {640, 485},
+ {660, 473},
+ {680, 462},
+ {700, 452},
+ {720, 442},
+ {740, 433},
+ {760, 424},
+ {780, 416},
+ {800, 408},
+};
+
+static const struct qpnp_vadc_map_pt adcmap_qrd_skuaa_btm_threshold[] = {
+ {-200, 1476},
+ {-180, 1450},
+ {-160, 1422},
+ {-140, 1394},
+ {-120, 1365},
+ {-100, 1336},
+ {-80, 1306},
+ {-60, 1276},
+ {-40, 1246},
+ {-20, 1216},
+ {0, 1185},
+ {20, 1155},
+ {40, 1126},
+ {60, 1096},
+ {80, 1068},
+ {100, 1040},
+ {120, 1012},
+ {140, 986},
+ {160, 960},
+ {180, 935},
+ {200, 911},
+ {220, 888},
+ {240, 866},
+ {260, 844},
+ {280, 824},
+ {300, 805},
+ {320, 786},
+ {340, 769},
+ {360, 752},
+ {380, 737},
+ {400, 722},
+ {420, 707},
+ {440, 694},
+ {460, 681},
+ {480, 669},
+ {500, 658},
+ {520, 648},
+ {540, 637},
+ {560, 628},
+ {580, 619},
+ {600, 611},
+ {620, 603},
+ {640, 595},
+ {660, 588},
+ {680, 582},
+ {700, 575},
+ {720, 569},
+ {740, 564},
+ {760, 559},
+ {780, 554},
+ {800, 549},
};
/* Voltage to temperature */
@@ -539,6 +593,25 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
+int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t bat_voltage = 0;
+
+ bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+
+ return qpnp_adc_map_temp_voltage(
+ adcmap_qrd_skuaa_btm_threshold,
+ ARRAY_SIZE(adcmap_qrd_skuaa_btm_threshold),
+ bat_voltage,
+ &adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_skuaa_batt_therm);
+
int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *chip,
int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index c4a2567..548764f 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -126,6 +126,7 @@
[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
+ [SCALE_QRD_SKUAA_BATT_THERM] = {qpnp_adc_scale_qrd_skuaa_batt_therm},
};
static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index 4b78903..8775ab9 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -52,6 +52,8 @@
#define MMA8X5X_STATUS_ZYXDR 0x08
#define MMA8X5X_BUF_SIZE 7
+#define MMA_SHUTTEDDOWN (1 << 31)
+
struct sensor_regulator {
struct regulator *vreg;
const char *name;
@@ -615,6 +617,9 @@
struct mma8x5x_data *pdata = i2c_get_clientdata(client);
if (pdata->active == MMA_ACTIVED)
mma8x5x_device_stop(client);
+ if (!mma8x5x_config_regulator(client, 0))
+ /* The highest bit sotres the power state */
+ pdata->active |= MMA_SHUTTEDDOWN;
return 0;
}
@@ -623,11 +628,33 @@
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+ if (pdata->active & MMA_SHUTTEDDOWN) {
+ if (mma8x5x_config_regulator(client, 1))
+ goto out;
+
+ if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
+ goto out;
+
+ if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
+ pdata->mode))
+ goto out;
+
+ /* The BT(boot time) for mma8x5x is 1.55ms according to
+ Freescale mma8450Q document. Document Number:MMA8450Q
+ Rev: 9.1, 04/2012
+ */
+ usleep_range(1600, 2000);
+ pdata->active &= ~MMA_SHUTTEDDOWN;
+ }
if (pdata->active == MMA_ACTIVED) {
val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
}
+
return 0;
+out:
+ dev_err(&client->dev, "%s:failed during resume operation", __func__);
+ return -EIO;
}
#endif
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index ded2b6e..e0d8a47 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -320,15 +320,19 @@
if (sensor->use_poll)
schedule_delayed_work(&sensor->input_work,
msecs_to_jiffies(sensor->poll_interval));
- else
+ else {
i2c_smbus_write_byte_data(sensor->client,
MPU3050_INT_CFG,
MPU3050_ACTIVE_LOW |
MPU3050_OPEN_DRAIN |
MPU3050_RAW_RDY_EN);
+ enable_irq(sensor->client->irq);
+ }
} else {
if (sensor->use_poll)
cancel_delayed_work_sync(&sensor->input_work);
+ else
+ disable_irq(sensor->client->irq);
gpio_set_value(sensor->enable_gpio, 0);
pm_runtime_put(sensor->dev);
}
@@ -448,6 +452,7 @@
mpu3050_config_regulator(client, 1);
udelay(10);
gpio_set_value(sensor->enable_gpio, 1);
+ msleep(60);
}
value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
@@ -709,7 +714,6 @@
}
mpu3050_set_power_mode(client, 1);
- msleep(10);
ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
if (ret < 0) {
@@ -864,6 +868,10 @@
static int mpu3050_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (!sensor->use_poll)
+ disable_irq(client->irq);
mpu3050_set_power_mode(client, 0);
@@ -879,9 +887,12 @@
static int mpu3050_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
mpu3050_set_power_mode(client, 1);
- msleep(100); /* wait for gyro chip resume */
+
+ if (!sensor->use_poll)
+ enable_irq(client->irq);
return 0;
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b43c13e..9b0c5c7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1008,4 +1008,16 @@
If unsure, say N.
+config TOUCHSCREEN_GT9XX
+ bool "Goodix touchpanel GT9xx series"
+ depends on I2C
+ help
+ Say Y here if you have a Goodix GT9xx touchscreen.
+ Gt9xx controllers are multi touch controllers which can
+ report 5 touches at a time.
+
+ If unsure, say N.
+
+source "drivers/input/touchscreen/gt9xx/Kconfig"
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 1f309d8..3acc612 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -82,3 +82,4 @@
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o
+obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b725200..06ca31c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -394,7 +394,7 @@
const char *fw_name;
bool no_force_update;
bool lpm_support;
- bool regs_enabled;
+ bool dev_sleep;
#if defined(CONFIG_SECURE_TOUCH)
atomic_t st_enabled;
@@ -2162,11 +2162,6 @@
if (on == false)
goto power_off;
- if (data->regs_enabled) {
- dev_dbg(&data->client->dev, "regs are already enabled\n");
- return 0;
- }
-
rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
if (rc < 0) {
dev_err(&data->client->dev,
@@ -2215,8 +2210,6 @@
}
}
- data->regs_enabled = true;
-
msleep(130);
return 0;
@@ -2237,12 +2230,6 @@
return rc;
power_off:
-
- if (!data->regs_enabled) {
- dev_dbg(&data->client->dev, "regs are already disabled\n");
- return 0;
- }
-
reg_set_optimum_mode_check(data->vcc_ana, 0);
regulator_disable(data->vcc_ana);
if (data->pdata->digital_pwr_regulator) {
@@ -2254,8 +2241,6 @@
regulator_disable(data->vcc_i2c);
}
- data->regs_enabled = false;
-
msleep(50);
return 0;
}
@@ -2455,6 +2440,11 @@
struct input_dev *input_dev = data->input_dev;
int error;
+ if (data->dev_sleep) {
+ dev_dbg(dev, "Device already in sleep\n");
+ return 0;
+ }
+
disable_irq(data->irq);
mutex_lock(&input_dev->mutex);
@@ -2485,6 +2475,7 @@
}
}
+ data->dev_sleep = true;
return 0;
}
@@ -2495,6 +2486,11 @@
struct input_dev *input_dev = data->input_dev;
int error;
+ if (!data->dev_sleep) {
+ dev_dbg(dev, "Device already in resume\n");
+ return 0;
+ }
+
/* put regulators back in active power mode */
if (data->lpm_support) {
error = mxt_regulator_lpm(data, false);
@@ -2538,6 +2534,7 @@
enable_irq(data->irq);
+ data->dev_sleep = false;
return 0;
}
@@ -2924,6 +2921,7 @@
data->pdata = pdata;
data->no_force_update = pdata->no_force_update;
data->lpm_support = !pdata->no_lpm_support;
+ data->dev_sleep = false;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
diff --git a/drivers/input/touchscreen/gt9xx/Kconfig b/drivers/input/touchscreen/gt9xx/Kconfig
new file mode 100644
index 0000000..9d36403
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/Kconfig
@@ -0,0 +1,51 @@
+#
+# Goodix GT9xx Touchscreen driver
+#
+
+config GT9XX_TOUCHPANEL_DRIVER
+ tristate "Goodix GT9xx touchpanel driver"
+ depends on TOUCHSCREEN_GT9XX
+ default n
+ help
+ This is the main file for touchpanel driver for Goodix GT9xx
+ touchscreens.
+
+ Say Y here if you have a Goodix GT9xx touchscreen connected
+ to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gt9xx_update.
+
+config GT9XX_TOUCHPANEL_UPDATE
+ tristate "Goodix GT9xx touchpanel auto update support"
+ depends on GT9XX_TOUCHPANEL_DRIVER
+ default n
+ help
+ This enables support for firmware update for Goodix GT9xx
+ touchscreens.
+
+ Say Y here if you have a Goodix GT9xx touchscreen connected
+ to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gt9xx_update.
+
+config GT9XX_TOUCHPANEL_DEBUG
+ tristate "Goodix GT9xx Tools for debuging"
+ depends on GT9XX_TOUCHPANEL_DRIVER
+ default n
+ help
+ This is application debug interface support for Goodix GT9xx
+ touchscreens.
+
+ Say Y here if you want to have a Android app debug interface
+ to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gt9xx_update.
diff --git a/drivers/input/touchscreen/gt9xx/Makefile b/drivers/input/touchscreen/gt9xx/Makefile
new file mode 100644
index 0000000..482d869
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/Makefile
@@ -0,0 +1,8 @@
+#gt915 touchpanel driver
+
+
+obj-$(CONFIG_GT9XX_TOUCHPANEL_DRIVER) += gt9xx.o
+#gt915 update file
+obj-$(CONFIG_GT9XX_TOUCHPANEL_UPDATE) += gt9xx_update.o
+#debug tool
+obj-$(CONFIG_GT9XX_TOUCHPANEL_DEBUG) += goodix_tool.o
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index 3dfe4e1..bdac3fd 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -1,615 +1,549 @@
-/* drivers/input/touchscreen/goodix_tool.c
- *
- * 2010 - 2012 Goodix Technology.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be a reference
- * to you, when you are integrating the GOODiX's CTP IC into your system,
- * 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.
- *
- * Version:1.6
- * V1.0:2012/05/01,create file.
- * V1.2:2012/06/08,modify some warning.
- * V1.4:2012/08/28,modified to support GT9XX
- * V1.6:new proc name
- */
-
-#include "gt9xx.h"
-
-#define DATA_LENGTH_UINT 512
-#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*))
-static char procname[20] = {0};
-
-#define UPDATE_FUNCTIONS
-
-#ifdef UPDATE_FUNCTIONS
-extern s32 gup_enter_update_mode(struct i2c_client *client);
-extern void gup_leave_update_mode(void);
-extern s32 gup_update_proc(void *dir);
-#endif
-
-extern void gtp_irq_disable(struct goodix_ts_data *);
-extern void gtp_irq_enable(struct goodix_ts_data *);
-
-#pragma pack(1)
-typedef struct{
- u8 wr; //write read flag£¬0:R 1:W 2:PID 3:
- u8 flag; //0:no need flag/int 1: need flag 2:need int
- u8 flag_addr[2]; //flag address
- u8 flag_val; //flag val
- u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:<
- u16 circle; //polling cycle
- u8 times; //plling times
- u8 retry; //I2C retry times
- u16 delay; //delay befor read or after write
- u16 data_len; //data length
- u8 addr_len; //address length
- u8 addr[2]; //address
- u8 res[3]; //reserved
- u8* data; //data pointer
-}st_cmd_head;
-#pragma pack()
-st_cmd_head cmd_head;
-
-static struct i2c_client *gt_client = NULL;
-
-static struct proc_dir_entry *goodix_proc_entry;
-
-static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data);
-static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data );
-static s32 (*tool_i2c_read)(u8 *, u16);
-static s32 (*tool_i2c_write)(u8 *, u16);
-
-#if GTP_ESD_PROTECT
-extern void gtp_esd_switch(struct i2c_client *, s32);
-#endif
-s32 DATA_LENGTH = 0;
-s8 IC_TYPE[16] = {0};
-
-static void tool_set_proc_name(char * procname)
-{
- char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
- "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- char date[20] = {0};
- char month[4] = {0};
- int i = 0, n_month = 1, n_day = 0, n_year = 0;
-
- sprintf(date, "%s", __DATE__);
-
- //GTP_DEBUG("compile date: %s", date);
-
- sscanf(date, "%s %d %d", month, &n_day, &n_year);
-
- for (i = 0; i < 12; ++i)
- {
- if (!memcmp(months[i], month, 3))
- {
- n_month = i+1;
- break;
- }
- }
-
- sprintf(procname, "gmnode%04d%02d%02d", n_year, n_month, n_day);
-
- //GTP_DEBUG("procname = %s", procname);
-}
-
-
-static s32 tool_i2c_read_no_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- s32 i = 0;
- struct i2c_msg msgs[2];
-
- msgs[0].flags = !I2C_M_RD;
- msgs[0].addr = gt_client->addr;
- msgs[0].len = cmd_head.addr_len;
- msgs[0].buf = &buf[0];
-
- msgs[1].flags = I2C_M_RD;
- msgs[1].addr = gt_client->addr;
- msgs[1].len = len;
- msgs[1].buf = &buf[GTP_ADDR_LENGTH];
-
- for (i = 0; i < cmd_head.retry; i++)
- {
- ret=i2c_transfer(gt_client->adapter, msgs, 2);
- if (ret > 0)
- {
- break;
- }
- }
- return ret;
-}
-
-static s32 tool_i2c_write_no_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- s32 i = 0;
- struct i2c_msg msg;
-
- msg.flags = !I2C_M_RD;
- msg.addr = gt_client->addr;
- msg.len = len;
- msg.buf = buf;
-
- for (i = 0; i < cmd_head.retry; i++)
- {
- ret=i2c_transfer(gt_client->adapter, &msg, 1);
- if (ret > 0)
- {
- break;
- }
- }
- return ret;
-}
-
-static s32 tool_i2c_read_with_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- u8 pre[2] = {0x0f, 0xff};
- u8 end[2] = {0x80, 0x00};
-
- tool_i2c_write_no_extra(pre, 2);
- ret = tool_i2c_read_no_extra(buf, len);
- tool_i2c_write_no_extra(end, 2);
-
- return ret;
-}
-
-static s32 tool_i2c_write_with_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- u8 pre[2] = {0x0f, 0xff};
- u8 end[2] = {0x80, 0x00};
-
- tool_i2c_write_no_extra(pre, 2);
- ret = tool_i2c_write_no_extra(buf, len);
- tool_i2c_write_no_extra(end, 2);
-
- return ret;
-}
-
-static void register_i2c_func(void)
-{
-// if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
-// || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
-// || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
-// || !strncmp(IC_TYPE, "GT813", 5))
- if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
- && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
- && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
- && strncmp(IC_TYPE, "GTxxx", 5))
- {
- tool_i2c_read = tool_i2c_read_with_extra;
- tool_i2c_write = tool_i2c_write_with_extra;
- GTP_DEBUG("I2C function: with pre and end cmd!");
- }
- else
- {
- tool_i2c_read = tool_i2c_read_no_extra;
- tool_i2c_write = tool_i2c_write_no_extra;
- GTP_INFO("I2C function: without pre and end cmd!");
- }
-}
-
-static void unregister_i2c_func(void)
-{
- tool_i2c_read = NULL;
- tool_i2c_write = NULL;
- GTP_INFO("I2C function: unregister i2c transfer function!");
-}
-
-
-s32 init_wr_node(struct i2c_client *client)
-{
- s32 i;
-
- gt_client = client;
- memset(&cmd_head, 0, sizeof(cmd_head));
- cmd_head.data = NULL;
-
- i = 5;
- while ((!cmd_head.data) && i)
- {
- cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
- if (NULL != cmd_head.data)
- {
- break;
- }
- i--;
- }
- if (i)
- {
- DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
- GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
- }
- else
- {
- GTP_ERROR("Apply for memory failed.");
- return FAIL;
- }
-
- cmd_head.addr_len = 2;
- cmd_head.retry = 5;
-
- register_i2c_func();
-
- tool_set_proc_name(procname);
- goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
- if (goodix_proc_entry == NULL)
- {
- GTP_ERROR("Couldn't create proc entry!");
- return FAIL;
- }
- else
- {
- GTP_INFO("Create proc entry success!");
- goodix_proc_entry->write_proc = goodix_tool_write;
- goodix_proc_entry->read_proc = goodix_tool_read;
- }
-
- return SUCCESS;
-}
-
-void uninit_wr_node(void)
-{
- kfree(cmd_head.data);
- cmd_head.data = NULL;
- unregister_i2c_func();
- remove_proc_entry(procname, NULL);
-}
-
-static u8 relation(u8 src, u8 dst, u8 rlt)
-{
- u8 ret = 0;
-
- switch (rlt)
- {
- case 0:
- ret = (src != dst) ? true : false;
- break;
-
- case 1:
- ret = (src == dst) ? true : false;
- GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32)ret);
- break;
-
- case 2:
- ret = (src > dst) ? true : false;
- break;
-
- case 3:
- ret = (src < dst) ? true : false;
- break;
-
- case 4:
- ret = (src & dst) ? true : false;
- break;
-
- case 5:
- ret = (!(src | dst)) ? true : false;
- break;
-
- default:
- ret = false;
- break;
- }
-
- return ret;
-}
-
-/*******************************************************
-Function:
- Comfirm function.
-Input:
- None.
-Output:
- Return write length.
-********************************************************/
-static u8 comfirm(void)
-{
- s32 i = 0;
- u8 buf[32];
-
-// memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len], &cmd_head.flag_addr, cmd_head.addr_len);
-// memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);//Modified by Scott, 2012-02-17
- memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
-
- for (i = 0; i < cmd_head.times; i++)
- {
- if (tool_i2c_read(buf, 1) <= 0)
- {
- GTP_ERROR("Read flag data failed!");
- return FAIL;
- }
- if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation))
- {
- GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]);
- GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
- break;
- }
-
- msleep(cmd_head.circle);
- }
-
- if (i >= cmd_head.times)
- {
- GTP_ERROR("Didn't get the flag to continue!");
- return FAIL;
- }
-
- return SUCCESS;
-}
-
-/*******************************************************
-Function:
- Goodix tool write function.
-Input:
- standard proc write function param.
-Output:
- Return write length.
-********************************************************/
-static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
-{
- s32 ret = 0;
- GTP_DEBUG_FUNC();
- GTP_DEBUG_ARRAY((u8*)buff, len);
-
- ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
- if(ret)
- {
- GTP_ERROR("copy_from_user failed.");
- }
-
- GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
- GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
- GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]);
- GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
- GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
- GTP_DEBUG("circle :%d.", (s32)cmd_head.circle);
- GTP_DEBUG("times :%d.", (s32)cmd_head.times);
- GTP_DEBUG("retry :%d.", (s32)cmd_head.retry);
- GTP_DEBUG("delay :%d.", (s32)cmd_head.delay);
- GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
- GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
- GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
- GTP_DEBUG("len:%d.", (s32)len);
- GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
-
- if (1 == cmd_head.wr)
- {
- // copy_from_user(&cmd_head.data[cmd_head.addr_len], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- if(ret)
- {
- GTP_ERROR("copy_from_user failed.");
- }
- memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], cmd_head.addr, cmd_head.addr_len);
-
- GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + cmd_head.addr_len);
- GTP_DEBUG_ARRAY((u8*)&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
-
- if (1 == cmd_head.flag)
- {
- if (FAIL == comfirm())
- {
- GTP_ERROR("[WRITE]Comfirm fail!");
- return FAIL;
- }
- }
- else if (2 == cmd_head.flag)
- {
- //Need interrupt!
- }
- if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
- cmd_head.data_len + cmd_head.addr_len) <= 0)
- {
- GTP_ERROR("[WRITE]Write data failed!");
- return FAIL;
- }
-
- GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],cmd_head.data_len + cmd_head.addr_len);
- if (cmd_head.delay)
- {
- msleep(cmd_head.delay);
- }
-
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- }
- else if (3 == cmd_head.wr) //Write ic type
- {
- ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- if(ret)
- {
- GTP_ERROR("copy_from_user failed.");
- }
- memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
-
- register_i2c_func();
-
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- }
- else if (5 == cmd_head.wr)
- {
- //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
-
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- }
- else if (7 == cmd_head.wr)//disable irq!
- {
- gtp_irq_disable(i2c_get_clientdata(gt_client));
-
- #if GTP_ESD_PROTECT
- gtp_esd_switch(gt_client, SWITCH_OFF);
- #endif
- return CMD_HEAD_LENGTH;
- }
- else if (9 == cmd_head.wr) //enable irq!
- {
- gtp_irq_enable(i2c_get_clientdata(gt_client));
-
- #if GTP_ESD_PROTECT
- gtp_esd_switch(gt_client, SWITCH_ON);
- #endif
- return CMD_HEAD_LENGTH;
- }
- else if(17 == cmd_head.wr)
- {
- struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
- ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- if(ret)
- {
- GTP_DEBUG("copy_from_user failed.");
- }
- if(cmd_head.data[GTP_ADDR_LENGTH])
- {
- GTP_DEBUG("gtp enter rawdiff.");
- ts->gtp_rawdiff_mode = true;
- }
- else
- {
- ts->gtp_rawdiff_mode = false;
- GTP_DEBUG("gtp leave rawdiff.");
- }
- return CMD_HEAD_LENGTH;
- }
-#ifdef UPDATE_FUNCTIONS
- else if (11 == cmd_head.wr)//Enter update mode!
- {
- if (FAIL == gup_enter_update_mode(gt_client))
- {
- return FAIL;
- }
- }
- else if (13 == cmd_head.wr)//Leave update mode!
- {
- gup_leave_update_mode();
- }
- else if (15 == cmd_head.wr) //Update firmware!
- {
- show_len = 0;
- total_len = 0;
- memset(cmd_head.data, 0, cmd_head.data_len + 1);
- memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
-
- if (FAIL == gup_update_proc((void*)cmd_head.data))
- {
- return FAIL;
- }
- }
-#endif
-
- return CMD_HEAD_LENGTH;
-}
-
-/*******************************************************
-Function:
- Goodix tool read function.
-Input:
- standard proc read function param.
-Output:
- Return read length.
-********************************************************/
-static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )
-{
- GTP_DEBUG_FUNC();
-
- if (cmd_head.wr % 2)
- {
- return FAIL;
- }
- else if (!cmd_head.wr)
- {
- u16 len = 0;
- s16 data_len = 0;
- u16 loc = 0;
-
- if (1 == cmd_head.flag)
- {
- if (FAIL == comfirm())
- {
- GTP_ERROR("[READ]Comfirm fail!");
- return FAIL;
- }
- }
- else if (2 == cmd_head.flag)
- {
- //Need interrupt!
- }
-
- memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
-
- GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], cmd_head.data[1]);
- GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
-
- if (cmd_head.delay)
- {
- msleep(cmd_head.delay);
- }
-
- data_len = cmd_head.data_len;
- while(data_len > 0)
- {
- if (data_len > DATA_LENGTH)
- {
- len = DATA_LENGTH;
- }
- else
- {
- len = data_len;
- }
- data_len -= DATA_LENGTH;
-
- if (tool_i2c_read(cmd_head.data, len) <= 0)
- {
- GTP_ERROR("[READ]Read data failed!");
- return FAIL;
- }
- memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH], len);
- loc += len;
-
- GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
- GTP_DEBUG_ARRAY(page, len);
- }
- }
- else if (2 == cmd_head.wr)
- {
- // memcpy(page, "gt8", cmd_head.data_len);
- // memcpy(page, "GT818", 5);
- // page[5] = 0;
-
- GTP_DEBUG("Return ic type:%s len:%d.", page, (s32)cmd_head.data_len);
- return cmd_head.data_len;
- //return sizeof(IC_TYPE_NAME);
- }
- else if (4 == cmd_head.wr)
- {
- page[0] = show_len >> 8;
- page[1] = show_len & 0xff;
- page[2] = total_len >> 8;
- page[3] = total_len & 0xff;
-
- return cmd_head.data_len;
- }
- else if (6 == cmd_head.wr)
- {
- //Read error code!
- }
- else if (8 == cmd_head.wr) //Read driver version
- {
- // memcpy(page, GTP_DRIVER_VERSION, strlen(GTP_DRIVER_VERSION));
- s32 tmp_len;
- tmp_len = strlen(GTP_DRIVER_VERSION);
- memcpy(page, GTP_DRIVER_VERSION, tmp_len);
- page[tmp_len] = 0;
- }
-
- return cmd_head.data_len;
-}
+/* drivers/input/touchscreen/goodix_tool.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version:1.6
+ * V1.0:2012/05/01,create file.
+ * V1.2:2012/06/08,modify some warning.
+ * V1.4:2012/08/28,modified to support GT9XX
+ * V1.6:new proc name
+ */
+
+#include "gt9xx.h"
+
+#define DATA_LENGTH_UINT 512
+#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8 *))
+static char procname[20] = {0};
+
+#define UPDATE_FUNCTIONS
+
+#pragma pack(1)
+struct {
+ u8 wr; /* write read flag£¬0:R 1:W 2:PID 3: */
+ u8 flag; /* 0:no need flag/int 1: need flag 2:need int */
+ u8 flag_addr[2];/* flag address */
+ u8 flag_val; /* flag val */
+ u8 flag_relation; /* flag_val:flag 0:not equal 1:equal 2:> 3:< */
+ u16 circle; /* polling cycle */
+ u8 times; /* plling times */
+ u8 retry; /* I2C retry times */
+ u16 delay; /* delay befor read or after write */
+ u16 data_len; /* data length */
+ u8 addr_len; /* address length */
+ u8 addr[2]; /* address */
+ u8 res[3]; /* reserved */
+ u8 *data; /* data pointer */
+} st_cmd_head;
+#pragma pack()
+st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client;
+
+static struct proc_dir_entry *goodix_proc_entry;
+
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+ unsigned long len, void *data);
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data);
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+s32 DATA_LENGTH;
+s8 IC_TYPE[16] = {0};
+
+static void tool_set_proc_name(char *procname)
+{
+ char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ char date[20] = {0};
+ char month[4] = {0};
+ int i = 0, n_month = 1, n_day = 0, n_year = 0;
+ snprintf(date, 20, "%s", __DATE__);
+
+ /* GTP_DEBUG("compile date: %s", date); */
+
+ sscanf(date, "%s %d %d", month, &n_day, &n_year);
+
+ for (i = 0; i < 12; ++i) {
+ if (!memcmp(months[i], month, 3)) {
+ n_month = i+1;
+ break;
+ }
+ }
+
+ snprintf(procname, 20, "gmnode%04d%02d%02d", n_year, n_month, n_day);
+ /* GTP_DEBUG("procname = %s", procname); */
+}
+
+static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msgs[2];
+
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = gt_client->addr;
+ msgs[0].len = cmd_head.addr_len;
+ msgs[0].buf = &buf[0];
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = gt_client->addr;
+ msgs[1].len = len;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+
+ for (i = 0; i < cmd_head.retry; i++) {
+ ret = i2c_transfer(gt_client->adapter, msgs, 2);
+ if (ret > 0)
+ break;
+ }
+
+ return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msg;
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = gt_client->addr;
+ msg.len = len;
+ msg.buf = buf;
+
+ for (i = 0; i < cmd_head.retry; i++) {
+ ret = i2c_transfer(gt_client->adapter, &msg, 1);
+ if (ret > 0)
+ break;
+ }
+
+ return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_read_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_write_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static void register_i2c_func(void)
+{
+ /* if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
+ || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
+ || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
+ || !strncmp(IC_TYPE, "GT813", 5)) */
+
+ if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
+ && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
+ && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
+ && strncmp(IC_TYPE, "GTxxx", 5)) {
+ tool_i2c_read = tool_i2c_read_with_extra;
+ tool_i2c_write = tool_i2c_write_with_extra;
+ GTP_DEBUG("I2C function: with pre and end cmd!");
+ } else {
+ tool_i2c_read = tool_i2c_read_no_extra;
+ tool_i2c_write = tool_i2c_write_no_extra;
+ GTP_INFO("I2C function: without pre and end cmd!");
+ }
+}
+
+static void unregister_i2c_func(void)
+{
+ tool_i2c_read = NULL;
+ tool_i2c_write = NULL;
+ GTP_INFO("I2C function: unregister i2c transfer function!");
+}
+
+s32 init_wr_node(struct i2c_client *client)
+{
+ s32 i;
+
+ gt_client = client;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.data = NULL;
+
+ i = 5;
+ while ((!cmd_head.data) && i) {
+ cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+ if (NULL != cmd_head.data)
+ break;
+ i--;
+ }
+ if (i) {
+ DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
+ GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+ } else {
+ GTP_ERROR("Apply for memory failed.");
+ return FAIL;
+ }
+
+ cmd_head.addr_len = 2;
+ cmd_head.retry = 5;
+
+ register_i2c_func();
+
+ tool_set_proc_name(procname);
+ goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+ if (goodix_proc_entry == NULL) {
+ GTP_ERROR("Couldn't create proc entry!");
+ return FAIL;
+ } else {
+ GTP_INFO("Create proc entry success!");
+ goodix_proc_entry->write_proc = goodix_tool_write;
+ dix_proc_entry->read_proc = goodix_tool_read;
+ }
+
+ return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+ kfree(cmd_head.data);
+ cmd_head.data = NULL;
+ unregister_i2c_func();
+ remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+ u8 ret = 0;
+
+ switch (rlt) {
+
+ case 0:
+ ret = (src != dst) ? true : false;
+ break;
+
+ case 1:
+ ret = (src == dst) ? true : false;
+ GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.",
+ src, dst, (s32)ret);
+ break;
+
+ case 2:
+ ret = (src > dst) ? true : false;
+ break;
+
+ case 3:
+ ret = (src < dst) ? true : false;
+ break;
+
+ case 4:
+ ret = (src & dst) ? true : false;
+ break;
+
+ case 5:
+ ret = (!(src | dst)) ? true : false;
+ break;
+
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Comfirm function.
+Input:
+ None.
+Output:
+ Return write length.
+********************************************************/
+static u8 comfirm(void)
+{
+ s32 i = 0;
+ u8 buf[32];
+
+/* memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ &cmd_head.flag_addr, cmd_head.addr_len);
+ memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);
+ //Modified by Scott, 2012-02-17 */
+ memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+ for (i = 0; i < cmd_head.times; i++) {
+ if (tool_i2c_read(buf, 1) <= 0) {
+ GTP_ERROR("Read flag data failed!");
+ return FAIL;
+ }
+ if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val,
+ cmd_head.flag_relation)) {
+ GTP_DEBUG("value at flag addr:0x%02x.",
+ buf[GTP_ADDR_LENGTH]);
+ GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
+ break;
+ }
+
+ msleep(cmd_head.circle);
+ }
+
+ if (i >= cmd_head.times) {
+ GTP_ERROR("Didn't get the flag to continue!");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+/********************************************************
+Function:
+ Goodix tool write function.
+nput:
+ standard proc write function param.
+Output:
+ Return write length.
+********************************************************/
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+ unsigned long len, void *data)
+{
+ s32 ret = 0;
+ GTP_DEBUG_FUNC();
+ GTP_DEBUG_ARRAY((u8 *)buff, len);
+
+ ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+ if (ret)
+ GTP_ERROR("copy_from_user failed.");
+
+ GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
+ GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
+ GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0],
+ cmd_head.flag_addr[1]);
+ GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
+ GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
+ GTP_DEBUG("circle :%d.", (s32)cmd_head.circle);
+ GTP_DEBUG("times :%d.", (s32)cmd_head.times);
+ GTP_DEBUG("retry :%d.", (s32)cmd_head.retry);
+ GTP_DEBUG("delay :%d.", (s32)cmd_head.delay);
+ GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
+ GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
+ GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+ GTP_DEBUG("len:%d.", (s32)len);
+ GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+
+ if (cmd_head.wr == 1) {
+ /* copy_from_user(&cmd_head.data[cmd_head.addr_len],
+ &buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+ &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if (ret)
+ GTP_ERROR("copy_from_user failed.");
+
+ memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG_ARRAY(cmd_head.data,
+ cmd_head.data_len + cmd_head.addr_len);
+ GTP_DEBUG_ARRAY((u8 *)&buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+
+ if (cmd_head.flag == 1) {
+ if (FAIL == comfirm()) {
+ GTP_ERROR("[WRITE]Comfirm fail!");
+ return FAIL;
+ }
+ } else if (cmd_head.flag == 2) {
+ /* Need interrupt! */
+ }
+ if (tool_i2c_write(
+ &cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.data_len + cmd_head.addr_len) <= 0) {
+ GTP_ERROR("[WRITE]Write data failed!");
+ return FAIL;
+ }
+
+ GTP_DEBUG_ARRAY(
+ &cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.data_len + cmd_head.addr_len);
+ if (cmd_head.delay)
+ msleep(cmd_head.delay);
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 3) { /* Write ic type */
+
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+ if (ret)
+ GTP_ERROR("copy_from_user failed.");
+
+ memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+ register_i2c_func();
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 3) {
+
+ /* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 7) { /* disable irq! */
+ gtp_irq_disable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_OFF);
+ #endif
+ return CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 9) { /* enable irq! */
+ gtp_irq_enable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_ON);
+ #endif
+ return CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 17) {
+ struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+ &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if (ret)
+ GTP_DEBUG("copy_from_user failed.");
+ if (cmd_head.data[GTP_ADDR_LENGTH]) {
+ GTP_DEBUG("gtp enter rawdiff.");
+ ts->gtp_rawdiff_mode = true;
+ } else {
+ ts->gtp_rawdiff_mode = false;
+ GTP_DEBUG("gtp leave rawdiff.");
+ }
+ return CMD_HEAD_LENGTH;
+ }
+#ifdef UPDATE_FUNCTIONS
+ else if (cmd_head.wr == 11) { /* Enter update mode! */
+ if (FAIL == gup_enter_update_mode(gt_client))
+ return FAIL;
+ } else if (cmd_head.wr == 13) { /* Leave update mode! */
+ gup_leave_update_mode();
+ } else if (cmd_head.wr == 15) { /* Update firmware! */
+ show_len = 0;
+ total_len = 0;
+ memset(cmd_head.data, 0, cmd_head.data_len + 1);
+ memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+
+ if (FAIL == gup_update_proc((void *)cmd_head.data))
+ return FAIL;
+ }
+#endif
+
+ return CMD_HEAD_LENGTH;
+}
+
+/*******************************************************
+Function:
+ Goodix tool read function.
+Input:
+ standard proc read function param.
+Output:
+ Return read length.
+********************************************************/
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ GTP_DEBUG_FUNC();
+
+ if (cmd_head.wr % 2) {
+ return FAIL;
+ } else if (!cmd_head.wr) {
+ u16 len = 0;
+ s16 data_len = 0;
+ u16 loc = 0;
+
+ if (cmd_head.flag == 1) {
+ if (FAIL == comfirm()) {
+ GTP_ERROR("[READ]Comfirm fail!");
+ return FAIL;
+ }
+ } else if (cmd_head.flag == 2) {
+ /* Need interrupt! */
+ }
+
+ memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0],
+ cmd_head.data[1]);
+ GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0],
+ cmd_head.addr[1]);
+
+ if (cmd_head.delay)
+ msleep(cmd_head.delay);
+
+ data_len = cmd_head.data_len;
+ while (data_len > 0) {
+ if (data_len > DATA_LENGTH)
+ len = DATA_LENGTH;
+ else
+ len = data_len;
+
+ data_len -= DATA_LENGTH;
+
+ if (tool_i2c_read(cmd_head.data, len) <= 0) {
+ GTP_ERROR("[READ]Read data failed!");
+ return FAIL;
+ }
+ memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
+ len);
+ loc += len;
+
+ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
+ GTP_DEBUG_ARRAY(page, len);
+ }
+ } else if (cmd_head.wr == 2) {
+ /* memcpy(page, "gt8", cmd_head.data_len);
+ memcpy(page, "GT818", 5);
+ page[5] = 0; */
+
+ GTP_DEBUG("Return ic type:%s len:%d.", page,
+ (s32)cmd_head.data_len);
+ return cmd_head.data_len;
+ /* return sizeof(IC_TYPE_NAME); */
+ } else if (cmd_head.wr == 4) {
+ page[0] = show_len >> 8;
+ page[1] = show_len & 0xff;
+ page[2] = total_len >> 8;
+ page[3] = total_len & 0xff;
+
+ return cmd_head.data_len;
+ } else if (6 == cmd_head.wr) {
+ /* Read error code! */
+ } else if (8 == cmd_head.wr) { /*Read driver version */
+ /* memcpy(page, GTP_DRIVER_VERSION,
+ strlen(GTP_DRIVER_VERSION)); */
+ s32 tmp_len;
+ tmp_len = strlen(GTP_DRIVER_VERSION);
+ memcpy(page, GTP_DRIVER_VERSION, tmp_len);
+ page[tmp_len] = 0;
+ }
+
+ return cmd_head.data_len;
+}
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index b1dc08b..4450cde 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -1,1762 +1,2242 @@
/* drivers/input/touchscreen/gt9xx.c
- *
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
+ *
* 2010 - 2013 Goodix Technology.
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be a reference
- * to you, when you are integrating the GOODiX's CTP IC into your system,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
- *
+ *
* Version: 1.8
* Authors: andrew@goodix.com, meta@goodix.com
* Release Date: 2013/04/25
* Revision record:
- * V1.0:
- * first Release. By Andrew, 2012/08/31
+ * V1.0:
+ * first Release. By Andrew, 2012/08/31
* V1.2:
- * modify gtp_reset_guitar,slot report,tracking_id & 0x0F. By Andrew, 2012/10/15
+ * modify gtp_reset_guitar,slot report,tracking_id & 0x0F.
+ * By Andrew, 2012/10/15
* V1.4:
* modify gt9xx_update.c. By Andrew, 2012/12/12
- * V1.6:
+ * V1.6:
* 1. new heartbeat/esd_protect mechanism(add external watchdog)
- * 2. doze mode, sliding wakeup
- * 3. 3 more cfg_group(GT9 Sensor_ID: 0~5)
+ * 2. doze mode, sliding wakeup
+ * 3. 3 more cfg_group(GT9 Sensor_ID: 0~5)
* 3. config length verification
* 4. names & comments
* By Meta, 2013/03/11
* V1.8:
- * 1. pen/stylus identification
+ * 1. pen/stylus identification
* 2. read double check & fixed config support
* 2. new esd & slide wakeup optimization
* By Meta, 2013/06/08
*/
-#include <linux/irq.h>
+#include <linux/regulator/consumer.h>
#include "gt9xx.h"
+#include <linux/of_gpio.h>
+
#if GTP_ICS_SLOT_REPORT
- #include <linux/input/mt.h>
+#include <linux/input/mt.h>
#endif
-static const char *goodix_ts_name = "Goodix Capacitive TouchScreen";
-static struct workqueue_struct *goodix_wq;
-struct i2c_client * i2c_connect_client = NULL;
-u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]
- = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+#define GOODIX_DEV_NAME "Goodix Capacitive TouchScreen"
+#define CFG_MAX_TOUCH_POINTS 5
+#define GOODIX_COORDS_ARR_SIZE 4
+#define MAX_BUTTONS 4
+
+/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+#define GTP_I2C_ADDRESS_HIGH 0x14
+#define GTP_I2C_ADDRESS_LOW 0x5D
+#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+
+#define GOODIX_VTG_MIN_UV 2600000
+#define GOODIX_VTG_MAX_UV 3300000
+#define GOODIX_I2C_VTG_MIN_UV 1800000
+#define GOODIX_I2C_VTG_MAX_UV 1800000
+#define GOODIX_VDD_LOAD_MIN_UA 0
+#define GOODIX_VDD_LOAD_MAX_UA 10000
+#define GOODIX_VIO_LOAD_MIN_UA 0
+#define GOODIX_VIO_LOAD_MAX_UA 10000
+
+#define RESET_DELAY_T3_US 200 /* T3: > 100us */
+#define RESET_DELAY_T4 20 /* T4: > 5ms */
+
+#define PHY_BUF_SIZE 32
+
+#define GTP_MAX_TOUCH 5
+#define GTP_ESD_CHECK_CIRCLE_MS 2000
#if GTP_HAVE_TOUCH_KEY
- static const u16 touch_key_array[] = GTP_KEY_TAB;
- #define GTP_MAX_KEY_NUM (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
-
+static const u16 touch_key_array[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK};
+#define GTP_MAX_KEY_NUM (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
+
#if GTP_DEBUG_ON
- static const int key_codes[] = {KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH};
- static const char *key_names[] = {"Key_Home", "Key_Back", "Key_Menu", "Key_Search"};
+static const int key_codes[] = {
+ KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH
+};
+static const char *const key_names[] = {
+ "Key_Home", "Key_Back", "Key_Menu", "Key_Search"
+};
#endif
-
#endif
-static s8 gtp_i2c_test(struct i2c_client *client);
-void gtp_reset_guitar(struct i2c_client *client, s32 ms);
-void gtp_int_sync(s32 ms);
+static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
+static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
+static int gtp_i2c_test(struct i2c_client *client);
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void goodix_ts_early_suspend(struct early_suspend *h);
static void goodix_ts_late_resume(struct early_suspend *h);
#endif
-
-#if GTP_CREATE_WR_NODE
-extern s32 init_wr_node(struct i2c_client*);
-extern void uninit_wr_node(void);
-#endif
-
-#if GTP_AUTO_UPDATE
-extern u8 gup_init_update_proc(struct goodix_ts_data *);
-#endif
#if GTP_ESD_PROTECT
static struct delayed_work gtp_esd_check_work;
-static struct workqueue_struct * gtp_esd_check_workqueue = NULL;
-static void gtp_esd_check_func(struct work_struct *);
-static s32 gtp_init_ext_watchdog(struct i2c_client *client);
-void gtp_esd_switch(struct i2c_client *, s32);
+static struct workqueue_struct *gtp_esd_check_workqueue;
+static void gtp_esd_check_func(struct work_struct *work);
+static int gtp_init_ext_watchdog(struct i2c_client *client);
+struct i2c_client *i2c_connect_client;
#endif
-
#if GTP_SLIDE_WAKEUP
-typedef enum
-{
- DOZE_DISABLED = 0,
- DOZE_ENABLED = 1,
- DOZE_WAKEUP = 2,
-}DOZE_T;
-static DOZE_T doze_status = DOZE_DISABLED;
+enum doze_status {
+ DOZE_DISABLED = 0,
+ DOZE_ENABLED = 1,
+ DOZE_WAKEUP = 2,
+};
+static enum doze_status = DOZE_DISABLED;
static s8 gtp_enter_doze(struct goodix_ts_data *ts);
#endif
-
-static u8 chip_gt9xxs = 0; // true if ic is gt9xxs, like gt915s
-u8 grp_cfg_version = 0;
+bool init_done;
+static u8 chip_gt9xxs; /* true if ic is gt9xxs, like gt915s */
+u8 grp_cfg_version;
/*******************************************************
Function:
- Read data from the i2c slave device.
+ Read data from the i2c slave device.
Input:
- client: i2c device.
- buf[0~1]: read start address.
- buf[2~len-1]: read data buffer.
- len: GTP_ADDR_LENGTH + read bytes count
+ client: i2c device.
+ buf[0~1]: read start address.
+ buf[2~len-1]: read data buffer.
+ len: GTP_ADDR_LENGTH + read bytes count
Output:
- numbers of i2c_msgs to transfer:
- 2: succeed, otherwise: failed
+ numbers of i2c_msgs to transfer:
+ 2: succeed, otherwise: failed
*********************************************************/
-s32 gtp_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
{
- struct i2c_msg msgs[2];
- s32 ret=-1;
- s32 retries = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ struct i2c_msg msgs[2];
+ int ret = -EIO;
+ int retries = 0;
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- msgs[0].flags = !I2C_M_RD;
- msgs[0].addr = client->addr;
- msgs[0].len = GTP_ADDR_LENGTH;
- msgs[0].buf = &buf[0];
- //msgs[0].scl_rate = 300 * 1000; // for Rockchip
-
- msgs[1].flags = I2C_M_RD;
- msgs[1].addr = client->addr;
- msgs[1].len = len - GTP_ADDR_LENGTH;
- msgs[1].buf = &buf[GTP_ADDR_LENGTH];
- //msgs[1].scl_rate = 300 * 1000;
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = client->addr;
+ msgs[0].len = GTP_ADDR_LENGTH;
+ msgs[0].buf = &buf[0];
- while(retries < 5)
- {
- ret = i2c_transfer(client->adapter, msgs, 2);
- if(ret == 2)break;
- retries++;
- }
- if((retries >= 5))
- {
- #if GTP_SLIDE_WAKEUP
- // reset chip would quit doze mode
- if (DOZE_ENABLED == doze_status)
- {
- return ret;
- }
- #endif
- GTP_DEBUG("I2C communication timeout, resetting chip...");
- gtp_reset_guitar(client, 10);
- }
- return ret;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = client->addr;
+ msgs[1].len = len - GTP_ADDR_LENGTH;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+
+ while (retries < 5) {
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret == 2)
+ break;
+ retries++;
+ }
+ if (retries >= 5) {
+#if GTP_SLIDE_WAKEUP
+ /* reset chip would quit doze mode */
+ if (DOZE_ENABLED == doze_status)
+ return ret;
+#endif
+ GTP_DEBUG("I2C communication timeout, resetting chip...");
+ if (init_done)
+ gtp_reset_guitar(ts, 10);
+ else
+ dev_warn(&client->dev,
+ "<GTP> gtp_reset_guitar exit init_done=%d:\n",
+ init_done);
+ }
+ return ret;
}
/*******************************************************
Function:
- Write data to the i2c slave device.
+ Write data to the i2c slave device.
Input:
- client: i2c device.
- buf[0~1]: write start address.
- buf[2~len-1]: data buffer
- len: GTP_ADDR_LENGTH + write bytes count
+ client: i2c device.
+ buf[0~1]: write start address.
+ buf[2~len-1]: data buffer
+ len: GTP_ADDR_LENGTH + write bytes count
Output:
- numbers of i2c_msgs to transfer:
- 1: succeed, otherwise: failed
+ numbers of i2c_msgs to transfer:
+ 1: succeed, otherwise: failed
*********************************************************/
-s32 gtp_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
{
- struct i2c_msg msg;
- s32 ret = -1;
- s32 retries = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ struct i2c_msg msg;
+ int ret = -EIO;
+ int retries = 0;
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- msg.flags = !I2C_M_RD;
- msg.addr = client->addr;
- msg.len = len;
- msg.buf = buf;
- //msg.scl_rate = 300 * 1000; // for Rockchip
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = len;
+ msg.buf = buf;
- while(retries < 5)
- {
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret == 1)break;
- retries++;
- }
- if((retries >= 5))
- {
- #if GTP_SLIDE_WAKEUP
- if (DOZE_ENABLED == doze_status)
- {
- return ret;
- }
- #endif
- GTP_DEBUG("I2C communication timeout, resetting chip...");
- gtp_reset_guitar(client, 10);
- }
- return ret;
+ while (retries < 5) {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)
+ break;
+ retries++;
+ }
+ if ((retries >= 5)) {
+#if GTP_SLIDE_WAKEUP
+ if (DOZE_ENABLED == doze_status)
+ return ret;
+#endif
+ GTP_DEBUG("I2C communication timeout, resetting chip...");
+ if (init_done)
+ gtp_reset_guitar(ts, 10);
+ else
+ dev_warn(&client->dev,
+ "<GTP> gtp_reset_guitar exit init_done=%d:\n",
+ init_done);
+ }
+ return ret;
}
/*******************************************************
Function:
- i2c read twice, compare the results
+ i2c read twice, compare the results
Input:
- client: i2c device
- addr: operate address
- rxbuf: read data to store, if compare successful
- len: bytes to read
+ client: i2c device
+ addr: operate address
+ rxbuf: read data to store, if compare successful
+ len: bytes to read
Output:
- FAIL: read failed
- SUCCESS: read successful
+ FAIL: read failed
+ SUCCESS: read successful
*********************************************************/
-s32 gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, u8 *rxbuf, int len)
+int gtp_i2c_read_dbl_check(struct i2c_client *client,
+ u16 addr, u8 *rxbuf, int len)
{
- u8 buf[16] = {0};
- u8 confirm_buf[16] = {0};
- u8 retry = 0;
-
- while (retry++ < 3)
- {
- memset(buf, 0xAA, 16);
- buf[0] = (u8)(addr >> 8);
- buf[1] = (u8)(addr & 0xFF);
- gtp_i2c_read(client, buf, len + 2);
-
- memset(confirm_buf, 0xAB, 16);
- confirm_buf[0] = (u8)(addr >> 8);
- confirm_buf[1] = (u8)(addr & 0xFF);
- gtp_i2c_read(client, confirm_buf, len + 2);
-
- if (!memcmp(buf, confirm_buf, len+2))
- {
- break;
- }
- }
- if (retry < 3)
- {
- memcpy(rxbuf, confirm_buf+2, len);
- return SUCCESS;
- }
- else
- {
- GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len);
- return FAIL;
- }
+ u8 buf[16] = {0};
+ u8 confirm_buf[16] = {0};
+ u8 retry = 0;
+
+ while (retry++ < 3) {
+ memset(buf, 0xAA, 16);
+ buf[0] = (u8)(addr >> 8);
+ buf[1] = (u8)(addr & 0xFF);
+ gtp_i2c_read(client, buf, len + 2);
+
+ memset(confirm_buf, 0xAB, 16);
+ confirm_buf[0] = (u8)(addr >> 8);
+ confirm_buf[1] = (u8)(addr & 0xFF);
+ gtp_i2c_read(client, confirm_buf, len + 2);
+
+ if (!memcmp(buf, confirm_buf, len + 2))
+ break;
+ }
+ if (retry < 3) {
+ memcpy(rxbuf, confirm_buf + 2, len);
+ return SUCCESS;
+ } else {
+ dev_err(&client->dev,
+ "i2c read 0x%04X, %d bytes, double check failed!",
+ addr, len);
+ return FAIL;
+ }
}
/*******************************************************
Function:
- Send config.
+ Send config data.
Input:
- client: i2c device.
+ client: i2c device.
Output:
- result of i2c write operation.
- 1: succeed, otherwise: failed
+ result of i2c write operation.
+ > 0: succeed, otherwise: failed
*********************************************************/
-s32 gtp_send_cfg(struct i2c_client *client)
+static int gtp_send_cfg(struct goodix_ts_data *ts)
{
- s32 ret = 2;
-
+ int ret;
#if GTP_DRIVER_SEND_CFG
- s32 retry = 0;
- struct goodix_ts_data *ts = i2c_get_clientdata(client);
-
- if (ts->fixed_cfg)
- {
- GTP_INFO("Ic fixed config, no config sent!");
- return 2;
- }
- GTP_INFO("driver send config");
- for (retry = 0; retry < 5; retry++)
- {
- ret = gtp_i2c_write(client, config , GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
- if (ret > 0)
- {
- break;
- }
- }
+ int retry = 0;
+
+ if (ts->fixed_cfg) {
+ dev_dbg(&ts->client->dev,
+ "Ic fixed config, no config sent!");
+ ret = 2;
+ } else {
+ for (retry = 0; retry < 5; retry++) {
+ ret = gtp_i2c_write(ts->client,
+ ts->config_data,
+ GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+ if (ret > 0)
+ break;
+ }
+ }
#endif
- return ret;
+ return ret;
}
/*******************************************************
Function:
- Disable irq function
+ Disable irq function
Input:
- ts: goodix i2c_client private data
+ ts: goodix i2c_client private data
Output:
- None.
+ None.
*********************************************************/
void gtp_irq_disable(struct goodix_ts_data *ts)
{
- unsigned long irqflags;
+ unsigned long irqflags;
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- spin_lock_irqsave(&ts->irq_lock, irqflags);
- if (!ts->irq_is_disable)
- {
- ts->irq_is_disable = 1;
- disable_irq_nosync(ts->client->irq);
- }
- spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+ spin_lock_irqsave(&ts->irq_lock, irqflags);
+ if (!ts->irq_is_disabled) {
+ ts->irq_is_disabled = true;
+ disable_irq_nosync(ts->client->irq);
+ }
+ spin_unlock_irqrestore(&ts->irq_lock, irqflags);
}
/*******************************************************
Function:
- Enable irq function
+ Enable irq function
Input:
- ts: goodix i2c_client private data
+ ts: goodix i2c_client private data
Output:
- None.
+ None.
*********************************************************/
void gtp_irq_enable(struct goodix_ts_data *ts)
{
- unsigned long irqflags = 0;
+ unsigned long irqflags = 0;
- GTP_DEBUG_FUNC();
-
- spin_lock_irqsave(&ts->irq_lock, irqflags);
- if (ts->irq_is_disable)
- {
- enable_irq(ts->client->irq);
- ts->irq_is_disable = 0;
- }
- spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+ GTP_DEBUG_FUNC();
+
+ spin_lock_irqsave(&ts->irq_lock, irqflags);
+ if (ts->irq_is_disabled) {
+ enable_irq(ts->client->irq);
+ ts->irq_is_disabled = false;
+ }
+ spin_unlock_irqrestore(&ts->irq_lock, irqflags);
}
-
/*******************************************************
Function:
- Report touch point event
+ Report touch point event
Input:
- ts: goodix i2c_client private data
- id: trackId
- x: input x coordinate
- y: input y coordinate
- w: input pressure
+ ts: goodix i2c_client private data
+ id: trackId
+ x: input x coordinate
+ y: input y coordinate
+ w: input pressure
Output:
- None.
+ None.
*********************************************************/
-static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
+static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y,
+ int w)
{
#if GTP_CHANGE_X2Y
- GTP_SWAP(x, y);
+ GTP_SWAP(x, y);
#endif
#if GTP_ICS_SLOT_REPORT
- input_mt_slot(ts->input_dev, id);
- input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
- input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
- input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+ input_mt_slot(ts->input_dev, id);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
#else
- input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
- input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
- input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
- input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
- input_mt_sync(ts->input_dev);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
+ input_mt_sync(ts->input_dev);
#endif
- GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
+ GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
}
/*******************************************************
Function:
- Report touch release event
+ Report touch release event
Input:
- ts: goodix i2c_client private data
+ ts: goodix i2c_client private data
Output:
- None.
+ None.
*********************************************************/
-static void gtp_touch_up(struct goodix_ts_data* ts, s32 id)
+static void gtp_touch_up(struct goodix_ts_data *ts, int id)
{
#if GTP_ICS_SLOT_REPORT
- input_mt_slot(ts->input_dev, id);
- input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
- GTP_DEBUG("Touch id[%2d] release!", id);
+ input_mt_slot(ts->input_dev, id);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+ GTP_DEBUG("Touch id[%2d] release!", id);
#else
- input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
- input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
- input_mt_sync(ts->input_dev);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
+ input_mt_sync(ts->input_dev);
#endif
}
+
/*******************************************************
Function:
- Goodix touchscreen work function
+ Goodix touchscreen work function
Input:
- work: work struct of goodix_workqueue
+ work: work struct of goodix_workqueue
Output:
- None.
+ None.
*********************************************************/
static void goodix_ts_work_func(struct work_struct *work)
{
- u8 end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
- u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
- u8 touch_num = 0;
- u8 finger = 0;
- static u16 pre_touch = 0;
- static u8 pre_key = 0;
+ u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8,
+ GTP_READ_COOR_ADDR & 0xFF, 0};
+ u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = {
+ GTP_READ_COOR_ADDR >> 8,
+ GTP_READ_COOR_ADDR & 0xFF};
+ u8 touch_num = 0;
+ u8 finger = 0;
+ static u16 pre_touch;
+ static u8 pre_key;
#if GTP_WITH_PEN
- static u8 pre_pen = 0;
+ static u8 pre_pen;
#endif
- u8 key_value = 0;
- u8* coor_data = NULL;
- s32 input_x = 0;
- s32 input_y = 0;
- s32 input_w = 0;
- s32 id = 0;
- s32 i = 0;
- s32 ret = -1;
- struct goodix_ts_data *ts = NULL;
+ u8 key_value = 0;
+ u8 *coor_data = NULL;
+ s32 input_x = 0;
+ s32 input_y = 0;
+ s32 input_w = 0;
+ s32 id = 0;
+ s32 i = 0;
+ int ret = -1;
+ struct goodix_ts_data *ts = NULL;
#if GTP_SLIDE_WAKEUP
- u8 doze_buf[3] = {0x81, 0x4B};
+ u8 doze_buf[3] = {0x81, 0x4B};
#endif
- GTP_DEBUG_FUNC();
- ts = container_of(work, struct goodix_ts_data, work);
- if (ts->enter_update)
- {
- return;
- }
+ GTP_DEBUG_FUNC();
+
+ ts = container_of(work, struct goodix_ts_data, work);
+#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
+ if (ts->enter_update)
+ return;
+#endif
+
#if GTP_SLIDE_WAKEUP
- if (DOZE_ENABLED == doze_status)
- {
- ret = gtp_i2c_read(i2c_connect_client, doze_buf, 3);
- GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
- if (ret > 0)
- {
- if (doze_buf[2] == 0xAA)
- {
- GTP_INFO("Slide(0xAA) To Light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- // clear 0x814B
- doze_buf[2] = 0x00;
- gtp_i2c_write(i2c_connect_client, doze_buf, 3);
- }
- else if (doze_buf[2] == 0xBB)
- {
- GTP_INFO("Slide(0xBB) To Light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- // clear 0x814B
- doze_buf[2] = 0x00;
- gtp_i2c_write(i2c_connect_client, doze_buf, 3);
- }
- else if (0xC0 == (doze_buf[2] & 0xC0))
- {
- GTP_INFO("double click to light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- // clear 0x814B
- doze_buf[2] = 0x00;
- gtp_i2c_write(i2c_connect_client, doze_buf, 3);
- }
- else
- {
- gtp_enter_doze(ts);
- }
- }
- if (ts->use_irq)
- {
- gtp_irq_enable(ts);
- }
- return;
- }
+ if (DOZE_ENABLED == doze_status) {
+ ret = gtp_i2c_read(ts->client, doze_buf, 3);
+ GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
+ if (ret > 0) {
+ if (doze_buf[2] == 0xAA) {
+ dev_dbg(&ts->client->dev,
+ "Slide(0xAA) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(
+ ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(
+ ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else if (doze_buf[2] == 0xBB) {
+ dev_dbg(&ts->client->dev,
+ "Slide(0xBB) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B*/
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else if (0xC0 == (doze_buf[2] & 0xC0)) {
+ dev_dbg(&ts->client->dev,
+ "double click to light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else {
+ gtp_enter_doze(ts);
+ }
+ }
+ if (ts->use_irq)
+ gtp_irq_enable(ts);
+
+ return;
+ }
#endif
- ret = gtp_i2c_read(ts->client, point_data, 12);
- if (ret < 0)
- {
- GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
- goto exit_work_func;
- }
+ ret = gtp_i2c_read(ts->client, point_data, 12);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "I2C transfer error. errno:%d\n ", ret);
+ goto exit_work_func;
+ }
- finger = point_data[GTP_ADDR_LENGTH];
- if((finger & 0x80) == 0)
- {
- goto exit_work_func;
- }
+ finger = point_data[GTP_ADDR_LENGTH];
+ if ((finger & 0x80) == 0)
+ goto exit_work_func;
- touch_num = finger & 0x0f;
- if (touch_num > GTP_MAX_TOUCH)
- {
- goto exit_work_func;
- }
+ touch_num = finger & 0x0f;
+ if (touch_num > GTP_MAX_TOUCH)
+ goto exit_work_func;
- if (touch_num > 1)
- {
- u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff};
+ if (touch_num > 1) {
+ u8 buf[8 * GTP_MAX_TOUCH] = { (GTP_READ_COOR_ADDR + 10) >> 8,
+ (GTP_READ_COOR_ADDR + 10) & 0xff };
- ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1));
- memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
- }
+ ret = gtp_i2c_read(ts->client, buf,
+ 2 + 8 * (touch_num - 1));
+ memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
+ }
#if GTP_HAVE_TOUCH_KEY
- key_value = point_data[3 + 8 * touch_num];
-
- if(key_value || pre_key)
- {
- for (i = 0; i < GTP_MAX_KEY_NUM; i++)
- {
- #if GTP_DEBUG_ON
- for (ret = 0; ret < 4; ++ret)
- {
- if (key_codes[ret] == touch_key_array[i])
- {
- GTP_DEBUG("Key: %s %s", key_names[ret], (key_value & (0x01 << i)) ? "Down" : "Up");
- break;
- }
- }
- #endif
- input_report_key(ts->input_dev, touch_key_array[i], key_value & (0x01<<i));
- }
- touch_num = 0;
- pre_touch = 0;
- }
-#endif
- pre_key = key_value;
+ key_value = point_data[3 + 8 * touch_num];
- GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
+ if (key_value || pre_key) {
+ for (i = 0; i < GTP_MAX_KEY_NUM; i++) {
+#if GTP_DEBUG_ON
+ for (ret = 0; ret < 4; ++ret) {
+ if (key_codes[ret] == touch_key_array[i]) {
+ GTP_DEBUG("Key: %s %s",
+ key_names[ret],
+ (key_value & (0x01 << i))
+ ? "Down" : "Up");
+ break;
+ }
+ }
+#endif
+
+ input_report_key(ts->input_dev,
+ touch_key_array[i], key_value & (0x01<<i));
+ }
+ touch_num = 0;
+ pre_touch = 0;
+ }
+#endif
+ pre_key = key_value;
+
+ GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
#if GTP_ICS_SLOT_REPORT
-
#if GTP_WITH_PEN
- if (pre_pen && (touch_num == 0))
- {
- GTP_DEBUG("Pen touch UP(Slot)!");
- input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
- input_mt_slot(ts->input_dev, 5);
- input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
- pre_pen = 0;
- }
+ if (pre_pen && (touch_num == 0)) {
+ GTP_DEBUG("Pen touch UP(Slot)!");
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+ pre_pen = 0;
+ }
#endif
- if (pre_touch || touch_num)
- {
- s32 pos = 0;
- u16 touch_index = 0;
+ if (pre_touch || touch_num) {
+ s32 pos = 0;
+ u16 touch_index = 0;
- coor_data = &point_data[3];
-
- if(touch_num)
- {
- id = coor_data[pos] & 0x0F;
-
- #if GTP_WITH_PEN
- id = coor_data[pos];
- if ((id == 128))
- {
- GTP_DEBUG("Pen touch DOWN(Slot)!");
- input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
- input_y = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
- input_w = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
-
- input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
- input_mt_slot(ts->input_dev, 5);
- input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 5);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
- input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
- GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]", input_x, input_y, input_w);
- pre_pen = 1;
- pre_touch = 0;
- }
- #endif
-
- touch_index |= (0x01<<id);
- }
-
- GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",id, touch_index,pre_touch);
- for (i = 0; i < GTP_MAX_TOUCH; i++)
- {
- #if GTP_WITH_PEN
- if (pre_pen == 1)
- {
- break;
- }
- #endif
-
- if (touch_index & (0x01<<i))
- {
- input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
- input_y = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
- input_w = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
+ coor_data = &point_data[3];
+ if (touch_num) {
+ id = coor_data[pos] & 0x0F;
+#if GTP_WITH_PEN
+ id = coor_data[pos];
+ if (id == 128) {
+ GTP_DEBUG("Pen touch DOWN(Slot)!");
+ input_x = coor_data[pos + 1]
+ | (coor_data[pos + 2] << 8);
+ input_y = coor_data[pos + 3]
+ | (coor_data[pos + 4] << 8);
+ input_w = coor_data[pos + 5]
+ | (coor_data[pos + 6] << 8);
- gtp_touch_down(ts, id, input_x, input_y, input_w);
- pre_touch |= 0x01 << i;
-
- pos += 8;
- id = coor_data[pos] & 0x0F;
- touch_index |= (0x01<<id);
- }
- else
- {
- gtp_touch_up(ts, i);
- pre_touch &= ~(0x01 << i);
- }
- }
- }
+ input_report_key(ts->input_dev,
+ BTN_TOOL_PEN, 1);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev,
+ ABS_MT_TRACKING_ID, 5);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_X, input_x);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_Y, input_y);
+ input_report_abs(ts->input_dev,
+ ABS_MT_TOUCH_MAJOR, input_w);
+ GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]",
+ input_x, input_y, input_w);
+ pre_pen = 1;
+ pre_touch = 0;
+ }
+#endif
+
+ touch_index |= (0x01<<id);
+ }
+
+ GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",
+ id, touch_index, pre_touch);
+ for (i = 0; i < GTP_MAX_TOUCH; i++) {
+#if GTP_WITH_PEN
+ if (pre_pen == 1)
+ break;
+#endif
+ if (touch_index & (0x01<<i)) {
+ input_x = coor_data[pos + 1] |
+ coor_data[pos + 2] << 8;
+ input_y = coor_data[pos + 3] |
+ coor_data[pos + 4] << 8;
+ input_w = coor_data[pos + 5] |
+ coor_data[pos + 6] << 8;
+
+ gtp_touch_down(ts, id,
+ input_x, input_y, input_w);
+ pre_touch |= 0x01 << i;
+
+ pos += 8;
+ id = coor_data[pos] & 0x0F;
+ touch_index |= (0x01<<id);
+ } else {
+ gtp_touch_up(ts, i);
+ pre_touch &= ~(0x01 << i);
+ }
+ }
+ }
#else
- input_report_key(ts->input_dev, BTN_TOUCH, (touch_num || key_value));
- if (touch_num)
- {
- for (i = 0; i < touch_num; i++)
- {
- coor_data = &point_data[i * 8 + 3];
+ input_report_key(ts->input_dev, BTN_TOUCH, (touch_num || key_value));
+ if (touch_num) {
+ for (i = 0; i < touch_num; i++) {
+ coor_data = &point_data[i * 8 + 3];
- id = coor_data[0]; // & 0x0F;
- input_x = coor_data[1] | (coor_data[2] << 8);
- input_y = coor_data[3] | (coor_data[4] << 8);
- input_w = coor_data[5] | (coor_data[6] << 8);
-
- #if GTP_WITH_PEN
- if (id == 128)
- {
- GTP_DEBUG("Pen touch DOWN!");
- input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
- pre_pen = 1;
- id = 0;
- }
- #endif
-
- gtp_touch_down(ts, id, input_x, input_y, input_w);
- }
- }
- else if (pre_touch)
- {
-
- #if GTP_WITH_PEN
- if (pre_pen == 1)
- {
- GTP_DEBUG("Pen touch UP!");
- input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
- pre_pen = 0;
- }
- #endif
-
- GTP_DEBUG("Touch Release!");
- gtp_touch_up(ts, 0);
- }
+ id = coor_data[0];
+ input_x = coor_data[1] | coor_data[2] << 8;
+ input_y = coor_data[3] | coor_data[4] << 8;
+ input_w = coor_data[5] | coor_data[6] << 8;
+#if GTP_WITH_PEN
+ if (id == 128) {
+ GTP_DEBUG("Pen touch DOWN!");
+ input_report_key(ts->input_dev,
+ BTN_TOOL_PEN, 1);
+ pre_pen = 1;
+ id = 0;
+ }
+#endif
+ gtp_touch_down(ts, id, input_x, input_y, input_w);
+ }
+ } else if (pre_touch) {
+#if GTP_WITH_PEN
+ if (pre_pen == 1) {
+ GTP_DEBUG("Pen touch UP!");
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+ pre_pen = 0;
+ }
+#endif
+ GTP_DEBUG("Touch Released!");
+ gtp_touch_up(ts, 0);
+ }
- pre_touch = touch_num;
+ pre_touch = touch_num;
#endif
- input_sync(ts->input_dev);
+ input_sync(ts->input_dev);
exit_work_func:
- if(!ts->gtp_rawdiff_mode)
- {
- ret = gtp_i2c_write(ts->client, end_cmd, 3);
- if (ret < 0)
- {
- GTP_INFO("I2C write end_cmd error!");
- }
- }
- if (ts->use_irq)
- {
- gtp_irq_enable(ts);
- }
+ if (!ts->gtp_rawdiff_mode) {
+ ret = gtp_i2c_write(ts->client, end_cmd, 3);
+ if (ret < 0)
+ dev_warn(&ts->client->dev, "I2C write end_cmd error!\n");
+
+ }
+ if (ts->use_irq)
+ gtp_irq_enable(ts);
+
+ return;
}
/*******************************************************
Function:
- Timer interrupt service routine for polling mode.
+ Timer interrupt service routine for polling mode.
Input:
- timer: timer struct pointer
+ timer: timer struct pointer
Output:
- Timer work mode.
- HRTIMER_NORESTART: no restart mode
+ Timer work mode.
+ HRTIMER_NORESTART: no restart mode
*********************************************************/
static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
{
- struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer);
+ struct goodix_ts_data
+ *ts = container_of(timer, struct goodix_ts_data, timer);
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- queue_work(goodix_wq, &ts->work);
- hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME+6)*1000000), HRTIMER_MODE_REL);
- return HRTIMER_NORESTART;
+ queue_work(ts->goodix_wq, &ts->work);
+ hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
+ HRTIMER_MODE_REL);
+ return HRTIMER_NORESTART;
}
/*******************************************************
Function:
- External interrupt service routine for interrupt mode.
+ External interrupt service routine for interrupt mode.
Input:
- irq: interrupt number.
- dev_id: private data pointer
+ irq: interrupt number.
+ dev_id: private data pointer
Output:
- Handle Result.
- IRQ_HANDLED: interrupt handled successfully
+ Handle Result.
+ IRQ_HANDLED: interrupt handled successfully
*********************************************************/
static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
- struct goodix_ts_data *ts = dev_id;
+ struct goodix_ts_data *ts = dev_id;
- GTP_DEBUG_FUNC();
-
- gtp_irq_disable(ts);
+ GTP_DEBUG_FUNC();
- queue_work(goodix_wq, &ts->work);
-
- return IRQ_HANDLED;
+ gtp_irq_disable(ts);
+
+ queue_work(ts->goodix_wq, &ts->work);
+
+ return IRQ_HANDLED;
}
/*******************************************************
Function:
- Synchronization.
+ Synchronization.
Input:
- ms: synchronization time in millisecond.
+ ms: synchronization time in millisecond.
Output:
- None.
+ None.
*******************************************************/
-void gtp_int_sync(s32 ms)
+void gtp_int_sync(struct goodix_ts_data *ts, int ms)
{
- GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
- msleep(ms);
- GTP_GPIO_AS_INT(GTP_INT_PORT);
+ gpio_direction_output(ts->pdata->irq_gpio, 0);
+ msleep(ms);
+ gpio_direction_input(ts->pdata->irq_gpio);
}
/*******************************************************
Function:
- Reset chip.
+ Reset chip.
Input:
- ms: reset time in millisecond
+ ms: reset time in millisecond, must >10ms
Output:
- None.
+ None.
*******************************************************/
-void gtp_reset_guitar(struct i2c_client *client, s32 ms)
+static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
{
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- GTP_GPIO_OUTPUT(GTP_RST_PORT, 0); // begin select I2C slave addr
- msleep(ms); // T2: > 10ms
- // HIGH: 0x28/0x29, LOW: 0xBA/0xBB
- GTP_GPIO_OUTPUT(GTP_INT_PORT, client->addr == 0x14);
+ /* This reset sequence will selcet I2C slave address */
+ gpio_direction_output(ts->pdata->reset_gpio, 0);
+ msleep(ms);
- msleep(2); // T3: > 100us
- GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
-
- msleep(6); // T4: > 5ms
+ if (ts->client->addr == GTP_I2C_ADDRESS_HIGH)
+ gpio_direction_output(ts->pdata->irq_gpio, 1);
+ else
+ gpio_direction_output(ts->pdata->irq_gpio, 0);
- GTP_GPIO_AS_INPUT(GTP_RST_PORT); // end select I2C slave addr
+ usleep(RESET_DELAY_T3_US);
+ gpio_direction_output(ts->pdata->reset_gpio, 1);
+ msleep(RESET_DELAY_T4);
- gtp_int_sync(50);
-
+ gpio_direction_input(ts->pdata->reset_gpio);
+
+ gtp_int_sync(ts, 50);
+
#if GTP_ESD_PROTECT
- gtp_init_ext_watchdog(client);
+ gtp_init_ext_watchdog(ts->client);
#endif
}
+#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
#if GTP_SLIDE_WAKEUP
/*******************************************************
Function:
- Enter doze mode for sliding wakeup.
+ Enter doze mode for sliding wakeup.
Input:
- ts: goodix tp private data
+ ts: goodix tp private data
Output:
- 1: succeed, otherwise failed
+ 1: succeed, otherwise failed
*******************************************************/
static s8 gtp_enter_doze(struct goodix_ts_data *ts)
{
- s8 ret = -1;
- s8 retry = 0;
- u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8};
+ int ret = -1;
+ s8 retry = 0;
+ u8 i2c_control_buf[3] = {
+ (u8)(GTP_REG_SLEEP >> 8),
+ (u8)GTP_REG_SLEEP, 8};
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
#if GTP_DBL_CLK_WAKEUP
- i2c_control_buf[2] = 0x09;
+ i2c_control_buf[2] = 0x09;
#endif
+ gtp_irq_disable(ts);
- gtp_irq_disable(ts);
-
- GTP_DEBUG("entering doze mode...");
- while(retry++ < 5)
- {
- i2c_control_buf[0] = 0x80;
- i2c_control_buf[1] = 0x46;
- ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
- if (ret < 0)
- {
- GTP_DEBUG("failed to set doze flag into 0x8046, %d", retry);
- continue;
- }
- i2c_control_buf[0] = 0x80;
- i2c_control_buf[1] = 0x40;
- ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
- if (ret > 0)
- {
- doze_status = DOZE_ENABLED;
- GTP_INFO("GTP has been working in doze mode!");
- gtp_irq_enable(ts);
- return ret;
- }
- msleep(10);
- }
- GTP_ERROR("GTP send doze cmd failed.");
- gtp_irq_enable(ts);
- return ret;
+ GTP_DEBUG("entering doze mode...");
+ while (retry++ < 5) {
+ i2c_control_buf[0] = 0x80;
+ i2c_control_buf[1] = 0x46;
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret < 0) {
+ GTP_DEBUG(
+ "failed to set doze flag into 0x8046, %d",
+ retry);
+ continue;
+ }
+ i2c_control_buf[0] = 0x80;
+ i2c_control_buf[1] = 0x40;
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret > 0) {
+ doze_status = DOZE_ENABLED;
+ dev_dbg(&ts->client->dev,
+ "GTP has been working in doze mode!");
+ gtp_irq_enable(ts);
+ return ret;
+ }
+ msleep(20);
+ }
+ dev_err(&ts->client->dev, "GTP send doze cmd failed.\n");
+ gtp_irq_enable(ts);
+ return ret;
}
-#else
-/*******************************************************
-Function:
- Enter sleep mode.
-Input:
- ts: private data.
-Output:
- Executive outcomes.
- 1: succeed, otherwise failed.
-*******************************************************/
-static s8 gtp_enter_sleep(struct goodix_ts_data * ts)
-{
- s8 ret = -1;
- s8 retry = 0;
- u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5};
-
- GTP_DEBUG_FUNC();
-
- GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
- msleep(5);
-
- while(retry++ < 5)
- {
- ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
- if (ret > 0)
- {
- GTP_INFO("GTP enter sleep!");
-
- return ret;
- }
- msleep(10);
- }
- GTP_ERROR("GTP send sleep cmd failed.");
- return ret;
-}
-#endif
-/*******************************************************
-Function:
- Wakeup from sleep.
-Input:
- ts: private data.
-Output:
- Executive outcomes.
- >0: succeed, otherwise: failed.
-*******************************************************/
-static s8 gtp_wakeup_sleep(struct goodix_ts_data * ts)
-{
- u8 retry = 0;
- s8 ret = -1;
-
- GTP_DEBUG_FUNC();
-
-#if GTP_POWER_CTRL_SLEEP
- while(retry++ < 5)
- {
- gtp_reset_guitar(ts->client, 20);
-
- ret = gtp_send_cfg(ts->client);
- if (ret < 0)
- {
- GTP_INFO("Wakeup sleep send config failed!");
- continue;
- }
- GTP_INFO("GTP wakeup sleep");
- return 1;
- }
#else
- while(retry++ < 10)
- {
- #if GTP_SLIDE_WAKEUP
- if (DOZE_WAKEUP != doze_status) // wakeup not by slide
- {
- gtp_reset_guitar(ts->client, 10);
- }
- else // wakeup by slide
- {
- doze_status = DOZE_DISABLED;
- }
- #else
- if (chip_gt9xxs == 1)
- {
- gtp_reset_guitar(ts->client, 10);
- }
- else
- {
- GTP_GPIO_OUTPUT(GTP_INT_PORT, 1);
- msleep(5);
- }
- #endif
- ret = gtp_i2c_test(ts->client);
- if (ret > 0)
- {
- GTP_INFO("GTP wakeup sleep.");
-
- #if (!GTP_SLIDE_WAKEUP)
- if (chip_gt9xxs == 0)
- {
- gtp_int_sync(25);
- msleep(20);
- #if GTP_ESD_PROTECT
- gtp_init_ext_watchdog(ts->client);
- #endif
- }
- #endif
- return ret;
- }
- gtp_reset_guitar(ts->client, 20);
- }
-#endif
+/*******************************************************
+Function:
+ Enter sleep mode.
+Input:
+ ts: private data.
+Output:
+ Executive outcomes.
+ 1: succeed, otherwise failed.
+*******************************************************/
+static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
+{
+ int ret = -1;
+ s8 retry = 0;
+ u8 i2c_control_buf[3] = {
+ (u8)(GTP_REG_SLEEP >> 8),
+ (u8)GTP_REG_SLEEP, 5};
- GTP_ERROR("GTP wakeup sleep failed.");
- return ret;
+ GTP_DEBUG_FUNC();
+
+ ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
+ usleep(5000);
+ while (retry++ < 5) {
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret > 0) {
+ dev_dbg(&ts->client->dev,
+ "GTP enter sleep!");
+ return ret;
+ }
+ msleep(20);
+ }
+ dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
+ return ret;
}
+#endif
/*******************************************************
Function:
- Initialize gtp.
+ Wakeup from sleep.
Input:
- ts: goodix private data
+ ts: private data.
Output:
- Executive outcomes.
- 0: succeed, otherwise: failed
+ Executive outcomes.
+ >0: succeed, otherwise: failed.
*******************************************************/
-static s32 gtp_init_panel(struct goodix_ts_data *ts)
+static s8 gtp_wakeup_sleep(struct goodix_ts_data *ts)
{
- s32 ret = -1;
+ u8 retry = 0;
+ s8 ret = -1;
+
+ GTP_DEBUG_FUNC();
+
+#if GTP_POWER_CTRL_SLEEP
+ gtp_reset_guitar(ts, 20);
+
+ ret = gtp_send_cfg(ts);
+ if (ret > 0) {
+ dev_dbg(&ts->client->dev,
+ "Wakeup sleep send config success.");
+ return 1;
+ }
+#else
+ while (retry++ < 10) {
+#if GTP_SLIDE_WAKEUP
+ /* wakeup not by slide */
+ if (DOZE_WAKEUP != doze_status)
+ gtp_reset_guitar(ts, 10);
+ else
+ /* wakeup by slide */
+ doze_status = DOZE_DISABLED;
+#else
+ if (chip_gt9xxs == 1) {
+ gtp_reset_guitar(ts, 10);
+ } else {
+ ret = gpio_direction_output(ts->pdata->irq_gpio, 1);
+ usleep(5000);
+ }
+#endif
+ ret = gtp_i2c_test(ts->client);
+ if (ret > 0) {
+ dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
+#if (!GTP_SLIDE_WAKEUP)
+ if (chip_gt9xxs == 0) {
+ gtp_int_sync(ts, 25);
+ msleep(20);
+#if GTP_ESD_PROTECT
+ gtp_init_ext_watchdog(ts->client);
+#endif
+ }
+#endif
+ return ret;
+ }
+ gtp_reset_guitar(ts, 20);
+ }
+#endif
+
+ dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
+ return ret;
+}
+#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
+
+/*******************************************************
+Function:
+ Initialize gtp.
+Input:
+ ts: goodix private data
+Output:
+ Executive outcomes.
+ > =0: succeed, otherwise: failed
+*******************************************************/
+static int gtp_init_panel(struct goodix_ts_data *ts)
+{
+ struct i2c_client *client = ts->client;
+ unsigned char *config_data;
+ int ret = -EIO;
#if GTP_DRIVER_SEND_CFG
- s32 i;
- u8 check_sum = 0;
- u8 opr_buf[16];
- u8 sensor_id = 0;
+ int i;
+ u8 check_sum = 0;
+ u8 opr_buf[16];
+ u8 sensor_id = 0;
- u8 cfg_info_group1[] = CTP_CFG_GROUP1;
- u8 cfg_info_group2[] = CTP_CFG_GROUP2;
- u8 cfg_info_group3[] = CTP_CFG_GROUP3;
- u8 cfg_info_group4[] = CTP_CFG_GROUP4;
- u8 cfg_info_group5[] = CTP_CFG_GROUP5;
- u8 cfg_info_group6[] = CTP_CFG_GROUP6;
- u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
- cfg_info_group4, cfg_info_group5, cfg_info_group6};
- u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
- CFG_GROUP_LEN(cfg_info_group2),
- CFG_GROUP_LEN(cfg_info_group3),
- CFG_GROUP_LEN(cfg_info_group4),
- CFG_GROUP_LEN(cfg_info_group5),
- CFG_GROUP_LEN(cfg_info_group6)};
+ u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+ u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+ u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+ u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+ u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+ u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+ u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2,
+ cfg_info_group3, cfg_info_group4,
+ cfg_info_group5, cfg_info_group6};
- GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
- cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], cfg_info_len[3],
- cfg_info_len[4], cfg_info_len[5]);
+ u8 cfg_info_len[] = {CFG_GROUP_LEN(cfg_info_group1),
+ CFG_GROUP_LEN(cfg_info_group2),
+ CFG_GROUP_LEN(cfg_info_group3),
+ CFG_GROUP_LEN(cfg_info_group4),
+ CFG_GROUP_LEN(cfg_info_group5),
+ CFG_GROUP_LEN(cfg_info_group6)};
- ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
- if (SUCCESS == ret)
- {
- if (opr_buf[0] != 0xBE)
- {
- ts->fw_error = 1;
- GTP_ERROR("Firmware error, no config sent!");
- return -1;
- }
- }
+ GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
+ cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
+ cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
- if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
- (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
- (!cfg_info_len[5]))
- {
- sensor_id = 0;
- }
- else
- {
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
- if (SUCCESS == ret)
- {
- if (sensor_id >= 0x06)
- {
- GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
- return -1;
- }
- }
- else
- {
- GTP_ERROR("Failed to get sensor_id, No config sent!");
- return -1;
- }
- }
- GTP_DEBUG("Sensor_ID: %d", sensor_id);
-
- ts->gtp_cfg_len = cfg_info_len[sensor_id];
-
- if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
- {
- GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
- return -1;
- }
-
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
-
- if (ret == SUCCESS)
- {
- GTP_DEBUG("CFG_GROUP%d Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X", sensor_id+1,
- send_cfg_buf[sensor_id][0], send_cfg_buf[sensor_id][0], opr_buf[0], opr_buf[0]);
-
- if (opr_buf[0] < 90)
- {
- grp_cfg_version = send_cfg_buf[sensor_id][0]; // backup group config version
- send_cfg_buf[sensor_id][0] = 0x00;
- ts->fixed_cfg = 0;
- }
- else // treated as fixed config, not send config
- {
- GTP_INFO("Ic fixed config with config version(%d, 0x%02X)", opr_buf[0], opr_buf[0]);
- ts->fixed_cfg = 1;
- }
- }
- else
- {
- GTP_ERROR("Failed to get ic config version!No config sent!");
- return -1;
- }
-
- memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
- memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+ ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+ if (SUCCESS == ret) {
+ if (opr_buf[0] != 0xBE) {
+ ts->fw_error = 1;
+ dev_err(&client->dev,
+ "Firmware error, no config sent!");
+ return -EINVAL;
+ }
+ }
+ if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && (!cfg_info_len[3])
+ && (!cfg_info_len[4]) && (!cfg_info_len[5])) {
+ sensor_id = 0;
+ } else {
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+ &sensor_id, 1);
+ if (SUCCESS == ret) {
+ if (sensor_id >= 0x06) {
+ dev_err(&client->dev,
+ "Invalid sensor_id(0x%02X), No Config Sent!",
+ sensor_id);
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&client->dev,
+ "Failed to get sensor_id, No config sent!");
+ return -EINVAL;
+ }
+ }
+ GTP_DEBUG("Sensor_ID: %d", sensor_id);
+
+ ts->gtp_cfg_len = cfg_info_len[sensor_id];
+
+ if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+ dev_err(&client->dev,
+ "Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!\n",
+ sensor_id);
+ return -EINVAL;
+ }
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+ &opr_buf[0], 1);
+
+ if (ret == SUCCESS) {
+ if (opr_buf[0] < 90) {
+ /* backup group config version */
+ grp_cfg_version = send_cfg_buf[sensor_id][0];
+ send_cfg_buf[sensor_id][0] = 0x00;
+ ts->fixed_cfg = 0;
+ } else {
+ /* treated as fixed config, not send config */
+ dev_warn(&client->dev,
+ "Ic fixed config with config version(%d, 0x%02X)",
+ opr_buf[0], opr_buf[0]);
+ ts->fixed_cfg = 1;
+ }
+ } else {
+ dev_err(&client->dev,
+ "Failed to get ic config version!No config sent!");
+ return -EINVAL;
+ }
+
+ if (ts->pdata->gtp_cfg_len) {
+ config_data = ts->pdata->config_data;
+ ts->config_data = ts->pdata->config_data;
+ ts->gtp_cfg_len = ts->pdata->gtp_cfg_len;
+ } else {
+ config_data = devm_kzalloc(&client->dev,
+ GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+ GFP_KERNEL);
+ if (!config_data) {
+ dev_err(&client->dev,
+ "Not enough memory for panel config data\n");
+ return -ENOMEM;
+ }
+
+ ts->config_data = config_data;
+ config_data[0] = GTP_REG_CONFIG_DATA >> 8;
+ config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
+ memset(&config_data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+ memcpy(&config_data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+ ts->gtp_cfg_len);
+ }
#if GTP_CUSTOM_CFG
- config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH;
- config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
- config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
- config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
-
- if (GTP_INT_TRIGGER == 0) //RISING
- {
- config[TRIGGER_LOC] &= 0xfe;
- }
- else if (GTP_INT_TRIGGER == 1) //FALLING
- {
- config[TRIGGER_LOC] |= 0x01;
- }
-#endif // GTP_CUSTOM_CFG
-
- check_sum = 0;
- for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
- {
- check_sum += config[i];
- }
- config[ts->gtp_cfg_len] = (~check_sum) + 1;
-
-#else // DRIVER NOT SEND CONFIG
- ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
- ret = gtp_i2c_read(ts->client, config, ts->gtp_cfg_len + GTP_ADDR_LENGTH);
- if (ret < 0)
- {
- GTP_ERROR("Read Config Failed, Using Default Resolution & INT Trigger!");
- ts->abs_x_max = GTP_MAX_WIDTH;
- ts->abs_y_max = GTP_MAX_HEIGHT;
- ts->int_trigger_type = GTP_INT_TRIGGER;
- }
-#endif // GTP_DRIVER_SEND_CFG
+ config_data[RESOLUTION_LOC] =
+ (unsigned char)(GTP_MAX_WIDTH && 0xFF);
+ config_data[RESOLUTION_LOC + 1] =
+ (unsigned char)(GTP_MAX_WIDTH >> 8);
+ config_data[RESOLUTION_LOC + 2] =
+ (unsigned char)(GTP_MAX_HEIGHT && 0xFF);
+ config_data[RESOLUTION_LOC + 3] =
+ (unsigned char)(GTP_MAX_HEIGHT >> 8);
- GTP_DEBUG_FUNC();
- if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0))
- {
- ts->abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC];
- ts->abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2];
- ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03;
- }
- ret = gtp_send_cfg(ts->client);
- if (ret < 0)
- {
- GTP_ERROR("Send config error.");
- }
- GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
- ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type);
+ if (GTP_INT_TRIGGER == 0)
+ config_data[TRIGGER_LOC] &= 0xfe;
+ else if (GTP_INT_TRIGGER == 1)
+ config_data[TRIGGER_LOC] |= 0x01;
+#endif /* !GTP_CUSTOM_CFG */
- msleep(10);
- return 0;
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+ check_sum += config_data[i];
+
+ config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+#else /* DRIVER NOT SEND CONFIG */
+ ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+ ret = gtp_i2c_read(ts->client, config_data,
+ ts->gtp_cfg_len + GTP_ADDR_LENGTH);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n");
+ ts->abs_x_max = GTP_MAX_WIDTH;
+ ts->abs_y_max = GTP_MAX_HEIGHT;
+ ts->int_trigger_type = GTP_INT_TRIGGER;
+ }
+#endif /* !DRIVER NOT SEND CONFIG */
+
+ GTP_DEBUG_FUNC();
+ if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
+ ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
+ + config_data[RESOLUTION_LOC];
+ ts->abs_y_max = (config_data[RESOLUTION_LOC + 3] << 8)
+ + config_data[RESOLUTION_LOC + 2];
+ ts->int_trigger_type = (config_data[TRIGGER_LOC]) & 0x03;
+ }
+ ret = gtp_send_cfg(ts);
+ if (ret < 0)
+ dev_err(&client->dev, "%s: Send config error.\n", __func__);
+
+ GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+ ts->abs_x_max, ts->abs_y_max,
+ ts->int_trigger_type);
+
+ msleep(20);
+ return ret;
}
/*******************************************************
Function:
- Read chip version.
+ Read chip version.
Input:
- client: i2c device
- version: buffer to keep ic firmware version
+ client: i2c device
+ version: buffer to keep ic firmware version
Output:
- read operation return.
- 2: succeed, otherwise: failed
+ read operation return.
+ 2: succeed, otherwise: failed
*******************************************************/
-s32 gtp_read_version(struct i2c_client *client, u16* version)
+int gtp_read_version(struct i2c_client *client, u16 *version)
{
- s32 ret = -1;
- u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+ int ret = -EIO;
+ u8 buf[8] = { GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff };
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- ret = gtp_i2c_read(client, buf, sizeof(buf));
- if (ret < 0)
- {
- GTP_ERROR("GTP read version failed");
- return ret;
- }
+ ret = gtp_i2c_read(client, buf, sizeof(buf));
+ if (ret < 0) {
+ dev_err(&client->dev, "GTP read version failed.\n");
+ return ret;
+ }
- if (version)
- {
- *version = (buf[7] << 8) | buf[6];
- }
-
- if (buf[5] == 0x00)
- {
- GTP_INFO("IC Version: %c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[7], buf[6]);
- }
- else
- {
- if (buf[5] == 'S' || buf[5] == 's')
- {
- chip_gt9xxs = 1;
- }
- GTP_INFO("IC Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
- }
- return ret;
+ if (version)
+ *version = (buf[7] << 8) | buf[6];
+
+ if (buf[5] == 0x00) {
+ dev_dbg(&client->dev, "IC Version: %c%c%c_%02x%02x\n", buf[2],
+ buf[3], buf[4], buf[7], buf[6]);
+ } else {
+ if (buf[5] == 'S' || buf[5] == 's')
+ chip_gt9xxs = 1;
+ dev_dbg(&client->dev, "IC Version: %c%c%c%c_%02x%02x\n", buf[2],
+ buf[3], buf[4], buf[5], buf[7], buf[6]);
+ }
+ return ret;
}
/*******************************************************
Function:
- I2c test Function.
+ I2c test Function.
Input:
- client:i2c client.
+ client:i2c client.
Output:
- Executive outcomes.
- 2: succeed, otherwise failed.
+ Executive outcomes.
+ 2: succeed, otherwise failed.
*******************************************************/
-static s8 gtp_i2c_test(struct i2c_client *client)
+static int gtp_i2c_test(struct i2c_client *client)
{
- u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
- u8 retry = 0;
- s8 ret = -1;
-
- GTP_DEBUG_FUNC();
-
- while(retry++ < 5)
- {
- ret = gtp_i2c_read(client, test, 3);
- if (ret > 0)
- {
- return ret;
- }
- GTP_ERROR("GTP i2c test failed time %d.",retry);
- msleep(10);
- }
- return ret;
+ u8 buf[3] = { GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff };
+ int retry = 5;
+ int ret = -EIO;
+
+ GTP_DEBUG_FUNC();
+
+ while (retry--) {
+ ret = gtp_i2c_read(client, buf, 3);
+ if (ret > 0)
+ return ret;
+ dev_err(&client->dev, "GTP i2c test failed time %d.\n", retry);
+ msleep(20);
+ }
+ return ret;
}
/*******************************************************
Function:
- Request gpio(INT & RST) ports.
+ Request gpio(INT & RST) ports.
Input:
- ts: private data.
+ ts: private data.
Output:
- Executive outcomes.
- >= 0: succeed, < 0: failed
+ Executive outcomes.
+ = 0: succeed, != 0: failed
*******************************************************/
-static s8 gtp_request_io_port(struct goodix_ts_data *ts)
+static int gtp_request_io_port(struct goodix_ts_data *ts)
{
- s32 ret = 0;
+ struct i2c_client *client = ts->client;
+ struct goodix_ts_platform_data *pdata = ts->pdata;
+ int ret;
+ if (gpio_is_valid(pdata->irq_gpio)) {
+ ret = gpio_request(pdata->irq_gpio, "goodix_ts_irq_gpio");
+ if (ret) {
+ dev_err(&client->dev, "irq gpio request failed\n");
+ goto pwr_off;
+ }
+ ret = gpio_direction_input(pdata->irq_gpio);
+ if (ret) {
+ dev_err(&client->dev,
+ "set_direction for irq gpio failed\n");
+ goto free_irq_gpio;
+ }
+ } else {
+ dev_err(&client->dev, "irq gpio is invalid!\n");
+ ret = -EINVAL;
+ goto free_irq_gpio;
+ }
- ret = GTP_GPIO_REQUEST(GTP_INT_PORT, "GTP_INT_IRQ");
- if (ret < 0)
- {
- GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32)GTP_INT_PORT, ret);
- ret = -ENODEV;
- }
- else
- {
- GTP_GPIO_AS_INT(GTP_INT_PORT);
- ts->client->irq = GTP_INT_IRQ;
- }
+ if (gpio_is_valid(pdata->reset_gpio)) {
+ ret = gpio_request(pdata->reset_gpio, "goodix_ts__reset_gpio");
+ if (ret) {
+ dev_err(&client->dev, "reset gpio request failed\n");
+ goto free_irq_gpio;
+ }
- ret = GTP_GPIO_REQUEST(GTP_RST_PORT, "GTP_RST_PORT");
- if (ret < 0)
- {
- GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d",(s32)GTP_RST_PORT,ret);
- ret = -ENODEV;
- }
+ ret = gpio_direction_output(pdata->reset_gpio, 0);
+ if (ret) {
+ dev_err(&client->dev,
+ "set_direction for reset gpio failed\n");
+ goto free_reset_gpio;
+ }
+ } else {
+ dev_err(&client->dev, "reset gpio is invalid!\n");
+ ret = -EINVAL;
+ goto free_reset_gpio;
+ }
+ gpio_direction_input(pdata->reset_gpio);
- GTP_GPIO_AS_INPUT(GTP_RST_PORT);
- gtp_reset_guitar(ts->client, 20);
+ return ret;
-
- if(ret < 0)
- {
- GTP_GPIO_FREE(GTP_RST_PORT);
- GTP_GPIO_FREE(GTP_INT_PORT);
- }
-
- return ret;
+free_reset_gpio:
+ if (gpio_is_valid(pdata->reset_gpio))
+ gpio_free(pdata->reset_gpio);
+free_irq_gpio:
+ if (gpio_is_valid(pdata->irq_gpio))
+ gpio_free(pdata->irq_gpio);
+pwr_off:
+ return ret;
}
/*******************************************************
Function:
- Request interrupt.
+ Request interrupt.
Input:
- ts: private data.
+ ts: private data.
Output:
- Executive outcomes.
- 0: succeed, -1: failed.
+ Executive outcomes.
+ 0: succeed, -1: failed.
*******************************************************/
-static s8 gtp_request_irq(struct goodix_ts_data *ts)
+static int gtp_request_irq(struct goodix_ts_data *ts)
{
- s32 ret = -1;
- const u8 irq_table[] = GTP_IRQ_TAB;
+ int ret;
+ const u8 irq_table[] = GTP_IRQ_TAB;
- GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type);
+ GTP_DEBUG("INT trigger type:%x, irq=%d", ts->int_trigger_type,
+ ts->client->irq);
- ret = request_irq(ts->client->irq,
- goodix_ts_irq_handler,
- irq_table[ts->int_trigger_type],
- ts->client->name,
- ts);
- if (ret)
- {
- GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret);
- GTP_GPIO_AS_INPUT(GTP_INT_PORT);
- GTP_GPIO_FREE(GTP_INT_PORT);
+ ret = request_irq(ts->client->irq, goodix_ts_irq_handler,
+ irq_table[ts->int_trigger_type],
+ ts->client->name, ts);
+ if (ret) {
+ dev_err(&ts->client->dev, "Request IRQ failed!ERRNO:%d.\n",
+ ret);
+ gpio_direction_input(ts->pdata->irq_gpio);
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- ts->timer.function = goodix_ts_timer_handler;
- hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
- return -1;
- }
- else
- {
- gtp_irq_disable(ts);
- ts->use_irq = 1;
- return 0;
- }
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ ts->timer.function = goodix_ts_timer_handler;
+ hrtimer_start(&ts->timer, ktime_set(1, 0),
+ HRTIMER_MODE_REL);
+ ts->use_irq = false;
+ return ret;
+ } else {
+ gtp_irq_disable(ts);
+ ts->use_irq = true;
+ return 0;
+ }
}
/*******************************************************
Function:
- Request input device Function.
+ Request input device Function.
Input:
- ts:private data.
+ ts:private data.
Output:
- Executive outcomes.
- 0: succeed, otherwise: failed.
+ Executive outcomes.
+ 0: succeed, otherwise: failed.
*******************************************************/
-static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
+static int gtp_request_input_dev(struct goodix_ts_data *ts)
{
- s8 ret = -1;
- s8 phys[32];
+ int ret;
+ char phys[PHY_BUF_SIZE];
#if GTP_HAVE_TOUCH_KEY
- u8 index = 0;
+ int index = 0;
#endif
-
- GTP_DEBUG_FUNC();
-
- ts->input_dev = input_allocate_device();
- if (ts->input_dev == NULL)
- {
- GTP_ERROR("Failed to allocate input device.");
- return -ENOMEM;
- }
- ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
+ GTP_DEBUG_FUNC();
+
+ ts->input_dev = input_allocate_device();
+ if (ts->input_dev == NULL) {
+ dev_err(&ts->client->dev,
+ "Failed to allocate input device.\n");
+ return -ENOMEM;
+ }
+
+ ts->input_dev->evbit[0] =
+ BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
#if GTP_ICS_SLOT_REPORT
- __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
- input_mt_init_slots(ts->input_dev, 10); // in case of "out of memory"
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ input_mt_init_slots(ts->input_dev, 10);/* in case of "out of memory" */
#else
- ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
#endif
#if GTP_HAVE_TOUCH_KEY
- for (index = 0; index < GTP_MAX_KEY_NUM; index++)
- {
- input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]);
- }
+ for (index = 0; index < GTP_MAX_KEY_NUM; index++) {
+ input_set_capability(ts->input_dev,
+ EV_KEY, touch_key_array[index]);
+ }
#endif
#if GTP_SLIDE_WAKEUP
- input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
-#endif
+ input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
+#endif
#if GTP_WITH_PEN
- // pen support
- __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
- __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
- __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+ /* pen support */
+ __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
#endif
#if GTP_CHANGE_X2Y
- GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
+ GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
#endif
- input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
- input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
- input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
- input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
- input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+ 0, ts->abs_x_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+ 0, ts->abs_y_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+ 0, 255, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, 255, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
+ 0, 255, 0, 0);
- sprintf(phys, "input/ts");
- ts->input_dev->name = goodix_ts_name;
- ts->input_dev->phys = phys;
- ts->input_dev->id.bustype = BUS_I2C;
- ts->input_dev->id.vendor = 0xDEAD;
- ts->input_dev->id.product = 0xBEEF;
- ts->input_dev->id.version = 10427;
-
- ret = input_register_device(ts->input_dev);
- if (ret)
- {
- GTP_ERROR("Register %s input device failed", ts->input_dev->name);
- return -ENODEV;
- }
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
- ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- ts->early_suspend.suspend = goodix_ts_early_suspend;
- ts->early_suspend.resume = goodix_ts_late_resume;
- register_early_suspend(&ts->early_suspend);
-#endif
+ snprintf(phys, PHY_BUF_SIZE, "input/ts");
+ ts->input_dev->name = GOODIX_DEV_NAME;
+ ts->input_dev->phys = phys;
+ ts->input_dev->id.bustype = BUS_I2C;
+ ts->input_dev->id.vendor = 0xDEAD;
+ ts->input_dev->id.product = 0xBEEF;
+ ts->input_dev->id.version = 10427;
- return 0;
+ ret = input_register_device(ts->input_dev);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Register %s input device failed.\n",
+ ts->input_dev->name);
+ goto exit_free_inputdev;
+ }
+
+ return 0;
+
+exit_free_inputdev:
+ input_free_device(ts->input_dev);
+ ts->input_dev = NULL;
+ return ret;
+}
+
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
+{
+ return (regulator_count_voltages(reg) > 0) ?
+ regulator_set_optimum_mode(reg, load_uA) : 0;
+}
+
+/**
+ * goodix_power_on - Turn device power ON
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_on(struct goodix_ts_data *ts)
+{
+ int ret;
+
+ if (!IS_ERR(ts->avdd)) {
+ ret = reg_set_optimum_mode_check(ts->avdd,
+ GOODIX_VDD_LOAD_MAX_UA);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Regulator avdd set_opt failed rc=%d\n", ret);
+ goto err_set_opt_avdd;
+ }
+ ret = regulator_enable(ts->avdd);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator avdd enable failed ret=%d\n", ret);
+ goto err_enable_avdd;
+ }
+ }
+
+ if (!IS_ERR(ts->vdd)) {
+ ret = regulator_set_voltage(ts->vdd, GOODIX_VTG_MIN_UV,
+ GOODIX_VTG_MAX_UV);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator set_vtg failed vdd ret=%d\n", ret);
+ goto err_set_vtg_vdd;
+ }
+ ret = reg_set_optimum_mode_check(ts->vdd,
+ GOODIX_VDD_LOAD_MAX_UA);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Regulator vdd set_opt failed rc=%d\n", ret);
+ goto err_set_opt_vdd;
+ }
+ ret = regulator_enable(ts->vdd);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator vdd enable failed ret=%d\n", ret);
+ goto err_enable_vdd;
+ }
+ }
+
+ if (!IS_ERR(ts->vcc_i2c)) {
+ ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
+ GOODIX_I2C_VTG_MAX_UV);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator set_vtg failed vcc_i2c ret=%d\n",
+ ret);
+ goto err_set_vtg_vcc_i2c;
+ }
+ ret = reg_set_optimum_mode_check(ts->vcc_i2c,
+ GOODIX_VIO_LOAD_MAX_UA);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Regulator vcc_i2c set_opt failed rc=%d\n",
+ ret);
+ goto err_set_opt_vcc_i2c;
+ }
+ ret = regulator_enable(ts->vcc_i2c);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator vcc_i2c enable failed ret=%d\n",
+ ret);
+ regulator_disable(ts->vdd);
+ goto err_enable_vcc_i2c;
+ }
+ }
+
+ return 0;
+
+err_enable_vcc_i2c:
+err_set_opt_vcc_i2c:
+ if (!IS_ERR(ts->vcc_i2c))
+ regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV);
+err_set_vtg_vcc_i2c:
+ if (!IS_ERR(ts->vdd))
+ regulator_disable(ts->vdd);
+err_enable_vdd:
+err_set_opt_vdd:
+ if (!IS_ERR(ts->vdd))
+ regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV);
+err_set_vtg_vdd:
+ if (!IS_ERR(ts->avdd))
+ regulator_disable(ts->avdd);
+err_enable_avdd:
+err_set_opt_avdd:
+ return ret;
+}
+
+/**
+ * goodix_power_off - Turn device power OFF
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_off(struct goodix_ts_data *ts)
+{
+ int ret;
+
+ if (!IS_ERR(ts->vcc_i2c)) {
+ ret = regulator_set_voltage(ts->vcc_i2c, 0,
+ GOODIX_I2C_VTG_MAX_UV);
+ if (ret < 0)
+ dev_err(&ts->client->dev,
+ "Regulator vcc_i2c set_vtg failed ret=%d\n",
+ ret);
+ ret = regulator_disable(ts->vcc_i2c);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "Regulator vcc_i2c disable failed ret=%d\n",
+ ret);
+ }
+
+ if (!IS_ERR(ts->vdd)) {
+ ret = regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV);
+ if (ret < 0)
+ dev_err(&ts->client->dev,
+ "Regulator vdd set_vtg failed ret=%d\n", ret);
+ ret = regulator_disable(ts->vdd);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "Regulator vdd disable failed ret=%d\n", ret);
+ }
+
+ if (!IS_ERR(ts->avdd)) {
+ ret = regulator_disable(ts->avdd);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "Regulator avdd disable failed ret=%d\n", ret);
+ }
+
+ return 0;
+}
+
+/**
+ * goodix_power_init - Initialize device power
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_init(struct goodix_ts_data *ts)
+{
+ int ret;
+
+ ts->avdd = regulator_get(&ts->client->dev, "avdd");
+ if (IS_ERR(ts->avdd)) {
+ ret = PTR_ERR(ts->avdd);
+ dev_info(&ts->client->dev,
+ "Regulator get failed avdd ret=%d\n", ret);
+ }
+
+ ts->vdd = regulator_get(&ts->client->dev, "vdd");
+ if (IS_ERR(ts->vdd)) {
+ ret = PTR_ERR(ts->vdd);
+ dev_info(&ts->client->dev,
+ "Regulator get failed vdd ret=%d\n", ret);
+ }
+
+ ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc-i2c");
+ if (IS_ERR(ts->vcc_i2c)) {
+ ret = PTR_ERR(ts->vcc_i2c);
+ dev_info(&ts->client->dev,
+ "Regulator get failed vcc_i2c ret=%d\n", ret);
+ }
+
+ return 0;
+}
+
+/**
+ * goodix_power_deinit - Deinitialize device power
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_deinit(struct goodix_ts_data *ts)
+{
+ regulator_put(ts->vdd);
+ regulator_put(ts->vcc_i2c);
+ regulator_put(ts->avdd);
+
+ return 0;
+}
+
+static int goodix_ts_get_dt_coords(struct device *dev, char *name,
+ struct goodix_ts_platform_data *pdata)
+{
+ struct property *prop;
+ struct device_node *np = dev->of_node;
+ int rc;
+ u32 coords[GOODIX_COORDS_ARR_SIZE];
+
+ prop = of_find_property(np, name, NULL);
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ rc = of_property_read_u32_array(np, name, coords,
+ GOODIX_COORDS_ARR_SIZE);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read %s\n", name);
+ return rc;
+ }
+
+ if (!strcmp(name, "goodix,panel-coords")) {
+ pdata->panel_minx = coords[0];
+ pdata->panel_miny = coords[1];
+ pdata->panel_maxx = coords[2];
+ pdata->panel_maxy = coords[3];
+ } else if (!strcmp(name, "goodix,display-coords")) {
+ pdata->x_min = coords[0];
+ pdata->y_min = coords[1];
+ pdata->x_max = coords[2];
+ pdata->y_max = coords[3];
+ } else {
+ dev_err(dev, "unsupported property %s\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int goodix_parse_dt(struct device *dev,
+ struct goodix_ts_platform_data *pdata)
+{
+ int rc;
+ struct device_node *np = dev->of_node;
+ struct property *prop;
+ u32 temp_val, num_buttons;
+ u32 button_map[MAX_BUTTONS];
+
+ rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata);
+ if (rc && (rc != -EINVAL))
+ return rc;
+
+ rc = goodix_ts_get_dt_coords(dev, "goodix,display-coords", pdata);
+ if (rc)
+ return rc;
+
+ pdata->i2c_pull_up = of_property_read_bool(np,
+ "goodix,i2c-pull-up");
+
+ pdata->no_force_update = of_property_read_bool(np,
+ "goodix,no-force-update");
+ /* reset, irq gpio info */
+ pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
+ 0, &pdata->reset_gpio_flags);
+ if (pdata->reset_gpio < 0)
+ return pdata->reset_gpio;
+
+ pdata->irq_gpio = of_get_named_gpio_flags(np, "interrupt-gpios",
+ 0, &pdata->irq_gpio_flags);
+ if (pdata->irq_gpio < 0)
+ return pdata->irq_gpio;
+
+ rc = of_property_read_u32(np, "goodix,family-id", &temp_val);
+ if (!rc)
+ pdata->family_id = temp_val;
+ else
+ return rc;
+
+ prop = of_find_property(np, "goodix,button-map", NULL);
+ if (prop) {
+ num_buttons = prop->length / sizeof(temp_val);
+ if (num_buttons > MAX_BUTTONS)
+ return -EINVAL;
+
+ rc = of_property_read_u32_array(np,
+ "goodix,button-map", button_map,
+ num_buttons);
+ if (rc) {
+ dev_err(dev, "Unable to read key codes\n");
+ return rc;
+ }
+ }
+
+ prop = of_find_property(np, "goodix,cfg-data", &pdata->gtp_cfg_len);
+ if (prop && prop->value) {
+ pdata->config_data = devm_kzalloc(dev,
+ GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, GFP_KERNEL);
+ if (!pdata->config_data) {
+ dev_err(dev, "Not enough memory for panel config data\n");
+ return -ENOMEM;
+ }
+
+ pdata->config_data[0] = GTP_REG_CONFIG_DATA >> 8;
+ pdata->config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
+ memset(&pdata->config_data[GTP_ADDR_LENGTH], 0,
+ GTP_CONFIG_MAX_LENGTH);
+ memcpy(&pdata->config_data[GTP_ADDR_LENGTH],
+ prop->value, pdata->gtp_cfg_len);
+ } else {
+ dev_err(dev,
+ "Unable to get configure data, default will be used.\n");
+ pdata->gtp_cfg_len = 0;
+ }
+
+ return 0;
}
/*******************************************************
Function:
- I2c probe.
+ I2c probe.
Input:
- client: i2c device struct.
- id: device id.
+ client: i2c device struct.
+ id: device id.
Output:
- Executive outcomes.
- 0: succeed.
+ Executive outcomes.
+ 0: succeed.
*******************************************************/
-static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+
+static int goodix_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- s32 ret = -1;
- struct goodix_ts_data *ts;
- u16 version_info;
+ struct goodix_ts_platform_data *pdata;
+ struct goodix_ts_data *ts;
+ u16 version_info;
+ int ret;
- GTP_DEBUG_FUNC();
-
- //do NOT remove these logs
- GTP_INFO("GTP Driver Version: %s", GTP_DRIVER_VERSION);
- GTP_INFO("GTP Driver Built@%s, %s", __TIME__, __DATE__);
- GTP_INFO("GTP I2C Address: 0x%02x", client->addr);
+ dev_dbg(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr);
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct goodix_ts_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev,
+ "GTP Failed to allocate memory for pdata\n");
+ return -ENOMEM;
+ }
- i2c_connect_client = client;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- {
- GTP_ERROR("I2C check functionality failed.");
- return -ENODEV;
- }
- ts = kzalloc(sizeof(*ts), GFP_KERNEL);
- if (ts == NULL)
- {
- GTP_ERROR("Alloc GFP_KERNEL memory failed.");
- return -ENOMEM;
- }
-
- memset(ts, 0, sizeof(*ts));
- INIT_WORK(&ts->work, goodix_ts_work_func);
- ts->client = client;
- spin_lock_init(&ts->irq_lock); // 2.6.39 later
- // ts->irq_lock = SPIN_LOCK_UNLOCKED; // 2.6.39 & before
- i2c_set_clientdata(client, ts);
-
- ts->gtp_rawdiff_mode = 0;
+ ret = goodix_parse_dt(&client->dev, pdata);
+ if (ret)
+ return ret;
+ } else {
+ pdata = client->dev.platform_data;
+ }
- ret = gtp_request_io_port(ts);
- if (ret < 0)
- {
- GTP_ERROR("GTP request IO port failed.");
- kfree(ts);
- return ret;
- }
+ if (!pdata) {
+ dev_err(&client->dev, "GTP invalid pdata\n");
+ return -EINVAL;
+ }
- ret = gtp_i2c_test(client);
- if (ret < 0)
- {
- GTP_ERROR("I2C communication ERROR!");
- }
+#if GTP_ESD_PROTECT
+ i2c_connect_client = client;
+#endif
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "GTP I2C not supported\n");
+ return -ENODEV;
+ }
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (!ts) {
+ dev_err(&client->dev, "GTP not enough memory for ts\n");
+ return -ENOMEM;
+ }
+
+ memset(ts, 0, sizeof(*ts));
+ ts->client = client;
+ ts->pdata = pdata;
+ /* For 2.6.39 & later use spin_lock_init(&ts->irq_lock)
+ * For 2.6.39 & before, use ts->irq_lock = SPIN_LOCK_UNLOCKED
+ */
+ spin_lock_init(&ts->irq_lock);
+ i2c_set_clientdata(client, ts);
+ ts->gtp_rawdiff_mode = 0;
+
+ ret = goodix_power_init(ts);
+ if (ret) {
+ dev_err(&client->dev, "GTP power init failed\n");
+ goto exit_free_client_data;
+ }
+
+ ret = goodix_power_on(ts);
+ if (ret) {
+ dev_err(&client->dev, "GTP power on failed\n");
+ goto exit_deinit_power;
+ }
+
+ ret = gtp_request_io_port(ts);
+ if (ret) {
+ dev_err(&client->dev, "GTP request IO port failed.\n");
+ goto exit_power_off;
+ }
+
+ gtp_reset_guitar(ts, 20);
+
+ ret = gtp_i2c_test(client);
+ if (ret != 2) {
+ dev_err(&client->dev, "I2C communication ERROR!\n");
+ goto exit_free_io_port;
+ }
#if GTP_AUTO_UPDATE
- ret = gup_init_update_proc(ts);
- if (ret < 0)
- {
- GTP_ERROR("Create update thread error.");
- }
+ ret = gup_init_update_proc(ts);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "GTP Create firmware update thread error.\n");
+ goto exit_free_io_port;
+ }
#endif
-
- ret = gtp_init_panel(ts);
- if (ret < 0)
- {
- GTP_ERROR("GTP init panel failed.");
- ts->abs_x_max = GTP_MAX_WIDTH;
- ts->abs_y_max = GTP_MAX_HEIGHT;
- ts->int_trigger_type = GTP_INT_TRIGGER;
- }
- ret = gtp_request_input_dev(ts);
- if (ret < 0)
- {
- GTP_ERROR("GTP request input dev failed");
- }
-
- ret = gtp_request_irq(ts);
- if (ret < 0)
- {
- GTP_INFO("GTP works in polling mode.");
- }
- else
- {
- GTP_INFO("GTP works in interrupt mode.");
- }
+ ret = gtp_init_panel(ts);
+ if (ret < 0) {
+ dev_err(&client->dev, "GTP init panel failed.\n");
+ ts->abs_x_max = GTP_MAX_WIDTH;
+ ts->abs_y_max = GTP_MAX_HEIGHT;
+ ts->int_trigger_type = GTP_INT_TRIGGER;
+ }
- ret = gtp_read_version(client, &version_info);
- if (ret < 0)
- {
- GTP_ERROR("Read version failed.");
- }
- if (ts->use_irq)
- {
- gtp_irq_enable(ts);
- }
-
+ ret = gtp_request_input_dev(ts);
+ if (ret) {
+ dev_err(&client->dev, "GTP request input dev failed.\n");
+ goto exit_free_inputdev;
+ }
+
+#if defined(CONFIG_FB)
+ ts->fb_notif.notifier_call = fb_notifier_callback;
+ ret = fb_register_client(&ts->fb_notif);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "Unable to register fb_notifier: %d\n",
+ ret);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->early_suspend.suspend = goodix_ts_early_suspend;
+ ts->early_suspend.resume = goodix_ts_late_resume;
+ register_early_suspend(&ts->early_suspend);
+#endif
+
+ ts->goodix_wq = create_singlethread_workqueue("goodix_wq");
+ INIT_WORK(&ts->work, goodix_ts_work_func);
+
+ ret = gtp_request_irq(ts);
+ if (ret < 0)
+ dev_info(&client->dev, "GTP works in polling mode.\n");
+ else
+ dev_info(&client->dev, "GTP works in interrupt mode.\n");
+
+ ret = gtp_read_version(client, &version_info);
+ if (ret != 2) {
+ dev_err(&client->dev, "Read version failed.\n");
+ goto exit_free_irq;
+ }
+ if (ts->use_irq)
+ gtp_irq_enable(ts);
+
#if GTP_CREATE_WR_NODE
- init_wr_node(client);
+ init_wr_node(client);
#endif
-
-#if GTP_ESD_PROTECT
- gtp_esd_switch(client, SWITCH_ON);
-#endif
- return 0;
-}
+#if GTP_ESD_PROTECT
+ gtp_esd_switch(client, SWITCH_ON);
+#endif
+ init_done = true;
+ return 0;
+exit_free_irq:
+#if defined(CONFIG_FB)
+ if (fb_unregister_client(&ts->fb_notif))
+ dev_err(&client->dev,
+ "Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ unregister_early_suspend(&ts->early_suspend);
+#endif
+ if (ts->use_irq)
+ free_irq(client->irq, ts);
+ else
+ hrtimer_cancel(&ts->timer);
+ cancel_work_sync(&ts->work);
+ flush_workqueue(ts->goodix_wq);
+ destroy_workqueue(ts->goodix_wq);
+
+ input_unregister_device(ts->input_dev);
+ if (ts->input_dev) {
+ input_free_device(ts->input_dev);
+ ts->input_dev = NULL;
+ }
+exit_free_inputdev:
+ kfree(ts->config_data);
+exit_free_io_port:
+ if (gpio_is_valid(pdata->reset_gpio))
+ gpio_free(pdata->reset_gpio);
+ if (gpio_is_valid(pdata->irq_gpio))
+ gpio_free(pdata->irq_gpio);
+exit_power_off:
+ goodix_power_off(ts);
+exit_deinit_power:
+ goodix_power_deinit(ts);
+exit_free_client_data:
+ i2c_set_clientdata(client, NULL);
+ kfree(ts);
+ return ret;
+}
/*******************************************************
Function:
- Goodix touchscreen driver release function.
+ Goodix touchscreen driver release function.
Input:
- client: i2c device struct.
+ client: i2c device struct.
Output:
- Executive outcomes. 0---succeed.
+ Executive outcomes. 0---succeed.
*******************************************************/
static int goodix_ts_remove(struct i2c_client *client)
{
- struct goodix_ts_data *ts = i2c_get_clientdata(client);
-
- GTP_DEBUG_FUNC();
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
- unregister_early_suspend(&ts->early_suspend);
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ GTP_DEBUG_FUNC();
+#if defined(CONFIG_FB)
+ if (fb_unregister_client(&ts->fb_notif))
+ dev_err(&client->dev,
+ "Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ unregister_early_suspend(&ts->early_suspend);
#endif
#if GTP_CREATE_WR_NODE
- uninit_wr_node();
+ uninit_wr_node();
#endif
#if GTP_ESD_PROTECT
- destroy_workqueue(gtp_esd_check_workqueue);
+ cancel_work_sync(gtp_esd_check_workqueue);
+ flush_workqueue(gtp_esd_check_workqueue);
+ destroy_workqueue(gtp_esd_check_workqueue);
#endif
- if (ts)
- {
- if (ts->use_irq)
- {
- GTP_GPIO_AS_INPUT(GTP_INT_PORT);
- GTP_GPIO_FREE(GTP_INT_PORT);
- free_irq(client->irq, ts);
- }
- else
- {
- hrtimer_cancel(&ts->timer);
- }
- }
-
- GTP_INFO("GTP driver removing...");
- i2c_set_clientdata(client, NULL);
- input_unregister_device(ts->input_dev);
- kfree(ts);
+ if (ts) {
+ if (ts->use_irq)
+ free_irq(client->irq, ts);
+ else
+ hrtimer_cancel(&ts->timer);
- return 0;
+ cancel_work_sync(&ts->work);
+ flush_workqueue(ts->goodix_wq);
+ destroy_workqueue(ts->goodix_wq);
+
+ input_unregister_device(ts->input_dev);
+ if (ts->input_dev) {
+ input_free_device(ts->input_dev);
+ ts->input_dev = NULL;
+ }
+ kfree(ts->config_data);
+
+ if (gpio_is_valid(ts->pdata->reset_gpio))
+ gpio_free(ts->pdata->reset_gpio);
+ if (gpio_is_valid(ts->pdata->irq_gpio))
+ gpio_free(ts->pdata->irq_gpio);
+
+ goodix_power_off(ts);
+ goodix_power_deinit(ts);
+ i2c_set_clientdata(client, NULL);
+ kfree(ts);
+ }
+
+ return 0;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
/*******************************************************
Function:
- Early suspend function.
+ Early suspend function.
Input:
- h: early_suspend struct.
+ h: early_suspend struct.
Output:
- None.
+ None.
+*******************************************************/
+static void goodix_ts_suspend(struct goodix_ts_data *ts)
+{
+ int ret = -1, i;
+
+ GTP_DEBUG_FUNC();
+
+#if GTP_ESD_PROTECT
+ ts->gtp_is_suspend = 1;
+ gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+
+#if GTP_SLIDE_WAKEUP
+ ret = gtp_enter_doze(ts);
+#else
+ if (ts->use_irq)
+ gtp_irq_disable(ts);
+ else
+ hrtimer_cancel(&ts->timer);
+
+ for (i = 0; i < GTP_MAX_TOUCH; i++)
+ gtp_touch_up(ts, i);
+
+ input_report_key(ts->input_dev, BTN_TOUCH, 0);
+ input_sync(ts->input_dev);
+
+ ret = gtp_enter_sleep(ts);
+#endif
+ if (ret < 0)
+ dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+ /* to avoid waking up while not sleeping,
+ * delay 48 + 10ms to ensure reliability
+ */
+ msleep(58);
+}
+
+/*******************************************************
+Function:
+ Late resume function.
+Input:
+ h: early_suspend struct.
+Output:
+ None.
+*******************************************************/
+static void goodix_ts_resume(struct goodix_ts_data *ts)
+{
+ int ret = -1;
+
+ GTP_DEBUG_FUNC();
+
+ ret = gtp_wakeup_sleep(ts);
+
+#if GTP_SLIDE_WAKEUP
+ doze_status = DOZE_DISABLED;
+#endif
+
+ if (ret < 0)
+ dev_err(&ts->client->dev, "GTP resume failed.\n");
+
+ if (ts->use_irq)
+ gtp_irq_enable(ts);
+ else
+ hrtimer_start(&ts->timer,
+ ktime_set(1, 0), HRTIMER_MODE_REL);
+
+#if GTP_ESD_PROTECT
+ ts->gtp_is_suspend = 0;
+ gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+}
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct goodix_ts_data *ts =
+ container_of(self, struct goodix_ts_data, fb_notif);
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+ ts && ts->client) {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK)
+ goodix_ts_resume(ts);
+ else if (*blank == FB_BLANK_POWERDOWN)
+ goodix_ts_suspend(ts);
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+/*******************************************************
+Function:
+ Early suspend function.
+Input:
+ h: early_suspend struct.
+Output:
+ None.
*******************************************************/
static void goodix_ts_early_suspend(struct early_suspend *h)
{
- struct goodix_ts_data *ts;
- s8 ret = -1;
- ts = container_of(h, struct goodix_ts_data, early_suspend);
-
- GTP_DEBUG_FUNC();
+ struct goodix_ts_data *ts;
-#if GTP_ESD_PROTECT
- ts->gtp_is_suspend = 1;
- gtp_esd_switch(ts->client, SWITCH_OFF);
-#endif
-
-#if GTP_SLIDE_WAKEUP
- ret = gtp_enter_doze(ts);
-#else
- if (ts->use_irq)
- {
- gtp_irq_disable(ts);
- }
- else
- {
- hrtimer_cancel(&ts->timer);
- }
- ret = gtp_enter_sleep(ts);
-#endif
- if (ret < 0)
- {
- GTP_ERROR("GTP early suspend failed.");
- }
- // to avoid waking up while not sleeping
- // delay 48 + 10ms to ensure reliability
- msleep(58);
+ ts = container_of(h, struct goodix_ts_data, early_suspend);
+ goodix_ts_suspend(ts);
+ return;
}
/*******************************************************
Function:
- Late resume function.
+ Late resume function.
Input:
- h: early_suspend struct.
+ h: early_suspend struct.
Output:
- None.
+ None.
*******************************************************/
static void goodix_ts_late_resume(struct early_suspend *h)
{
- struct goodix_ts_data *ts;
- s8 ret = -1;
- ts = container_of(h, struct goodix_ts_data, early_suspend);
-
- GTP_DEBUG_FUNC();
-
- ret = gtp_wakeup_sleep(ts);
+ struct goodix_ts_data *ts;
-#if GTP_SLIDE_WAKEUP
- doze_status = DOZE_DISABLED;
-#endif
-
- if (ret < 0)
- {
- GTP_ERROR("GTP later resume failed.");
- }
-
- if (ts->use_irq)
- {
- gtp_irq_enable(ts);
- }
- else
- {
- hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
- }
-
-#if GTP_ESD_PROTECT
- ts->gtp_is_suspend = 0;
- gtp_esd_switch(ts->client, SWITCH_ON);
-#endif
+ ts = container_of(h, struct goodix_ts_data, early_suspend);
+ goodix_ts_late_resume(ts);
+ return;
}
#endif
+#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
#if GTP_ESD_PROTECT
/*******************************************************
Function:
- switch on & off esd delayed work
+ switch on & off esd delayed work
Input:
- client: i2c device
- on: SWITCH_ON / SWITCH_OFF
+ client: i2c device
+ on: SWITCH_ON / SWITCH_OFF
Output:
- void
+ void
*********************************************************/
-void gtp_esd_switch(struct i2c_client *client, s32 on)
+void gtp_esd_switch(struct i2c_client *client, int on)
{
- struct goodix_ts_data *ts;
-
- ts = i2c_get_clientdata(client);
- if (SWITCH_ON == on) // switch on esd
- {
- if (!ts->esd_running)
- {
- ts->esd_running = 1;
- GTP_INFO("Esd started");
- queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE);
- }
- }
- else // switch off esd
- {
- if (ts->esd_running)
- {
- ts->esd_running = 0;
- GTP_INFO("Esd cancelled");
- cancel_delayed_work_sync(>p_esd_check_work);
- }
- }
+ struct goodix_ts_data *ts;
+
+ ts = i2c_get_clientdata(client);
+ if (SWITCH_ON == on) {
+ /* switch on esd */
+ if (!ts->esd_running) {
+ ts->esd_running = 1;
+ dev_dbg(&client->dev, "Esd started\n");
+ queue_delayed_work(gtp_esd_check_workqueue,
+ >p_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+ }
+ } else {
+ /* switch off esd */
+ if (ts->esd_running) {
+ ts->esd_running = 0;
+ dev_dbg(&client->dev, "Esd cancelled\n");
+ cancel_delayed_work_sync(>p_esd_check_work);
+ }
+ }
}
/*******************************************************
Function:
- Initialize external watchdog for esd protect
+ Initialize external watchdog for esd protect
Input:
- client: i2c device.
+ client: i2c device.
Output:
- result of i2c write operation.
- 1: succeed, otherwise: failed
+ result of i2c write operation.
+ 1: succeed, otherwise: failed
*********************************************************/
-static s32 gtp_init_ext_watchdog(struct i2c_client *client)
+static int gtp_init_ext_watchdog(struct i2c_client *client)
{
- u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
-
- struct i2c_msg msg; // in case of recursively reset by calling gtp_i2c_write
- s32 ret = -1;
- s32 retries = 0;
+ /* in case of recursively reset by calling gtp_i2c_write*/
+ struct i2c_msg msg;
+ u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
+ int ret;
+ int retries = 0;
- GTP_DEBUG("Init external watchdog...");
- GTP_DEBUG_FUNC();
+ GTP_DEBUG("Init external watchdog...");
+ GTP_DEBUG_FUNC();
- msg.flags = !I2C_M_RD;
- msg.addr = client->addr;
- msg.len = 4;
- msg.buf = opr_buffer;
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = 4;
+ msg.buf = opr_buffer;
- while(retries < 5)
- {
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret == 1)
- {
- return 1;
- }
- retries++;
- }
- if (retries >= 5)
- {
- GTP_ERROR("init external watchdog failed!");
- }
- return 0;
+ while (retries < 5) {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)
+ return 1;
+ retries++;
+ }
+ if (retries >= 5)
+ dev_err(&client->dev, "init external watchdog failed!");
+ return 0;
}
/*******************************************************
Function:
- Esd protect function.
- Added external watchdog by meta, 2013/03/07
+ Esd protect function.
+ Added external watchdog by meta, 2013/03/07
Input:
- work: delayed work
+ work: delayed work
Output:
- None.
+ None.
*******************************************************/
static void gtp_esd_check_func(struct work_struct *work)
{
- s32 i;
- s32 ret = -1;
- struct goodix_ts_data *ts = NULL;
- u8 test[4] = {0x80, 0x40};
-
- GTP_DEBUG_FUNC();
-
- ts = i2c_get_clientdata(i2c_connect_client);
+ s32 i;
+ s32 ret = -1;
+ struct goodix_ts_data *ts = NULL;
+ u8 test[4] = {0x80, 0x40};
- if (ts->gtp_is_suspend)
- {
- ts->esd_running = 0;
- GTP_INFO("Esd terminated!");
- return;
- }
-
- for (i = 0; i < 3; i++)
- {
- ret = gtp_i2c_read(ts->client, test, 4);
-
- GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
- if ((ret < 0))
- {
- // IIC communication problem
- continue;
- }
- else
- {
- if ((test[2] == 0xAA) || (test[3] != 0xAA))
- {
- // IC works abnormally..
- i = 3;
- break;
- }
- else
- {
- // IC works normally, Write 0x8040 0xAA, feed the dog
- test[2] = 0xAA;
- gtp_i2c_write(ts->client, test, 3);
- break;
- }
- }
- }
- if (i >= 3)
- {
- GTP_ERROR("IC Working ABNORMALLY, Resetting Guitar...");
- gtp_reset_guitar(ts->client, 50);
- }
+ GTP_DEBUG_FUNC();
- if(!ts->gtp_is_suspend)
- {
- queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE);
- }
- else
- {
- GTP_INFO("Esd terminated!");
- ts->esd_running = 0;
- }
- return;
+ ts = i2c_get_clientdata(i2c_connect_client);
+
+ if (ts->gtp_is_suspend) {
+ dev_dbg(&ts->client->dev, "Esd terminated!\n");
+ ts->esd_running = 0;
+ return;
+ }
+#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
+ if (ts->enter_update)
+ return;
+#endif
+
+ for (i = 0; i < 3; i++) {
+ ret = gtp_i2c_read(ts->client, test, 4);
+
+ GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
+ if ((ret < 0)) {
+ /* IC works abnormally..*/
+ continue;
+ } else {
+ if ((test[2] == 0xAA) || (test[3] != 0xAA)) {
+ /* IC works abnormally..*/
+ i = 3;
+ break;
+ } else {
+ /* IC works normally, Write 0x8040 0xAA*/
+ test[2] = 0xAA;
+ gtp_i2c_write(ts->client, test, 3);
+ break;
+ }
+ }
+ }
+ if (i >= 3) {
+ dev_err(&ts->client->dev,
+ "IC Working ABNORMALLY, Resetting Guitar...\n");
+ gtp_reset_guitar(ts, 50);
+ }
+
+ if (!ts->gtp_is_suspend)
+ queue_delayed_work(gtp_esd_check_workqueue,
+ >p_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+ else {
+ dev_dbg(&ts->client->dev, "Esd terminated!\n");
+ ts->esd_running = 0;
+ }
+
+ return;
}
#endif
static const struct i2c_device_id goodix_ts_id[] = {
- { GTP_I2C_NAME, 0 },
- { }
+ { GTP_I2C_NAME, 0 },
+ { }
+};
+
+static struct of_device_id goodix_match_table[] = {
+ { .compatible = "goodix,gt9xx", },
+ { },
};
static struct i2c_driver goodix_ts_driver = {
- .probe = goodix_ts_probe,
- .remove = goodix_ts_remove,
-#ifndef CONFIG_HAS_EARLYSUSPEND
- .suspend = goodix_ts_early_suspend,
- .resume = goodix_ts_late_resume,
+ .probe = goodix_ts_probe,
+ .remove = goodix_ts_remove,
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ .suspend = goodix_ts_early_suspend,
+ .resume = goodix_ts_late_resume,
#endif
- .id_table = goodix_ts_id,
- .driver = {
- .name = GTP_I2C_NAME,
- .owner = THIS_MODULE,
- },
+ .id_table = goodix_ts_id,
+ .driver = {
+ .name = GTP_I2C_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = goodix_match_table,
+ },
};
-/*******************************************************
+/*******************************************************
Function:
Driver Install function.
Input:
@@ -1766,41 +2246,29 @@
********************************************************/
static int __devinit goodix_ts_init(void)
{
- s32 ret;
+ int ret;
- GTP_DEBUG_FUNC();
- GTP_INFO("GTP driver installing...");
- goodix_wq = create_singlethread_workqueue("goodix_wq");
- if (!goodix_wq)
- {
- GTP_ERROR("Creat workqueue failed.");
- return -ENOMEM;
- }
+ GTP_DEBUG_FUNC();
#if GTP_ESD_PROTECT
- INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func);
- gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
+ INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func);
+ gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
#endif
- ret = i2c_add_driver(&goodix_ts_driver);
- return ret;
+ ret = i2c_add_driver(&goodix_ts_driver);
+ return ret;
}
-/*******************************************************
+/*******************************************************
Function:
- Driver uninstall function.
+ Driver uninstall function.
Input:
- None.
+ None.
Output:
- Executive Outcomes. 0---succeed.
+ Executive Outcomes. 0---succeed.
********************************************************/
static void __exit goodix_ts_exit(void)
{
- GTP_DEBUG_FUNC();
- GTP_INFO("GTP driver exited.");
- i2c_del_driver(&goodix_ts_driver);
- if (goodix_wq)
- {
- destroy_workqueue(goodix_wq);
- }
+ GTP_DEBUG_FUNC();
+ i2c_del_driver(&goodix_ts_driver);
}
late_initcall(goodix_ts_init);
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index e375af5..eef170f 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -1,241 +1,281 @@
/* drivers/input/touchscreen/gt9xx.h
- *
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
+ *
* 2010 - 2013 Goodix Technology.
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be a reference
- * to you, when you are integrating the GOODiX's CTP IC into your system,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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 _GOODIX_GT9XX_H_
#define _GOODIX_GT9XX_H_
#include <linux/kernel.h>
-#include <linux/hrtimer.h>
#include <linux/i2c.h>
+#include <linux/irq.h>
#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/proc_fs.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <mach/gpio.h>
-#include <linux/earlysuspend.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#define GOODIX_SUSPEND_LEVEL 1
+#endif
+
+struct goodix_ts_platform_data {
+ int irq_gpio;
+ u32 irq_gpio_flags;
+ int reset_gpio;
+ u32 reset_gpio_flags;
+ u32 family_id;
+ u32 x_max;
+ u32 y_max;
+ u32 x_min;
+ u32 y_min;
+ u32 panel_minx;
+ u32 panel_miny;
+ u32 panel_maxx;
+ u32 panel_maxy;
+ bool no_force_update;
+ bool i2c_pull_up;
+ int gtp_cfg_len;
+ u8 *config_data;
+};
struct goodix_ts_data {
- spinlock_t irq_lock;
- struct i2c_client *client;
- struct input_dev *input_dev;
- struct hrtimer timer;
- struct work_struct work;
- struct early_suspend early_suspend;
- s32 irq_is_disable;
- s32 use_irq;
- u16 abs_x_max;
- u16 abs_y_max;
- u8 max_touch_num;
- u8 int_trigger_type;
- u8 green_wake_mode;
- u8 chip_type;
- u8 enter_update;
- u8 gtp_is_suspend;
- u8 gtp_rawdiff_mode;
- u8 gtp_cfg_len;
- u8 fixed_cfg;
- u8 esd_running;
- u8 fw_error;
+ spinlock_t irq_lock;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct goodix_ts_platform_data *pdata;
+ struct hrtimer timer;
+ struct workqueue_struct *goodix_wq;
+ struct work_struct work;
+ s32 irq_is_disabled;
+ s32 use_irq;
+ u16 abs_x_max;
+ u16 abs_y_max;
+ u8 max_touch_num;
+ u8 int_trigger_type;
+ u8 green_wake_mode;
+ u8 chip_type;
+ u8 *config_data;
+ u8 enter_update;
+ u8 gtp_is_suspend;
+ u8 gtp_rawdiff_mode;
+ u8 gtp_cfg_len;
+ u8 fixed_cfg;
+ u8 esd_running;
+ u8 fw_error;
+ struct regulator *avdd;
+ struct regulator *vdd;
+ struct regulator *vcc_i2c;
+#if defined(CONFIG_FB)
+ struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+#endif
};
extern u16 show_len;
extern u16 total_len;
-//***************************PART1:ON/OFF define*******************************
-#define GTP_CUSTOM_CFG 0
-#define GTP_CHANGE_X2Y 0
-#define GTP_DRIVER_SEND_CFG 1
-#define GTP_HAVE_TOUCH_KEY 0
-#define GTP_POWER_CTRL_SLEEP 0
-#define GTP_ICS_SLOT_REPORT 0
+/***************************PART1:ON/OFF define*******************************/
+#define GTP_CUSTOM_CFG 0
+#define GTP_CHANGE_X2Y 0
+#define GTP_DRIVER_SEND_CFG 1
+#define GTP_HAVE_TOUCH_KEY 1
+#define GTP_POWER_CTRL_SLEEP 0
+#define GTP_ICS_SLOT_REPORT 1
-#define GTP_AUTO_UPDATE 1 // auto updated by .bin file as default
-#define GTP_HEADER_FW_UPDATE 0 // auto updated by head_fw_array in gt9xx_firmware.h, function together with GTP_AUTO_UPDATE
-
-#define GTP_CREATE_WR_NODE 1
-#define GTP_ESD_PROTECT 0
-#define GTP_WITH_PEN 0
+/* auto updated by .bin file as default */
+#define GTP_AUTO_UPDATE 0
+/* auto updated by head_fw_array in gt9xx_firmware.h,
+ * function together with GTP_AUTO_UPDATE */
+#define GTP_HEADER_FW_UPDATE 0
-#define GTP_SLIDE_WAKEUP 0
-#define GTP_DBL_CLK_WAKEUP 0 // double-click wakeup, function together with GTP_SLIDE_WAKEUP
+#define GTP_CREATE_WR_NODE 0
+#define GTP_ESD_PROTECT 0
+#define GTP_WITH_PEN 0
-#define GTP_DEBUG_ON 1
-#define GTP_DEBUG_ARRAY_ON 0
-#define GTP_DEBUG_FUNC_ON 0
+#define GTP_SLIDE_WAKEUP 0
+/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
+#define GTP_DBL_CLK_WAKEUP 0
-//*************************** PART2:TODO define **********************************
-// STEP_1(REQUIRED): Define Configuration Information Group(s)
-// Sensor_ID Map:
+#define GTP_DEBUG_ON 1
+#define GTP_DEBUG_ARRAY_ON 0
+#define GTP_DEBUG_FUNC_ON 0
+
+/*************************** PART2:TODO define *******************************/
+/* STEP_1(REQUIRED): Define Configuration Information Group(s) */
+/* Sensor_ID Map: */
/* sensor_opt1 sensor_opt2 Sensor_ID
- GND GND 0
- VDDIO GND 1
- NC GND 2
- GND NC/300K 3
- VDDIO NC/300K 4
- NC NC/300K 5
+ * GND GND 0
+ * VDDIO GND 1
+ * NC GND 2
+ * GND NC/300K 3
+ * VDDIO NC/300K 4
+ * NC NC/300K 5
*/
-// TODO: define your own default or for Sensor_ID == 0 config here.
-// The predefined one is just a sample config, which is not suitable for your tp in most cases.
+/* Define your own default or for Sensor_ID == 0 config here */
+/* The predefined one is just a sample config,
+ * which is not suitable for your tp in most cases. */
#define CTP_CFG_GROUP1 {\
- 0x41,0x1C,0x02,0xC0,0x03,0x0A,0x05,0x01,0x01,0x0F,\
- 0x23,0x0F,0x5F,0x41,0x03,0x05,0x00,0x00,0x00,0x00,\
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x00,0x0A,\
- 0x28,0x00,0xB8,0x0B,0x00,0x00,0x00,0x9A,0x03,0x25,\
- 0x00,0x00,0x00,0x00,0x00,0x03,0x64,0x32,0x00,0x00,\
- 0x00,0x32,0x8C,0x94,0x05,0x01,0x05,0x00,0x00,0x96,\
- 0x0C,0x22,0xD8,0x0E,0x23,0x56,0x11,0x25,0xFF,0x13,\
- 0x28,0xA7,0x15,0x2E,0x00,0x00,0x10,0x30,0x48,0x00,\
- 0x56,0x4A,0x3A,0xFF,0xFF,0x16,0x00,0x00,0x00,0x00,\
- 0x00,0x01,0x1B,0x14,0x0D,0x19,0x00,0x00,0x01,0x00,\
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
- 0x00,0x00,0x1A,0x18,0x16,0x14,0x12,0x10,0x0E,0x0C,\
- 0x0A,0x08,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
- 0xFF,0xFF,0x1D,0x1E,0x1F,0x20,0x22,0x24,0x28,0x29,\
- 0x0C,0x0A,0x08,0x00,0x02,0x04,0x05,0x06,0x0E,0xFF,\
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
- 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
- 0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x01\
- }
-
-// TODO: define your config for Sensor_ID == 1 here, if needed
+ 0x41, 0x1C, 0x02, 0xC0, 0x03, 0x0A, 0x05, 0x01, 0x01, 0x0F,\
+ 0x23, 0x0F, 0x5F, 0x41, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x0A,\
+ 0x28, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x00, 0x9A, 0x03, 0x25,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32, 0x00, 0x00,\
+ 0x00, 0x32, 0x8C, 0x94, 0x05, 0x01, 0x05, 0x00, 0x00, 0x96,\
+ 0x0C, 0x22, 0xD8, 0x0E, 0x23, 0x56, 0x11, 0x25, 0xFF, 0x13,\
+ 0x28, 0xA7, 0x15, 0x2E, 0x00, 0x00, 0x10, 0x30, 0x48, 0x00,\
+ 0x56, 0x4A, 0x3A, 0xFF, 0xFF, 0x16, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x01, 0x1B, 0x14, 0x0D, 0x19, 0x00, 0x00, 0x01, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0E, 0x0C,\
+ 0x0A, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+ 0xFF, 0xFF, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x24, 0x28, 0x29,\
+ 0x0C, 0x0A, 0x08, 0x00, 0x02, 0x04, 0x05, 0x06, 0x0E, 0xFF,\
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x01\
+ }
+
+/* Define your config for Sensor_ID == 1 here, if needed */
#define CTP_CFG_GROUP2 {\
- }
-// TODO: define your config for Sensor_ID == 2 here, if needed
+ }
+
+/* Define your config for Sensor_ID == 2 here, if needed */
#define CTP_CFG_GROUP3 {\
- }
+ }
-// TODO: define your config for Sensor_ID == 3 here, if needed
+/* Define your config for Sensor_ID == 3 here, if needed */
#define CTP_CFG_GROUP4 {\
- }
+ }
-// TODO: define your config for Sensor_ID == 4 here, if needed
+/* Define your config for Sensor_ID == 4 here, if needed */
#define CTP_CFG_GROUP5 {\
- }
+ }
-// TODO: define your config for Sensor_ID == 5 here, if needed
+/* Define your config for Sensor_ID == 5 here, if needed */
#define CTP_CFG_GROUP6 {\
- }
+ }
-// STEP_2(REQUIRED): Customize your I/O ports & I/O operations
-#define GTP_RST_PORT S5PV210_GPJ3(6)
-#define GTP_INT_PORT S5PV210_GPH1(3)
-#define GTP_INT_IRQ gpio_to_irq(GTP_INT_PORT)
-#define GTP_INT_CFG S3C_GPIO_SFN(0xF)
+#define GTP_IRQ_TAB {\
+ IRQ_TYPE_EDGE_RISING,\
+ IRQ_TYPE_EDGE_FALLING,\
+ IRQ_TYPE_LEVEL_LOW,\
+ IRQ_TYPE_LEVEL_HIGH\
+ }
-#define GTP_GPIO_AS_INPUT(pin) do{\
- gpio_direction_input(pin);\
- s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE);\
- }while(0)
-#define GTP_GPIO_AS_INT(pin) do{\
- GTP_GPIO_AS_INPUT(pin);\
- s3c_gpio_cfgpin(pin, GTP_INT_CFG);\
- }while(0)
-#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin)
-#define GTP_GPIO_OUTPUT(pin,level) gpio_direction_output(pin,level)
-#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label)
-#define GTP_GPIO_FREE(pin) gpio_free(pin)
-#define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH}
-
-// STEP_3(optional): Specify your special config info if needed
+/* STEP_3(optional): Specify your special config info if needed */
+#define GTP_IRQ_TAB_RISING 0
+#define GTP_IRQ_TAB_FALLING 1
#if GTP_CUSTOM_CFG
- #define GTP_MAX_HEIGHT 800
- #define GTP_MAX_WIDTH 480
- #define GTP_INT_TRIGGER 0 // 0: Rising 1: Falling
+#define GTP_MAX_HEIGHT 800
+#define GTP_MAX_WIDTH 480
+#define GTP_INT_TRIGGER GTP_IRQ_TAB_RISING
#else
- #define GTP_MAX_HEIGHT 4096
- #define GTP_MAX_WIDTH 4096
- #define GTP_INT_TRIGGER 1
+#define GTP_MAX_HEIGHT 4096
+#define GTP_MAX_WIDTH 4096
+#define GTP_INT_TRIGGER GTP_IRQ_TAB_FALLING
#endif
+
#define GTP_MAX_TOUCH 5
-#define GTP_ESD_CHECK_CIRCLE 2000 // jiffy: ms
+#define GTP_ESD_CHECK_CIRCLE 2000 /* jiffy: ms */
-// STEP_4(optional): If keys are available and reported as keys, config your key info here
-#if GTP_HAVE_TOUCH_KEY
- #define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK}
+/***************************PART3:OTHER define*********************************/
+#define GTP_DRIVER_VERSION "V1.8<2013/06/08>"
+#define GTP_I2C_NAME "Goodix-TS"
+#define GTP_POLL_TIME 10 /* jiffy: ms*/
+#define GTP_ADDR_LENGTH 2
+#define GTP_CONFIG_MIN_LENGTH 186
+#define GTP_CONFIG_MAX_LENGTH 240
+#define FAIL 0
+#define SUCCESS 1
+#define SWITCH_OFF 0
+#define SWITCH_ON 1
+
+/* Registers define */
+#define GTP_READ_COOR_ADDR 0x814E
+#define GTP_REG_SLEEP 0x8040
+#define GTP_REG_SENSOR_ID 0x814A
+#define GTP_REG_CONFIG_DATA 0x8047
+#define GTP_REG_VERSION 0x8140
+
+#define RESOLUTION_LOC 3
+#define TRIGGER_LOC 8
+
+#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+/* Log define */
+#define GTP_DEBUG(fmt, arg...) do {\
+ if (GTP_DEBUG_ON) {\
+ pr_debug("<<-GTP-DEBUG->> [%d]"fmt"\n",\
+ __LINE__, ##arg); } \
+ } while (0)
+
+#define GTP_DEBUG_ARRAY(array, num) do {\
+ s32 i; \
+ u8 *a = array; \
+ if (GTP_DEBUG_ARRAY_ON) {\
+ pr_debug("<<-GTP-DEBUG-ARRAY->>\n");\
+ for (i = 0; i < (num); i++) { \
+ pr_debug("%02x ", (a)[i]);\
+ if ((i + 1) % 10 == 0) { \
+ pr_debug("\n");\
+ } \
+ } \
+ pr_debug("\n");\
+ } \
+ } while (0)
+
+#define GTP_DEBUG_FUNC() do {\
+ if (GTP_DEBUG_FUNC_ON)\
+ pr_debug("<<-GTP-FUNC->> Func:%s@Line:%d\n",\
+ __func__, __LINE__);\
+ } while (0)
+
+#define GTP_SWAP(x, y) do {\
+ typeof(x) z = x;\
+ x = y;\
+ y = z;\
+ } while (0)
+/*****************************End of Part III********************************/
+
+void gtp_esd_switch(struct i2c_client *client, int on);
+
+#if GTP_CREATE_WR_NODE
+extern s32 init_wr_node(struct i2c_client *client);
+extern void uninit_wr_node(void);
#endif
-//***************************PART3:OTHER define*********************************
-#define GTP_DRIVER_VERSION "V1.8<2013/06/08>"
-#define GTP_I2C_NAME "Goodix-TS"
-#define GTP_POLL_TIME 10 // jiffy: ms
-#define GTP_ADDR_LENGTH 2
-#define GTP_CONFIG_MIN_LENGTH 186
-#define GTP_CONFIG_MAX_LENGTH 240
-#define FAIL 0
-#define SUCCESS 1
-#define SWITCH_OFF 0
-#define SWITCH_ON 1
-
-// Registers define
-#define GTP_READ_COOR_ADDR 0x814E
-#define GTP_REG_SLEEP 0x8040
-#define GTP_REG_SENSOR_ID 0x814A
-#define GTP_REG_CONFIG_DATA 0x8047
-#define GTP_REG_VERSION 0x8140
-
-#define RESOLUTION_LOC 3
-#define TRIGGER_LOC 8
-
-#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
-// Log define
-#define GTP_INFO(fmt,arg...) printk("<<-GTP-INFO->> "fmt"\n",##arg)
-#define GTP_ERROR(fmt,arg...) printk("<<-GTP-ERROR->> "fmt"\n",##arg)
-#define GTP_DEBUG(fmt,arg...) do{\
- if(GTP_DEBUG_ON)\
- printk("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
- }while(0)
-#define GTP_DEBUG_ARRAY(array, num) do{\
- s32 i;\
- u8* a = array;\
- if(GTP_DEBUG_ARRAY_ON)\
- {\
- printk("<<-GTP-DEBUG-ARRAY->>\n");\
- for (i = 0; i < (num); i++)\
- {\
- printk("%02x ", (a)[i]);\
- if ((i + 1 ) %10 == 0)\
- {\
- printk("\n");\
- }\
- }\
- printk("\n");\
- }\
- }while(0)
-#define GTP_DEBUG_FUNC() do{\
- if(GTP_DEBUG_FUNC_ON)\
- printk("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
- }while(0)
-#define GTP_SWAP(x, y) do{\
- typeof(x) z = x;\
- x = y;\
- y = z;\
- }while (0)
-
-//*****************************End of Part III********************************
-
+#if GTP_AUTO_UPDATE
+extern u8 gup_init_update_proc(struct goodix_ts_data *ts);
+#endif
#endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
index 3998bf0..81e3aff 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
@@ -1,6 +1,6 @@
-// make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
-// define your own firmware array here
-const unsigned char header_fw_array[] =
-{
-
-};
\ No newline at end of file
+/*
+ * make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
+ * define your own firmware array here
+*/
+const unsigned char header_fw_array[] = {
+};
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
index f564a6b..cf83154 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -1,21 +1,22 @@
/* drivers/input/touchscreen/gt9xx_update.c
- *
+ *
* 2010 - 2012 Goodix Technology.
- *
+ * 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be a reference
- * to you, when you are integrating the GOODiX's CTP IC into your system,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
- *
+ *
* Latest Version:1.6
* Author: andrew@goodix.com
- * Revision Record:
+ * Revision Record:
* V1.0:
* first release. By Andrew, 2012/08/31
* V1.2:
@@ -25,7 +26,7 @@
* 2. modify enter_update_mode;
* 3. add update file cal checksum.
* By Andrew, 2012/12/12
- * V1.6:
+ * V1.6:
* 1. replace guitar_client with i2c_connect_client;
* 2. support firmware header array update.
* By Meta, 2013/03/11
@@ -47,8 +48,8 @@
#define UPDATE_FILE_PATH_2 "/data/_goodix_update_.bin"
#define UPDATE_FILE_PATH_1 "/sdcard/_goodix_update_.bin"
-#define CONFIG_FILE_PATH_1 "/data/_goodix_config_.cfg"
-#define CONFIG_FILE_PATH_2 "/sdcard/_goodix_config_.cfg"
+#define CONFIG_FILE_PATH_1 "/data/_goodix_config_.cfg"
+#define CONFIG_FILE_PATH_2 "/sdcard/_goodix_config_.cfg"
#define FW_HEAD_LENGTH 14
#define FW_SECTION_LENGTH 0x2000
@@ -73,39 +74,27 @@
#define SUCCESS 1
#pragma pack(1)
-typedef struct
-{
- u8 hw_info[4]; //hardware info//
- u8 pid[8]; //product id //
- u16 vid; //version id //
-}st_fw_head;
+struct {
+ u8 hw_info[4]; /* hardware info */
+ u8 pid[8]; /* product id */
+ u16 vid; /* version id */
+} st_fw_head;
#pragma pack()
-typedef struct
-{
- u8 force_update;
- u8 fw_flag;
- struct file *file;
- struct file *cfg_file;
- st_fw_head ic_fw_msg;
- mm_segment_t old_fs;
-}st_update_msg;
+struct {
+ u8 force_update;
+ u8 fw_flag;
+ struct file *file;
+ struct file *cfg_file;
+ st_fw_head ic_fw_msg;
+ mm_segment_t old_fs;
+} st_update_msg;
st_update_msg update_msg;
u16 show_len;
u16 total_len;
-u8 got_file_flag = 0;
-u8 searching_file = 0;
-extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
-extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
-extern s32 gtp_send_cfg(struct i2c_client *client);
-extern struct i2c_client * i2c_connect_client;
-extern void gtp_irq_enable(struct goodix_ts_data *ts);
-extern void gtp_irq_disable(struct goodix_ts_data *ts);
-extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int);
-#if GTP_ESD_PROTECT
-extern void gtp_esd_switch(struct i2c_client *, s32);
-#endif
+u8 got_file_flag;
+u8 searching_file;
/*******************************************************
Function:
Read data from the i2c slave device.
@@ -115,37 +104,37 @@
buf[2~len-1]: read data buffer.
len: GTP_ADDR_LENGTH + read bytes count
Output:
- numbers of i2c_msgs to transfer:
+ numbers of i2c_msgs to transfer:
2: succeed, otherwise: failed
*********************************************************/
s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
{
- struct i2c_msg msgs[2];
- s32 ret=-1;
- s32 retries = 0;
+ struct i2c_msg msgs[2];
+ s32 ret = -1;
+ s32 retries = 0;
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- msgs[0].flags = !I2C_M_RD;
- msgs[0].addr = client->addr;
- msgs[0].len = GTP_ADDR_LENGTH;
- msgs[0].buf = &buf[0];
- //msgs[0].scl_rate = 300 * 1000; // for Rockchip
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = client->addr;
+ msgs[0].len = GTP_ADDR_LENGTH;
+ msgs[0].buf = &buf[0];
+ /* msgs[0].scl_rate = 300 * 1000; (for Rockchip) */
- msgs[1].flags = I2C_M_RD;
- msgs[1].addr = client->addr;
- msgs[1].len = len - GTP_ADDR_LENGTH;
- msgs[1].buf = &buf[GTP_ADDR_LENGTH];
- //msgs[1].scl_rate = 300 * 1000;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = client->addr;
+ msgs[1].len = len - GTP_ADDR_LENGTH;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+ /* msgs[1].scl_rate = 300 * 1000; */
- while(retries < 5)
- {
- ret = i2c_transfer(client->adapter, msgs, 2);
- if(ret == 2)break;
- retries++;
- }
+ while (retries < 5) {
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret == 2)
+ break;
+ retries++;
+ }
- return ret;
+ return ret;
}
/*******************************************************
@@ -157,1774 +146,1632 @@
buf[2~len-1]: data buffer
len: GTP_ADDR_LENGTH + write bytes count
Output:
- numbers of i2c_msgs to transfer:
- 1: succeed, otherwise: failed
+ numbers of i2c_msgs to transfer:
+ 1: succeed, otherwise: failed
*********************************************************/
-s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+s32 gup_i2c_write(struct i2c_client *client, u8 *buf, s32 len)
{
- struct i2c_msg msg;
- s32 ret=-1;
- s32 retries = 0;
+ struct i2c_msg msg;
+ s32 ret = -1;
+ s32 retries = 0;
- GTP_DEBUG_FUNC();
+ GTP_DEBUG_FUNC();
- msg.flags = !I2C_M_RD;
- msg.addr = client->addr;
- msg.len = len;
- msg.buf = buf;
- //msg.scl_rate = 300 * 1000; // for Rockchip
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = len;
+ msg.buf = buf;
+ /* msg.scl_rate = 300 * 1000; (for Rockchip) */
- while(retries < 5)
- {
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret == 1)break;
- retries++;
- }
+ while (retries < 5) {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)
+ break;
+ retries++;
+ }
- return ret;
+ return ret;
}
static s32 gup_init_panel(struct goodix_ts_data *ts)
{
- s32 ret = 0;
- s32 i = 0;
- u8 check_sum = 0;
- u8 opr_buf[16];
- u8 sensor_id = 0;
+ s32 ret = 0;
+ s32 i = 0;
+ u8 check_sum = 0;
+ u8 opr_buf[16];
+ u8 sensor_id = 0;
- u8 cfg_info_group1[] = CTP_CFG_GROUP1;
- u8 cfg_info_group2[] = CTP_CFG_GROUP2;
- u8 cfg_info_group3[] = CTP_CFG_GROUP3;
- u8 cfg_info_group4[] = CTP_CFG_GROUP4;
- u8 cfg_info_group5[] = CTP_CFG_GROUP5;
- u8 cfg_info_group6[] = CTP_CFG_GROUP6;
- u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
- cfg_info_group4, cfg_info_group5, cfg_info_group6};
- u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
- CFG_GROUP_LEN(cfg_info_group2),
- CFG_GROUP_LEN(cfg_info_group3),
- CFG_GROUP_LEN(cfg_info_group4),
- CFG_GROUP_LEN(cfg_info_group5),
- CFG_GROUP_LEN(cfg_info_group6)};
-
- if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
- (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
- (!cfg_info_len[5]))
- {
- sensor_id = 0;
- }
- else
- {
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
- if (SUCCESS == ret)
- {
- if (sensor_id >= 0x06)
- {
- GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
- return -1;
- }
- }
- else
- {
- GTP_ERROR("Failed to get sensor_id, No config sent!");
- return -1;
- }
- }
-
- GTP_DEBUG("Sensor_ID: %d", sensor_id);
-
- ts->gtp_cfg_len = cfg_info_len[sensor_id];
-
- if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
- {
- GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
- return -1;
- }
-
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
-
- if (ret == SUCCESS)
- {
- GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version: %d", sensor_id+1,
- send_cfg_buf[sensor_id][0], opr_buf[0]);
-
- send_cfg_buf[sensor_id][0] = opr_buf[0];
- ts->fixed_cfg = 0;
- /*
- if (opr_buf[0] < 90)
- {
- grp_cfg_version = send_cfg_buf[sensor_id][0]; // backup group config version
- send_cfg_buf[sensor_id][0] = 0x00;
- ts->fixed_cfg = 0;
- }
- else // treated as fixed config, not send config
- {
- GTP_INFO("Ic fixed config with config version(%d)", opr_buf[0]);
- ts->fixed_cfg = 1;
- }*/
- }
- else
- {
- GTP_ERROR("Failed to get ic config version!No config sent!");
- return -1;
- }
-
- memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
- memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+ u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+ u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+ u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+ u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+ u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+ u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+ u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+ cfg_info_group4, cfg_info_group5, cfg_info_group6};
+ u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+ CFG_GROUP_LEN(cfg_info_group2),
+ CFG_GROUP_LEN(cfg_info_group3),
+ CFG_GROUP_LEN(cfg_info_group4),
+ CFG_GROUP_LEN(cfg_info_group5),
+ CFG_GROUP_LEN(cfg_info_group6)};
- GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
- ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+ if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+ (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+ (!cfg_info_len[5])) {
+ sensor_id = 0;
+ } else {
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+ &sensor_id, 1);
+ if (SUCCESS == ret) {
+ if (sensor_id >= 0x06) {
+ GTP_ERROR("Invalid sensor_id(0x%02X), " \
+ "No Config Sent!", sensor_id);
+ return -EINVAL;
+ }
+ } else {
+ GTP_ERROR("Failed to get sensor_id, No config sent!");
+ return -EINVAL;
+ }
+ }
- config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH;
- config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
- config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
- config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
-
- if (GTP_INT_TRIGGER == 0) //RISING
- {
- config[TRIGGER_LOC] &= 0xfe;
- }
- else if (GTP_INT_TRIGGER == 1) //FALLING
- {
- config[TRIGGER_LOC] |= 0x01;
- }
-
- check_sum = 0;
- for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
- {
- check_sum += config[i];
- }
- config[ts->gtp_cfg_len] = (~check_sum) + 1;
+ GTP_DEBUG("Sensor_ID: %d", sensor_id);
- GTP_DEBUG_FUNC();
- ret = gtp_send_cfg(ts->client);
- if (ret < 0)
- {
- GTP_ERROR("Send config error.");
- }
+ ts->gtp_cfg_len = cfg_info_len[sensor_id];
- msleep(10);
- return 0;
+ if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+ GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG" \
+ " GROUP! NO Config Sent! You need to check you header" \
+ " file CFG_GROUP section!", sensor_id);
+ return -EINVAL;
+ }
+
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+ &opr_buf[0], 1);
+
+ if (ret == SUCCESS) {
+ GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version:" \
+ " %d", sensor_id+1, send_cfg_buf[sensor_id][0], opr_buf[0]);
+
+ send_cfg_buf[sensor_id][0] = opr_buf[0];
+ ts->fixed_cfg = 0;
+ /*
+ if (opr_buf[0] < 90) {
+ grp_cfg_version = send_cfg_buf[sensor_id][0];
+ *** backup group config version ***
+ send_cfg_buf[sensor_id][0] = 0x00;
+ ts->fixed_cfg = 0;
+ } else { *** treated as fixed config, not send config ***
+ GTP_INFO("Ic fixed config with config version(%d)",
+ opr_buf[0]);
+ ts->fixed_cfg = 1;
+ }*/
+ } else {
+ GTP_ERROR("Failed to get ic config version!No config sent!");
+ return -EINVAL;
+ }
+
+ memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+ memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+ ts->gtp_cfg_len);
+
+ GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+ ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+
+ config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH;
+ config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+ config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+ config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+
+ if (GTP_INT_TRIGGER == 0) /* RISING */
+ config[TRIGGER_LOC] &= 0xfe;
+ else if (GTP_INT_TRIGGER == 1) /* FALLING */
+ config[TRIGGER_LOC] |= 0x01;
+
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+ check_sum += config[i];
+
+ config[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+ GTP_DEBUG_FUNC();
+ ret = gtp_send_cfg(ts->client);
+ if (ret < 0)
+ GTP_ERROR("Send config error.");
+
+ msleep(20);
+ return 0;
}
-static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len)
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len)
{
- s32 i = 0;
+ s32 i = 0;
- msg[0] = (addr >> 8) & 0xff;
- msg[1] = addr & 0xff;
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
- for (i = 0; i < 5; i++)
- {
- if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
- {
- break;
- }
- }
+ for (i = 0; i < 5; i++)
+ if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+ break;
- if (i >= 5)
- {
- GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
- return FAIL;
- }
+ if (i >= 5) {
+ GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+ return FAIL;
+ }
- return SUCCESS;
+ return SUCCESS;
}
static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
{
- s32 i = 0;
- u8 msg[3];
+ s32 i = 0;
+ u8 msg[3];
- msg[0] = (addr >> 8) & 0xff;
- msg[1] = addr & 0xff;
- msg[2] = val;
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
+ msg[2] = val;
- for (i = 0; i < 5; i++)
- {
- if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
- {
- break;
- }
- }
+ for (i = 0; i < 5; i++)
+ if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+ break;
- if (i >= 5)
- {
- GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
- return FAIL;
- }
+ if (i >= 5) {
+ GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+ return FAIL;
+ }
- return SUCCESS;
+ return SUCCESS;
}
static u8 gup_get_ic_fw_msg(struct i2c_client *client)
{
- s32 ret = -1;
- u8 retry = 0;
- u8 buf[16];
- u8 i;
-
- // step1:get hardware info
- ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, &buf[GTP_ADDR_LENGTH], 4);
- if (FAIL == ret)
- {
- GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
- return FAIL;
- }
-
- // buf[2~5]: 00 06 90 00
- // hw_info: 00 90 06 00
- for(i=0; i<4; i++)
- {
- update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
- }
- GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
- update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
- // step2:get firmware message
- for(retry=0; retry<2; retry++)
- {
- ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
- if(FAIL == ret)
- {
- GTP_ERROR("Read firmware message fail.");
- return ret;
- }
-
- update_msg.force_update = buf[GTP_ADDR_LENGTH];
- if((0xBE != update_msg.force_update)&&(!retry))
- {
- GTP_INFO("The check sum in ic is error.");
- GTP_INFO("The IC will be updated by force.");
- continue;
- }
- break;
- }
- GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
-
- // step3:get pid & vid
- ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, &buf[GTP_ADDR_LENGTH], 6);
- if (FAIL == ret)
- {
- GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
- return FAIL;
- }
-
- memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
- memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
- GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
-
- //GT9XX PID MAPPING
- /*|-----FLASH-----RAM-----|
- |------918------918-----|
- |------968------968-----|
- |------913------913-----|
- |------913P-----913P----|
- |------927------927-----|
- |------927P-----927P----|
- |------9110-----9110----|
- |------9110P----9111----|*/
- if(update_msg.ic_fw_msg.pid[0] != 0)
- {
- if(!memcmp(update_msg.ic_fw_msg.pid, "9111", 4))
- {
- GTP_DEBUG("IC Mapping Product id:%s", update_msg.ic_fw_msg.pid);
- memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
- }
- }
-
- update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH+4] + (buf[GTP_ADDR_LENGTH+5]<<8);
- GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
-
- return SUCCESS;
+ s32 ret = -1;
+ u8 retry = 0;
+ u8 buf[16];
+ u8 i;
+
+ /* step1:get hardware info */
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO,
+ &buf[GTP_ADDR_LENGTH], 4);
+ if (ret == FAIL) {
+ GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
+ return FAIL;
+ }
+
+ /* buf[2~5]: 00 06 90 00 */
+ /* hw_info: 00 90 06 00 */
+ for (i = 0; i < 4; i++)
+ update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+
+ GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x",
+ update_msg.ic_fw_msg.hw_info[0],
+ update_msg.ic_fw_msg.hw_info[1],
+ update_msg.ic_fw_msg.hw_info[2],
+ update_msg.ic_fw_msg.hw_info[3]);
+
+ /* step2:get firmware message */
+ for (retry = 0; retry < 2; retry++) {
+ ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+ if (ret == FAIL) {
+ GTP_ERROR("Read firmware message fail.");
+ return ret;
+ }
+
+ update_msg.force_update = buf[GTP_ADDR_LENGTH];
+ if ((0xBE != update_msg.force_update) && (!retry)) {
+ GTP_INFO("The check sum in ic is error.");
+ GTP_INFO("The IC will be updated by force.");
+ continue;
+ }
+ break;
+ }
+ GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
+
+ /* step3:get pid & vid */
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID,
+ &buf[GTP_ADDR_LENGTH], 6);
+ if (FAIL == ret) {
+ GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
+ return FAIL;
+ }
+
+ memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+ memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+ GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
+
+ /* GT9XX PID MAPPING
+ |-----FLASH-----RAM-----|
+ |------918------918-----|
+ |------968------968-----|
+ |------913------913-----|
+ |------913P-----913P----|
+ |------927------927-----|
+ |------927P-----927P----|
+ |------9110-----9110----|
+ |------9110P----9111----|*/
+ if (update_msg.ic_fw_msg.pid[0] != 0) {
+ if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) {
+ GTP_DEBUG("IC Mapping Product id:%s",
+ update_msg.ic_fw_msg.pid);
+ memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+ }
+ }
+
+ update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] +
+ (buf[GTP_ADDR_LENGTH + 5] << 8);
+ GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
+
+ return SUCCESS;
}
s32 gup_enter_update_mode(struct i2c_client *client)
{
- s32 ret = -1;
- s32 retry = 0;
- u8 rd_buf[3];
-
- //step1:RST output low last at least 2ms
- GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
- msleep(2);
-
- //step2:select I2C slave addr,INT:0--0xBA;1--0x28.
- GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
- msleep(2);
-
- //step3:RST output high reset guitar
- GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
-
- //20121211 modify start
- msleep(5);
- while(retry++ < 200)
- {
- //step4:Hold ss51 & dsp
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
- continue;
- }
-
- //step5:Confirm hold
- ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
- continue;
- }
- if(0x0C == rd_buf[GTP_ADDR_LENGTH])
- {
- GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
- break;
- }
- GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d", rd_buf[GTP_ADDR_LENGTH]);
- }
- if(retry >= 200)
- {
- GTP_ERROR("Enter update Hold ss51 failed.");
- return FAIL;
- }
-
- //step6:DSP_CK and DSP_ALU_CK PowerOn
- ret = gup_set_ic_msg(client, 0x4010, 0x00);
-
- //20121211 modify end
- return ret;
+ s32 ret = -1;
+ s32 retry = 0;
+ u8 rd_buf[3];
+
+ /* step1:RST output low last at least 2ms */
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
+ msleep(20);
+
+ /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
+ msleep(20);
+
+ /* step3:RST output high reset guitar */
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+
+ /* 20121211 modify start */
+ msleep(20);
+ while (retry++ < 200) {
+ /* step4:Hold ss51 & dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+ continue;
+ }
+
+ /* step5:Confirm hold */
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+ continue;
+ }
+ if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) {
+ GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
+ break;
+ }
+ GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d",
+ rd_buf[GTP_ADDR_LENGTH]);
+ }
+ if (retry >= 200) {
+ GTP_ERROR("Enter update Hold ss51 failed.");
+ return FAIL;
+ }
+
+ /* step6:DSP_CK and DSP_ALU_CK PowerOn */
+ ret = gup_set_ic_msg(client, 0x4010, 0x00);
+
+ /* 20121211 modify end */
+ return ret;
}
void gup_leave_update_mode(void)
{
- GTP_GPIO_AS_INT(GTP_INT_PORT);
-
- GTP_DEBUG("[leave_update_mode]reset chip.");
- gtp_reset_guitar(i2c_connect_client, 20);
+ GTP_GPIO_AS_INT(GTP_INT_PORT);
+
+ GTP_DEBUG("[leave_update_mode]reset chip.");
+ gtp_reset_guitar(i2c_connect_client, 20);
}
-// Get the correct nvram data
-// The correct conditions:
-// 1. the hardware info is the same
-// 2. the product id is the same
-// 3. the firmware version in update file is greater than the firmware version in ic
-// or the check sum in ic is wrong
-/* Update Conditions:
- 1. Same hardware info
- 2. Same PID
- 3. File PID > IC PID
- Force Update Conditions:
- 1. Wrong ic firmware checksum
- 2. INVALID IC PID or VID
- 3. IC PID == 91XX || File PID == 91XX
+/* Get the correct nvram data
+ The correct conditions:
+ 1. the hardware info is the same
+ 2. the product id is the same
+ 3. the firmware version in update file is greater than the firmware
+ version in ic or the check sum in ic is wrong
+
+ Update Conditions:
+ 1. Same hardware info
+ 2. Same PID
+ 3. File PID > IC PID
+
+ Force Update Conditions:
+ 1. Wrong ic firmware checksum
+ 2. INVALID IC PID or VID
+ 3. IC PID == 91XX || File PID == 91XX
*/
static u8 gup_enter_update_judge(st_fw_head *fw_head)
{
- u16 u16_tmp;
- s32 i = 0;
-
- u16_tmp = fw_head->vid;
- fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+ u16 u16_tmp;
+ s32 i = 0;
- GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
- GTP_DEBUG("FILE PID:%s", fw_head->pid);
- GTP_DEBUG("FILE VID:%04x", fw_head->vid);
+ u16_tmp = fw_head->vid;
+ fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
- GTP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
- update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
- GTP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
- GTP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
+ GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0],
+ fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
+ TP_DEBUG("FILE PID:%s", fw_head->pid);
+ TP_DEBUG("FILE VID:%04x", fw_head->vid);
- //First two conditions
- if ( !memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, sizeof(update_msg.ic_fw_msg.hw_info)))
- {
- GTP_DEBUG("Get the same hardware info.");
- if( update_msg.force_update != 0xBE )
- {
- GTP_INFO("FW chksum error,need enter update.");
- return SUCCESS;
- }
-
- // 20130523 start
- if (strlen(update_msg.ic_fw_msg.pid) < 3)
- {
- GTP_INFO("Illegal IC pid, need enter update");
- return SUCCESS;
- }
- else
- {
- for (i = 0; i < 3; i++)
- {
- if ((update_msg.ic_fw_msg.pid[i] < 0x30) || (update_msg.ic_fw_msg.pid[i] > 0x39))
- {
- GTP_INFO("Illegal IC pid, out of bound, need enter update");
- return SUCCESS;
- }
- }
- }
- // 20130523 end
-
-
- if (( !memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, (strlen(fw_head->pid)<3?3:strlen(fw_head->pid))))||
- (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4))||
- (!memcmp(fw_head->pid, "91XX", 4)))
- {
- if(!memcmp(fw_head->pid, "91XX", 4))
- {
- GTP_DEBUG("Force none same pid update mode.");
- }
- else
- {
- GTP_DEBUG("Get the same pid.");
- }
- //The third condition
- if (fw_head->vid > update_msg.ic_fw_msg.vid)
- {
+ TP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x",
+ update_msg.ic_fw_msg.hw_info[0],
+ update_msg.ic_fw_msg.hw_info[1],
+ update_msg.ic_fw_msg.hw_info[2],
+ update_msg.ic_fw_msg.hw_info[3]);
+ TP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
+ TP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
- GTP_INFO("Need enter update.");
- return SUCCESS;
- }
- GTP_ERROR("Don't meet the third condition.");
- GTP_ERROR("File VID <= Ic VID, update aborted!");
- }
- else
- {
- GTP_ERROR("File PID != Ic PID, update aborted!");
- }
- }
- else
- {
- GTP_ERROR("Different Hardware, update aborted!");
- }
- return FAIL;
+ /* First two conditions */
+ if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info,
+ sizeof(update_msg.ic_fw_msg.hw_info))) {
+ GTP_DEBUG("Get the same hardware info.");
+ if (update_msg.force_update != 0xBE) {
+ GTP_INFO("FW chksum error,need enter update.");
+ return SUCCESS;
+ }
+
+ /* 20130523 start */
+ if (strlen(update_msg.ic_fw_msg.pid) < 3) {
+ GTP_INFO("Illegal IC pid, need enter update");
+ return SUCCESS;
+ } else {
+ for (i = 0; i < 3; i++) {
+ if ((update_msg.ic_fw_msg.pid[i] < 0x30) ||
+ (update_msg.ic_fw_msg.pid[i] > 0x39)) {
+ GTP_INFO("Illegal IC pid, out of " \
+ "bound, need enter update");
+ return SUCCESS;
+ }
+ }
+ }
+ /* 20130523 end */
+
+ if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid,
+ (strlen(fw_head->pid) < 3 ? 3 : strlen(fw_head->pid)))) ||
+ (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) ||
+ (!memcmp(fw_head->pid, "91XX", 4))) {
+ if (!memcmp(fw_head->pid, "91XX", 4))
+ GTP_DEBUG("Force none same pid update mode.");
+ else
+ GTP_DEBUG("Get the same pid.");
+
+ /* The third condition */
+ if (fw_head->vid > update_msg.ic_fw_msg.vid) {
+ GTP_INFO("Need enter update.");
+ return SUCCESS;
+ }
+ GTP_ERROR("Don't meet the third condition.");
+ GTP_ERROR("File VID <= Ic VID, update aborted!");
+ } else {
+ GTP_ERROR("File PID != Ic PID, update aborted!");
+ }
+ } else {
+ GTP_ERROR("Different Hardware, update aborted!");
+ }
+
+ return FAIL;
}
static u8 ascii2hex(u8 a)
{
- s8 value = 0;
+ s8 value = 0;
- if(a >= '0' && a <= '9')
- {
- value = a - '0';
- }
- else if(a >= 'A' && a <= 'F')
- {
- value = a - 'A' + 0x0A;
- }
- else if(a >= 'a' && a <= 'f')
- {
- value = a - 'a' + 0x0A;
- }
- else
- {
- value = 0xff;
- }
-
- return value;
+ if (a >= '0' && a <= '9')
+ value = a - '0';
+ else if (a >= 'A' && a <= 'F')
+ value = a - 'A' + 0x0A;
+ else if (a >= 'a' && a <= 'f')
+ value = a - 'a' + 0x0A;
+ else
+ value = 0xff;
+
+ return value;
}
static s8 gup_update_config(struct i2c_client *client)
{
- s32 file_len = 0;
- s32 ret = 0;
- s32 i = 0;
- s32 file_cfg_len = 0;
- s32 chip_cfg_len = 0;
- s32 count = 0;
- u8 *buf;
- u8 *pre_buf;
- u8 *file_config;
- //u8 checksum = 0;
- u8 pid[8];
-
- if(NULL == update_msg.cfg_file)
- {
- GTP_ERROR("[update_cfg]No need to upgrade config!");
- return FAIL;
- }
- file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_END);
-
- ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_cfg]Read product id & version id fail.");
- return FAIL;
- }
- pid[5] = '\0';
- GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
-
- chip_cfg_len = 186;
- if(!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
- !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
- !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3))
- {
- chip_cfg_len = 228;
- }
- GTP_DEBUG("[update_cfg]config file len:%d", file_len);
- GTP_DEBUG("[update_cfg]need config len:%d",chip_cfg_len);
- if((file_len+5) < chip_cfg_len*5)
- {
- GTP_ERROR("Config length error");
- return -1;
- }
-
- buf = (u8*)kzalloc(file_len, GFP_KERNEL);
- pre_buf = (u8*)kzalloc(file_len, GFP_KERNEL);
- file_config = (u8*)kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
- update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
-
- GTP_DEBUG("[update_cfg]Read config from file.");
- ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file, (char*)pre_buf, file_len, &update_msg.cfg_file->f_pos);
- if(ret<0)
- {
- GTP_ERROR("[update_cfg]Read config file failed.");
- goto update_cfg_file_failed;
- }
-
- GTP_DEBUG("[update_cfg]Delete illgal charactor.");
- for(i=0,count=0; i<file_len; i++)
- {
- if (pre_buf[i] == ' ' || pre_buf[i] == '\r' || pre_buf[i] == '\n')
- {
- continue;
- }
- buf[count++] = pre_buf[i];
- }
-
- GTP_DEBUG("[update_cfg]Ascii to hex.");
- file_config[0] = GTP_REG_CONFIG_DATA >> 8;
- file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
- for(i=0,file_cfg_len=GTP_ADDR_LENGTH; i<count; i+=5)
- {
- if((buf[i]=='0') && ((buf[i+1]=='x') || (buf[i+1]=='X')))
- {
- u8 high,low;
- high = ascii2hex(buf[i+2]);
- low = ascii2hex(buf[i+3]);
-
- if((high == 0xFF) || (low == 0xFF))
- {
- ret = 0;
- GTP_ERROR("[update_cfg]Illegal config file.");
- goto update_cfg_file_failed;
- }
- file_config[file_cfg_len++] = (high<<4) + low;
- }
- else
- {
- ret = 0;
- GTP_ERROR("[update_cfg]Illegal config file.");
- goto update_cfg_file_failed;
- }
- }
-
-// //cal checksum
-// for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
-// {
-// checksum += file_config[i];
-// }
-// file_config[chip_cfg_len] = (~checksum) + 1;
-// file_config[chip_cfg_len+1] = 0x01;
-
- GTP_DEBUG("config:");
- GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
-
- i = 0;
- while(i++ < 5)
- {
- ret = gup_i2c_write(client, file_config, file_cfg_len);
- if(ret > 0)
- {
- GTP_INFO("[update_cfg]Send config SUCCESS.");
- break;
- }
- GTP_ERROR("[update_cfg]Send config i2c error.");
- }
-
+ s32 file_len = 0;
+ s32 ret = 0;
+ s32 i = 0;
+ s32 file_cfg_len = 0;
+ s32 chip_cfg_len = 0;
+ s32 count = 0;
+ u8 *buf;
+ u8 *pre_buf;
+ u8 *file_config;
+ /* u8 checksum = 0; */
+ u8 pid[8];
+
+ if (update_msg.cfg_file == NULL) {
+ GTP_ERROR("[update_cfg]No need to upgrade config!");
+ return FAIL;
+ }
+ file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file,
+ 0, SEEK_END);
+
+ ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_cfg]Read product id & version id fail.");
+ return FAIL;
+ }
+ pid[5] = '\0';
+ GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
+
+ chip_cfg_len = 186;
+ if (!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
+ !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
+ !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) {
+ chip_cfg_len = 228;
+ }
+ GTP_DEBUG("[update_cfg]config file len:%d", file_len);
+ GTP_DEBUG("[update_cfg]need config len:%d", chip_cfg_len);
+ if ((file_len+5) < chip_cfg_len*5) {
+ GTP_ERROR("Config length error");
+ return -EINVAL;
+ }
+
+ buf = kzalloc(file_len, GFP_KERNEL);
+ pre_buf = kzalloc(file_len, GFP_KERNEL);
+ file_config = kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
+ update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
+
+ GTP_DEBUG("[update_cfg]Read config from file.");
+ ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file,
+ (char *)pre_buf, file_len, &update_msg.cfg_file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("[update_cfg]Read config file failed.");
+ goto update_cfg_file_failed;
+ }
+
+ GTP_DEBUG("[update_cfg]Delete illgal charactor.");
+ for (i = 0, count = 0; i < file_len; i++) {
+ if (pre_buf[i] == ' ' || pre_buf[i] == '\r'
+ || pre_buf[i] == '\n')
+ continue;
+ buf[count++] = pre_buf[i];
+ }
+
+ GTP_DEBUG("[update_cfg]Ascii to hex.");
+ file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+ file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+ for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i + = 5) {
+ if ((buf[i] == '0') && ((buf[i+1] == 'x') ||
+ (buf[i+1] == 'X'))) {
+ u8 high, low;
+ high = ascii2hex(buf[i+2]);
+ low = ascii2hex(buf[i+3]);
+
+ if ((high == 0xFF) || (low == 0xFF)) {
+ ret = 0;
+ GTP_ERROR("[update_cfg]Illegal config file.");
+ goto update_cfg_file_failed;
+ }
+ file_config[file_cfg_len++] = (high<<4) + low;
+ } else {
+ ret = 0;
+ GTP_ERROR("[update_cfg]Illegal config file.");
+ goto update_cfg_file_failed;
+ }
+ }
+
+ /* cal checksum */
+ /* for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
+ checksum += file_config[i];
+ file_config[chip_cfg_len] = (~checksum) + 1;
+ file_config[chip_cfg_len+1] = 0x01; */
+
+ GTP_DEBUG("config:");
+ GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
+
+ i = 0;
+ while (i++ < 5) {
+ ret = gup_i2c_write(client, file_config, file_cfg_len);
+ if (ret > 0) {
+ GTP_INFO("[update_cfg]Send config SUCCESS.");
+ break;
+ }
+ GTP_ERROR("[update_cfg]Send config i2c error.");
+ }
+
update_cfg_file_failed:
- kfree(pre_buf);
- kfree(buf);
- kfree(file_config);
- return ret;
+ kfree(pre_buf);
+ kfree(buf);
+ kfree(file_config);
+ return ret;
}
#if GTP_HEADER_FW_UPDATE
static u8 gup_check_fs_mounted(char *path_name)
{
- struct path root_path;
- struct path path;
- int err;
- err = kern_path("/", LOOKUP_FOLLOW, &root_path);
+ struct path root_path;
+ struct path path;
+ int err;
+ err = kern_path("/", LOOKUP_FOLLOW, &root_path);
- if (err)
- {
- GTP_DEBUG("\"/\" NOT Mounted: %d", err);
- return FAIL;
- }
- err = kern_path(path_name, LOOKUP_FOLLOW, &path);
+ if (err) {
+ GTP_DEBUG("\"/\" NOT Mounted: %d", err);
+ return FAIL;
+ }
+ err = kern_path(path_name, LOOKUP_FOLLOW, &path);
- if (err)
- {
- GTP_DEBUG("/data/ NOT Mounted: %d", err);
- return FAIL;
- }
+ if (err) {
+ GTP_DEBUG("/data/ NOT Mounted: %d", err);
+ return FAIL;
+ }
- return SUCCESS;
-
- /*
- if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
- {
- //-- not mounted
- return FAIL;
- }
- else
- {
- return SUCCESS;
- }*/
+ return SUCCESS;
+ /* if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
+ return FAIL;
+ else
+ return SUCCESS; */
}
#endif
-static u8 gup_check_update_file(struct i2c_client *client, st_fw_head* fw_head, u8* path)
+
+static u8 gup_check_update_file(struct i2c_client *client, st_fw_head *fw_head,
+ u8 *path)
{
- s32 ret = 0;
- s32 i = 0;
- s32 fw_checksum = 0;
- u8 buf[FW_HEAD_LENGTH];
-
- if (path)
- {
- GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
- update_msg.file = filp_open(path, O_RDONLY, 0);
+ s32 ret = 0;
+ s32 i = 0;
+ s32 fw_checksum = 0;
+ u8 buf[FW_HEAD_LENGTH];
- if (IS_ERR(update_msg.file))
- {
- GTP_ERROR("Open update file(%s) error!", path);
- return FAIL;
- }
- }
- else
- {
+ if (path) {
+ GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
+ update_msg.file = file_open(path, O_RDONLY, 0);
+
+ if (IS_ERR(update_msg.file)) {
+ GTP_ERROR("Open update file(%s) error!", path);
+ return FAIL;
+ }
+ } else {
#if GTP_HEADER_FW_UPDATE
- for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++)
- {
- GTP_DEBUG("Waiting for /data mounted [%d]", i);
+ for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++) {
+ GTP_DEBUG("Waiting for /data mounted [%d]", i);
- if (gup_check_fs_mounted("/data") == SUCCESS)
- {
- GTP_DEBUG("/data Mounted!");
- break;
- }
- msleep(3000);
- }
- if (i >= (GUP_SEARCH_FILE_TIMES))
- {
- GTP_ERROR("Wait for /data mounted timeout!");
- return FAIL;
- }
-
- // update config
- update_msg.cfg_file = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0);
- if (IS_ERR(update_msg.cfg_file))
- {
- GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
- }
- else
- {
- GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
- ret = gup_update_config(client);
- if(ret <= 0)
- {
- GTP_ERROR("Update config failed.");
- }
- filp_close(update_msg.cfg_file, NULL);
- }
-
- if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH))
- {
- GTP_ERROR("INVALID header_fw_array, check your gt9xx_firmware.h file!");
- return FAIL;
- }
- update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_CREAT | O_RDWR, 0666);
- if ((IS_ERR(update_msg.file)))
- {
- GTP_ERROR("Failed to Create file: %s for fw_header!", UPDATE_FILE_PATH_2);
- return FAIL;
- }
- update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
- update_msg.file->f_op->write(update_msg.file, (char *)header_fw_array, sizeof(header_fw_array), &update_msg.file->f_pos);
- filp_close(update_msg.file, NULL);
- update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
+ if (gup_check_fs_mounted("/data") == SUCCESS) {
+ GTP_DEBUG("/data Mounted!");
+ break;
+ }
+ msleep(3000);
+ }
+ if (i >= (GUP_SEARCH_FILE_TIMES)) {
+ GTP_ERROR("Wait for /data mounted timeout!");
+ return FAIL;
+ }
+
+ /* update config */
+ update_msg.cfg_file = file_open(CONFIG_FILE_PATH_1,
+ O_RDONLY, 0);
+
+ if (IS_ERR(update_msg.cfg_file)) {
+ GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
+ } else {
+ GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
+ ret = gup_update_config(client);
+ if (ret <= 0)
+ GTP_ERROR("Update config failed.");
+ filp_close(update_msg.cfg_file, NULL);
+ }
+
+ if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH
+ *4 + FW_DSP_ISP_LENGTH+FW_DSP_LENGTH + FW_BOOT_LENGTH)) {
+ GTP_ERROR("INVALID header_fw_array, check your " \
+ "gt9xx_firmware.h file!");
+ return FAIL;
+ }
+ update_msg.file = file_open(UPDATE_FILE_PATH_2, O_CREAT |
+ O_RDWR, 0666);
+ if ((IS_ERR(update_msg.file))) {
+ GTP_ERROR("Failed to Create file: %s for fw_header!",
+ UPDATE_FILE_PATH_2);
+ return FAIL;
+ }
+ update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+ update_msg.file->f_op->write(update_msg.file,
+ (char *)header_fw_array, sizeof(header_fw_array),
+ &update_msg.file->f_pos);
+ file_close(update_msg.file, NULL);
+ update_msg.file = file_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
#else
- u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(UPDATE_FILE_PATH_2));
- u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1), sizeof(CONFIG_FILE_PATH_2));
- u8 *search_update_path = (u8*)kzalloc(fp_len, GFP_KERNEL);
- u8 *search_cfg_path = (u8*)kzalloc(cfp_len, GFP_KERNEL);
- //Begin to search update file,the config file & firmware file must be in the same path,single or double.
- searching_file = 1;
- for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++)
- {
- if (searching_file == 0)
- {
- kfree(search_update_path);
- kfree(search_cfg_path);
- GTP_INFO(".bin/.cfg update file search forcely terminated!");
- return FAIL;
- }
- if(i%2)
- {
- memcpy(search_update_path, UPDATE_FILE_PATH_1, sizeof(UPDATE_FILE_PATH_1));
- memcpy(search_cfg_path, CONFIG_FILE_PATH_1, sizeof(CONFIG_FILE_PATH_1));
- }
- else
- {
- memcpy(search_update_path, UPDATE_FILE_PATH_2, sizeof(UPDATE_FILE_PATH_2));
- memcpy(search_cfg_path, CONFIG_FILE_PATH_2, sizeof(CONFIG_FILE_PATH_2));
- }
-
- if(!(got_file_flag&0x0F))
- {
- update_msg.file = filp_open(search_update_path, O_RDONLY, 0);
- if(!IS_ERR(update_msg.file))
- {
- GTP_DEBUG("Find the bin file");
- got_file_flag |= 0x0F;
- }
- }
- if(!(got_file_flag&0xF0))
- {
- update_msg.cfg_file = filp_open(search_cfg_path, O_RDONLY, 0);
- if(!IS_ERR(update_msg.cfg_file))
- {
- GTP_DEBUG("Find the cfg file");
- got_file_flag |= 0xF0;
- }
- }
-
- if(got_file_flag)
- {
- if(got_file_flag == 0xFF)
- {
- break;
- }
- else
- {
- i += 4;
- }
- }
- GTP_DEBUG("%3d:Searching %s %s file...", i, (got_file_flag&0x0F)?"":"bin", (got_file_flag&0xF0)?"":"cfg");
- msleep(3000);
- }
- searching_file = 0;
- kfree(search_update_path);
- kfree(search_cfg_path);
-
- if(!got_file_flag)
- {
- GTP_ERROR("Can't find update file.");
- goto load_failed;
- }
-
- if(got_file_flag&0xF0)
- {
- GTP_DEBUG("Got the update config file.");
- ret = gup_update_config(client);
- if(ret <= 0)
- {
- GTP_ERROR("Update config failed.");
- }
- filp_close(update_msg.cfg_file, NULL);
- msleep(500); //waiting config to be stored in FLASH.
- }
- if(got_file_flag&0x0F)
- {
- GTP_DEBUG("Got the update firmware file.");
- }
- else
- {
- GTP_ERROR("No need to upgrade firmware.");
- goto load_failed;
- }
+ u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1),
+ sizeof(UPDATE_FILE_PATH_2));
+ u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1),
+ sizeof(CONFIG_FILE_PATH_2));
+ u8 *search_update_path = kzalloc(fp_len, GFP_KERNEL);
+ u8 *search_cfg_path = kzalloc(cfp_len, GFP_KERNEL);
+ /* Begin to search update file,the config file & firmware
+ file must be in the same path,single or double. */
+ searching_file = 1;
+ for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++) {
+ if (searching_file == 0) {
+ kfree(search_update_path);
+ kfree(search_cfg_path);
+ GTP_INFO(".bin/.cfg update file search " \
+ "forcely terminated!");
+ return FAIL;
+ }
+ if (i % 2) {
+ memcpy(search_update_path, UPDATE_FILE_PATH_1,
+ sizeof(UPDATE_FILE_PATH_1));
+ memcpy(search_cfg_path, CONFIG_FILE_PATH_1,
+ sizeof(CONFIG_FILE_PATH_1));
+ } else {
+ memcpy(search_update_path, UPDATE_FILE_PATH_2,
+ sizeof(UPDATE_FILE_PATH_2));
+ memcpy(search_cfg_path, CONFIG_FILE_PATH_2,
+ sizeof(CONFIG_FILE_PATH_2));
+ }
+
+ if (!(got_file_flag&0x0F)) {
+ update_msg.file = file_open(search_update_path,
+ O_RDONLY, 0);
+ if (!IS_ERR(update_msg.file)) {
+ GTP_DEBUG("Find the bin file");
+ got_file_flag |= 0x0F;
+ }
+ }
+ if (!(got_file_flag & 0xF0)) {
+ update_msg.cfg_file = file_open(search_cfg_path,
+ O_RDONLY, 0);
+ if (!IS_ERR(update_msg.cfg_file)) {
+ GTP_DEBUG("Find the cfg file");
+ got_file_flag |= 0xF0;
+ }
+ }
+
+ if (got_file_flag) {
+ if (got_file_flag == 0xFF)
+ break;
+ else
+ i += 4;
+ }
+ GTP_DEBUG("%3d:Searching %s %s file...", i,
+ (got_file_flag & 0x0F) ? "" : "bin",
+ (got_file_flag & 0xF0) ? "" : "cfg");
+
+ msleep(3000);
+ }
+
+ searching_file = 0;
+ kfree(search_update_path);
+ kfree(search_cfg_path);
+
+ if (!got_file_flag) {
+ GTP_ERROR("Can't find update file.");
+ goto load_failed;
+ }
+
+ if (got_file_flag & 0xF0) {
+ GTP_DEBUG("Got the update config file.");
+ ret = gup_update_config(client);
+ if (ret <= 0)
+ GTP_ERROR("Update config failed.");
+ filp_close(update_msg.cfg_file, NULL);
+ msleep(500); /* waiting config to be stored in FLASH. */
+ }
+ if (got_file_flag & 0x0F) {
+ GTP_DEBUG("Got the update firmware file.");
+ } else {
+ GTP_ERROR("No need to upgrade firmware.");
+ goto load_failed;
+ }
#endif
- }
-
- update_msg.old_fs = get_fs();
- set_fs(KERNEL_DS);
+ }
- update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
- //update_msg.file->f_pos = 0;
+ update_msg.old_fs = get_fs();
+ set_fs(KERNEL_DS);
- ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos);
- if (ret < 0)
- {
- GTP_ERROR("Read firmware head in update file error.");
- goto load_failed;
- }
- memcpy(fw_head, buf, FW_HEAD_LENGTH);
-
- //check firmware legality
- fw_checksum = 0;
- for(i=0; i<FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH; i+=2)
- {
- u16 temp;
- ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, 2, &update_msg.file->f_pos);
- if (ret < 0)
- {
- GTP_ERROR("Read firmware file error.");
- goto load_failed;
- }
- //GTP_DEBUG("BUF[0]:%x", buf[0]);
- temp = (buf[0]<<8) + buf[1];
- fw_checksum += temp;
- }
-
- GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
- if(fw_checksum&0xFFFF)
- {
- GTP_ERROR("Illegal firmware file.");
- goto load_failed;
- }
-
- return SUCCESS;
+ update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+ /* update_msg.file->f_pos = 0; */
+
+ ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+ FW_HEAD_LENGTH, &update_msg.file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("Read firmware head in update file error.");
+ goto load_failed;
+ }
+ memcpy(fw_head, buf, FW_HEAD_LENGTH);
+
+ /* check firmware legality */
+ fw_checksum = 0;
+ for (i = 0; i < FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH +
+ FW_DSP_LENGTH + FW_BOOT_LENGTH; i + = 2) {
+ u16 temp;
+ ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+ 2, &update_msg.file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("Read firmware file error.");
+ goto load_failed;
+ }
+ /* GTP_DEBUG("BUF[0]:%x", buf[0]); */
+ temp = (buf[0]<<8) + buf[1];
+ fw_checksum += temp;
+ }
+
+ GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
+ if (fw_checksum & 0xFFFF) {
+ GTP_ERROR("Illegal firmware file.");
+ goto load_failed;
+ }
+
+ return SUCCESS;
load_failed:
- set_fs(update_msg.old_fs);
- return FAIL;
+ set_fs(update_msg.old_fs);
+ return FAIL;
}
#if 0
-static u8 gup_check_update_header(struct i2c_client *client, st_fw_head* fw_head)
+static u8 gup_check_update_header(struct i2c_client *client,
+ st_fw_head *fw_head)
{
- const u8* pos;
- int i = 0;
- u8 mask_num = 0;
- s32 ret = 0;
+ const u8 *pos;
+ int i = 0;
+ u8 mask_num = 0;
+ s32 ret = 0;
- pos = HEADER_UPDATE_DATA;
-
- memcpy(fw_head, pos, FW_HEAD_LENGTH);
- pos += FW_HEAD_LENGTH;
+ pos = HEADER_UPDATE_DATA;
- ret = gup_enter_update_judge(fw_head);
- if(SUCCESS == ret)
- {
- return SUCCESS;
- }
- return FAIL;
+ memcpy(fw_head, pos, FW_HEAD_LENGTH);
+ pos += FW_HEAD_LENGTH;
+
+ ret = gup_enter_update_judge(fw_head);
+ if (SUCCESS == ret)
+ return SUCCESS;
+ return FAIL;
}
#endif
-static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, u16 total_length)
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr,
+ u16 total_length)
{
- s32 ret = 0;
- u16 burn_addr = start_addr;
- u16 frame_length = 0;
- u16 burn_length = 0;
- u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
- u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
- u8 retry = 0;
-
- GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024), start_addr);
- while(burn_length < total_length)
- {
- GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
- frame_length = ((total_length - burn_length) > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length);
- wr_buf[0] = (u8)(burn_addr>>8);
- rd_buf[0] = wr_buf[0];
- wr_buf[1] = (u8)burn_addr;
- rd_buf[1] = wr_buf[1];
- memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], frame_length);
-
- for(retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++)
- {
- ret = gup_i2c_write(client, wr_buf, GTP_ADDR_LENGTH + frame_length);
- if(ret <= 0)
- {
- GTP_ERROR("Write frame data i2c error.");
- continue;
- }
- ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + frame_length);
- if(ret <= 0)
- {
- GTP_ERROR("Read back frame data i2c error.");
- continue;
- }
-
- if(memcmp(&wr_buf[GTP_ADDR_LENGTH], &rd_buf[GTP_ADDR_LENGTH], frame_length))
- {
- GTP_ERROR("Check frame data fail,not equal.");
- GTP_DEBUG("write array:");
- GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], frame_length);
- GTP_DEBUG("read array:");
- GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
- continue;
- }
- else
- {
- //GTP_DEBUG("Check frame data success.");
- break;
- }
- }
- if(retry >= MAX_FRAME_CHECK_TIME)
- {
- GTP_ERROR("Burn frame data time out,exit.");
- return FAIL;
- }
- burn_length += frame_length;
- burn_addr += frame_length;
- }
- return SUCCESS;
+ s32 ret = 0;
+ u16 burn_addr = start_addr;
+ u16 frame_length = 0;
+ u16 burn_length = 0;
+ u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 retry = 0;
+
+ GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024),
+ start_addr);
+ while (burn_length < total_length) {
+ GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
+ frame_length = ((total_length - burn_length) > PACK_SIZE)
+ ? PACK_SIZE : (total_length - burn_length);
+ wr_buf[0] = (u8)(burn_addr>>8);
+ rd_buf[0] = wr_buf[0];
+ wr_buf[1] = (u8)burn_addr;
+ rd_buf[1] = wr_buf[1];
+ memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length],
+ frame_length);
+
+ for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) {
+ ret = gup_i2c_write(client, wr_buf,
+ GTP_ADDR_LENGTH + frame_length);
+ if (ret <= 0) {
+ GTP_ERROR("Write frame data i2c error.");
+ continue;
+ }
+ ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH +
+ frame_length);
+ if (ret <= 0) {
+ GTP_ERROR("Read back frame data i2c error.");
+ continue;
+ }
+
+ if (memcmp(&wr_buf[GTP_ADDR_LENGTH],
+ &rd_buf[GTP_ADDR_LENGTH], frame_length)) {
+ GTP_ERROR("Check frame data fail,not equal.");
+ GTP_DEBUG("write array:");
+ GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH],
+ frame_length);
+ GTP_DEBUG("read array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH],
+ frame_length);
+ continue;
+ } else {
+ /* GTP_DEBUG("Check frame data success."); */
+ break;
+ }
+ }
+ if (retry >= MAX_FRAME_CHECK_TIME) {
+ GTP_ERROR("Burn frame data time out,exit.");
+ return FAIL;
+ }
+ burn_length += frame_length;
+ burn_addr += frame_length;
+ }
+ return SUCCESS;
}
-static u8 gup_load_section_file(u8* buf, u16 offset, u16 length)
+static u8 gup_load_section_file(u8 *buf, u16 offset, u16 length)
{
- s32 ret = 0;
-
- if(update_msg.file == NULL)
- {
- GTP_ERROR("cannot find update file,load section file fail.");
- return FAIL;
- }
- update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
-
- ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, length, &update_msg.file->f_pos);
- if(ret < 0)
- {
- GTP_ERROR("Read update file fail.");
- return FAIL;
- }
-
- return SUCCESS;
+ s32 ret = 0;
+
+ if (update_msg.file == NULL) {
+ GTP_ERROR("cannot find update file,load section file fail.");
+ return FAIL;
+ }
+ update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
+
+ ret = update_msg.file->f_op->read(update_msg.file, (char *)buf, length,
+ &update_msg.file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("Read update file fail.");
+ return FAIL;
+ }
+
+ return SUCCESS;
}
-static u8 gup_recall_check(struct i2c_client *client, u8* chk_src, u16 start_rd_addr, u16 chk_length)
+static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src,
+ u16 start_rd_addr, u16 chk_length)
{
- u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
- s32 ret = 0;
- u16 recall_addr = start_rd_addr;
- u16 recall_length = 0;
- u16 frame_length = 0;
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ s32 ret = 0;
+ u16 recall_addr = start_rd_addr;
+ u16 recall_length = 0;
+ u16 frame_length = 0;
- while(recall_length < chk_length)
- {
- frame_length = ((chk_length - recall_length) > PACK_SIZE) ? PACK_SIZE : (chk_length - recall_length);
- ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
- if(ret <= 0)
- {
- GTP_ERROR("recall i2c error,exit");
- return FAIL;
- }
-
- if(memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], frame_length))
- {
- GTP_ERROR("Recall frame data fail,not equal.");
- GTP_DEBUG("chk_src array:");
- GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
- GTP_DEBUG("recall array:");
- GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
- return FAIL;
- }
-
- recall_length += frame_length;
- recall_addr += frame_length;
- }
- GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
-
- return SUCCESS;
+ while (recall_length < chk_length) {
+ frame_length = ((chk_length - recall_length) > PACK_SIZE)
+ ? PACK_SIZE : (chk_length - recall_length);
+ ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+ if (ret <= 0) {
+ GTP_ERROR("recall i2c error,exit");
+ return FAIL;
+ }
+
+ if (memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length],
+ frame_length)) {
+ GTP_ERROR("Recall frame data fail,not equal.");
+ GTP_DEBUG("chk_src array:");
+ GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+ GTP_DEBUG("recall array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+ return FAIL;
+ }
+
+ recall_length += frame_length;
+ recall_addr += frame_length;
+ }
+ GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
+
+ return SUCCESS;
}
-static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd )
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section,
+ u16 start_addr, u8 bank_cmdi)
{
- s32 ret = 0;
- u8 rd_buf[5];
-
- //step1:hold ss51 & dsp
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
- return FAIL;
- }
-
- //step2:set scramble
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]set scramble fail.");
- return FAIL;
- }
-
- //step3:select bank
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
- return FAIL;
- }
-
- //step4:enable accessing code
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]enable accessing code fail.");
- return FAIL;
- }
-
- //step5:burn 8k fw section
- ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_section]burn fw_section fail.");
- return FAIL;
- }
-
- //step6:hold ss51 & release dsp
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
- return FAIL;
- }
- //must delay
- msleep(1);
-
- //step7:send burn cmd to move data to flash from sram
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]send burn cmd fail.");
- return FAIL;
- }
- GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
- do{
- ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]Get burn state fail");
- return FAIL;
- }
- msleep(10);
- //GTP_DEBUG("[burn_fw_section]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
- }while(rd_buf[GTP_ADDR_LENGTH]);
+ s32 ret = 0;
+ u8 rd_buf[5];
- //step8:select bank
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
- return FAIL;
- }
-
- //step9:enable accessing code
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]enable accessing code fail.");
- return FAIL;
- }
-
- //step10:recall 8k fw section
- ret = gup_recall_check(client, fw_section, start_addr, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
- return FAIL;
- }
-
- //step11:disable accessing code
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]disable accessing code fail.");
- return FAIL;
- }
-
- return SUCCESS;
+ /* step1:hold ss51 & dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
+ return FAIL;
+ }
+
+ /* step2:set scramble */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]set scramble fail.");
+ return FAIL;
+ }
+
+ /* step3:select bank */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+ (bank_cmd >> 4)&0x0F);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]select bank %d fail.",
+ (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ /* step4:enable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ /* step5:burn 8k fw section */
+ ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_section]burn fw_section fail.");
+ return FAIL;
+ }
+
+ /* step6:hold ss51 & release dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
+ return FAIL;
+ }
+ /* must delay */
+ msleep(20);
+
+ /* step7:send burn cmd to move data to flash from sram */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]send burn cmd fail.");
+ return FAIL;
+ }
+ GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]Get burn state fail");
+ return FAIL;
+ }
+ msleep(20);
+ /* GTP_DEBUG("[burn_fw_section]Get burn state:%d.",
+ rd_buf[GTP_ADDR_LENGTH]); */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step8:select bank */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+ (bank_cmd >> 4)&0x0F);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]select bank %d fail.",
+ (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ /* step9:enable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ /* step10:recall 8k fw section */
+ ret = gup_recall_check(client, fw_section, start_addr,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
+ return FAIL;
+ }
+
+ /* step11:disable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]disable accessing code fail.");
+ return FAIL;
+ }
+
+ return SUCCESS;
}
static u8 gup_burn_dsp_isp(struct i2c_client *client)
{
- s32 ret = 0;
- u8* fw_dsp_isp = NULL;
- u8 retry = 0;
-
- GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
-
- //step1:alloc memory
- GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
- while(retry++ < 5)
- {
- fw_dsp_isp = (u8*)kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
- if(fw_dsp_isp == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.", (FW_DSP_ISP_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load dsp isp file data
- GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
- ret = gup_load_section_file(fw_dsp_isp, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
- goto exit_burn_dsp_isp;
- }
-
- //step3:disable wdt,clear cache enable
- GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
- ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step4:hold ss51 & dsp
- GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step5:set boot from sram
- GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step6:software reboot
- GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
- ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]software reboot fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step7:select bank2
- GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step8:enable accessing code
- GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step9:burn 4k dsp_isp
- GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
- ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
- goto exit_burn_dsp_isp;
- }
-
- //step10:set scramble
- GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]set scramble fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
- ret = SUCCESS;
+ s32 ret = 0;
+ u8 *fw_dsp_isp = NULL;
+ u8 retry = 0;
+
+ GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
+
+ /* step1:alloc memory */
+ GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+ if (fw_dsp_isp == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.",
+ (FW_DSP_ISP_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load dsp isp file data */
+ GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
+ ret = gup_load_section_file(fw_dsp_isp, (4 * FW_SECTION_LENGTH +
+ FW_DSP_LENGTH + FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step3:disable wdt,clear cache enable */
+ GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step4:hold ss51 & dsp */
+ GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step5:set boot from sram */
+ GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step6:software reboot */
+ GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
+ ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]software reboot fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step7:select bank2 */
+ GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step8:enable accessing code */
+ GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step9:burn 4k dsp_isp */
+ GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
+ ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step10:set scramble */
+ GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ ret = SUCCESS;
exit_burn_dsp_isp:
- kfree(fw_dsp_isp);
- return ret;
+ kfree(fw_dsp_isp);
+ return ret;
}
static u8 gup_burn_fw_ss51(struct i2c_client *client)
{
- u8* fw_ss51 = NULL;
- u8 retry = 0;
- s32 ret = 0;
-
- GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
-
- //step1:alloc memory
- GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
- while(retry++ < 5)
- {
- fw_ss51 = (u8*)kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
- if(fw_ss51 == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load ss51 firmware section 1 file data
- GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
- ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step3:clear control flag
- GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
- ret = FAIL;
- goto exit_burn_fw_ss51;
- }
-
- //step4:burn ss51 firmware section 1
- GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
- ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step5:load ss51 firmware section 2 file data
- GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
- ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step6:burn ss51 firmware section 2
- GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
- ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step7:load ss51 firmware section 3 file data
- GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
- ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step8:burn ss51 firmware section 3
- GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
- ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step9:load ss51 firmware section 4 file data
- GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
- ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step10:burn ss51 firmware section 4
- GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
- ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
- goto exit_burn_fw_ss51;
- }
-
- ret = SUCCESS;
-
+ u8 *fw_ss51 = NULL;
+ u8 retry = 0;
+ s32 ret = 0;
+
+ GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
+
+ /* step1:alloc memory */
+ GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+ if (fw_ss51 == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load ss51 firmware section 1 file data */
+ GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
+ ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step3:clear control flag */
+ GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
+ ret = FAIL;
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step4:burn ss51 firmware section 1 */
+ GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step5:load ss51 firmware section 2 file data */
+ GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+ ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step6:burn ss51 firmware section 2 */
+ GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step7:load ss51 firmware section 3 file data */
+ GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+ ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step8:burn ss51 firmware section 3 */
+ GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step9:load ss51 firmware section 4 file data */
+ GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+ ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step10:burn ss51 firmware section 4 */
+ GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ ret = SUCCESS;
+
exit_burn_fw_ss51:
- kfree(fw_ss51);
- return ret;
+ kfree(fw_ss51);
+ return ret;
}
static u8 gup_burn_fw_dsp(struct i2c_client *client)
{
- s32 ret = 0;
- u8* fw_dsp = NULL;
- u8 retry = 0;
- u8 rd_buf[5];
-
- GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
- //step1:alloc memory
- GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
- while(retry++ < 5)
- {
- fw_dsp = (u8*)kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
- if(fw_dsp == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load firmware dsp
- GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
- ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
- goto exit_burn_fw_dsp;
- }
-
- //step3:select bank3
- GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
-
- //step4:hold ss51 & dsp
- GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
-
- //step5:set scramble
- GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]set scramble fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
-
- //step6:release ss51 & dsp
- GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
- //must delay
- msleep(1);
-
- //step7:burn 4k dsp firmware
- GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
- ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
- goto exit_burn_fw_dsp;
- }
-
- //step8:send burn cmd to move data to flash from sram
- GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash from sram");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
- goto exit_burn_fw_dsp;
- }
- GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
- do{
- ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]Get burn state fail");
- goto exit_burn_fw_dsp;
- }
- msleep(10);
- //GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
- }while(rd_buf[GTP_ADDR_LENGTH]);
-
- //step9:recall check 4k dsp firmware
- GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
- ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
- goto exit_burn_fw_dsp;
- }
-
- ret = SUCCESS;
-
+ s32 ret = 0;
+ u8 *fw_dsp = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
+ /* step1:alloc memory */
+ GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+ if (fw_dsp == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware dsp */
+ GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
+ ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step3:select bank3 */
+ GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* Step4:hold ss51 & dsp */
+ GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step5:set scramble */
+ GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step6:release ss51 & dsp */
+ GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+ /* must delay */
+ msleep(20);
+
+ /* step7:burn 4k dsp firmware */
+ GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
+ ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if (FAIL == ret) {
+ GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step8:send burn cmd to move data to flash from sram */
+ GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash" \
+ "from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
+ goto exit_burn_fw_dsp;
+ }
+ GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]Get burn state fail");
+ goto exit_burn_fw_dsp;
+ }
+ msleep(20);
+ /* GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.",
+ rd_buf[GTP_ADDR_LENGTH]); */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step9:recall check 4k dsp firmware */
+ GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
+ ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ ret = SUCCESS;
+
exit_burn_fw_dsp:
- kfree(fw_dsp);
- return ret;
+ kfree(fw_dsp);
+ return ret;
}
static u8 gup_burn_fw_boot(struct i2c_client *client)
{
- s32 ret = 0;
- u8* fw_boot = NULL;
- u8 retry = 0;
- u8 rd_buf[5];
-
- GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
-
- //step1:Alloc memory
- GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
- while(retry++ < 5)
- {
- fw_boot = (u8*)kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
- if(fw_boot == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.", (FW_BOOT_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load firmware bootloader
- GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
- ret = gup_load_section_file(fw_boot, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH), FW_BOOT_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
- goto exit_burn_fw_boot;
- }
-
- //step3:hold ss51 & dsp
- GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step4:set scramble
- GTP_DEBUG("[burn_fw_boot]step4:set scramble");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]set scramble fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step5:release ss51 & dsp
- GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
- //must delay
- msleep(1);
-
- //step6:select bank3
- GTP_DEBUG("[burn_fw_boot]step6:select bank3");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]select bank3 fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step7:burn 2k bootloader firmware
- GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
- ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
- goto exit_burn_fw_boot;
- }
-
- //step7:send burn cmd to move data to flash from sram
- GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to flash from sram");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
- goto exit_burn_fw_boot;
- }
- GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
- do{
- ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]Get burn state fail");
- goto exit_burn_fw_boot;
- }
- msleep(10);
- //GTP_DEBUG("[burn_fw_boot]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
- }while(rd_buf[GTP_ADDR_LENGTH]);
-
- //step8:recall check 2k bootloader firmware
- GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
- ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
- goto exit_burn_fw_boot;
- }
-
- //step9:enable download DSP code
- GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step10:release ss51 & hold dsp
- GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- ret = SUCCESS;
-
+ s32 ret = 0;
+ u8 *fw_boot = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
+
+ /* step1:Alloc memory */
+ GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
+ while (retry++ < 5) {
+ fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+ if (fw_boot == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.",
+ (FW_BOOT_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware bootloader */
+ GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
+ ret = gup_load_section_file(fw_boot, (4 * FW_SECTION_LENGTH +
+ FW_DSP_LENGTH), FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step3:hold ss51 & dsp */
+ GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step4:set scramble */
+ GTP_DEBUG("[burn_fw_boot]step4:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step5:release ss51 & dsp */
+ GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+ /* must delay */
+ msleep(20);
+
+ /* step6:select bank3 */
+ GTP_DEBUG("[burn_fw_boot]step6:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step7:burn 2k bootloader firmware */
+ GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
+ ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step7:send burn cmd to move data to flash from sram */
+ GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to" \
+ "flash from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
+ goto exit_burn_fw_boot;
+ }
+ GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]Get burn state fail");
+ goto exit_burn_fw_boot;
+ }
+ msleep(20);
+ /* GTP_DEBUG("[burn_fw_boot]Get burn state:%d.",
+ rd_buf[GTP_ADDR_LENGTH]); */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step8:recall check 2k bootloader firmware */
+ GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
+ ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step9:enable download DSP code */
+ GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step10:release ss51 & hold dsp */
+ GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ ret = SUCCESS;
+
exit_burn_fw_boot:
- kfree(fw_boot);
- return ret;
+ kfree(fw_boot);
+ return ret;
}
s32 gup_update_proc(void *dir)
{
- s32 ret = 0;
- u8 retry = 0;
- st_fw_head fw_head;
- struct goodix_ts_data *ts = NULL;
-
- GTP_DEBUG("[update_proc]Begin update ......");
-
- show_len = 1;
- total_len = 100;
- if(dir == NULL)
- {
- msleep(3000); //wait main thread to be completed
- }
-
- ts = i2c_get_clientdata(i2c_connect_client);
-
- if (searching_file)
- {
- searching_file = 0; // exit .bin update file searching
- GTP_INFO("Exiting searching .bin update file...");
- while ((show_len != 200) && (show_len != 100)) // wait for auto update quitted completely
- {
- msleep(100);
- }
- }
-
- update_msg.file = NULL;
- ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8*)dir); //20121211
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]check update file fail.");
- goto file_fail;
- }
-
- //gtp_reset_guitar(i2c_connect_client, 20);
- ret = gup_get_ic_fw_msg(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]get ic message fail.");
- goto file_fail;
- }
-
- ret = gup_enter_update_judge(&fw_head);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]Check *.bin file fail.");
- goto file_fail;
- }
-
- ts->enter_update = 1;
- gtp_irq_disable(ts);
+ s32 ret = 0;
+ u8 retry = 0;
+ st_fw_head fw_head;
+ struct goodix_ts_data *ts = NULL;
+
+ GTP_DEBUG("[update_proc]Begin update ......");
+
+ show_len = 1;
+ total_len = 100;
+ if (dir == NULL)
+ /* wait main thread to be completed */
+ msleep(3000);
+
+ ts = i2c_get_clientdata(i2c_connect_client);
+
+ if (searching_file) {
+ /* exit .bin update file searching */
+ searching_file = 0;
+ GTP_INFO("Exiting searching .bin update file...");
+ /* wait for auto update quitted completely */
+ while ((show_len != 200) && (show_len != 100))
+ msleep(100);
+ }
+
+ update_msg.file = NULL;
+ ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8 *)dir);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]check update file fail.");
+ goto file_fail;
+ }
+
+ /* gtp_reset_guitar(i2c_connect_client, 20); */
+ ret = gup_get_ic_fw_msg(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]get ic message fail.");
+ goto file_fail;
+ }
+
+ ret = gup_enter_update_judge(&fw_head);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]Check *.bin file fail.");
+ goto file_fail;
+ }
+
+ ts->enter_update = 1;
+ gtp_irq_disable(ts);
#if GTP_ESD_PROTECT
- gtp_esd_switch(ts->client, SWITCH_OFF);
+ gtp_esd_switch(ts->client, SWITCH_OFF);
#endif
- ret = gup_enter_update_mode(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]enter update mode fail.");
- goto update_fail;
- }
-
- while(retry++ < 5)
- {
- show_len = 10;
- total_len = 100;
- ret = gup_burn_dsp_isp(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn dsp isp fail.");
- continue;
- }
-
- show_len += 10;
- ret = gup_burn_fw_ss51(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn ss51 firmware fail.");
- continue;
- }
-
- show_len += 40;
- ret = gup_burn_fw_dsp(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn dsp firmware fail.");
- continue;
- }
-
- show_len += 20;
- ret = gup_burn_fw_boot(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn bootloader firmware fail.");
- continue;
- }
- show_len += 10;
- GTP_INFO("[update_proc]UPDATE SUCCESS.");
- break;
- }
- if(retry >= 5)
- {
- GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
- goto update_fail;
- }
-
- GTP_DEBUG("[update_proc]leave update mode.");
- gup_leave_update_mode();
-
- msleep(100);
-// GTP_DEBUG("[update_proc]send config.");
-// ret = gtp_send_cfg(i2c_connect_client);
-// if(ret < 0)
-// {
-// GTP_ERROR("[update_proc]send config fail.");
-// }
- if (ts->fw_error)
- {
- GTP_INFO("firmware error auto update, resent config!");
- gup_init_panel(ts);
- }
- show_len = 100;
- total_len = 100;
- ts->enter_update = 0;
- gtp_irq_enable(ts);
-
+ ret = gup_enter_update_mode(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]enter update mode fail.");
+ goto update_fail;
+ }
+
+ while (retry++ < 5) {
+ show_len = 10;
+ total_len = 100;
+ ret = gup_burn_dsp_isp(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn dsp isp fail.");
+ continue;
+ }
+
+ show_len += 10;
+ ret = gup_burn_fw_ss51(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn ss51 firmware fail.");
+ continue;
+ }
+
+ show_len += 40;
+ ret = gup_burn_fw_dsp(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn dsp firmware fail.");
+ continue;
+ }
+
+ show_len += 20;
+ ret = gup_burn_fw_boot(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn bootloader fw fail.");
+ continue;
+ }
+ show_len += 10;
+ GTP_INFO("[update_proc]UPDATE SUCCESS.");
+ break;
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
+ goto update_fail;
+ }
+
+ GTP_DEBUG("[update_proc]leave update mode.");
+ gup_leave_update_mode();
+
+ msleep(100);
+
+ /* GTP_DEBUG("[update_proc]send config.");
+ ret = gtp_send_cfg(i2c_connect_client);
+ if(ret < 0) {
+ GTP_ERROR("[update_proc]send config fail.");
+ } */
+
+ if (ts->fw_error) {
+ GTP_INFO("firmware error auto update, resent config!");
+ gup_init_panel(ts);
+ }
+ show_len = 100;
+ total_len = 100;
+ ts->enter_update = 0;
+ gtp_irq_enable(ts);
+
#if GTP_ESD_PROTECT
- gtp_esd_switch(ts->client, SWITCH_ON);
+ gtp_esd_switch(ts->client, SWITCH_ON);
#endif
- filp_close(update_msg.file, NULL);
- return SUCCESS;
-
+ filp_close(update_msg.file, NULL);
+ return SUCCESS;
+
update_fail:
- ts->enter_update = 0;
- gtp_irq_enable(ts);
-
+ ts->enter_update = 0;
+ gtp_irq_enable(ts);
+
#if GTP_ESD_PROTECT
- gtp_esd_switch(ts->client, SWITCH_ON);
+ gtp_esd_switch(ts->client, SWITCH_ON);
#endif
file_fail:
- if(update_msg.file && !IS_ERR(update_msg.file))
- {
- filp_close(update_msg.file, NULL);
- }
- show_len = 200;
- total_len = 100;
- return FAIL;
+ if (update_msg.file && !IS_ERR(update_msg.file))
+ filp_close(update_msg.file, NULL);
+
+ show_len = 200;
+ total_len = 100;
+ return FAIL;
}
#if GTP_AUTO_UPDATE
u8 gup_init_update_proc(struct goodix_ts_data *ts)
{
- struct task_struct *thread = NULL;
+ struct task_struct *thread = NULL;
- GTP_INFO("Ready to run update thread.");
- thread = kthread_run(gup_update_proc, (void*)NULL, "guitar_update");
- if (IS_ERR(thread))
- {
- GTP_ERROR("Failed to create update thread.\n");
- return -1;
- }
+ GTP_INFO("Ready to run update thread.");
+ thread = kthread_run(gup_update_proc, (void *)NULL, "guitar_update");
+ if (IS_ERR(thread)) {
+ GTP_ERROR("Failed to create update thread.\n");
+ return -EINVAL;
+ }
- return 0;
+ return 0;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
index 79c533e..de0ed97 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
@@ -433,7 +433,7 @@
}
}
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds)
{
int is_copy_to_user = -1;
uint32_t data;
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
index aa6c4aa1..4d08282 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
@@ -94,7 +94,8 @@
void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p,
+ uint32_t m_cmds);
void msm_gemini_io_dump(int size);
#define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP 128MHz */
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
index 50c7284..0796b8d 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
@@ -23,6 +23,8 @@
#include "msm_gemini_platform.h"
#include "msm_gemini_common.h"
+#define UINT32_MAX (0xFFFFFFFFU)
+
static int release_buf;
/* size is based on 4k page size */
@@ -804,7 +806,7 @@
void * __user arg)
{
int is_copy_to_user;
- int len;
+ uint32_t len;
uint32_t m;
struct msm_gemini_hw_cmds *hw_cmds_p;
struct msm_gemini_hw_cmd *hw_cmd_p;
@@ -814,6 +816,12 @@
return -EFAULT;
}
+ if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_gemini_hw_cmds)) /
+ sizeof(struct msm_gemini_hw_cmd)))) {
+ GMN_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
len = sizeof(struct msm_gemini_hw_cmds) +
sizeof(struct msm_gemini_hw_cmd) * (m - 1);
hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
index 96470fd..da6f69f 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
@@ -426,7 +426,7 @@
}
}
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds)
{
int is_copy_to_user = -1;
uint32_t data;
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
index 84eed72..f4c32a7 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
@@ -94,7 +94,8 @@
void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p,
+ uint32_t m_cmds);
void msm_gemini_io_dump(int size);
#define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP 128MHz */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
index 8f84a2c..ebf8d4b 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
@@ -23,6 +23,8 @@
#include "msm_gemini_platform.h"
#include "msm_gemini_common.h"
+#define UINT32_MAX (0xFFFFFFFFU)
+
static int release_buf;
/* size is based on 4k page size */
@@ -808,7 +810,7 @@
void * __user arg)
{
int is_copy_to_user;
- int len;
+ uint32_t len;
uint32_t m;
struct msm_gemini_hw_cmds *hw_cmds_p;
struct msm_gemini_hw_cmd *hw_cmd_p;
@@ -818,6 +820,12 @@
return -EFAULT;
}
+ if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_gemini_hw_cmds)) /
+ sizeof(struct msm_gemini_hw_cmd)))) {
+ GMN_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
len = sizeof(struct msm_gemini_hw_cmds) +
sizeof(struct msm_gemini_hw_cmd) * (m - 1);
hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 8c42ed2..4aa423f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -49,6 +49,16 @@
uint32_t active;
};
+enum msm_isp_pack_fmt {
+ QCOM,
+ MIPI,
+ DPCM6,
+ DPCM8,
+ PLAIN8,
+ PLAIN16,
+ MAX_ISP_PACK_FMT,
+};
+
enum msm_isp_camif_update_state {
NO_UPDATE,
ENABLE_CAMIF,
@@ -290,7 +300,7 @@
enum msm_vfe_inputmux input_mux;
uint32_t width;
long pixel_clock;
- uint32_t input_format;
+ uint32_t input_format;/*V4L2 pix format with bayer pattern*/
};
enum msm_wm_ub_cfg_type {
@@ -386,10 +396,12 @@
struct resource *vfe_irq;
struct resource *vfe_mem;
struct resource *vfe_vbif_mem;
+ struct resource *tcsr_mem;
struct resource *vfe_io;
struct resource *vfe_vbif_io;
void __iomem *vfe_base;
void __iomem *vfe_vbif_base;
+ void __iomem *tcsr_base;
struct device *iommu_ctx[MAX_IOMMU_CTX];
@@ -414,6 +426,7 @@
struct msm_vfe_tasklet_queue_cmd
tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
+ uint32_t soc_hw_version;
uint32_t vfe_hw_version;
struct msm_vfe_hardware_info *hw_info;
struct msm_vfe_axi_shared_data axi_data;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 95b3a51..a6972e4 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -484,7 +484,7 @@
static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
- int bpp, bpp_reg = 0;
+ int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
uint32_t io_format_reg;
bpp = msm_isp_get_bit_per_pixel(io_format);
@@ -499,6 +499,34 @@
bpp_reg = 1 << 1;
break;
}
+
+ if (stream_src == IDEAL_RAW) {
+ pack_fmt = msm_isp_get_pack_format(io_format);
+ switch (pack_fmt) {
+ case QCOM:
+ pack_reg = 0x0;
+ break;
+ case MIPI:
+ pack_reg = 0x1;
+ break;
+ case DPCM6:
+ pack_reg = 0x2;
+ break;
+ case DPCM8:
+ pack_reg = 0x3;
+ break;
+ case PLAIN8:
+ pack_reg = 0x4;
+ break;
+ case PLAIN16:
+ pack_reg = 0x5;
+ break;
+ default:
+ pr_err("%s: invalid pack fmt!\n", __func__);
+ return;
+ }
+ }
+
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
switch (stream_src) {
case PIX_ENCODER:
@@ -509,7 +537,7 @@
break;
case IDEAL_RAW:
io_format_reg &= 0xFFFFFFC8;
- io_format_reg |= bpp_reg << 4;
+ io_format_reg |= bpp_reg << 4 | pack_reg;
break;
case RDI_INTF_0:
case RDI_INTF_1:
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 84b95f1..4ff8849 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -290,6 +290,14 @@
goto vbif_remap_failed;
}
+ vfe_dev->tcsr_base = ioremap(vfe_dev->tcsr_mem->start,
+ resource_size(vfe_dev->tcsr_mem));
+ if (!vfe_dev->tcsr_base) {
+ rc = -ENOMEM;
+ pr_err("%s: tcsr ioremap failed\n", __func__);
+ goto tcsr_remap_failed;
+ }
+
rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq,
IRQF_TRIGGER_RISING, "vfe", vfe_dev);
if (rc < 0) {
@@ -298,6 +306,8 @@
}
return rc;
irq_req_failed:
+ iounmap(vfe_dev->tcsr_base);
+tcsr_remap_failed:
iounmap(vfe_dev->vfe_vbif_base);
vbif_remap_failed:
iounmap(vfe_dev->vfe_base);
@@ -316,6 +326,7 @@
{
free_irq(vfe_dev->vfe_irq->start, vfe_dev);
tasklet_kill(&vfe_dev->vfe_tasklet);
+ iounmap(vfe_dev->tcsr_base);
iounmap(vfe_dev->vfe_vbif_base);
iounmap(vfe_dev->vfe_base);
msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
@@ -690,8 +701,9 @@
static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
- int bpp, bpp_reg = 0;
- uint32_t io_format_reg;
+ int bpp, bpp_reg = 0, pack_reg = 0;
+ enum msm_isp_pack_fmt pack_fmt = 0;
+ uint32_t io_format_reg; /*io format register bit*/
bpp = msm_isp_get_bit_per_pixel(io_format);
switch (bpp) {
@@ -705,6 +717,35 @@
bpp_reg = 1 << 1;
break;
}
+
+ if (stream_src == IDEAL_RAW) {
+ /*use io_format(v4l2_pix_fmt) to get pack format*/
+ pack_fmt = msm_isp_get_pack_format(io_format);
+ switch (pack_fmt) {
+ case QCOM:
+ pack_reg = 0x0;
+ break;
+ case MIPI:
+ pack_reg = 0x1;
+ break;
+ case DPCM6:
+ pack_reg = 0x2;
+ break;
+ case DPCM8:
+ pack_reg = 0x3;
+ break;
+ case PLAIN8:
+ pack_reg = 0x4;
+ break;
+ case PLAIN16:
+ pack_reg = 0x5;
+ break;
+ default:
+ pr_err("%s: invalid pack fmt!\n", __func__);
+ return;
+ }
+ }
+
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
switch (stream_src) {
case PIX_ENCODER:
@@ -715,7 +756,7 @@
break;
case IDEAL_RAW:
io_format_reg &= 0xFFFFFFC8;
- io_format_reg |= bpp_reg << 4;
+ io_format_reg |= bpp_reg << 4 | pack_reg;
break;
case RDI_INTF_0:
case RDI_INTF_1:
@@ -1262,6 +1303,14 @@
goto vfe_no_resource;
}
+ vfe_dev->tcsr_mem = platform_get_resource_byname(vfe_dev->pdev,
+ IORESOURCE_MEM, "tcsr");
+ if (!vfe_dev->tcsr_mem) {
+ pr_err("%s: no mem resource?\n", __func__);
+ rc = -ENODEV;
+ goto vfe_no_resource;
+ }
+
vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev,
IORESOURCE_IRQ, "vfe");
if (!vfe_dev->vfe_irq) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 3786b09..f547b0e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -300,7 +300,16 @@
struct msm_vfe_axi_stream *stream_info;
enum msm_vfe_axi_state valid_state =
(stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE;
+
+ if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
+
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+ > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
stream_info = &axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
spin_lock_irqsave(&stream_info->lock, flags);
@@ -852,7 +861,16 @@
int i;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+ if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+ return;
+ }
+
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+ > MAX_NUM_STREAM) {
+ return;
+ }
stream_info =
&axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
@@ -1032,7 +1050,16 @@
uint32_t wm_reload_mask = 0x0;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+ if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
+
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+ > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
stream_info = &axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
src_state = axi_data->src_info[
@@ -1085,7 +1112,16 @@
uint8_t wait_for_complete = 0;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+ if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
+
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+ > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
stream_info = &axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
@@ -1175,8 +1211,18 @@
return -EBUSY;
}
+ /*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/
+ if (update_cmd->num_streams > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
+
for (i = 0; i < update_cmd->num_streams; i++) {
update_info = &update_cmd->update_info[i];
+ /*check array reference bounds*/
+ if (HANDLE_TO_IDX(update_info->stream_handle)
+ > MAX_NUM_STREAM) {
+ return -EINVAL;
+ }
stream_info = &axi_data->stream_info[
HANDLE_TO_IDX(update_info->stream_handle)];
if (stream_info->state != ACTIVE &&
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 590b636..fcdf34e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -27,6 +27,8 @@
#define MSM_ISP_MIN_AB 300000000
#define MSM_ISP_MIN_IB 450000000
+#define VFE40_8974V2_VERSION 0x1001001A
+
static struct msm_bus_vectors msm_isp_init_vectors[] = {
{
.src = MSM_BUS_MASTER_VFE,
@@ -537,6 +539,9 @@
}
break;
}
+ case GET_SOC_HW_VER:
+ *cfg_data = vfe_dev->soc_hw_version;
+ break;
}
return 0;
}
@@ -668,6 +673,42 @@
return val;
}
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format)
+{
+ switch (output_format) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ return MIPI;
+ case V4L2_PIX_FMT_QBGGR8:
+ case V4L2_PIX_FMT_QGBRG8:
+ case V4L2_PIX_FMT_QGRBG8:
+ case V4L2_PIX_FMT_QRGGB8:
+ case V4L2_PIX_FMT_QBGGR10:
+ case V4L2_PIX_FMT_QGBRG10:
+ case V4L2_PIX_FMT_QGRBG10:
+ case V4L2_PIX_FMT_QRGGB10:
+ case V4L2_PIX_FMT_QBGGR12:
+ case V4L2_PIX_FMT_QGBRG12:
+ case V4L2_PIX_FMT_QGRBG12:
+ case V4L2_PIX_FMT_QRGGB12:
+ return QCOM;
+ default:
+ pr_err("%s: Invalid output format\n", __func__);
+ break;
+ }
+ return -EINVAL;
+}
+
int msm_isp_get_bit_per_pixel(uint32_t output_format)
{
switch (output_format) {
@@ -902,6 +943,15 @@
vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 28);
+ switch (vfe_dev->vfe_hw_version) {
+ case VFE40_8974V2_VERSION:
+ vfe_dev->soc_hw_version = msm_camera_io_r(vfe_dev->tcsr_base);
+ break;
+ default:
+ /* SOC HARDWARE VERSION NOT SUPPORTED */
+ vfe_dev->soc_hw_version = 0x00;
+ }
+
memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data));
memset(&vfe_dev->stats_data, 0,
sizeof(struct msm_vfe_stats_shared_data));
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
index 34b9859..ee901c3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -63,6 +63,7 @@
int msm_isp_cal_word_per_line(uint32_t output_format,
uint32_t pixel_per_line);
int msm_isp_get_bit_per_pixel(uint32_t output_format);
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format);
irqreturn_t msm_isp_process_irq(int irq_num, void *data);
void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
void msm_isp_do_tasklet(unsigned long data);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index c38771b..0a0fa04 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -325,7 +325,7 @@
}
}
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds,
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
uint32_t max_size, void *base)
{
int is_copy_to_user = -1;
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
index 084e36b..4ff4292 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
@@ -96,7 +96,7 @@
void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *);
int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *);
void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int);
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, int ,
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t ,
uint32_t , void *);
void msm_jpeg_hw_region_dump(int size);
void msm_jpeg_io_dump(void *base, int size);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index c3c4632..80ff9e5 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -25,6 +25,7 @@
#define JPEG_REG_SIZE 0x308
#define JPEG_DEV_CNT 3
#define JPEG_DEC_ID 2
+#define UINT32_MAX (0xFFFFFFFFU)
inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
{
@@ -677,7 +678,7 @@
void * __user arg)
{
int is_copy_to_user;
- int len;
+ uint32_t len;
uint32_t m;
struct msm_jpeg_hw_cmds *hw_cmds_p;
struct msm_jpeg_hw_cmd *hw_cmd_p;
@@ -687,6 +688,12 @@
return -EFAULT;
}
+ if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) /
+ sizeof(struct msm_jpeg_hw_cmd)))) {
+ JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
len = sizeof(struct msm_jpeg_hw_cmds) +
sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
index cc38b56..790dd28 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
@@ -33,6 +33,18 @@
static struct msm_sensor_power_setting gc0339_power_setting[] = {
{
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 0,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 0,
+ },
+ {
.seq_type = SENSOR_VREG,
.seq_val = CAM_VIO,
.config_val = 0,
@@ -51,12 +63,6 @@
.delay = 0,
},
{
- .seq_type = SENSOR_GPIO,
- .seq_val = SENSOR_GPIO_STANDBY,
- .config_val = GPIO_OUT_HIGH,
- .delay = 0,
- },
- {
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
@@ -74,18 +80,6 @@
.config_val = GPIO_OUT_HIGH,
.delay = 1,
},
- {
- .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 = 1,
- },
};
static struct v4l2_subdev_info gc0339_subdev_info[] = {
@@ -223,6 +217,12 @@
goto power_up_failed;
}
}
+
+ s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
+ s_ctrl->sensor_i2c_client,
+ 0xfc,
+ 0x10, MSM_CAMERA_I2C_BYTE_DATA);
+
if (s_ctrl->func_tbl->sensor_match_id)
rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
else
@@ -297,6 +297,11 @@
s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
}
+ s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
+ s_ctrl->sensor_i2c_client,
+ 0xfc,
+ 0x01, MSM_CAMERA_I2C_BYTE_DATA);
+
for (index = (power_setting_array->size - 1); index >= 0; index--) {
CDBG("%s index %d\n", __func__, index);
power_setting = &power_setting_array->power_setting[index];
@@ -356,10 +361,7 @@
{
int32_t rc = 0;
uint16_t chipid = 0;
- s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
- s_ctrl->sensor_i2c_client,
- 0xfc,
- 0x10, MSM_CAMERA_I2C_BYTE_DATA);
+
rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
s_ctrl->sensor_i2c_client,
s_ctrl->sensordata->slave_info->sensor_id_reg_addr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index de651df..73226ed 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -1010,13 +1010,472 @@
};
static struct msm_camera_i2c_reg_conf hi256_sleep_settings[] = {
+
{0x03, 0x00},
{0x01, 0xf1},
{0x03, 0x02},
{0x55, 0x10},
+
{0x01, 0xf1},
{0x01, 0xf3},
{0x01, 0xf1},
+
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_saturation[11][3] = {
+ {
+ {0x03, 0x10},
+ {0x61, 0x1c},
+ {0x62, 0x1c},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0x30},
+ {0x62, 0x30},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0x44},
+ {0x62, 0x44},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0x58},
+ {0x62, 0x58},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0x6c},
+ {0x62, 0x6c},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0x80},
+ {0x62, 0x80},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0x94},
+ {0x62, 0x94},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0xa8},
+ {0x62, 0xa8},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0xbc},
+ {0x62, 0xbc},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0xd0},
+ {0x62, 0xd0},
+ },
+ {
+ {0x03, 0x10},
+ {0x61, 0xe4},
+ {0x62, 0xe4},
+ },
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_contrast[11][3] = {
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0x1c},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0x30},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0x44},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0x58},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0x6c},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0x80},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0x94},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0xa8},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0xbc},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0xd0},
+ },
+ {
+ {0x03, 0x10},
+ {0x13, 0x02},
+ {0x48, 0xe4},
+ },
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_sharpness[7][9] = {
+ {
+ {0x03, 0x13},
+ {0x20, 0x00},
+ {0x21, 0x00},
+ {0x23, 0x04},
+ {0x24, 0x80},
+ {0x90, 0x00},
+ {0x91, 0x00},
+ {0x94, 0x24},
+ {0x95, 0x65},
+ }, /* SHARPNESS LEVEL 0*/
+ {
+ {0x03, 0x13},
+ {0x20, 0x04},
+ {0x21, 0x03},
+ {0x23, 0x04},
+ {0x24, 0x80},
+ {0x90, 0x08},
+ {0x91, 0x08},
+ {0x94, 0x24},
+ {0x95, 0x65},
+ }, /* SHARPNESS LEVEL 1*/
+ {
+ {0x03, 0x13},
+ {0x20, 0x08},
+ {0x21, 0x07},
+ {0x23, 0x04},
+ {0x24, 0x80},
+ {0x90, 0x32},
+ {0x91, 0x32},
+ {0x94, 0x04},
+ {0x95, 0x0a},
+ }, /* SHARPNESS LEVEL 2*/
+ {
+ {0x03, 0x13},
+ {0x20, 0x15},
+ {0x21, 0x15},
+ {0x23, 0x09},
+ {0x24, 0x11},
+ {0x90, 0x05},
+ {0x91, 0x05},
+ {0x94, 0x10},
+ {0x95, 0x5a},
+ }, /* SHARPNESS LEVEL 3*/
+ {
+ {0x03, 0x13},
+ {0x20, 0x15},
+ {0x21, 0x15},
+ {0x23, 0x04},
+ {0x24, 0x80},
+ {0x90, 0xaf},
+ {0x91, 0xaf},
+ {0x94, 0x24},
+ {0x95, 0x65},
+ }, /* SHARPNESS LEVEL 4*/
+ {
+ {0x03, 0x13},
+ {0x20, 0x20},
+ {0x21, 0x20},
+ {0x23, 0x04},
+ {0x24, 0x80},
+ {0x90, 0xdf},
+ {0x91, 0xdf},
+ {0x94, 0x24},
+ {0x95, 0x65},
+ }, /* SHARPNESS LEVEL 5*/
+ {
+ {0x03, 0x13},
+ {0x20, 0x25},
+ {0x21, 0x25},
+ {0x23, 0x04},
+ {0x24, 0x80},
+ {0x90, 0xff},
+ {0x91, 0xff},
+ {0x94, 0x24},
+ {0x95, 0x65},
+ }, /* SHARPNESS LEVEL 6*/
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_iso[7][3] = {
+ /* auto */
+ {
+ {0x03, 0x20},
+ {0x10, 0x9c},
+ {0xb0, 0x18},
+ },
+ /* auto hjt */
+ {
+ {0x03, 0x20},
+ {0x10, 0x9c},
+ {0xb0, 0x18},
+ },
+ /* iso 100 */
+ {
+ {0x03, 0x20},
+ {0x10, 0x0c},
+ {0xb0, 0x1B},
+ },
+ /* iso 200 */
+ {
+ {0x03, 0x20},
+ {0x10, 0x0c},
+ {0xb0, 0x35},
+ },
+ /* iso 400 */
+ {
+ {0x03, 0x20},
+ {0x10, 0x0c},
+ {0xb0, 0x65},
+ },
+ /* iso 800 */
+ {
+ {0x03, 0x20},
+ {0x10, 0x0c},
+ {0xb0, 0x95},
+ },
+ /* iso 1600 */
+ {
+ {0x03, 0x20},
+ {0x10, 0x0c},
+ {0xb0, 0xd0},
+ },
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_exposure_compensation[5][2] = {
+ /* -2 */
+ {
+ {0x03, 0x10},
+ {0x40, 0xa4},
+ },
+ /* -1 */
+ {
+ {0x03, 0x10},
+ {0x40, 0x94},
+ },
+ /* 0 */
+ {
+ {0x03, 0x10},
+ {0x40, 0x80},
+ },
+ /* 1 */
+ {
+ {0x03, 0x10},
+ {0x40, 0x14},
+ },
+ /* 2 */
+ {
+ {0x03, 0x10},
+ {0x40, 0x24},
+ },
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_antibanding[][2] = {
+ /* OFF */
+ {
+ {0x03, 0x20},
+ {0x10, 0xcc},
+ },
+ /* 50Hz */
+ {
+ {0x03, 0x20},
+ {0x10, 0x9c},
+ },
+ /* 60Hz */
+ {
+ {0x03, 0x20},
+ {0x10, 0x8c},
+ },
+ /* AUTO */
+ {
+ {0x03, 0x20},
+ {0x10, 0xcc},
+ },
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_normal[] = {
+ /* normal: */
+ {0x03, 0x20},
+ {0x28, 0xe7},
+ {0x03, 0x10},
+ {0x11, 0x03},
+ {0x12, 0X30},
+ {0x13, 0x0a},
+ {0x44, 0x80},
+ {0x45, 0x80},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_black_white[] = {
+ /* B&W: */
+ {0x03, 0x20},
+ {0x28, 0xe7},
+ {0x03, 0x10},
+ {0x11, 0x03},
+ {0x12, 0x33},
+ {0x13, 0x02},
+ {0x44, 0x80},
+ {0x45, 0x80},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_negative[] = {
+ /* Negative: */
+ {0x03, 0x20},
+ {0x28, 0xe7},
+ {0x03, 0x10},
+ {0x11, 0x03},
+ {0x12, 0x08},
+ {0x13, 0x0a},
+ {0x14, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_old_movie[] = {
+ /* Sepia(antique): */
+ {0x03, 0x20},
+ {0x28, 0xe7},
+ {0x03, 0x10},
+ {0x11, 0x03},
+ {0x12, 0x33},
+ {0x13, 0x0a},
+ {0x44, 0x25},
+ {0x45, 0xa6},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_solarize[] = {
+ {0x03, 0x20},
+ {0x28, 0xe7},
+ {0x03, 0x10},
+ {0x11, 0x0b},
+ {0x12, 0x00},
+ {0x13, 0x00},
+ {0x14, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_auto[] = {
+ /* <SCENE_auto> */
+ {0x03, 0x20},
+ {0x10, 0x1c},
+ {0x18, 0x38},
+ {0x88, 0x05},
+ {0x89, 0x7e},
+ {0x8a, 0x40},
+ {0x10, 0x9c},
+ {0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_portrait[] = {
+ /* <CAMTUNING_SCENE_PORTRAIT> */
+ {0x03, 0x20},
+ {0x10, 0x1c},
+ {0x18, 0x38},
+ {0x88, 0x05},
+ {0x89, 0x7e},
+ {0x8a, 0x40},
+ {0x10, 0x9c},
+ {0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_landscape[] = {
+ /* <CAMTUNING_SCENE_LANDSCAPE> */
+ {0x03, 0x20},
+ {0x10, 0x1c},
+ {0x18, 0x38},
+ {0x88, 0x05},
+ {0x89, 0x7e},
+ {0x8a, 0x40},
+ {0x10, 0x9c},
+ {0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_night[] = {
+ /* <SCENE_NIGHT> */
+ {0x03, 0x20},
+ {0x10, 0x1c},
+ {0x18, 0x38},
+ {0x88, 0x09},
+ {0x89, 0x27},
+ {0x8a, 0xc0},
+ {0x10, 0x9c},
+ {0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_auto[] = {
+ /* Auto: */
+ {0x03, 0x22},
+ {0x11, 0x2e},
+ {0x83, 0x60},
+ {0x84, 0x0a},
+ {0x85, 0x60},
+ {0x86, 0x15},
+ {0x10, 0xfd},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_sunny[] = {
+ /* Sunny: */
+ {0x03, 0x22},
+ {0x11, 0x28},
+ {0x80, 0x33},
+ {0x82, 0x3d},
+ {0x83, 0x2e},
+ {0x84, 0x24},
+ {0x85, 0x43},
+ {0x86, 0x3d},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_cloudy[] = {
+ /* Cloudy: */
+ {0x03, 0x22},
+ {0x11, 0x28},
+ {0x80, 0x49},
+ {0x82, 0x24},
+ {0x83, 0x50},
+ {0x84, 0x45},
+ {0x85, 0x24},
+ {0x86, 0x1E},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_office[] = {
+ /* Office: */
+ {0x03, 0x22},
+ {0x11, 0x28},
+ {0x80, 0x20},
+ {0x82, 0x58},
+ {0x83, 0x27},
+ {0x84, 0x22},
+ {0x85, 0x58},
+ {0x86, 0x52},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_home[] = {
+ /* Home: */
+ {0x03, 0x22},
+ {0x11, 0x28},
+ {0x80, 0x29},
+ {0x82, 0x54},
+ {0x83, 0x2e},
+ {0x84, 0x23},
+ {0x85, 0x58},
+ {0x86, 0x4f},
};
@@ -1080,7 +1539,6 @@
}
table++;
}
-
}
static int32_t hi256_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
@@ -1144,6 +1602,153 @@
return rc;
}
+static void hi256_set_stauration(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+ pr_debug("%s %d", __func__, value);
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_saturation[value][0],
+ ARRAY_SIZE(HI256_reg_saturation[value]));
+}
+
+static void hi256_set_contrast(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+ pr_debug("%s %d", __func__, value);
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_contrast[value][0],
+ ARRAY_SIZE(HI256_reg_contrast[value]));
+}
+
+static void hi256_set_sharpness(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+ int val = value / 6;
+ pr_debug("%s %d", __func__, value);
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_sharpness[val][0],
+ ARRAY_SIZE(HI256_reg_sharpness[val]));
+}
+
+
+static void hi256_set_iso(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+ pr_debug("%s %d", __func__, value);
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_iso[value][0],
+ ARRAY_SIZE(HI256_reg_iso[value]));
+}
+
+static void hi256_set_exposure_compensation(struct msm_sensor_ctrl_t *s_ctrl,
+ int value)
+{
+ int val = (value + 12) / 6;
+ pr_debug("%s %d", __func__, val);
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_exposure_compensation[val][0],
+ ARRAY_SIZE(HI256_reg_exposure_compensation[val]));
+}
+
+static void hi256_set_effect(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+ pr_debug("%s %d", __func__, value);
+ switch (value) {
+ case MSM_CAMERA_EFFECT_MODE_OFF: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0],
+ ARRAY_SIZE(HI256_reg_effect_normal));
+ break;
+ }
+ case MSM_CAMERA_EFFECT_MODE_MONO: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_black_white[0],
+ ARRAY_SIZE(HI256_reg_effect_black_white));
+ break;
+ }
+ case MSM_CAMERA_EFFECT_MODE_NEGATIVE: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_negative[0],
+ ARRAY_SIZE(HI256_reg_effect_negative));
+ break;
+ }
+ case MSM_CAMERA_EFFECT_MODE_SEPIA: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_old_movie[0],
+ ARRAY_SIZE(HI256_reg_effect_old_movie));
+ break;
+ }
+ case MSM_CAMERA_EFFECT_MODE_SOLARIZE: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_solarize[0],
+ ARRAY_SIZE(HI256_reg_effect_solarize));
+ break;
+ }
+ default:
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0],
+ ARRAY_SIZE(HI256_reg_effect_normal));
+ }
+}
+
+static void hi256_set_antibanding(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+ pr_debug("%s %d", __func__, value);
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_antibanding[value][0],
+ ARRAY_SIZE(HI256_reg_antibanding[value]));
+}
+
+static void hi256_set_scene_mode(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+ pr_debug("%s %d", __func__, value);
+ switch (value) {
+ case MSM_CAMERA_SCENE_MODE_OFF: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0],
+ ARRAY_SIZE(HI256_reg_scene_auto));
+ break;
+ }
+ case MSM_CAMERA_SCENE_MODE_NIGHT: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_night[0],
+ ARRAY_SIZE(HI256_reg_scene_night));
+ break;
+ }
+ case MSM_CAMERA_SCENE_MODE_LANDSCAPE: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_landscape[0],
+ ARRAY_SIZE(HI256_reg_scene_landscape));
+ break;
+ }
+ case MSM_CAMERA_SCENE_MODE_PORTRAIT: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_portrait[0],
+ ARRAY_SIZE(HI256_reg_scene_portrait));
+ break;
+ }
+ default:
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0],
+ ARRAY_SIZE(HI256_reg_scene_auto));
+ }
+}
+
+static void hi256_set_white_balance_mode(struct msm_sensor_ctrl_t *s_ctrl,
+ int value)
+{
+ pr_debug("%s %d", __func__, value);
+ switch (value) {
+ case MSM_CAMERA_WB_MODE_AUTO: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0],
+ ARRAY_SIZE(HI256_reg_wb_auto));
+ break;
+ }
+ case MSM_CAMERA_WB_MODE_INCANDESCENT: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_home[0],
+ ARRAY_SIZE(HI256_reg_wb_home));
+ break;
+ }
+ case MSM_CAMERA_WB_MODE_DAYLIGHT: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_sunny[0],
+ ARRAY_SIZE(HI256_reg_wb_sunny));
+ break;
+ }
+ case MSM_CAMERA_WB_MODE_FLUORESCENT: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_office[0],
+ ARRAY_SIZE(HI256_reg_wb_office));
+ break;
+ }
+ case MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT: {
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_cloudy[0],
+ ARRAY_SIZE(HI256_reg_wb_cloudy));
+ break;
+ }
+ default:
+ hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0],
+ ARRAY_SIZE(HI256_reg_wb_auto));
+ }
+}
+
int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
void __user *argp)
{
@@ -1397,6 +2002,117 @@
}
break;
}
+ case CFG_SET_SATURATION: {
+ int32_t sat_lev;
+ if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Saturation Value is %d", __func__, sat_lev);
+ hi256_set_stauration(s_ctrl, sat_lev);
+ break;
+ }
+ case CFG_SET_CONTRAST: {
+ int32_t con_lev;
+ if (copy_from_user(&con_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Contrast Value is %d", __func__, con_lev);
+ hi256_set_contrast(s_ctrl, con_lev);
+ break;
+ }
+ case CFG_SET_SHARPNESS: {
+ int32_t shp_lev;
+ if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Sharpness Value is %d", __func__, shp_lev);
+ hi256_set_sharpness(s_ctrl, shp_lev);
+ break;
+ }
+ case CFG_SET_ISO: {
+ int32_t iso_lev;
+ if (copy_from_user(&iso_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: ISO Value is %d", __func__, iso_lev);
+ hi256_set_iso(s_ctrl, iso_lev);
+ break;
+ }
+ case CFG_SET_EXPOSURE_COMPENSATION: {
+ int32_t ec_lev;
+ if (copy_from_user(&ec_lev, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Exposure compensation Value is %d",
+ __func__, ec_lev);
+ hi256_set_exposure_compensation(s_ctrl, ec_lev);
+ break;
+ }
+ case CFG_SET_EFFECT: {
+ int32_t effect_mode;
+ if (copy_from_user(&effect_mode, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: Effect mode is %d", __func__, effect_mode);
+ hi256_set_effect(s_ctrl, effect_mode);
+ break;
+ }
+ case CFG_SET_ANTIBANDING: {
+ int32_t antibanding_mode;
+ if (copy_from_user(&antibanding_mode,
+ (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: anti-banding mode is %d", __func__,
+ antibanding_mode);
+ hi256_set_antibanding(s_ctrl, antibanding_mode);
+ break;
+ }
+ case CFG_SET_BESTSHOT_MODE: {
+ int32_t bs_mode;
+ if (copy_from_user(&bs_mode, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: best shot mode is %d", __func__, bs_mode);
+ hi256_set_scene_mode(s_ctrl, bs_mode);
+ break;
+ }
+ case CFG_SET_WHITE_BALANCE: {
+ int32_t wb_mode;
+ if (copy_from_user(&wb_mode, (void *)cdata->cfg.setting,
+ sizeof(int32_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: white balance is %d", __func__, wb_mode);
+ hi256_set_white_balance_mode(s_ctrl, wb_mode);
+ break;
+ }
default:
rc = -EFAULT;
break;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
index 3256c5c..e17c94e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -21,55 +21,55 @@
.seq_type = SENSOR_VREG,
.seq_val = CAM_VIO,
.config_val = 0,
- .delay = 5,
+ .delay = 1,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VANA,
.config_val = 0,
- .delay = 5,
+ .delay = 1,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VDIG,
.config_val = 0,
- .delay = 5,
+ .delay = 1,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VAF,
.config_val = 0,
- .delay = 15,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_LOW,
- .delay = 15,
+ .delay = 1,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_LOW,
- .delay = 40,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_HIGH,
- .delay = 40,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_HIGH,
- .delay = 40,
+ .delay = 10,
},
{
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
- .delay = 5,
+ .delay = 10,
},
{
.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
index 56af02b..99bf03a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
@@ -46,7 +46,7 @@
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_HIGH,
- .delay = 30,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
@@ -58,13 +58,13 @@
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_HIGH,
- .delay = 30,
+ .delay = 10,
},
{
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
- .delay = 5,
+ .delay = 10,
},
{
.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 02b36f8..ef2c12a 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1160,6 +1160,19 @@
pkt->size += sizeof(u32) * 2;
break;
}
+ case HAL_PARAM_VDEC_CONCEAL_COLOR:
+ {
+ struct hfi_conceal_color *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
+ hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
+ if (hfi)
+ hfi->conceal_color =
+ ((struct hfi_conceal_color *) pdata)->
+ conceal_color;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
case HAL_CONFIG_VPE_OPERATIONS:
break;
case HAL_PARAM_VENC_INTRA_REFRESH:
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index cf96ca2..50149dc 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -210,7 +210,8 @@
fail_nomem:
return rc;
}
-static int msm_v4l2_release_output_buffers(struct msm_v4l2_vid_inst *v4l2_inst)
+static int msm_v4l2_release_buffers(struct msm_v4l2_vid_inst *v4l2_inst,
+ int buffer_type)
{
struct list_head *ptr, *next;
struct buffer_info *bi;
@@ -220,7 +221,7 @@
int i;
list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
bi = list_entry(ptr, struct buffer_info, list);
- if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (bi->type == buffer_type) {
buffer_info.type = bi->type;
for (i = 0; (i < bi->num_planes)
&& (i < VIDEO_MAX_PLANES); i++) {
@@ -266,7 +267,8 @@
int i;
vidc_inst = get_vidc_inst(filp, NULL);
v4l2_inst = get_v4l2_inst(filp, NULL);
- rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ rc = msm_v4l2_release_buffers(v4l2_inst,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
@@ -339,7 +341,7 @@
int rc = 0;
v4l2_inst = get_v4l2_inst(file, NULL);
if (b->count == 0)
- rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ rc = msm_v4l2_release_buffers(v4l2_inst, b->type);
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
@@ -617,7 +619,8 @@
int rc = 0;
v4l2_inst = get_v4l2_inst(file, NULL);
if (dec->cmd == V4L2_DEC_CMD_STOP)
- rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ rc = msm_v4l2_release_buffers(v4l2_inst,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
"Failed to release dec output buffers: %d\n", rc);
@@ -632,7 +635,8 @@
int rc = 0;
v4l2_inst = get_v4l2_inst(file, NULL);
if (enc->cmd == V4L2_ENC_CMD_STOP)
- rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ rc = msm_v4l2_release_buffers(v4l2_inst,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
"Failed to release enc output buffers: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 86928f2..73ff9fa 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -22,6 +22,7 @@
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MAX_NUM_OUTPUT_BUFFERS 6
+#define DEFAULT_CONCEAL_COLOR 0x0
enum msm_vdec_ctrl_cluster {
MSM_VDEC_CTRL_CLUSTER_MAX = 1 << 0,
@@ -1028,18 +1029,16 @@
mutex_unlock(&inst->lock);
break;
}
- if (*num_buffers && *num_buffers >
+ if (*num_buffers && *num_buffers >=
bufreq->buffer_count_actual) {
property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
new_buf_count.buffer_count_actual = *num_buffers;
rc = call_hfi_op(hdev, session_set_property,
inst->session, property_id, &new_buf_count);
+ } else {
+ *num_buffers = bufreq->buffer_count_min;
}
- if (bufreq->buffer_count_actual > *num_buffers)
- *num_buffers = bufreq->buffer_count_actual;
- else
- bufreq->buffer_count_actual = *num_buffers;
mutex_unlock(&inst->lock);
dprintk(VIDC_DBG, "count = %d, size = %d, alignment = %d\n",
inst->buff_req.buffer[1].buffer_count_actual,
@@ -1129,17 +1128,28 @@
{
struct msm_vidc_inst *inst;
int rc = 0;
+ int pdata = DEFAULT_CONCEAL_COLOR;
+ struct hfi_device *hdev;
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
dprintk(VIDC_DBG,
"Streamon called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *) inst->session,
+ HAL_PARAM_VDEC_CONCEAL_COLOR,
+ (void *) &pdata);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index bc3b93d..44c9613 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -381,7 +381,7 @@
}
static inline void q6_hfi_add_apr_hdr(struct q6_hfi_device *dev,
- struct apr_hdr *hdr, u32 pkt_size, u32 opcode)
+ struct apr_hdr *hdr, u32 pkt_size)
{
hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(sizeof(struct apr_hdr)),
@@ -394,7 +394,7 @@
hdr->dest_port = 0;
hdr->pkt_size = pkt_size;
hdr->token = 0;
- hdr->opcode = opcode;
+ hdr->opcode = VIDEO_HFI_CMD_ID;
}
static int q6_hfi_apr_callback(struct apr_client_data *data, void *priv)
@@ -496,7 +496,7 @@
goto err_core_init;
}
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
if (rc) {
@@ -529,22 +529,6 @@
return 0;
}
-static int q6_hfi_core_pc_prep(void *device)
-{
- (void) device;
-
- /* Q6 does not support core_pc_prep*/
- return 0;
-}
-
-static int q6_hfi_core_ping(void *device)
-{
- (void) device;
-
- /* Q6 does not support cmd_sys_ping */
- return 0;
-}
-
static void *q6_hfi_session_init(void *device, u32 session_id,
enum hal_domain session_type, enum hal_video_codec codec_type)
{
@@ -567,8 +551,7 @@
new_session->is_decoder = 1;
new_session->device = dev;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SYS_SESSION_INIT);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
if (create_pkt_cmd_sys_session_init(&apr.pkt, (u32)new_session,
session_type, codec_type)) {
@@ -605,7 +588,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), pkt_type);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_cmd(&apr.pkt, pkt_type, (u32)session);
if (rc) {
@@ -670,8 +653,7 @@
return 0;
apr = (struct q6_apr_cmd_session_set_buffers_packet *)packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
- HFI_CMD_SESSION_SET_BUFFERS);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
rc = create_pkt_cmd_session_set_buffers(&apr->pkt,
(u32)session, buffer_info);
@@ -713,8 +695,7 @@
apr = (struct q6_apr_cmd_session_release_buffer_packet *) packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
- HFI_CMD_SESSION_RELEASE_BUFFERS);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
rc = create_pkt_cmd_session_release_buffers(&apr->pkt,
(u32)session, buffer_info);
@@ -788,8 +769,7 @@
if (session->is_decoder) {
struct q6_apr_cmd_session_empty_buffer_compressed_packet apr;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_EMPTY_BUFFER);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_etb_decoder(&apr.pkt,
(u32)session, input_frame);
@@ -811,8 +791,7 @@
} else {
struct
q6_apr_cmd_session_empty_buffer_uncompressed_plane0_packet apr;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_EMPTY_BUFFER);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_etb_encoder(&apr.pkt,
(u32)session, input_frame);
@@ -848,8 +827,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_FILL_BUFFER);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_ftb(&apr.pkt, (u32)session, output_frame);
if (rc) {
@@ -886,8 +864,7 @@
apr = (struct q6_apr_cmd_session_parse_sequence_header_packet *) packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
- HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
rc = create_pkt_cmd_session_parse_seq_header(&apr->pkt,
(u32)session, seq_hdr);
@@ -925,8 +902,7 @@
apr = (struct q6_apr_cmd_session_get_sequence_header_packet *) packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
- HFI_CMD_SESSION_GET_SEQUENCE_HEADER);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
rc = create_pkt_cmd_session_get_seq_hdr(&apr->pkt, (u32)session,
seq_hdr);
@@ -960,8 +936,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_GET_PROPERTY);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_get_buf_req(&apr.pkt, (u32)session);
if (rc) {
@@ -993,8 +968,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_FLUSH);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_flush(&apr.pkt, (u32)session, flush_mode);
if (rc) {
@@ -1031,8 +1005,7 @@
dev = session->device;
dprintk(VIDC_DBG, "in set_prop,with prop id: 0x%x", ptype);
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
- HFI_CMD_SESSION_SET_PROPERTY);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
rc = create_pkt_cmd_session_set_property(&apr->pkt,
(u32)session, ptype, pdata);
@@ -1177,28 +1150,6 @@
return 0;
}
-static int q6_hfi_scale_clocks(void *dev, int load)
-{
- (void)dev;
- (void)load;
-
- /* Q6 does not support clocks scaling */
- return 0;
-}
-
-static int q6_hfi_scale_bus(void *dev, int load,
- enum session_type type, enum mem_type mtype)
-{
- (void)dev;
- (void)load;
- (void)type;
- (void)mtype;
-
- /* Q6 does not support bus scaling */
- return 0;
-
-}
-
static int q6_hfi_unset_ocmem(void *dev)
{
(void)dev;
@@ -1207,23 +1158,6 @@
return -EINVAL;
}
-static int q6_hfi_alloc_ocmem(void *dev, unsigned long size)
-{
- (void)dev;
- (void)size;
-
- /* Q6 does not support ocmem */
- return 0;
-}
-
-static int q6_hfi_free_ocmem(void *dev)
-{
- (void)dev;
-
- /* Q6 does not support ocmem */
- return 0;
-}
-
static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
u32 buffer_type, int *domain, int *partition)
{
@@ -1373,14 +1307,6 @@
}
}
-static int q6_hfi_get_fw_info(void *dev, enum fw_info info)
-{
- (void)dev;
- (void)info;
-
- return 0;
-}
-
static int q6_hfi_get_stride_scanline(int color_fmt,
int width, int height, int *stride, int *scanlines) {
*stride = VENUS_Y_STRIDE(color_fmt, width);
@@ -1392,8 +1318,6 @@
{
hdev->core_init = q6_hfi_core_init;
hdev->core_release = q6_hfi_core_release;
- hdev->core_pc_prep = q6_hfi_core_pc_prep;
- hdev->core_ping = q6_hfi_core_ping;
hdev->session_init = q6_hfi_session_init;
hdev->session_end = q6_hfi_session_end;
hdev->session_abort = q6_hfi_session_abort;
@@ -1414,15 +1338,10 @@
hdev->session_flush = q6_hfi_session_flush;
hdev->session_set_property = q6_hfi_session_set_property;
hdev->session_get_property = q6_hfi_session_get_property;
- hdev->scale_clocks = q6_hfi_scale_clocks;
- hdev->scale_bus = q6_hfi_scale_bus;
hdev->unset_ocmem = q6_hfi_unset_ocmem;
- hdev->alloc_ocmem = q6_hfi_alloc_ocmem;
- hdev->free_ocmem = q6_hfi_free_ocmem;
hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
hdev->load_fw = q6_hfi_load_fw;
hdev->unload_fw = q6_hfi_unload_fw;
- hdev->get_fw_info = q6_hfi_get_fw_info;
hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
}
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
index 3dc4607..67aed5a 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.h
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -20,6 +20,15 @@
#define Q6_IFACEQ_QUEUE_SIZE (8 * 1024)
+/* client to Q6 communication path : forward path */
+#define VIDEO_HFI_CMD_ID 0x00012ECC
+
+/* Q6 to client ACK msg: reverse path*/
+#define VIDEO_HFI_MSG_ID 0x00012ECD
+
+/* Q6 to client event notifications */
+#define VIDEO_HFI_EVT_ID 0x00012ECE
+
struct q6_resources {
struct msm_vidc_fw fw;
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 010f15d..494242d 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -176,6 +176,7 @@
HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
HAL_PARAM_BUFFER_ALLOC_MODE,
HAL_PARAM_VDEC_FRAME_ASSEMBLY,
+ HAL_PARAM_VDEC_CONCEAL_COLOR,
};
enum hal_domain {
@@ -200,7 +201,7 @@
HAL_VIDEO_CODEC_VP6 = 0x00000400,
HAL_VIDEO_CODEC_VP7 = 0x00000800,
HAL_VIDEO_CODEC_VP8 = 0x00001000,
- HAL_VIDEO_CODEC_HEVC = 0x00010000,
+ HAL_VIDEO_CODEC_HEVC = 0x00002000,
HAL_UNUSED_CODEC = 0x10000000,
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 0f1e896..61c6e15 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -79,7 +79,7 @@
#define HFI_VIDEO_CODEC_VC1 0x00000100
#define HFI_VIDEO_CODEC_SPARK 0x00000200
#define HFI_VIDEO_CODEC_VP8 0x00001000
-#define HFI_VIDEO_CODEC_HEVC 0x00010000
+#define HFI_VIDEO_CODEC_HEVC 0x00002000
#define HFI_H264_PROFILE_BASELINE 0x00000001
#define HFI_H264_PROFILE_MAIN 0x00000002
@@ -435,6 +435,10 @@
u32 max_num_b_frames;
};
+struct hfi_conceal_color {
+ u32 conceal_color;
+};
+
struct hfi_intra_period {
u32 pframes;
u32 bframes;
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 41d9ff8..0147e66 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -21,14 +21,12 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/smsc3503.h>
+#include <linux/smsc_hub.h>
#include <linux/module.h>
#include <mach/msm_xo.h>
-#define SMSC3503_I2C_ADDR 0x08
-#define SMSC_GSBI_I2C_BUS_ID 10
-static const unsigned short normal_i2c[] = {
-SMSC3503_I2C_ADDR, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = {
+0, I2C_CLIENT_END };
struct hsic_hub {
struct device *dev;
@@ -111,6 +109,22 @@
return i2c_smbus_write_byte_data(client, reg, (ret & ~value));
}
+static int smsc4604_send_connect_cmd(struct i2c_client *client)
+{
+ u8 buf[3];
+
+ buf[0] = 0xAA;
+ buf[1] = 0x55;
+ buf[2] = 0x00;
+
+ if (i2c_master_send(client, buf, 3) != 3) {
+ dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int i2c_hsic_hub_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -118,21 +132,37 @@
I2C_FUNC_SMBUS_WORD_DATA))
return -EIO;
- /* CONFIG_N bit in SP_ILOCK register has to be set before changing
- * other registers to change default configuration of hsic hub.
- */
- hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+ switch (smsc_hub->pdata->model_id) {
+ case SMSC3503_ID:
+ /*
+ * CONFIG_N bit in SP_ILOCK register has to be set before
+ * changing other registers to change default configuration
+ * of hsic hub.
+ */
+ hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
- /* Can change default configuartion like VID,PID, strings etc
- * by writing new values to hsic hub registers.
- */
- hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
+ /*
+ * Can change default configuartion like VID,PID,
+ * strings etc by writing new values to hsic hub registers
+ */
+ hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
- /* CONFIG_N bit in SP_ILOCK register has to be cleared for new
- * values in registers to be effective after writing to
- * other registers.
- */
- hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+ /*
+ * CONFIG_N bit in SP_ILOCK register has to be cleared
+ * for new values in registers to be effective after
+ * writing to other registers.
+ */
+ hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+ break;
+ case SMSC4604_ID:
+ /*
+ * SMSC4604 requires an I2C attach command to be issued
+ * if I2C bus is connected
+ */
+ return smsc4604_send_connect_cmd(client);
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -318,6 +348,8 @@
struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
struct platform_device *pdev)
{
+ int rc;
+ u32 temp_val;
struct device_node *node = pdev->dev.of_node;
struct smsc_hub_platform_data *pdata;
@@ -327,6 +359,14 @@
return ERR_PTR(-ENOMEM);
}
+ rc = of_property_read_u32(node, "smsc,model-id", &temp_val);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to read smsc,model-id\n");
+ return ERR_PTR(rc);
+ } else {
+ pdata->model_id = temp_val;
+ }
+
pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
if (pdata->hub_reset < 0)
return ERR_PTR(pdata->hub_reset);
@@ -399,18 +439,13 @@
}
gpio_direction_output(pdata->hub_reset, 0);
- /* Hub reset should be asserted for minimum 2microsec
+ /*
+ * Hub reset should be asserted for minimum 2microsec
* before deasserting.
*/
udelay(5);
gpio_direction_output(pdata->hub_reset, 1);
- ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
- goto uninit_gpio;
- }
-
if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
ret = regulator_enable(smsc_hub->hub_vbus_reg);
if (ret) {
@@ -436,14 +471,39 @@
memset(&i2c_info, 0, sizeof(struct i2c_board_info));
strlcpy(i2c_info.type, "i2c_hsic_hub", I2C_NAME_SIZE);
+ /* 250ms delay is required for SMSC4604 HUB to get I2C up */
+ msleep(250);
+
+ /* Assign I2C slave address per SMSC model */
+ switch (pdata->model_id) {
+ case SMSC3503_ID:
+ normal_i2c[0] = SMSC3503_I2C_ADDR;
+ break;
+ case SMSC4604_ID:
+ normal_i2c[0] = SMSC4604_I2C_ADDR;
+ break;
+ default:
+ dev_err(&pdev->dev, "unsupported SMSC model-id\n");
+ i2c_put_adapter(i2c_adap);
+ i2c_del_driver(&hsic_hub_driver);
+ goto uninit_gpio;
+ }
+
smsc_hub->client = i2c_new_probed_device(i2c_adap, &i2c_info,
normal_i2c, NULL);
i2c_put_adapter(i2c_adap);
- if (!smsc_hub->client)
- dev_err(&pdev->dev, "failed to connect to smsc_hub"
- "through I2C\n");
i2c_add_fail:
+ ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
+ goto uninit_gpio;
+ }
+
+ if (!smsc_hub->client)
+ dev_err(&pdev->dev,
+ "failed to connect to smsc_hub through I2C\n");
+
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 9471188..a2876e0 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -13,6 +13,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spmi.h>
+#include <linux/err.h>
+#include <linux/qpnp-revid.h>
#define REVID_REVISION1 0x0
#define REVID_REVISION2 0x1
@@ -36,6 +38,15 @@
"PMD9635",
};
+struct revid_chip {
+ struct list_head link;
+ struct device_node *dev_node;
+ struct pmic_revid_data data;
+};
+
+static LIST_HEAD(revid_chips);
+static DEFINE_MUTEX(revid_chips_lock);
+
static struct of_device_id qpnp_revid_match_table[] = {
{ .compatible = QPNP_REVID_DEV_NAME },
{}
@@ -54,6 +65,35 @@
return val;
}
+/**
+ * get_revid_data - Return the revision information of PMIC
+ * @dev_node: Pointer to the revid peripheral of the PMIC for which
+ * revision information is seeked
+ *
+ * CONTEXT: Should be called in non atomic context
+ *
+ * RETURNS: pointer to struct pmic_revid_data filled with the information
+ * about the PMIC revision
+ */
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+ struct revid_chip *revid_chip;
+
+ if (!dev_node)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&revid_chips_lock);
+ list_for_each_entry(revid_chip, &revid_chips, link) {
+ if (dev_node == revid_chip->dev_node) {
+ mutex_unlock(&revid_chips_lock);
+ return &revid_chip->data;
+ }
+ }
+ mutex_unlock(&revid_chips_lock);
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(get_revid_data);
+
#define PM8941_PERIPHERAL_SUBTYPE 0x01
#define PM8226_PERIPHERAL_SUBTYPE 0x04
static size_t build_pmic_string(char *buf, size_t n, int sid,
@@ -94,6 +134,7 @@
u8 option1, option2, option3, option4;
struct resource *resource;
char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'};
+ struct revid_chip *revid_chip;
resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
if (!resource) {
@@ -114,6 +155,23 @@
pmic_subtype = qpnp_read_byte(spmi, resource->start + REVID_SUBTYPE);
pmic_status = qpnp_read_byte(spmi, resource->start + REVID_STATUS1);
+ revid_chip = devm_kzalloc(&spmi->dev, sizeof(struct revid_chip),
+ GFP_KERNEL);
+ if (!revid_chip)
+ return -ENOMEM;
+
+ revid_chip->dev_node = spmi->dev.of_node;
+ revid_chip->data.rev1 = rev1;
+ revid_chip->data.rev2 = rev2;
+ revid_chip->data.rev3 = rev3;
+ revid_chip->data.rev4 = rev4;
+ revid_chip->data.pmic_subtype = pmic_subtype;
+ revid_chip->data.pmic_type = pmic_type;
+
+ mutex_lock(&revid_chips_lock);
+ list_add(&revid_chip->link, &revid_chips);
+ mutex_unlock(&revid_chips_lock);
+
option1 = pmic_status & 0x3;
option2 = (pmic_status >> 2) & 0x3;
option3 = (pmic_status >> 4) & 0x3;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 1deb765..2ad0926 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -29,6 +29,8 @@
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
#include <linux/of_batterydata.h>
+#include <linux/qpnp-revid.h>
+#include <linux/android_alarm.h>
/* Interrupt offsets */
#define INT_RT_STS(base) (base + 0x10)
@@ -85,6 +87,7 @@
#define CHGR_BAT_IF_VCP 0x42
#define CHGR_BAT_IF_BATFET_CTRL1 0x90
#define CHGR_MISC_BOOT_DONE 0x42
+#define CHGR_BUCK_PSTG_CTRL 0x73
#define CHGR_BUCK_COMPARATOR_OVRIDE_1 0xEB
#define CHGR_BUCK_COMPARATOR_OVRIDE_3 0xED
#define CHGR_BUCK_BCK_VBAT_REG_MODE 0x74
@@ -202,6 +205,7 @@
/* Workaround flags */
#define CHG_FLAGS_VCP_WA BIT(0)
#define BOOST_FLASH_WA BIT(1)
+#define POWER_STAGE_WA BIT(2)
struct qpnp_chg_irq {
unsigned int irq;
@@ -331,6 +335,7 @@
uint32_t flags;
struct qpnp_adc_tm_btm_param adc_param;
struct work_struct adc_measure_work;
+ struct work_struct adc_disable_work;
struct delayed_work arb_stop_work;
struct delayed_work eoc_work;
struct wake_lock eoc_wake_lock;
@@ -339,6 +344,9 @@
struct qpnp_vadc_chip *vadc_dev;
struct qpnp_adc_tm_chip *adc_tm_dev;
struct mutex jeita_configure_lock;
+ struct alarm reduce_power_stage_alarm;
+ struct work_struct reduce_power_stage_work;
+ bool power_stage_workaround_running;
};
@@ -606,6 +614,24 @@
return (dcin_valid_rt_sts & DCIN_VALID_IRQ) ? 1 : 0;
}
+static int
+qpnp_chg_is_ichg_loop_active(struct qpnp_chg_chip *chip)
+{
+ u8 buck_sts;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &buck_sts, INT_RT_STS(chip->buck_base), 1);
+
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ INT_RT_STS(chip->buck_base), rc);
+ return rc;
+ }
+ pr_debug("buck usb sts 0x%x\n", buck_sts);
+
+ return (buck_sts & ICHG_LOOP_IRQ) ? 1 : 0;
+}
+
#define QPNP_CHG_I_MAX_MIN_100 100
#define QPNP_CHG_I_MAX_MIN_150 150
#define QPNP_CHG_I_MAX_MIN_MA 200
@@ -933,6 +959,15 @@
pr_err("request ADC error\n");
}
+static void
+qpnp_bat_if_adc_disable_work(struct work_struct *work)
+{
+ struct qpnp_chg_chip *chip = container_of(work,
+ struct qpnp_chg_chip, adc_disable_work);
+
+ qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev, &chip->adc_param);
+}
+
static irqreturn_t
qpnp_chg_buck_vchg_loop_irq_handler(int irq, void *_chip)
{
@@ -1085,8 +1120,7 @@
schedule_work(&chip->adc_measure_work);
} else if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
&& !batt_present) {
- qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
- &chip->adc_param);
+ schedule_work(&chip->adc_disable_work);
pr_debug("disabling vadc notifications\n");
}
}
@@ -1654,6 +1688,15 @@
} else {
qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
}
+
+ if ((chip->flags & POWER_STAGE_WA)
+ && ((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
+ && !chip->power_stage_workaround_running) {
+ chip->power_stage_workaround_running = true;
+ pr_debug("usb wall chg inserted starting power stage workaround charger_monitor = %d\n",
+ charger_monitor);
+ schedule_work(&chip->reduce_power_stage_work);
+ }
}
chip->prev_usb_max_ma = ret.intval;
}
@@ -2475,6 +2518,199 @@
return rc;
}
+#define POWER_STAGE_REDUCE_CHECK_PERIOD_SECONDS 20
+#define POWER_STAGE_REDUCE_MAX_VBAT_UV 3900000
+#define POWER_STAGE_REDUCE_MIN_VCHG_UV 4800000
+#define POWER_STAGE_SEL_MASK 0x0F
+#define POWER_STAGE_REDUCED 0x01
+#define POWER_STAGE_DEFAULT 0x0F
+static bool
+qpnp_chg_is_power_stage_reduced(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 reg;
+
+ rc = qpnp_chg_read(chip, ®,
+ chip->buck_base + CHGR_BUCK_PSTG_CTRL,
+ 1);
+ if (rc) {
+ pr_err("Error %d reading power stage register\n", rc);
+ return false;
+ }
+
+ if ((reg & POWER_STAGE_SEL_MASK) == POWER_STAGE_DEFAULT)
+ return false;
+
+ return true;
+}
+
+static int
+qpnp_chg_power_stage_set(struct qpnp_chg_chip *chip, bool reduce)
+{
+ int rc;
+ u8 reg = 0xA5;
+
+ rc = qpnp_chg_write(chip, ®,
+ chip->buck_base + SEC_ACCESS,
+ 1);
+ if (rc) {
+ pr_err("Error %d writing 0xA5 to buck's 0x%x reg\n",
+ rc, SEC_ACCESS);
+ return rc;
+ }
+
+ reg = POWER_STAGE_DEFAULT;
+ if (reduce)
+ reg = POWER_STAGE_REDUCED;
+ rc = qpnp_chg_write(chip, ®,
+ chip->buck_base + CHGR_BUCK_PSTG_CTRL,
+ 1);
+
+ if (rc)
+ pr_err("Error %d writing 0x%x power stage register\n", rc, reg);
+ return rc;
+}
+
+static int
+qpnp_chg_get_vusbin_uv(struct qpnp_chg_chip *chip)
+{
+ int rc = 0;
+ struct qpnp_vadc_result results;
+
+ rc = qpnp_vadc_read(chip->vadc_dev, USBIN, &results);
+ if (rc) {
+ pr_err("Unable to read vbat rc=%d\n", rc);
+ return 0;
+ }
+ return results.physical;
+}
+
+static
+int get_vusb_averaged(struct qpnp_chg_chip *chip, int sample_count)
+{
+ int vusb_uv = 0;
+ int i;
+
+ /* avoid overflows */
+ if (sample_count > 256)
+ sample_count = 256;
+
+ for (i = 0; i < sample_count; i++)
+ vusb_uv += qpnp_chg_get_vusbin_uv(chip);
+
+ vusb_uv = vusb_uv / sample_count;
+ return vusb_uv;
+}
+
+static
+int get_vbat_averaged(struct qpnp_chg_chip *chip, int sample_count)
+{
+ int vbat_uv = 0;
+ int i;
+
+ /* avoid overflows */
+ if (sample_count > 256)
+ sample_count = 256;
+
+ for (i = 0; i < sample_count; i++)
+ vbat_uv += get_prop_battery_voltage_now(chip);
+
+ vbat_uv = vbat_uv / sample_count;
+ return vbat_uv;
+}
+
+static void
+qpnp_chg_reduce_power_stage(struct qpnp_chg_chip *chip)
+{
+ struct timespec ts;
+ bool power_stage_reduced_in_hw = qpnp_chg_is_power_stage_reduced(chip);
+ bool reduce_power_stage = false;
+ int vbat_uv = get_vbat_averaged(chip, 16);
+ int vusb_uv = get_vusb_averaged(chip, 16);
+ bool fast_chg =
+ (get_prop_charge_type(chip) == POWER_SUPPLY_CHARGE_TYPE_FAST);
+ static int count_restore_power_stage;
+ static int count_reduce_power_stage;
+ bool vchg_loop = get_prop_vchg_loop(chip);
+ bool ichg_loop = qpnp_chg_is_ichg_loop_active(chip);
+ bool usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+ bool usb_ma_above_wall =
+ (qpnp_chg_usb_iusbmax_get(chip) > USB_WALL_THRESHOLD_MA);
+
+ if (fast_chg
+ && usb_present
+ && usb_ma_above_wall
+ && vbat_uv < POWER_STAGE_REDUCE_MAX_VBAT_UV
+ && vusb_uv > POWER_STAGE_REDUCE_MIN_VCHG_UV)
+ reduce_power_stage = true;
+
+ if ((usb_present && usb_ma_above_wall)
+ && (vchg_loop || ichg_loop))
+ reduce_power_stage = true;
+
+ if (power_stage_reduced_in_hw && !reduce_power_stage) {
+ count_restore_power_stage++;
+ count_reduce_power_stage = 0;
+ } else if (!power_stage_reduced_in_hw && reduce_power_stage) {
+ count_reduce_power_stage++;
+ count_restore_power_stage = 0;
+ } else if (power_stage_reduced_in_hw == reduce_power_stage) {
+ count_restore_power_stage = 0;
+ count_reduce_power_stage = 0;
+ }
+
+ pr_debug("power_stage_hw = %d reduce_power_stage = %d usb_present = %d usb_ma_above_wall = %d vbat_uv(16) = %d vusb_uv(16) = %d fast_chg = %d , ichg = %d, vchg = %d, restore,reduce = %d, %d\n",
+ power_stage_reduced_in_hw, reduce_power_stage,
+ usb_present, usb_ma_above_wall,
+ vbat_uv, vusb_uv, fast_chg,
+ ichg_loop, vchg_loop,
+ count_restore_power_stage, count_reduce_power_stage);
+
+ if (!power_stage_reduced_in_hw && reduce_power_stage) {
+ if (count_reduce_power_stage >= 2) {
+ qpnp_chg_power_stage_set(chip, true);
+ power_stage_reduced_in_hw = true;
+ }
+ }
+
+ if (power_stage_reduced_in_hw && !reduce_power_stage) {
+ if (count_restore_power_stage >= 6
+ || (!usb_present || !usb_ma_above_wall)) {
+ qpnp_chg_power_stage_set(chip, false);
+ power_stage_reduced_in_hw = false;
+ }
+ }
+
+ if (usb_present && usb_ma_above_wall) {
+ getnstimeofday(&ts);
+ ts.tv_sec += POWER_STAGE_REDUCE_CHECK_PERIOD_SECONDS;
+ alarm_start_range(&chip->reduce_power_stage_alarm,
+ timespec_to_ktime(ts),
+ timespec_to_ktime(ts));
+ } else {
+ pr_debug("stopping power stage workaround\n");
+ chip->power_stage_workaround_running = false;
+ }
+}
+
+static void
+qpnp_chg_reduce_power_stage_work(struct work_struct *work)
+{
+ struct qpnp_chg_chip *chip = container_of(work,
+ struct qpnp_chg_chip, reduce_power_stage_work);
+
+ qpnp_chg_reduce_power_stage(chip);
+}
+
+static void
+qpnp_chg_reduce_power_stage_callback(struct alarm *alarm)
+{
+ struct qpnp_chg_chip *chip = container_of(alarm, struct qpnp_chg_chip,
+ reduce_power_stage_alarm);
+
+ schedule_work(&chip->reduce_power_stage_work);
+}
+
static int
qpnp_dc_power_set_property(struct power_supply *psy,
enum power_supply_property psp,
@@ -2543,15 +2779,39 @@
return rc;
}
-static void
+static int
qpnp_chg_setup_flags(struct qpnp_chg_chip *chip)
{
if (chip->revision > 0 && chip->type == SMBB)
chip->flags |= CHG_FLAGS_VCP_WA;
if (chip->type == SMBB)
chip->flags |= BOOST_FLASH_WA;
- if (chip->type == SMBBP)
- chip->flags |= BOOST_FLASH_WA;
+ if (chip->type == SMBBP) {
+ struct device_node *revid_dev_node;
+ struct pmic_revid_data *revid_data;
+
+ chip->flags |= BOOST_FLASH_WA;
+
+ revid_dev_node = of_parse_phandle(chip->spmi->dev.of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property\n");
+ return -EINVAL;
+ }
+ revid_data = get_revid_data(revid_dev_node);
+ if (IS_ERR(revid_data)) {
+ pr_err("Couldnt get revid data rc = %ld\n",
+ PTR_ERR(revid_data));
+ return PTR_ERR(revid_data);
+ }
+
+ if (revid_data->rev4 < PM8226_V2P1_REV4
+ || ((revid_data->rev4 == PM8226_V2P1_REV4)
+ && (revid_data->rev3 <= PM8226_V2P1_REV3))) {
+ chip->flags |= POWER_STAGE_WA;
+ }
+ }
+ return 0;
}
static int
@@ -3267,6 +3527,11 @@
}
mutex_init(&chip->jeita_configure_lock);
+ alarm_init(&chip->reduce_power_stage_alarm, ANDROID_ALARM_RTC_WAKEUP,
+ qpnp_chg_reduce_power_stage_callback);
+ INIT_WORK(&chip->reduce_power_stage_work,
+ qpnp_chg_reduce_power_stage_work);
+
/* Get all device tree properties */
rc = qpnp_charger_read_dt_props(chip);
if (rc)
@@ -3479,6 +3744,8 @@
}
INIT_WORK(&chip->adc_measure_work,
qpnp_bat_if_adc_measure_work);
+ INIT_WORK(&chip->adc_disable_work,
+ qpnp_bat_if_adc_disable_work);
}
wake_lock_init(&chip->eoc_wake_lock,
@@ -3506,13 +3773,17 @@
}
/* Turn on appropriate workaround flags */
- qpnp_chg_setup_flags(chip);
+ rc = qpnp_chg_setup_flags(chip);
+ if (rc < 0) {
+ pr_err("failed to setup flags rc=%d\n", rc);
+ goto unregister_dc_psy;
+ }
if (chip->maxinput_dc_ma && chip->dc_chgpth_base) {
rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
if (rc) {
pr_err("Error setting idcmax property %d\n", rc);
- goto unregister_batt;
+ goto unregister_dc_psy;
}
}
@@ -3532,14 +3803,14 @@
&chip->adc_param);
if (rc) {
pr_err("request ADC error %d\n", rc);
- goto fail_chg_enable;
+ goto unregister_dc_psy;
}
}
}
rc = qpnp_chg_bat_if_configure_btc(chip);
if (rc) {
pr_err("failed to configure btc %d\n", rc);
- goto unregister_batt;
+ goto unregister_dc_psy;
}
qpnp_chg_charge_en(chip, !chip->charging_disabled);
@@ -3549,7 +3820,7 @@
rc = qpnp_chg_request_irqs(chip);
if (rc) {
pr_err("failed to request interrupts %d\n", rc);
- goto unregister_batt;
+ goto unregister_dc_psy;
}
qpnp_chg_usb_usbin_valid_irq_handler(USBIN_VALID_IRQ, chip);
@@ -3571,6 +3842,9 @@
get_prop_batt_health(chip));
return 0;
+unregister_dc_psy:
+ if (chip->dc_chgpth_base)
+ power_supply_unregister(&chip->dc_psy);
unregister_batt:
if (chip->bat_if_base)
power_supply_unregister(&chip->batt_psy);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 69031dc..fcc5a8d 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -664,6 +664,15 @@
lower_thr = true;
}
if (upper_thr || lower_thr) {
+ unsigned long temp;
+ enum thermal_trip_type trip =
+ THERMAL_TRIP_CONFIGURABLE_LOW;
+
+ if (upper_thr)
+ trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp);
+ thermal_sensor_trip(tm->sensor[i].tz_dev, trip, temp);
+
/* Notify user space */
queue_work(tm->tsens_wq, &tm->sensor[i].work);
rc = tsens_get_sw_id_mapping(
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 974cadc..00df613 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -14,9 +14,11 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/msm_tsens.h>
#include <linux/workqueue.h>
+#include <linux/completion.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/msm_tsens.h>
@@ -29,6 +31,7 @@
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/android_alarm.h>
+#include <linux/thermal.h>
#include <mach/cpufreq.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
@@ -45,7 +48,10 @@
static uint32_t wakeup_ms;
static struct alarm thermal_rtc;
static struct kobject *tt_kobj;
+static struct kobject *cc_kobj;
static struct work_struct timer_work;
+static struct task_struct *hotplug_task;
+static struct completion hotplug_notify_complete;
static int enabled;
static int rails_cnt;
@@ -67,6 +73,14 @@
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
+struct cpu_info {
+ uint32_t cpu;
+ bool offline;
+ bool user_offline;
+ const char *sensor_type;
+ struct sensor_threshold thresh[2];
+};
+
struct rail {
const char *name;
uint32_t freq_req;
@@ -91,6 +105,7 @@
static struct psm_rail *psm_rails;
static struct rail *rails;
+static struct cpu_info cpus[NR_CPUS];
struct vdd_rstr_enable {
struct kobj_attribute ko_attr;
@@ -658,11 +673,67 @@
}
mutex_unlock(&core_control_mutex);
}
+/* Call with core_control_mutex locked */
+static int __ref update_offline_cores(int val)
+{
+ int cpu = 0;
+ int ret = 0;
+
+ if (!core_control_enabled)
+ return 0;
+
+ cpus_offlined = msm_thermal_info.core_control_mask & val;
+
+ for_each_possible_cpu(cpu) {
+ if (!(cpus_offlined & BIT(cpu)))
+ continue;
+ if (!cpu_online(cpu))
+ continue;
+ ret = cpu_down(cpu);
+ if (ret)
+ pr_err("%s: Unable to offline cpu%d\n",
+ KBUILD_MODNAME, cpu);
+ }
+ return ret;
+}
+
+static __ref int do_hotplug(void *data)
+{
+ int ret = 0;
+ int cpu = 0;
+ uint32_t mask = 0;
+
+ if (!core_control_enabled)
+ return -EINVAL;
+
+ while (!kthread_should_stop()) {
+ wait_for_completion(&hotplug_notify_complete);
+ INIT_COMPLETION(hotplug_notify_complete);
+ mask = 0;
+
+ mutex_lock(&core_control_mutex);
+ for_each_possible_cpu(cpu) {
+ if (cpus[cpu].offline || cpus[cpu].user_offline)
+ mask |= BIT(cpu);
+ }
+ if (mask != cpus_offlined)
+ update_offline_cores(mask);
+ mutex_unlock(&core_control_mutex);
+ sysfs_notify(cc_kobj, NULL, "cpus_offlined");
+ }
+
+ return ret;
+}
#else
static void do_core_control(long temp)
{
return;
}
+
+static __ref int do_hotplug(void *data)
+{
+ return 0;
+}
#endif
static int do_vdd_restriction(void)
@@ -848,7 +919,7 @@
if (core_control_enabled &&
(msm_thermal_info.core_control_mask & BIT(cpu)) &&
(cpus_offlined & BIT(cpu))) {
- pr_info(
+ pr_debug(
"%s: Preventing cpu%d from coming online.\n",
KBUILD_MODNAME, cpu);
return NOTIFY_BAD;
@@ -896,6 +967,112 @@
ts.tv_sec, ts.tv_usec);
}
+static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
+{
+ struct cpu_info *cpu_node = (struct cpu_info *)data;
+
+ pr_info("%s: %s reach temp threshold: %d\n", KBUILD_MODNAME,
+ cpu_node->sensor_type, temp);
+
+ if (!(msm_thermal_info.core_control_mask & BIT(cpu_node->cpu)))
+ return 0;
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ if (!(cpu_node->offline))
+ cpu_node->offline = 1;
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ if (cpu_node->offline)
+ cpu_node->offline = 0;
+ break;
+ default:
+ break;
+ }
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else
+ pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+ return 0;
+}
+/* Adjust cpus offlined bit based on temperature reading. */
+static int hotplug_init_cpu_offlined(void)
+{
+ struct tsens_device tsens_dev;
+ long temp = 0;
+ int cpu = 0;
+
+ mutex_lock(&core_control_mutex);
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+ continue;
+ tsens_dev.sensor_num = sensor_get_id(\
+ (char *)cpus[cpu].sensor_type);
+ if (tsens_get_temp(&tsens_dev, &temp)) {
+ pr_err("%s: Unable to read TSENS sensor %d\n",
+ KBUILD_MODNAME, tsens_dev.sensor_num);
+ return -EINVAL;
+ }
+
+ if (temp >= msm_thermal_info.hotplug_temp_degC)
+ cpus[cpu].offline = 1;
+ else if (temp <= (msm_thermal_info.hotplug_temp_degC -
+ msm_thermal_info.hotplug_temp_hysteresis_degC))
+ cpus[cpu].offline = 0;
+ }
+ mutex_unlock(&core_control_mutex);
+
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else {
+ pr_err("%s: Hotplug task is not initialized\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void hotplug_init(void)
+{
+ int cpu = 0;
+
+ if (hotplug_task)
+ return;
+
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+ continue;
+ cpus[cpu].cpu = (uint32_t)cpu;
+ cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
+ cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ cpus[cpu].thresh[0].notify = hotplug_notify;
+ cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
+ sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+ &cpus[cpu].thresh[0]);
+
+ cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
+ msm_thermal_info.hotplug_temp_hysteresis_degC;
+ cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ cpus[cpu].thresh[1].notify = hotplug_notify;
+ cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
+ sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+ &cpus[cpu].thresh[1]);
+
+ }
+ init_completion(&hotplug_notify_complete);
+ hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
+ if (IS_ERR(hotplug_task)) {
+ pr_err("%s: Failed to create do_hotplug thread\n",
+ KBUILD_MODNAME);
+ return;
+ }
+ /*
+ * Adjust cpus offlined bit when hotplug intitializes so that the new
+ * cpus offlined state is based on hotplug threshold range
+ */
+ if (hotplug_init_cpu_offlined())
+ kthread_stop(hotplug_task);
+}
+
/*
* We will reset the cpu frequencies limits here. The core online/offline
* status will be carried over to the process stopping the msm_thermal, as
@@ -922,9 +1099,10 @@
int ret = 0;
ret = param_set_bool(val, kp);
- if (!enabled)
+ if (!enabled) {
disable_msm_thermal();
- else
+ hotplug_init();
+ } else
pr_info("%s: no action for enabled = %d\n",
KBUILD_MODNAME, enabled);
@@ -941,37 +1119,6 @@
module_param_cb(enabled, &module_ops, &enabled, 0644);
MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
-
-#ifdef CONFIG_SMP
-/* Call with core_control_mutex locked */
-static int __ref update_offline_cores(int val)
-{
- int cpu = 0;
- int ret = 0;
-
- cpus_offlined = msm_thermal_info.core_control_mask & val;
- if (!core_control_enabled)
- return 0;
-
- for_each_possible_cpu(cpu) {
- if (!(cpus_offlined & BIT(cpu)))
- continue;
- if (!cpu_online(cpu))
- continue;
- ret = cpu_down(cpu);
- if (ret)
- pr_err("%s: Unable to offline cpu%d\n",
- KBUILD_MODNAME, cpu);
- }
- return ret;
-}
-#else
-static int update_offline_cores(int val)
-{
- return 0;
-}
-#endif
-
static ssize_t show_cc_enabled(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -984,7 +1131,6 @@
int ret = 0;
int val = 0;
- mutex_lock(&core_control_mutex);
ret = kstrtoint(buf, 10, &val);
if (ret) {
pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
@@ -998,14 +1144,17 @@
if (core_control_enabled) {
pr_info("%s: Core control enabled\n", KBUILD_MODNAME);
register_cpu_notifier(&msm_thermal_cpu_notifier);
- update_offline_cores(cpus_offlined);
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else
+ pr_err("%s: Hotplug task is not initialized\n",
+ KBUILD_MODNAME);
} else {
pr_info("%s: Core control disabled\n", KBUILD_MODNAME);
unregister_cpu_notifier(&msm_thermal_cpu_notifier);
}
done_store_cc:
- mutex_unlock(&core_control_mutex);
return count;
}
@@ -1020,6 +1169,7 @@
{
int ret = 0;
uint32_t val = 0;
+ int cpu;
mutex_lock(&core_control_mutex);
ret = kstrtouint(buf, 10, &val);
@@ -1034,10 +1184,16 @@
goto done_cc;
}
- if (cpus_offlined == val)
- goto done_cc;
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.core_control_mask & BIT(cpu)))
+ continue;
+ cpus[cpu].user_offline = !!(val & BIT(cpu));
+ }
- update_offline_cores(val);
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else
+ pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
done_cc:
mutex_unlock(&core_control_mutex);
return count;
@@ -1108,7 +1264,6 @@
static __init int msm_thermal_add_cc_nodes(void)
{
struct kobject *module_kobj = NULL;
- struct kobject *cc_kobj = NULL;
int ret = 0;
module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
@@ -1190,8 +1345,7 @@
return -EINVAL;
enabled = 1;
- if (num_possible_cpus() > 1)
- core_control_enabled = 1;
+
INIT_DELAYED_WORK(&check_temp_work, check_temp);
schedule_delayed_work(&check_temp_work, 0);
@@ -1602,12 +1756,76 @@
return ret;
}
+static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ char *key = NULL;
+ int cpu_cnt = 0;
+ int ret = 0;
+ int cpu = 0;
+
+ key = "qcom,core-limit-temp";
+ ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,core-temp-hysteresis";
+ ret = of_property_read_u32(node, key, &data->core_temp_hysteresis_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,core-control-mask";
+ ret = of_property_read_u32(node, key, &data->core_control_mask);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,hotplug-temp";
+ ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,hotplug-temp-hysteresis";
+ ret = of_property_read_u32(node, key,
+ &data->hotplug_temp_hysteresis_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,cpu-sensors";
+ cpu_cnt = of_property_count_strings(node, key);
+ if (cpu_cnt != num_possible_cpus()) {
+ pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
+ goto read_node_fail;
+ }
+
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].cpu = cpu;
+ cpus[cpu].offline = 0;
+ cpus[cpu].user_offline = 0;
+ ret = of_property_read_string_index(node, key, cpu,
+ &cpus[cpu].sensor_type);
+ if (ret)
+ goto read_node_fail;
+ }
+
+ if (num_possible_cpus() > 1)
+ core_control_enabled = 1;
+
+read_node_fail:
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ KBUILD_MODNAME, node->full_name, key);
+ core_control_enabled = 0;
+ }
+
+ return ret;
+}
+
static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
{
int ret = 0;
char *key = NULL;
struct device_node *node = pdev->dev.of_node;
-
struct msm_thermal_data data;
memset(&data, 0, sizeof(struct msm_thermal_data));
@@ -1640,15 +1858,7 @@
key = "qcom,freq-control-mask";
ret = of_property_read_u32(node, key, &data.freq_control_mask);
- key = "qcom,core-limit-temp";
- ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
-
- key = "qcom,core-temp-hysteresis";
- ret = of_property_read_u32(node, key, &data.core_temp_hysteresis_degC);
-
- key = "qcom,core-control-mask";
- ret = of_property_read_u32(node, key, &data.core_control_mask);
-
+ ret = probe_cc(node, &data, pdev);
/*
* Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 5b78cdd..467d89d 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1324,15 +1324,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t qpnp_adc_tm_isr(int irq, void *data)
-{
- struct qpnp_adc_tm_chip *chip = data;
-
- complete(&chip->adc->adc_rslt_completion);
-
- return IRQ_HANDLED;
-}
-
static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
unsigned long *temp)
{
@@ -1620,17 +1611,6 @@
goto fail;
}
- rc = devm_request_irq(&spmi->dev, chip->adc->adc_irq_eoc,
- qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
- "qpnp_adc_tm_interrupt", chip);
- if (rc) {
- dev_err(&spmi->dev,
- "failed to request adc irq with error %d\n", rc);
- goto fail;
- } else {
- enable_irq_wake(chip->adc->adc_irq_eoc);
- }
-
rc = devm_request_irq(&spmi->dev, chip->adc->adc_high_thr_irq,
qpnp_adc_tm_high_thr_isr,
IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index fd1a2fc..1cf901e 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -4,6 +4,7 @@
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -60,6 +61,273 @@
static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock);
+static LIST_HEAD(sensor_info_list);
+static DEFINE_MUTEX(sensor_list_lock);
+
+static struct sensor_info *get_sensor(uint32_t sensor_id)
+{
+ struct sensor_info *pos, *var;
+
+ list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+ if (pos->sensor_id == sensor_id)
+ break;
+ }
+
+ return pos;
+}
+
+int sensor_get_id(char *name)
+{
+ struct sensor_info *pos, *var;
+
+ list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+ if (!strcmp(pos->tz->type, name))
+ return pos->sensor_id;
+ }
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL(sensor_get_id);
+
+static void __update_sensor_thresholds(struct sensor_info *sensor)
+{
+ int min = INT_MIN;
+ int max = INT_MAX;
+ struct sensor_threshold *pos, *var;
+ enum thermal_trip_type type;
+ int i;
+ unsigned long curr_temp;
+
+ for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
+ (sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
+ i++) {
+ sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
+ if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+ sensor->max_idx = i;
+ if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+ sensor->min_idx = i;
+ }
+
+ get_cpu();
+ sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
+ list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+ (pos->temp < (int)curr_temp))
+ if (pos->temp > min)
+ min = pos->temp;
+ if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+ (pos->temp > (int)curr_temp))
+ if (pos->temp < max)
+ max = pos->temp;
+ }
+ put_cpu();
+
+ if (sensor->tz->ops->set_trip_temp) {
+ if (max != INT_MAX) {
+ sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->max_idx, max);
+ sensor->threshold_max = max;
+ }
+ if (min != INT_MIN) {
+ sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->min_idx, min);
+ sensor->threshold_min = min;
+ }
+ }
+
+ pr_debug("sensor %d, min: %d, max %d\n", sensor->sensor_id, min, max);
+}
+
+static void sensor_update_work(struct work_struct *work)
+{
+ struct sensor_info *sensor = container_of(work, struct sensor_info,
+ work);
+ mutex_lock(&sensor->lock);
+ __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+}
+
+/* May be called in an interrupt context.
+ * Do NOT call sensor_set_trip from this function
+ */
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type trip, unsigned long temp)
+{
+ struct sensor_threshold *pos, *var;
+ int ret = -ENODEV;
+
+ if (trip != THERMAL_TRIP_CONFIGURABLE_HI &&
+ trip != THERMAL_TRIP_CONFIGURABLE_LOW)
+ return 0;
+
+ if (list_empty(&tz->sensor.threshold_list))
+ return 0;
+
+ list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
+ if (pos->trip != trip)
+ continue;
+ if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+ (pos->temp <= tz->sensor.threshold_min) &&
+ (pos->temp >= (int) temp)) ||
+ ((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+ (pos->temp >= tz->sensor.threshold_max) &&
+ (pos->temp <= (int)temp))) {
+ pos->notify(trip, temp, pos->data);
+ }
+ }
+
+ schedule_work(&tz->sensor.work);
+
+ return ret;
+}
+EXPORT_SYMBOL(thermal_sensor_trip);
+
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+ struct sensor_threshold *pos, *var;
+ struct sensor_info *sensor = get_sensor(sensor_id);
+
+ if (!sensor)
+ return -ENODEV;
+
+ if (!threshold || !threshold->notify)
+ return -EFAULT;
+
+ mutex_lock(&sensor->lock);
+ list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if (pos == threshold)
+ break;
+ }
+
+ if (pos != threshold) {
+ INIT_LIST_HEAD(&threshold->list);
+ list_add(&threshold->list, &sensor->threshold_list);
+ }
+
+ __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+
+}
+EXPORT_SYMBOL(sensor_set_trip);
+
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+ struct sensor_threshold *pos, *var;
+ struct sensor_info *sensor = get_sensor(sensor_id);
+
+ if (!sensor)
+ return -ENODEV;
+
+ mutex_lock(&sensor->lock);
+ list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if (pos == threshold) {
+ list_del(&pos->list);
+ break;
+ }
+ }
+
+ __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(sensor_cancel_trip);
+
+static int sensor_get_trip_temp(struct thermal_zone_device *tz,
+ int type, unsigned long *temp)
+{
+ struct sensor_info *sensor = get_sensor(tz->id);
+
+ if (!sensor)
+ return -EFAULT;
+
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ *temp = tz->sensor.threshold_max;
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ *temp = tz->sensor.threshold_min;
+ break;
+ default:
+ tz->ops->get_trip_temp(tz, type, temp);
+ break;
+ }
+
+ return 0;
+}
+
+static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
+{
+ struct thermal_zone_device *tz = (struct thermal_zone_device *)data;
+
+ pr_debug("sensor %d tripped: type %d temp %d\n",
+ tz->sensor.sensor_id, type, temp);
+
+ return 0;
+}
+
+int sensor_set_trip_temp(struct thermal_zone_device *tz,
+ int trip, long temp)
+{
+ int ret = 0;
+ enum thermal_trip_type type;
+
+ if (!tz->ops->get_trip_type)
+ return -EPERM;
+
+ tz->ops->get_trip_type(tz, trip, &type);
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ tz->tz_threshold[0].temp = temp;
+ tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ tz->tz_threshold[0].notify = tz_notify_trip;
+ tz->tz_threshold[0].data = tz;
+ ret = sensor_set_trip(tz->sensor.sensor_id,
+ &tz->tz_threshold[0]);
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ tz->tz_threshold[1].temp = temp;
+ tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ tz->tz_threshold[1].notify = tz_notify_trip;
+ tz->tz_threshold[1].data = tz;
+ ret = sensor_set_trip(tz->sensor.sensor_id,
+ &tz->tz_threshold[1]);
+ break;
+ default:
+ ret = tz->ops->set_trip_temp(tz, trip, temp);
+ break;
+ }
+
+ return ret;
+}
+
+int sensor_init(struct thermal_zone_device *tz)
+{
+ struct sensor_info *sensor = &tz->sensor;
+
+ sensor->sensor_id = tz->id;
+ sensor->tz = tz;
+ sensor->threshold_min = 0;
+ sensor->threshold_max = INT_MAX;
+ sensor->max_idx = -1;
+ sensor->min_idx = -1;
+ mutex_init(&sensor->lock);
+ INIT_LIST_HEAD(&sensor->sensor_list);
+ INIT_LIST_HEAD(&sensor->threshold_list);
+ INIT_LIST_HEAD(&tz->tz_threshold[0].list);
+ INIT_LIST_HEAD(&tz->tz_threshold[1].list);
+ tz->tz_threshold[0].notify = NULL;
+ tz->tz_threshold[0].data = NULL;
+ tz->tz_threshold[1].notify = NULL;
+ tz->tz_threshold[1].data = NULL;
+ list_add(&sensor->sensor_list, &sensor_info_list);
+ INIT_WORK(&sensor->work, sensor_update_work);
+
+ return 0;
+}
+
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{
int err;
@@ -243,7 +511,7 @@
if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
return -EINVAL;
- ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+ ret = sensor_get_trip_temp(tz, trip, &temperature);
if (ret)
return ret;
@@ -268,7 +536,8 @@
if (!sscanf(buf, "%ld", &temperature))
return -EINVAL;
- ret = tz->ops->set_trip_temp(tz, trip, temperature);
+ ret = sensor_set_trip_temp(tz, trip, temperature);
+
if (ret)
return ret;
@@ -1313,6 +1582,7 @@
if (result)
break;
}
+ sensor_init(tz);
mutex_unlock(&thermal_list_lock);
INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
@@ -1372,6 +1642,10 @@
&trip_point_attrs[count * 2 + 1]);
}
thermal_remove_hwmon_sysfs(tz);
+ flush_work(&tz->sensor.work);
+ mutex_lock(&thermal_list_lock);
+ list_del(&tz->sensor.sensor_list);
+ mutex_unlock(&thermal_list_lock);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
mutex_destroy(&tz->lock);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index d520253..a4a4f28 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -47,6 +47,8 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/wakelock.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
#include <mach/board.h>
#include <mach/msm_serial_hs_lite.h>
#include <mach/msm_bus.h>
@@ -166,12 +168,17 @@
static inline void msm_hsl_write(struct uart_port *port,
unsigned int val, unsigned int off)
{
- iowrite32(val, port->membase + off);
+ __iowmb();
+ __raw_writel_no_log((__force __u32)cpu_to_le32(val),
+ port->membase + off);
}
static inline unsigned int msm_hsl_read(struct uart_port *port,
unsigned int off)
{
- return ioread32(port->membase + off);
+ unsigned int v = le32_to_cpu((__force __le32)__raw_readl_no_log(
+ port->membase + off));
+ __iormb();
+ return v;
}
static unsigned int msm_serial_hsl_has_gsbi(struct uart_port *port)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index db6fec9..98c6884 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -111,7 +111,33 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(mode);
+ /*
+ * Set this bit so that device attempts three more times at SS, even
+ * if it failed previously to operate in SS mode.
+ */
+ reg |= DWC3_GCTL_U2RSTECN;
+ if (mode == DWC3_GCTL_PRTCAP_HOST) {
+ /*
+ * Allow ITP generated off of ref clk based counter instead
+ * of UTMI/ULPI clk based counter, when superspeed only is
+ * active so that UTMI/ULPI PHY can be suspened.
+ */
+ reg |= DWC3_GCTL_SOFITPSYNC;
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
+ } else if (mode == DWC3_GCTL_PRTCAP_DEVICE) {
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
+ reg &= ~(DWC3_GCTL_SOFITPSYNC);
+ }
+ reg |= DWC3_GCTL_U2EXIT_LFPS;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
/**
@@ -127,6 +153,9 @@
reg |= DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ if (dwc->revision >= DWC3_REVISION_230A)
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
+
/* Assert USB3 PHY reset */
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
@@ -155,6 +184,9 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ if (dwc->revision >= DWC3_REVISION_230A)
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
}
/**
@@ -473,6 +505,20 @@
dwc3_gadget_restart(dwc);
}
+static void (*notify_event) (struct dwc3 *, unsigned);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned))
+{
+ notify_event = notify;
+}
+EXPORT_SYMBOL(dwc3_set_notifier);
+
+void dwc3_notify_event(struct dwc3 *dwc, unsigned event)
+{
+ if (dwc->notify_event)
+ dwc->notify_event(dwc, event);
+}
+EXPORT_SYMBOL(dwc3_notify_event);
+
#define DWC3_ALIGN_MASK (16 - 1)
static u64 dwc3_dma_mask = DMA_BIT_MASK(64);
@@ -504,6 +550,7 @@
if (!dev->coherent_dma_mask)
dev->coherent_dma_mask = DMA_BIT_MASK(64);
+ dwc->notify_event = notify_event;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing IRQ\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 2064c13..328f6f4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -163,7 +163,10 @@
/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
+#define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000)
#define DWC3_GCTL_U2RSTECN (1 << 16)
+#define DWC3_GCTL_SOFITPSYNC (1 << 10)
+#define DWC3_GCTL_U2EXIT_LFPS (1 << 2)
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
#define DWC3_GCTL_CLK_BUS (0)
#define DWC3_GCTL_CLK_PIPE (1)
@@ -643,6 +646,9 @@
__le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
};
+#define DWC3_CONTROLLER_ERROR_EVENT 0
+#define DWC3_CONTROLLER_RESET_EVENT 1
+#define DWC3_CONTROLLER_POST_RESET_EVENT 2
/**
* struct dwc3 - representation of our controller
* @ctrl_req: usb control request which is used for ep0
@@ -771,6 +777,7 @@
/* Indicate if software connect was issued by the usb_gadget_driver */
bool softconnect;
+ void (*notify_event) (struct dwc3 *, unsigned);
};
/* -------------------------------------------------------------------------- */
@@ -922,6 +929,9 @@
void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
int dwc3_event_buffers_setup(struct dwc3 *dwc);
+extern void dwc3_set_notifier(
+ void (*notify) (struct dwc3 *dwc3, unsigned event));
+extern void dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
extern int dwc3_get_device_id(void);
extern void dwc3_put_device_id(int id);
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index b156c5f..4901f4b 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -46,6 +46,7 @@
extern void dbg_setup(u8, const struct usb_ctrlrequest*);
extern int dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *);
+extern void dbg_print_reg(const char *name, int reg);
#else
static inline void dbg_event(u8, const char*, int)
{ }
@@ -57,6 +58,8 @@
{ }
static inline void dbg_setup(u8, const struct usb_ctrlrequest*)
{ }
+static inline void dbg_print_reg(const char *name, int reg)
+{ }
static inline int dwc3_debugfs_init(struct dwc3 *d)
{ return 0; }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index df95646..a2580fc 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -972,6 +972,28 @@
}
/**
+ * dbg_print_reg: prints a reg value
+ * @name: reg name
+ * @reg: reg value to be printed
+ */
+void dbg_print_reg(const char *name, int reg)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+ scnprintf(dbg_dwc3_data.buf[dbg_dwc3_data.idx], DBG_DATA_MSG,
+ "%s = 0x%08x\n", name, reg);
+
+ dbg_inc(&dbg_dwc3_data.idx);
+
+ write_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+ if (dbg_dwc3_data.tty != 0)
+ pr_notice("%s = 0x%08x\n", name, reg);
+}
+
+/**
* store_events: configure if events are going to be also printed to console
*
*/
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index d3ea3be..d7721dc 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -50,6 +50,7 @@
#include "dwc3_otg.h"
#include "core.h"
#include "gadget.h"
+#include "debug.h"
/* ADC threshold values */
static int adc_low_threshold = 700;
@@ -140,6 +141,7 @@
#define QSCRATCH_REG_OFFSET (0x000F8800)
#define QSCRATCH_CTRL_REG (QSCRATCH_REG_OFFSET + 0x04)
#define QSCRATCH_GENERAL_CFG (QSCRATCH_REG_OFFSET + 0x08)
+#define QSCRATCH_RAM1_REG (QSCRATCH_REG_OFFSET + 0x0C)
#define HS_PHY_CTRL_REG (QSCRATCH_REG_OFFSET + 0x10)
#define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
#define CHARGING_DET_CTRL_REG (QSCRATCH_REG_OFFSET + 0x18)
@@ -156,6 +158,8 @@
#define SS_CR_PROTOCOL_CAP_DATA_REG (QSCRATCH_REG_OFFSET + 0x48)
#define SS_CR_PROTOCOL_READ_REG (QSCRATCH_REG_OFFSET + 0x4C)
#define SS_CR_PROTOCOL_WRITE_REG (QSCRATCH_REG_OFFSET + 0x50)
+#define PWR_EVNT_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x58)
+#define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C)
struct dwc3_msm_req_complete {
struct list_head list_item;
@@ -223,7 +227,7 @@
bool ext_inuse;
enum dwc3_id_state id_state;
unsigned long lpm_flags;
-#define MDWC3_CORECLK_OFF BIT(0)
+#define MDWC3_PHY_REF_AND_CORECLK_OFF BIT(0)
#define MDWC3_TCXO_SHUTDOWN BIT(1)
u32 qscratch_ctl_val;
@@ -410,6 +414,37 @@
}
/**
+ * Dump all QSCRATCH registers.
+ *
+ */
+static void dwc3_msm_dump_phy_info(struct dwc3_msm *mdwc)
+{
+
+ dbg_print_reg("SSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+ SS_PHY_CTRL_REG));
+ dbg_print_reg("HSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+ HS_PHY_CTRL_REG));
+ dbg_print_reg("QSCRATCH_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+ QSCRATCH_CTRL_REG));
+ dbg_print_reg("QSCRATCH_GENERAL_CFG", dwc3_msm_read_reg(mdwc->base,
+ QSCRATCH_GENERAL_CFG));
+ dbg_print_reg("PARAMETER_OVERRIDE_X_REG", dwc3_msm_read_reg(mdwc->base,
+ PARAMETER_OVERRIDE_X_REG));
+ dbg_print_reg("HS_PHY_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+ HS_PHY_IRQ_STAT_REG));
+ dbg_print_reg("SS_PHY_PARAM_CTRL_1", dwc3_msm_read_reg(mdwc->base,
+ SS_PHY_PARAM_CTRL_1));
+ dbg_print_reg("SS_PHY_PARAM_CTRL_2", dwc3_msm_read_reg(mdwc->base,
+ SS_PHY_PARAM_CTRL_2));
+ dbg_print_reg("QSCRATCH_RAM1_REG", dwc3_msm_read_reg(mdwc->base,
+ QSCRATCH_RAM1_REG));
+ dbg_print_reg("PWR_EVNT_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+ PWR_EVNT_IRQ_STAT_REG));
+ dbg_print_reg("PWR_EVNT_IRQ_MASK_REG", dwc3_msm_read_reg(mdwc->base,
+ PWR_EVNT_IRQ_MASK_REG));
+}
+
+/**
* Return DBM EP number according to usb endpoint number.
*
*/
@@ -1381,8 +1416,14 @@
}
/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
-static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc,
+ unsigned event_status)
{
+ if (event_status == DWC3_CONTROLLER_POST_RESET_EVENT) {
+ dwc3_msm_ss_phy_reg_init(mdwc);
+ return;
+ }
+
/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
msleep(30);
@@ -1393,7 +1434,7 @@
dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
usleep_range(2000, 2200);
/* Ref clock must be stable now, enable ref clock for HS mode */
- dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210102);
+ dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x11210102);
usleep_range(2000, 2200);
/*
* HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
@@ -1401,8 +1442,8 @@
*/
dwc3_msm_write_reg(mdwc->base, HS_PHY_CTRL_REG, 0x5220bb2);
usleep_range(2000, 2200);
- /* Disable (bypass) VBUS and ID filters */
- dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x78);
+ /* Set XHCI_REV bit (2) to 1 - XHCI version 1.0 */
+ dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x4);
/*
* write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
* VBUS valid threshold, disconnect valid threshold, DC voltage level,
@@ -1415,14 +1456,14 @@
PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
mdwc->hsphy_init_seq & 0x03FFFFFF);
- /* Enable master clock for RAMs to allow BAM to access RAMs when
- * RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
+ /*
+ * Enable master clock for RAMs to allow BAM to access RAMs when
+ * RAM clock gating is enabled via DWC3's GCTL. Otherwise issues
* are seen where RAM clocks get turned OFF in SS mode
*/
dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);
- dwc3_msm_ss_phy_reg_init(mdwc);
/*
* This is required to restore the POR value after userspace
* is done with charger detection.
@@ -1431,6 +1472,31 @@
dwc3_msm_read_reg(mdwc->base, QSCRATCH_CTRL_REG);
}
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+ switch (event) {
+ case DWC3_CONTROLLER_ERROR_EVENT:
+ dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
+ dwc3_msm_dump_phy_info(mdwc);
+ break;
+ case DWC3_CONTROLLER_RESET_EVENT:
+ dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
+ dwc3_msm_qscratch_reg_init(mdwc, DWC3_CONTROLLER_RESET_EVENT);
+ break;
+ case DWC3_CONTROLLER_POST_RESET_EVENT:
+ dev_dbg(mdwc->dev,
+ "DWC3_CONTROLLER_POST_RESET_EVENT received\n");
+ dwc3_msm_qscratch_reg_init(mdwc,
+ DWC3_CONTROLLER_POST_RESET_EVENT);
+ break;
+ default:
+ dev_dbg(mdwc->dev, "unknown dwc3 event\n");
+ break;
+ }
+}
+
static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
{
struct dwc3_msm *mdwc = container_of(xceiv, struct dwc3_msm, ext_xceiv);
@@ -1447,9 +1513,6 @@
return;
usleep_range(10000, 12000);
-
- /* Reinitialize QSCRATCH registers after block reset */
- dwc3_msm_qscratch_reg_init(mdwc);
}
/* Reset the DBM */
@@ -1687,6 +1750,7 @@
bool dcp;
bool host_bus_suspend;
bool host_ss_active;
+ bool host_ss_suspend;
dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
@@ -1713,6 +1777,7 @@
(mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
(mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
host_bus_suspend = mdwc->host_mode == 1;
+ host_ss_suspend = host_bus_suspend && host_ss_active;
if (!dcp && !host_bus_suspend)
dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
@@ -1724,13 +1789,17 @@
* 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
* 4. Disable SSPHY ref clk
*/
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8), 0x0);
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28), 0x0);
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+ if (!host_ss_suspend) {
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+ 0x0);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+ 0x0);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
(1 << 26));
-
+ }
usleep_range(1000, 1200);
- clk_disable_unprepare(mdwc->ref_clk);
+ if (!host_ss_suspend)
+ clk_disable_unprepare(mdwc->ref_clk);
if (host_bus_suspend) {
/* Sequence for host bus suspend case:
@@ -1775,9 +1844,9 @@
if (!host_bus_suspend)
dwc3_msm_config_gdsc(mdwc, 0);
- if (!host_bus_suspend || !host_ss_active) {
+ if (!host_ss_suspend) {
clk_disable_unprepare(mdwc->core_clk);
- mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
+ mdwc->lpm_flags |= MDWC3_PHY_REF_AND_CORECLK_OFF;
}
clk_disable_unprepare(mdwc->iface_clk);
@@ -1825,6 +1894,7 @@
int ret;
bool dcp;
bool host_bus_suspend;
+ bool resume_from_core_clk_off = false;
dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
@@ -1835,6 +1905,9 @@
pm_stay_awake(mdwc->dev);
+ if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+ resume_from_core_clk_off = true;
+
if (mdwc->bus_perf_client) {
ret = msm_bus_scale_client_update_request(
mdwc->bus_perf_client, 1);
@@ -1873,13 +1946,14 @@
if (!host_bus_suspend && !dcp)
dwc3_hsusb_config_vddcx(mdwc, 1);
- clk_prepare_enable(mdwc->ref_clk);
+ if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+ clk_prepare_enable(mdwc->ref_clk);
usleep_range(1000, 1200);
clk_prepare_enable(mdwc->iface_clk);
- if (mdwc->lpm_flags & MDWC3_CORECLK_OFF) {
+ if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF) {
clk_prepare_enable(mdwc->core_clk);
- mdwc->lpm_flags &= ~MDWC3_CORECLK_OFF;
+ mdwc->lpm_flags &= ~MDWC3_PHY_REF_AND_CORECLK_OFF;
}
if (host_bus_suspend) {
@@ -1892,10 +1966,6 @@
/* Disable DP and DM HV interrupt */
dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
-
- /* Clear suspend bit in GUSB2PHYCONFIG register */
- dwc3_msm_write_readback(mdwc->base, DWC3_GUSB2PHYCFG(0),
- 0x40, 0x0);
} else {
/* Disable HV interrupt */
if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
@@ -1919,23 +1989,27 @@
}
- /* Assert SS PHY RESET */
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+ if (resume_from_core_clk_off) {
+ /* Assert SS PHY RESET */
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
(1 << 7));
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
(1 << 28));
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
(1 << 8));
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26), 0x0);
- /* 10usec delay required before de-asserting SS PHY RESET */
- udelay(10);
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7), 0x0);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+ 0x0);
+ /* 10usec delay required before de-asserting SS PHY RESET */
+ udelay(10);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+ 0x0);
- /*
- * Reinitilize SSPHY parameters as SS_PHY RESET will reset
- * the internal registers to default values.
- */
- dwc3_msm_ss_phy_reg_init(mdwc);
+ /*
+ * Reinitilize SSPHY parameters as SS_PHY RESET will reset
+ * the internal registers to default values.
+ */
+ dwc3_msm_ss_phy_reg_init(mdwc);
+ }
atomic_set(&mdwc->in_lpm, 0);
/* match disable_irq call from isr */
@@ -2072,7 +2146,7 @@
static struct dentry *dwc3_debugfs_root;
-static void dwc3_debugfs_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_debugfs_init(struct dwc3_msm *mdwc)
{
dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
@@ -2871,8 +2945,6 @@
else if (!mdwc->hsphy_init_seq)
dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
- dwc3_msm_qscratch_reg_init(mdwc);
-
pm_runtime_set_active(mdwc->dev);
pm_runtime_enable(mdwc->dev);
@@ -2891,7 +2963,7 @@
ret = -ENODEV;
goto disable_hs_ldo;
}
-
+ dwc3_set_notifier(&dwc3_msm_notify_event);
/* usb_psy required only for vbus_notifications or charging support */
if (mdwc->ext_xceiv.otg_capability ||
!mdwc->charger.charging_disabled) {
@@ -2990,7 +3062,7 @@
device_init_wakeup(mdwc->dev, 1);
pm_stay_awake(mdwc->dev);
- dwc3_debugfs_init(mdwc);
+ dwc3_msm_debugfs_init(mdwc);
return 0;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index d0d9d34..e912e86 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -56,6 +56,19 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST);
+ /*
+ * Allow ITP generated off of ref clk based counter instead
+ * of UTMI/ULPI clk based counter, when superspeed only is
+ * active so that UTMI/ULPI can be suspened.
+ */
+ reg |= DWC3_GCTL_SOFITPSYNC;
+ /*
+ * Set this bit so that device attempts three more times at SS,
+ * even if it failed previously to operate in SS mode.
+ */
+ reg |= DWC3_GCTL_U2RSTECN;
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
}
@@ -126,6 +139,14 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+ /*
+ * Set this bit so that device attempts three more times at SS,
+ * even if it failed previously to operate in SS mode.
+ */
+ reg |= DWC3_GCTL_U2RSTECN;
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
+ reg &= ~(DWC3_GCTL_SOFITPSYNC);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
}
@@ -847,7 +868,8 @@
* OCFG[1] - HNPCap = 0
* OCFG[0] - SRPCap = 0
*/
- dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
/*
* OCTL[6] - PeriMode = 1
@@ -859,7 +881,8 @@
* OCTL[0] - HstSetHNPEn = 0
*/
if (!once) {
- dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
once++;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index acda980..8cf8a6d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -63,6 +63,9 @@
MODULE_PARM_DESC(tx_fifo_resize_enable,
"Enable allocating Tx fifo for endpoints");
+static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend);
+static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
+
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
@@ -322,6 +325,16 @@
{
u32 timeout = 500;
u32 reg;
+ bool hsphy_suspend_enabled;
+ int ret;
+
+ /* Commands to controller will work only if PHY is not suspended */
+ hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+ DWC3_GUSB2PHYCFG_SUSPHY);
+
+ /* Disable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
@@ -331,7 +344,8 @@
if (!(reg & DWC3_DGCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
DWC3_DGCMD_STATUS(reg));
- return 0;
+ ret = 0;
+ break;
}
/*
@@ -339,10 +353,18 @@
* interrupt context.
*/
timeout--;
- if (!timeout)
- return -ETIMEDOUT;
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ break;
+ }
udelay(1);
} while (1);
+
+ /* Enable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+ return ret;
}
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
@@ -351,12 +373,22 @@
struct dwc3_ep *dep = dwc->eps[ep];
u32 timeout = 500;
u32 reg;
+ bool hsphy_suspend_enabled;
+ int ret;
dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
dep->name,
dwc3_gadget_ep_cmd_string(cmd), params->param0,
params->param1, params->param2);
+ /* Commands to controller will work only if PHY is not suspended */
+ hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+ DWC3_GUSB2PHYCFG_SUSPHY);
+
+ /* Disable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
+
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
@@ -374,9 +406,10 @@
* event. Hence return error in this case.
*/
if (reg & 0x2000)
- return -EAGAIN;
+ ret = -EAGAIN;
else
- return 0;
+ ret = 0;
+ break;
}
/*
@@ -384,11 +417,19 @@
* interrupt context.
*/
timeout--;
- if (!timeout)
- return -ETIMEDOUT;
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ break;
+ }
udelay(1);
} while (1);
+
+ /* Enable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+ return ret;
}
dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
@@ -1677,6 +1718,9 @@
reg |= DWC3_DCTL_HIRD_THRES(28);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+ dwc3_gadget_usb3_phy_suspend(dwc, true);
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2572,6 +2616,35 @@
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
}
+static void dwc3_dump_reg_info(struct dwc3 *dwc)
+{
+ dbg_event(0xFF, "REGDUMP", 0);
+
+ dbg_print_reg("GUSB3PIPCTL", dwc3_readl(dwc->regs,
+ DWC3_GUSB3PIPECTL(0)));
+ dbg_print_reg("GUSB2PHYCONFIG", dwc3_readl(dwc->regs,
+ DWC3_GUSB2PHYCFG(0)));
+ dbg_print_reg("GCTL", dwc3_readl(dwc->regs, DWC3_GCTL));
+ dbg_print_reg("GUCTL", dwc3_readl(dwc->regs, DWC3_GUCTL));
+ dbg_print_reg("GDBGLTSSM", dwc3_readl(dwc->regs, DWC3_GDBGLTSSM));
+ dbg_print_reg("DCFG", dwc3_readl(dwc->regs, DWC3_DCFG));
+ dbg_print_reg("DCTL", dwc3_readl(dwc->regs, DWC3_DCTL));
+ dbg_print_reg("DEVTEN", dwc3_readl(dwc->regs, DWC3_DEVTEN));
+ dbg_print_reg("DSTS", dwc3_readl(dwc->regs, DWC3_DSTS));
+ dbg_print_reg("DALPENA", dwc3_readl(dwc->regs, DWC3_DALEPENA));
+ dbg_print_reg("DGCMD", dwc3_readl(dwc->regs, DWC3_DGCMD));
+
+ dbg_print_reg("OCFG", dwc3_readl(dwc->regs, DWC3_OCFG));
+ dbg_print_reg("OCTL", dwc3_readl(dwc->regs, DWC3_OCTL));
+ dbg_print_reg("OEVT", dwc3_readl(dwc->regs, DWC3_OEVT));
+ dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
+
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
+
+ panic("DWC3 Erratic error\n");
+
+}
+
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
const struct dwc3_event_devt *event)
{
@@ -2600,6 +2673,7 @@
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
dbg_event(0xFF, "ERROR", 0);
dev_vdbg(dwc->dev, "Erratic Error\n");
+ dwc3_dump_reg_info(dwc);
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
dev_vdbg(dwc->dev, "Command Complete\n");
@@ -2824,8 +2898,8 @@
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
- dwc3_gadget_usb2_phy_suspend(dwc, false);
- dwc3_gadget_usb3_phy_suspend(dwc, false);
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+ dwc3_gadget_usb3_phy_suspend(dwc, true);
}
ret = device_register(&dwc->gadget.dev);
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index f90967f..3b94dd5 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -441,6 +441,10 @@
pr_debug("usb_qdss_disconnect_work\n");
+ status = uninit_data(qdss->data);
+ if (status)
+ pr_err("%s: uninit_data error\n", __func__);
+
/* notify qdss to cancell all active transfers*/
if (qdss->ch.notify) {
qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
@@ -458,22 +462,22 @@
{
struct f_qdss *qdss = func_to_qdss(f);
unsigned long flags;
- int status;
pr_debug("qdss_disable\n");
spin_lock_irqsave(&qdss->lock, flags);
+ if (!qdss->usb_connected) {
+ spin_unlock_irqrestore(&qdss->lock, flags);
+ return;
+ }
+
qdss->usb_connected = 0;
spin_unlock_irqrestore(&qdss->lock, flags);
/*cancell all active xfers*/
qdss_eps_disable(f);
- status = uninit_data(qdss->data);
- if (status)
- pr_err("%s: uninit_data error\n", __func__);
-
- schedule_work(&qdss->disconnect_w);
+ queue_work(qdss->wq, &qdss->disconnect_w);
}
static void usb_qdss_connect_work(struct work_struct *work)
@@ -521,6 +525,7 @@
if (gadget->speed != USB_SPEED_SUPER &&
gadget->speed != USB_SPEED_HIGH) {
pr_err("qdss_st_alt: qdss supportes HS or SS only\n");
+ ret = -EINVAL;
goto fail;
}
@@ -562,7 +567,7 @@
qdss->usb_connected = 1;
if (qdss->usb_connected && ch->app_conn)
- schedule_work(&qdss->connect_w);
+ queue_work(qdss->wq, &qdss->connect_w);
return 0;
fail:
@@ -610,7 +615,13 @@
spin_unlock_irqrestore(&d_lock, flags);
return -ENOMEM;
}
-
+ spin_unlock_irqrestore(&d_lock, flags);
+ qdss->wq = create_singlethread_workqueue(name);
+ if (!qdss->wq) {
+ kfree(qdss);
+ return -ENOMEM;
+ }
+ spin_lock_irqsave(&d_lock, flags);
ch = &qdss->ch;
ch->name = name;
list_add_tail(&ch->list, &usb_qdss_ch_list);
@@ -765,6 +776,13 @@
spin_unlock_irqrestore(&d_lock, flags);
return ERR_PTR(-ENOMEM);
}
+ spin_unlock_irqrestore(&d_lock, flags);
+ qdss->wq = create_singlethread_workqueue(name);
+ if (!qdss->wq) {
+ kfree(qdss);
+ return ERR_PTR(-ENOMEM);
+ }
+ spin_lock_irqsave(&d_lock, flags);
ch = &qdss->ch;
list_add_tail(&ch->list, &usb_qdss_ch_list);
} else {
@@ -781,7 +799,7 @@
/* the case USB cabel was connected befor qdss called qdss_open*/
if (qdss->usb_connected == 1)
- schedule_work(&qdss->connect_w);
+ queue_work(qdss->wq, &qdss->connect_w);
return ch;
}
@@ -819,7 +837,7 @@
_ch = list_entry(act, struct usb_qdss_ch, list);
qdss = container_of(_ch, struct f_qdss, ch);
spin_lock_irqsave(&d_lock, flags);
-
+ destroy_workqueue(qdss->wq);
if (!_ch->priv) {
list_del(&_ch->list);
kfree(qdss);
diff --git a/drivers/usb/gadget/f_qdss.h b/drivers/usb/gadget/f_qdss.h
index 93b5b1f..dcc80b7 100644
--- a/drivers/usb/gadget/f_qdss.h
+++ b/drivers/usb/gadget/f_qdss.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@
unsigned int data_enabled:1;
unsigned int ctrl_in_enabled:1;
unsigned int ctrl_out_enabled:1;
+ struct workqueue_struct *wq;
};
#endif
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index f2de17d..7f731d2 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -320,7 +320,7 @@
wmb();
}
-void msm_dsi_set_tx_power_mode(int mode)
+void dsi_set_tx_power_mode(int mode)
{
u32 data;
unsigned char *ctrl_base = dsi_host_private->dsi_base;
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 022d911..b1a4293 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -143,6 +143,29 @@
return 0;
}
+static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+ DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
+
+static void dsi_panel_bklt_dcs(struct mdss_panel_data *pdata, int level)
+{
+ struct mipi_panel_info *mipi;
+
+ mipi = &pdata->panel_info.mipi;
+
+ pr_debug("%s: dcs level=%d\n", __func__, level);
+
+ led_pwm1[1] = (unsigned char)level;
+
+ if (DSI_VIDEO_MODE == mipi->mode) {
+ dsi_set_tx_power_mode(0);
+ dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
+ &backlight_cmd,
+ 1);
+ dsi_set_tx_power_mode(1);
+ }
+}
+
void dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
if (pdata == NULL) {
@@ -166,13 +189,21 @@
if (enable == 2) {
dsi_panel_power(1);
gpio_request(panel_private->rst_gpio, "panel_reset");
+ gpio_set_value(panel_private->rst_gpio, 1);
if (gpio_is_valid(panel_private->disp_en_gpio)) {
gpio_request(panel_private->disp_en_gpio,
"panel_enable");
+ gpio_set_value(panel_private->disp_en_gpio, 1);
}
if (gpio_is_valid(panel_private->video_mode_gpio)) {
gpio_request(panel_private->video_mode_gpio,
"panel_video_mdoe");
+ if (pdata->panel_info.mipi.mode == DSI_VIDEO_MODE)
+ gpio_set_value(panel_private->video_mode_gpio,
+ 1);
+ else
+ gpio_set_value(panel_private->video_mode_gpio,
+ 0);
}
if (gpio_is_valid(panel_private->te_gpio))
gpio_request(panel_private->te_gpio, "panel_te");
@@ -233,6 +264,10 @@
led_trigger_event(bl_led_trigger, bl_level);
break;
+ case BL_DCS_CMD:
+ dsi_panel_bklt_dcs(pdata, bl_level);
+ break;
+
default:
pr_err("%s: Unknown bl_ctrl configuration\n",
__func__);
@@ -605,8 +640,11 @@
led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
*bl_ctrl = BL_WLED;
+ } else if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type,
+ "bl_ctrl_dcs", 11))) {
+ pr_debug("%s: SUCCESS-> DCS COMMAND register\n", __func__);
+ *bl_ctrl = BL_DCS_CMD;
}
-
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,mdss-pan-bl-levels", res, 2);
panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
@@ -620,6 +658,7 @@
const char *pdest;
u32 tmp;
int rc;
+ bool cont_splash_enabled = false;
pdest = of_get_property(pdev->dev.of_node,
"qcom,mdss-pan-dest", NULL);
@@ -641,6 +680,17 @@
"qcom,mdss-pan-underflow-clr", &tmp);
panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
+ cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
+ "qcom,cont-splash-enabled");
+ if (!cont_splash_enabled) {
+ pr_debug("%s:%d Continuous splash flag not found.\n",
+ __func__, __LINE__);
+ panel_data->panel_info.cont_splash_enabled = 0;
+ } else {
+ pr_debug("%s:%d Continuous splash flag enabled.\n",
+ __func__, __LINE__);
+ panel_data->panel_info.cont_splash_enabled = 1;
+ }
return rc;
}
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 96dd390..73df790 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -235,4 +235,6 @@
int dsi_long_read_resp(struct dsi_buf *rp);
+void dsi_set_tx_power_mode(int mode);
+
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index f6f722e..e899fa3 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -1173,6 +1173,11 @@
size_t size;
int rc;
+ if (pdata->panel_info.type != MIPI_VIDEO_PANEL) {
+ pr_debug("cmd mode panel, no need to copy splash image\n");
+ return 0;
+ }
+
rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
stride = stride & 0x3FFF;
@@ -1210,8 +1215,8 @@
status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN);
rc = status & 0x1;
} else {
- status = MDP3_REG_READ(MDP3_REG_DMA_P_START);
- rc = status & 01;
+ status = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG);
+ rc = status & 0x80000;
}
mdp3_clk_update(MDP3_CLK_AHB, 0);
@@ -1285,7 +1290,13 @@
return 0;
}
rc = mdp3_continuous_splash_on(pdata);
+ } else {
+ if (mdp3_is_display_on(pdata)) {
+ pr_err("lk continuous splash, but kerenl not\n");
+ rc = mdp3_continuous_splash_on(pdata);
+ }
}
+
return rc;
}
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index f77a2b3..0a0c272 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -88,20 +88,11 @@
return bufq->count;
}
-static void mdp3_dispatch_vsync(struct work_struct *work)
-{
- struct mdp3_session_data *mdp3_session;
- mdp3_session = container_of(work, struct mdp3_session_data, vsync_work);
- if (mdp3_session && mdp3_session->mfd)
- sysfs_notify(&mdp3_session->mfd->fbi->dev->kobj, NULL,
- "vsync_event");
-}
-
void vsync_notify_handler(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
session->vsync_time = ktime_get();
- schedule_work(&session->vsync_work);
+ sysfs_notify_dirent(session->vsync_event_sd);
}
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
@@ -370,6 +361,14 @@
struct mdp3_dma_output_config outputConfig;
struct mdp3_dma_source sourceConfig;
int frame_rate = mfd->panel_info->mipi.frame_rate;
+ int vbp, vfp, vspw;
+ int vtotal, vporch;
+
+ vbp = panel_info->lcdc.v_back_porch;
+ vfp = panel_info->lcdc.v_front_porch;
+ vspw = panel_info->lcdc.v_pulse_width;
+ vporch = vbp + vfp + vspw;
+ vtotal = vporch + panel_info->yres;
fix = &fbi->fix;
var = &fbi->var;
@@ -381,8 +380,9 @@
sourceConfig.y = 0;
sourceConfig.stride = fix->line_length;
sourceConfig.buf = (void *)mfd->iova;
+ sourceConfig.vporch = vporch;
sourceConfig.vsync_count =
- MDP_VSYNC_CLK_RATE / (frame_rate * sourceConfig.width);
+ MDP_VSYNC_CLK_RATE / (frame_rate * vtotal);
outputConfig.dither_en = 0;
outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd);
@@ -475,9 +475,6 @@
mdp3_fbmem_clear();
- if (panel->set_backlight)
- panel->set_backlight(panel, panel->panel_info.bl_max);
-
pr_debug("mdp3_ctrl_on dma start\n");
if (mfd->fbi->screen_base) {
rc = mdp3_session->dma->start(mdp3_session->dma,
@@ -520,18 +517,16 @@
mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
- pr_debug("mdp3_ctrl_off turn panel off\n");
- if (panel->set_backlight)
- panel->set_backlight(panel, 0);
+ rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+ if (rc)
+ pr_debug("fail to stop the MDP3 dma\n");
if (panel->event_handler)
rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
if (rc)
pr_err("fail to turn off the panel\n");
- rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
- if (rc)
- pr_err("fail to stop the MDP3 dma\n");
+
mdp3_irq_deregister();
@@ -789,6 +784,64 @@
return ret;
}
+int mdp3_validate_start_req(struct mdp_histogram_start_req *req)
+{
+ if (req->frame_cnt >= MDP_HISTOGRAM_FRAME_COUNT_MAX) {
+ pr_err("%s invalid req frame_cnt\n", __func__);
+ return -EINVAL;
+ }
+ if (req->bit_mask >= MDP_HISTOGRAM_BIT_MASK_MAX) {
+ pr_err("%s invalid req bit mask\n", __func__);
+ return -EINVAL;
+ }
+ if (req->block != MDP_BLOCK_DMA_P ||
+ req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
+ pr_err("mdp3_histogram_start invalid request\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int mdp3_validate_scale_config(struct mdp_bl_scale_data *data)
+{
+ if (data->scale > MDP_HISTOGRAM_BL_SCALE_MAX) {
+ pr_err("%s invalid bl_scale\n", __func__);
+ return -EINVAL;
+ }
+ if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) {
+ pr_err("%s invalid bl_min_lvl\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int mdp3_validate_csc_data(struct mdp_csc_cfg_data *data)
+{
+ int i;
+ for (i = 0; i < 9; i++) {
+ if (data->csc_data.csc_mv[i] >=
+ MDP_HISTOGRAM_CSC_MATRIX_MAX)
+ return -EINVAL;
+ }
+ for (i = 0; i < 3; i++) {
+ if (data->csc_data.csc_pre_bv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ if (data->csc_data.csc_post_bv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ }
+ for (i = 0; i < 6; i++) {
+ if (data->csc_data.csc_pre_lv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ if (data->csc_data.csc_post_lv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int mdp3_histogram_start(struct mdp3_session_data *session,
struct mdp_histogram_start_req *req)
{
@@ -796,11 +849,10 @@
struct mdp3_dma_histogram_config histo_config;
pr_debug("mdp3_histogram_start\n");
- if (req->block != MDP_BLOCK_DMA_P ||
- req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
- pr_err("mdp3_histogram_start invalid request\n");
- return -EINVAL;
- }
+
+ ret = mdp3_validate_start_req(req);
+ if (ret)
+ return ret;
if (!session->dma->histo_op ||
!session->dma->config_histo) {
@@ -1000,10 +1052,20 @@
switch (mdp_pp.op) {
case mdp_bl_scale_cfg:
+ ret = mdp3_validate_scale_config(&mdp_pp.data.bl_scale_data);
+ if (ret) {
+ pr_err("%s: invalid scale config\n", __func__);
+ break;
+ }
ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
&mdp_pp.data.bl_scale_data);
break;
case mdp_op_csc_cfg:
+ ret = mdp3_validate_csc_data(&(mdp_pp.data.csc_cfg_data));
+ if (ret) {
+ pr_err("%s: invalid csc data\n", __func__);
+ break;
+ }
ret = mdp3_csc_config(mdp3_session,
&(mdp_pp.data.csc_cfg_data));
break;
@@ -1235,7 +1297,6 @@
}
memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
mutex_init(&mdp3_session->lock);
- INIT_WORK(&mdp3_session->vsync_work, mdp3_dispatch_vsync);
mutex_init(&mdp3_session->histo_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
if (!mdp3_session->dma) {
@@ -1261,6 +1322,7 @@
goto init_done;
}
+ mdp3_session->dma->output_config.out_sel = intf_type;
mdp3_session->mfd = mfd;
mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
mdp3_session->status = 0;
@@ -1282,6 +1344,14 @@
goto init_done;
}
+ mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+ "vsync_event");
+ if (!mdp3_session->vsync_event_sd) {
+ pr_err("vsync_event sysfs lookup failed\n");
+ rc = -ENODEV;
+ goto init_done;
+ }
+
kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 9ea1c91..eb32797 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -43,10 +43,10 @@
ktime_t vsync_time;
struct timer_list vsync_timer;
int vsync_period;
+ struct sysfs_dirent *vsync_event_sd;
struct mdp_overlay overlay;
struct mdp3_buffer_queue bufq_in;
struct mdp3_buffer_queue bufq_out;
- struct work_struct vsync_work;
int histo_status;
struct mutex histo_lock;
int lut_sel;
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 88eedb9..f4421f2 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -247,16 +247,22 @@
pr_debug("mdp3_dma_sync_config\n");
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
- sync_config = (source_config->height - 1) << 21;
+ int porch = source_config->vporch;
+ int height = source_config->height;
+ int vtotal = height + porch;
+ sync_config = vtotal << 21;
sync_config |= source_config->vsync_count;
sync_config |= BIT(19);
sync_config |= BIT(20);
MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, sync_config);
MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, 0x024);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel, 0);
- MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, 0x00100000);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, 0x0);
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
+ height);
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x5);
+ MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, (4 << 16 | 2));
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, porch);
+ MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, 0x1);
}
return 0;
}
@@ -291,7 +297,7 @@
* the default 16 for MDP hang issue workaround
*/
MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
+
dma->source_config = *source_config;
dma->output_config = *output_config;
@@ -497,7 +503,7 @@
struct mdp3_dma_histogram_config *histo_config)
{
unsigned long flag;
- u32 histo_bit_mask, histo_control;
+ u32 histo_bit_mask = 0, histo_control = 0;
u32 histo_isr_mask = MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT |
MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT;
@@ -530,7 +536,7 @@
pr_debug("mdp3_dmap_update\n");
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
- cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+ cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
if (intf->active)
wait_for_completion_killable(&dma->dma_comp);
}
@@ -553,7 +559,8 @@
mdp3_dma_callback_enable(dma, cb_type);
pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
- wait_for_completion_killable(&dma->vsync_comp);
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+ wait_for_completion_killable(&dma->vsync_comp);
pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
return 0;
}
@@ -565,7 +572,7 @@
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
- cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+ cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
if (intf->active)
wait_for_completion_killable(&dma->dma_comp);
}
@@ -586,7 +593,8 @@
spin_unlock_irqrestore(&dma->dma_lock, flag);
mdp3_dma_callback_enable(dma, cb_type);
- wait_for_completion_killable(&dma->vsync_comp);
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+ wait_for_completion_killable(&dma->vsync_comp);
return 0;
}
@@ -631,7 +639,7 @@
return ret;
if (dma->histo_state != MDP3_DMA_HISTO_STATE_READY) {
- pr_err("mdp3_dmap_histo_get after dma shut down\n");
+ pr_debug("mdp3_dmap_histo_get after dma shut down\n");
return -EPERM;
}
@@ -694,9 +702,6 @@
unsigned long flag;
int ret;
- if (dma->histo_state == MDP3_DMA_HISTO_STATE_START)
- return -EINVAL;
-
spin_lock_irqsave(&dma->histo_lock, flag);
init_completion(&dma->histo_comp);
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index e4a28dc..6983e55 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -16,6 +16,12 @@
#include <linux/sched.h>
+#define MDP_HISTOGRAM_BL_SCALE_MAX 1024
+#define MDP_HISTOGRAM_BL_LEVEL_MAX 255
+#define MDP_HISTOGRAM_FRAME_COUNT_MAX 0x20
+#define MDP_HISTOGRAM_BIT_MASK_MAX 0x4
+#define MDP_HISTOGRAM_CSC_MATRIX_MAX 0x2000
+#define MDP_HISTOGRAM_CSC_VECTOR_MAX 0x200
#define MDP_HISTOGRAM_BIN_NUM 32
#define MDP_LUT_SIZE 256
@@ -145,6 +151,7 @@
void *buf;
int stride;
int vsync_count;
+ int vporch;
};
struct mdp3_dma_output_config {
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 924ec5a..8e1dd66 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -344,7 +344,7 @@
int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
{
struct mdss_panel_info *panel_info = mfd->panel_info;
- int ab = 0, ib = 0;
+ uint64_t ab = 0, ib = 0;
int rate = 0;
if (on_off) {
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 94fced0..3b8096b 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -573,9 +573,23 @@
static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
{
u32 temp = *bl_lvl;
+
pr_debug("input = %d, scale = %d", temp, mfd->bl_scale);
if (temp >= mfd->bl_min_lvl) {
- /* bl_scale is the numerator of scaling fraction (x/1024)*/
+ if (temp > mfd->panel_info->bl_max) {
+ pr_warn("%s: invalid bl level\n",
+ __func__);
+ temp = mfd->panel_info->bl_max;
+ }
+ if (mfd->bl_scale > 1024) {
+ pr_warn("%s: invalid bl scale\n",
+ __func__);
+ mfd->bl_scale = 1024;
+ }
+ /*
+ * bl_scale is the numerator of
+ * scaling fraction (x/1024)
+ */
temp = (temp * mfd->bl_scale) / 1024;
/*if less than minimum level, use min level*/
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
index 2cf47fc..b74f074 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_cec.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -22,6 +22,7 @@
/* Reference: HDMI 1.4a Specification section 7.1 */
#define RETRANSMIT_MAX_NUM 5
+#define MAX_OPERAND_SIZE 15
/*
* Ref. HDMI 1.4a: Supplement-1 CEC Section 6, 7
@@ -30,7 +31,7 @@
u8 sender_id;
u8 recvr_id;
u8 opcode;
- u8 operand[15];
+ u8 operand[MAX_OPERAND_SIZE];
u8 frame_size;
u8 retransmit;
};
@@ -738,6 +739,10 @@
}
spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ if (msg->frame_size > MAX_OPERAND_SIZE) {
+ DEV_ERR("%s: msg frame too big!\n", __func__);
+ return -EINVAL;
+ }
rc = hdmi_cec_msg_send(cec_ctrl, msg);
if (rc) {
DEV_ERR("%s: hdmi_cec_msg_send failed\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index ad134a0..0fd3655 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -430,7 +430,7 @@
static ssize_t hdmi_tx_sysfs_wta_vendor_name(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- ssize_t ret;
+ ssize_t ret, sz;
u8 *s = (u8 *) buf;
u8 *d = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -445,7 +445,8 @@
ret = strnlen(buf, PAGE_SIZE);
ret = (ret > 8) ? 8 : ret;
- memset(hdmi_ctrl->spd_vendor_name, 0, 8);
+ sz = sizeof(hdmi_ctrl->spd_vendor_name);
+ memset(hdmi_ctrl->spd_vendor_name, 0, sz);
while (*s) {
if (*s & 0x60 && *s ^ 0x7f) {
*d = *s;
@@ -459,6 +460,7 @@
d++;
}
+ hdmi_ctrl->spd_vendor_name[sz - 1] = 0;
DEV_DBG("%s: '%s'\n", __func__, hdmi_ctrl->spd_vendor_name);
@@ -486,7 +488,7 @@
static ssize_t hdmi_tx_sysfs_wta_product_description(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- ssize_t ret;
+ ssize_t ret, sz;
u8 *s = (u8 *) buf;
u8 *d = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -501,7 +503,8 @@
ret = strnlen(buf, PAGE_SIZE);
ret = (ret > 16) ? 16 : ret;
- memset(hdmi_ctrl->spd_product_description, 0, 16);
+ sz = sizeof(hdmi_ctrl->spd_product_description);
+ memset(hdmi_ctrl->spd_product_description, 0, sz);
while (*s) {
if (*s & 0x60 && *s ^ 0x7f) {
*d = *s;
@@ -515,6 +518,7 @@
d++;
}
+ hdmi_ctrl->spd_product_description[sz - 1] = 0;
DEV_DBG("%s: '%s'\n", __func__, hdmi_ctrl->spd_product_description);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 18ee782..fd95582 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -79,8 +79,8 @@
bool hdcp_feature_on;
u32 present_hdcp;
- u8 spd_vendor_name[8];
- u8 spd_product_description[16];
+ u8 spd_vendor_name[9];
+ u8 spd_product_description[17];
struct hdmi_tx_ddc_ctrl ddc_ctrl;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index aba77e3..91257f2 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -39,6 +39,7 @@
#define MAX_DOWNSCALE_RATIO 4
#define MAX_UPSCALE_RATIO 20
#define MAX_DECIMATION 4
+#define MDP_MIN_VBP 4
#define C3_ALPHA 3 /* alpha */
#define C2_R_Cr 2 /* R/Cr */
@@ -333,6 +334,7 @@
u8 mixer_stage;
u8 is_fg;
u8 alpha;
+ u8 blend_op;
u8 overfetch_disable;
u32 transp;
@@ -363,6 +365,7 @@
struct mdss_overlay_private {
int vsync_pending;
ktime_t vsync_time;
+ struct sysfs_dirent *vsync_event_sd;
int borderfill_enable;
int overlay_play_enable;
int hw_refresh;
@@ -375,7 +378,6 @@
struct list_head overlay_list;
struct list_head pipes_used;
struct list_head pipes_cleanup;
- struct work_struct vsync_work;
bool mixer_swap;
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d1595b3..4a426cf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -242,6 +242,7 @@
u32 *clk_rate)
{
struct mdss_mdp_pipe *pipe;
+ struct mdss_panel_info *pinfo = NULL;
int fps = DEFAULT_FRAME_RATE;
u32 v_total;
int i;
@@ -252,22 +253,21 @@
*clk_rate = 0;
if (!mixer->rotator_mode) {
- int is_writeback = false;
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
- struct mdss_panel_info *pinfo;
pinfo = &mixer->ctl->panel_data->panel_info;
fps = mdss_panel_get_framerate(pinfo);
v_total = mdss_panel_get_vtotal(pinfo);
if (pinfo->type == WRITEBACK_PANEL)
- is_writeback = true;
+ pinfo = NULL;
} else {
v_total = mixer->height;
-
- is_writeback = true;
}
*clk_rate = mixer->width * v_total * fps;
- if (is_writeback) {
+ if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP)
+ *clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(*clk_rate);
+
+ if (!pinfo) {
/* perf for bus writeback */
*bus_ab_quota = fps * mixer->width * mixer->height * 3;
*bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT;
@@ -280,11 +280,6 @@
pipe = mixer->stage_pipe[i];
if (pipe == NULL)
continue;
- if (pipe->is_fg) {
- ab_total = 0;
- ib_total = 0;
- max_clk_rate = 0;
- }
if (mdss_mdp_perf_calc_pipe(pipe, &perf))
continue;
@@ -1207,7 +1202,8 @@
{
struct mdss_mdp_pipe *pipe;
u32 off, blend_op, blend_stage;
- u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
+ u32 mixercfg = 0, blend_color_out = 0, bg_alpha_enable = 0;
+ u32 fg_alpha = 0, bg_alpha = 0;
int stage, secure = 0;
if (!mixer)
@@ -1227,7 +1223,7 @@
mixercfg = 1 << (3 * pipe->num);
}
if (pipe->src_fmt->alpha_enable)
- bgalpha = 1;
+ bg_alpha_enable = 1;
secure = pipe->flags & MDP_SECURE_OVERLAY_SESSION;
}
@@ -1244,48 +1240,79 @@
blend_stage = stage - MDSS_MDP_STAGE_0;
off = MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);
- if (pipe->is_fg) {
- bgalpha = 0;
- if (!secure)
- mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+ blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+ MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+ fg_alpha = pipe->alpha;
+ bg_alpha = 0xFF - pipe->alpha;
+ /* keep fg alpha */
+ blend_color_out |= 1 << (blend_stage + 1);
+
+ switch (pipe->blend_op) {
+ case BLEND_OP_OPAQUE:
blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
- /* keep fg alpha */
- blend_color_out |= 1 << (blend_stage + 1);
- pr_debug("pnum=%d stg=%d alpha=IS_FG\n", pipe->num,
+ pr_debug("pnum=%d stg=%d op=OPAQUE\n", pipe->num,
stage);
- } else if (pipe->src_fmt->alpha_enable) {
- bgalpha = 0;
- blend_op = (MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL |
- MDSS_MDP_BLEND_BG_INV_ALPHA);
- /* keep fg alpha */
- blend_color_out |= 1 << (blend_stage + 1);
+ break;
- pr_debug("pnum=%d stg=%d alpha=FG PIXEL\n", pipe->num,
+ case BLEND_OP_PREMULTIPLIED:
+ if (pipe->src_fmt->alpha_enable) {
+ blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+ MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL);
+ if (fg_alpha != 0xff) {
+ bg_alpha = fg_alpha;
+ blend_op |=
+ MDSS_MDP_BLEND_BG_MOD_ALPHA |
+ MDSS_MDP_BLEND_BG_INV_MOD_ALPHA;
+ } else {
+ blend_op |= MDSS_MDP_BLEND_BG_INV_ALPHA;
+ }
+ }
+ pr_debug("pnum=%d stg=%d op=PREMULTIPLIED\n", pipe->num,
stage);
- } else if (bgalpha) {
- blend_op = (MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL |
- MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL |
- MDSS_MDP_BLEND_FG_INV_ALPHA);
- /* keep bg alpha */
- pr_debug("pnum=%d stg=%d alpha=BG_PIXEL\n", pipe->num,
+ break;
+
+ case BLEND_OP_COVERAGE:
+ if (pipe->src_fmt->alpha_enable) {
+ blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_PIXEL |
+ MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL);
+ if (fg_alpha != 0xff) {
+ bg_alpha = fg_alpha;
+ blend_op |=
+ MDSS_MDP_BLEND_FG_MOD_ALPHA |
+ MDSS_MDP_BLEND_FG_INV_MOD_ALPHA |
+ MDSS_MDP_BLEND_BG_MOD_ALPHA |
+ MDSS_MDP_BLEND_BG_INV_MOD_ALPHA;
+ } else {
+ blend_op |= MDSS_MDP_BLEND_BG_INV_ALPHA;
+ }
+ }
+ pr_debug("pnum=%d stg=%d op=COVERAGE\n", pipe->num,
stage);
- } else {
+ break;
+
+ default:
blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
- pr_debug("pnum=%d stg=%d alpha=CONST\n", pipe->num,
+ pr_debug("pnum=%d stg=%d op=NONE\n", pipe->num,
stage);
+ break;
}
+ if (!pipe->src_fmt->alpha_enable && bg_alpha_enable)
+ blend_color_out = 0;
+
mixercfg |= stage << (3 * pipe->num);
+ pr_debug("stg=%d op=%x fg_alpha=%x bg_alpha=%x\n", stage,
+ blend_op, fg_alpha, bg_alpha);
mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
- pipe->alpha);
+ fg_alpha);
mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA,
- 0xFF - pipe->alpha);
+ bg_alpha);
}
if (mixer->cursor_enabled)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c4dee86..938cb1f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -491,6 +491,16 @@
pipe->is_fg = req->is_fg;
pipe->alpha = req->alpha;
pipe->transp = req->transp_mask;
+ pipe->blend_op = req->blend_op;
+ if (pipe->blend_op == BLEND_OP_NOT_DEFINED)
+ pipe->blend_op = fmt->alpha_enable ?
+ BLEND_OP_PREMULTIPLIED :
+ BLEND_OP_OPAQUE;
+
+ if (!fmt->alpha_enable && (pipe->blend_op != BLEND_OP_OPAQUE))
+ pr_warn("Unintended blend_op %d on layer with no alpha plane\n",
+ pipe->blend_op);
+
pipe->overfetch_disable = fmt->is_yuv &&
!(pipe->flags & MDP_SOURCE_ROTATED_90);
@@ -1341,15 +1351,6 @@
mutex_unlock(&mdp5_data->ov_lock);
}
-static void mdss_mdp_overlay_dispatch_vsync(struct work_struct *work)
-{
- struct mdss_overlay_private *mdp5_data;
- mdp5_data = container_of(work, struct mdss_overlay_private, vsync_work);
- if (mdp5_data->ctl && mdp5_data->ctl->mfd)
- sysfs_notify(&mdp5_data->ctl->mfd->fbi->dev->kobj, NULL,
- "vsync_event");
-}
-
/* function is called in irq context should have minimum processing */
static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
ktime_t t)
@@ -1366,7 +1367,7 @@
pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
mdp5_data->vsync_time = t;
- schedule_work(&mdp5_data->vsync_work);
+ sysfs_notify_dirent(mdp5_data->vsync_event_sd);
}
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
@@ -2120,7 +2121,6 @@
INIT_LIST_HEAD(&mdp5_data->pipes_used);
INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
- INIT_WORK(&mdp5_data->vsync_work, mdss_mdp_overlay_dispatch_vsync);
mutex_init(&mdp5_data->ov_lock);
mdp5_data->hw_refresh = true;
mdp5_data->overlay_play_enable = true;
@@ -2143,6 +2143,14 @@
goto init_fail;
}
+ mdp5_data->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+ "vsync_event");
+ if (!mdp5_data->vsync_event_sd) {
+ pr_err("vsync_event sysfs lookup failed\n");
+ rc = -ENODEV;
+ goto init_fail;
+ }
+
pm_runtime_set_suspended(&mfd->pdev->dev);
pm_runtime_enable(&mfd->pdev->dev);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 6cedd98..ebbf9e7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -2003,6 +2003,10 @@
u32 offset, disp_num, dspp_num = 0;
uint16_t *tbl_off;
struct mdp_gamut_cfg_data local_cfg;
+ uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
+ uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
+ uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
+
if (!ctl)
return -EINVAL;
@@ -2030,22 +2034,67 @@
offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
MDSS_MDP_REG_DSPP_GAMUT_BASE;
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ r_tbl[i] = kzalloc(
+ sizeof(uint16_t) * config->tbl_size[i],
+ GFP_KERNEL);
+ if (!r_tbl[i]) {
+ pr_err("%s: alloc failed\n", __func__);
+ goto gamut_config_exit;
+ }
for (j = 0; j < config->tbl_size[i]; j++)
- config->r_tbl[i][j] =
+ r_tbl[i][j] =
(u16)MDSS_MDP_REG_READ(offset);
offset += 4;
+ ret = copy_to_user(config->r_tbl[i], r_tbl[i],
+ sizeof(uint16_t) * config->tbl_size[i]);
+ kfree(r_tbl[i]);
+ if (ret) {
+ pr_err("%s: copy tbl to usr failed\n",
+ __func__);
+ goto gamut_config_exit;
+ }
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ g_tbl[i] = kzalloc(
+ sizeof(uint16_t) * config->tbl_size[i],
+ GFP_KERNEL);
+ if (!g_tbl[i]) {
+ pr_err("%s: alloc failed\n", __func__);
+ goto gamut_config_exit;
+ }
for (j = 0; j < config->tbl_size[i]; j++)
- config->g_tbl[i][j] =
+ g_tbl[i][j] =
(u16)MDSS_MDP_REG_READ(offset);
offset += 4;
+ ret = copy_to_user(config->g_tbl[i], g_tbl[i],
+ sizeof(uint16_t) * config->tbl_size[i]);
+ kfree(g_tbl[i]);
+ if (ret) {
+ pr_err("%s: copy tbl to usr failed\n",
+ __func__);
+ goto gamut_config_exit;
+ }
}
for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ b_tbl[i] = kzalloc(
+ sizeof(uint16_t) * config->tbl_size[i],
+ GFP_KERNEL);
+ if (!b_tbl[i]) {
+ pr_err("%s: alloc failed\n", __func__);
+ goto gamut_config_exit;
+ }
for (j = 0; j < config->tbl_size[i]; j++)
- config->b_tbl[i][j] =
+ b_tbl[i][j] =
(u16)MDSS_MDP_REG_READ(offset);
offset += 4;
+ ret = copy_to_user(config->b_tbl[i], b_tbl[i],
+ sizeof(uint16_t) * config->tbl_size[i]);
+ kfree(b_tbl[i]);
+ if (ret) {
+ pr_err("%s: copy tbl to usr failed\n",
+ __func__);
+ goto gamut_config_exit;
+ }
}
*copyback = 1;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index c66d50d..a759e86 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -357,14 +357,20 @@
static int mhl_sii_wait_for_rgnd(struct mhl_tx_ctrl *mhl_ctrl)
{
int timeout;
- /* let isr handle RGND interrupt */
+
pr_debug("%s:%u\n", __func__, __LINE__);
INIT_COMPLETION(mhl_ctrl->rgnd_done);
+ /*
+ * after toggling reset line and enabling disc
+ * tx can take a while to generate intr
+ */
timeout = wait_for_completion_interruptible_timeout
- (&mhl_ctrl->rgnd_done, HZ);
+ (&mhl_ctrl->rgnd_done, HZ * 3);
if (!timeout) {
- /* most likely nothing plugged in USB */
- /* USB HOST connected or already in USB mode */
+ /*
+ * most likely nothing plugged in USB
+ * USB HOST connected or already in USB mode
+ */
pr_warn("%s:%u timedout\n", __func__, __LINE__);
return -ENODEV;
}
@@ -380,9 +386,25 @@
struct i2c_client *client = mhl_ctrl->i2c_handle;
unsigned long flags;
- enable_irq(client->irq);
+ if (!mhl_ctrl->irq_req_done) {
+ rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
+ &mhl_tx_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->dev.driver->name, mhl_ctrl);
+ if (rc) {
+ pr_err("request_threaded_irq failed, status: %d\n",
+ rc);
+ return -EINVAL;
+ } else {
+ pr_debug("request_threaded_irq succeeded\n");
+ mhl_ctrl->irq_req_done = true;
+ }
+ } else {
+ enable_irq(client->irq);
+ }
+
/* wait for i2c interrupt line to be activated */
- msleep(300);
+ msleep(100);
if (id) {
/* When MHL cable is disconnected we get a sii8334
@@ -413,8 +435,10 @@
/* chipset PR recommends waiting for at least 100 ms
* the chipset needs longer to come out of D3 state.
*/
- msleep(300);
+ msleep(100);
mhl_init_reg_settings(mhl_ctrl, true);
+ /* allow tx to enable dev disc after D3 state */
+ msleep(100);
rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
} else {
if (mhl_ctrl->cur_state == POWER_STATE_D3) {
@@ -493,6 +517,10 @@
uint8_t i;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ /* Read the chip rev ID */
+ mhl_ctrl->chip_rev_id = MHL_SII_PAGE0_RD(0x04);
+ pr_debug("MHL: chip rev ID read=[%x]\n", mhl_ctrl->chip_rev_id);
+
/*
* REG_SRST
*/
@@ -1428,40 +1456,6 @@
return IRQ_HANDLED;
}
-static int mhl_tx_chip_init(struct mhl_tx_ctrl *mhl_ctrl)
-{
- uint8_t chip_rev_id = 0x00;
- struct i2c_client *client = mhl_ctrl->i2c_handle;
- unsigned long flags;
-
-
- spin_lock_irqsave(&mhl_ctrl->lock, flags);
- mhl_ctrl->dwnstream_hpd = 0;
- mhl_ctrl->tx_powered_off = false;
- spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
-
- /* Reset the TX chip */
- mhl_sii_reset_pin(mhl_ctrl, 0);
- msleep(20);
- mhl_sii_reset_pin(mhl_ctrl, 1);
- /* TX PR-guide requires a 100 ms wait here */
- msleep(100);
-
- /* Read the chip rev ID */
- chip_rev_id = MHL_SII_PAGE0_RD(0x04);
- pr_debug("MHL: chip rev ID read=[%x]\n", chip_rev_id);
- mhl_ctrl->chip_rev_id = chip_rev_id;
-
- /*
- * Need to disable MHL discovery if
- * MHL-USB handshake is implemented
- */
- mhl_init_reg_settings(mhl_ctrl, true);
- switch_mode(mhl_ctrl, POWER_STATE_D3, true);
- pr_debug("%s:%u: power_down\n", __func__, __LINE__);
- mhl_tx_down(mhl_ctrl);
- return 0;
-}
static int mhl_sii_reg_config(struct i2c_client *client, bool enable)
{
@@ -1791,30 +1785,12 @@
}
}
- rc = mhl_tx_chip_init(mhl_ctrl);
- if (rc) {
- pr_err("%s: tx chip init failed [%d]\n",
- __func__, rc);
- goto failed_probe;
- }
+ mhl_ctrl->dwnstream_hpd = 0;
+ mhl_ctrl->tx_powered_off = false;
+
init_completion(&mhl_ctrl->rgnd_done);
- pr_debug("%s: IRQ from GPIO INTR = %d\n",
- __func__, mhl_ctrl->i2c_handle->irq);
- pr_debug("%s: Driver name = [%s]\n", __func__,
- client->dev.driver->name);
- rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
- &mhl_tx_isr,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- client->dev.driver->name, mhl_ctrl);
- if (rc) {
- pr_err("request_threaded_irq failed, status: %d\n",
- rc);
- goto failed_probe;
- } else {
- pr_debug("request_threaded_irq succeeded\n");
- }
mhl_ctrl->mhl_psy.name = "ext-vbus";
mhl_ctrl->mhl_psy.type = POWER_SUPPLY_TYPE_USB_DCP;
@@ -1940,15 +1916,21 @@
#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
static int mhl_i2c_suspend_sub(struct i2c_client *client)
{
- enable_irq_wake(client->irq);
- disable_irq(client->irq);
+ struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+ if (mhl_ctrl->irq_req_done) {
+ enable_irq_wake(client->irq);
+ disable_irq(client->irq);
+ }
return 0;
}
static int mhl_i2c_resume_sub(struct i2c_client *client)
{
- disable_irq_wake(client->irq);
- enable_irq(client->irq);
+ struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+ if (mhl_ctrl->irq_req_done)
+ disable_irq_wake(client->irq);
return 0;
}
#endif /* defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP) */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index f6ca334..f66a034 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -260,6 +260,7 @@
header-y += msdos_fs.h
header-y += msg.h
header-y += msm_adc.h
+header-y += msm_dsps.h
header-y += msm_ion.h
header-y += epm_adc.h
header-y += mtio.h
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d1ee11c..71dec42 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -165,6 +165,7 @@
bool tx_powered_off;
uint8_t dwnstream_hpd;
bool mhl_det_discon;
+ bool irq_req_done;
};
int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/msm_dsps.h b/include/linux/msm_dsps.h
index 1f997ba..e3da576 100644
--- a/include/linux/msm_dsps.h
+++ b/include/linux/msm_dsps.h
@@ -1,17 +1,3 @@
-/*
- * Copyright (c) 2011, 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 _DSPS_H_
#define _DSPS_H_
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index f74fcbe..87047d2 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -20,10 +20,7 @@
#define KGSL_CONTEXT_TRASH_STATE 0x00000020
#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040
#define KGSL_CONTEXT_USER_GENERATED_TS 0x00000080
-#define KGSL_CONTEXT_END_OF_FRAME 0x00000100
-
#define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
-#define KGSL_CONTEXT_SYNC 0x00000400
/* bits [12:15] are reserved for future use */
#define KGSL_CONTEXT_TYPE_MASK 0x01F00000
#define KGSL_CONTEXT_TYPE_SHIFT 20
@@ -286,7 +283,7 @@
#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \
_IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid)
-/* DEPRECATED: issue indirect commands to the GPU.
+/* issue indirect commands to the GPU.
* drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE
* ibaddr and sizedwords must specify a subset of a buffer created
* with IOCTL_KGSL_SHAREDMEM_FROM_PMEM
@@ -294,9 +291,6 @@
* timestamp is a returned counter value which can be passed to
* other ioctls to determine when the commands have been executed by
* the GPU.
- *
- * This fucntion is deprecated - consider using IOCTL_KGSL_SUBMIT_COMMANDS
- * instead
*/
struct kgsl_ringbuffer_issueibcmds {
unsigned int drawctxt_id;
@@ -811,77 +805,6 @@
#define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
_IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
-/*
- * struct kgsl_cmd_syncpoint_timestamp
- * @context_id: ID of a KGSL context
- * @timestamp: GPU timestamp
- *
- * This structure defines a syncpoint comprising a context/timestamp pair. A
- * list of these may be passed by IOCTL_KGSL_SUBMIT_COMMANDS to define
- * dependencies that must be met before the command can be submitted to the
- * hardware
- */
-struct kgsl_cmd_syncpoint_timestamp {
- unsigned int context_id;
- unsigned int timestamp;
-};
-
-#define KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP 0
-
-struct kgsl_cmd_syncpoint_fence {
- int fd;
-};
-
-#define KGSL_CMD_SYNCPOINT_TYPE_FENCE 1
-
-/**
- * struct kgsl_cmd_syncpoint - Define a sync point for a command batch
- * @type: type of sync point defined here
- * @priv: Pointer to the type specific buffer
- * @size: Size of the type specific buffer
- *
- * This structure contains pointers defining a specific command sync point.
- * The pointer and size should point to a type appropriate structure.
- */
-struct kgsl_cmd_syncpoint {
- int type;
- void __user *priv;
- unsigned int size;
-};
-
-/**
- * struct kgsl_submit_commands - Argument to IOCTL_KGSL_SUBMIT_COMMANDS
- * @context_id: KGSL context ID that owns the commands
- * @flags:
- * @cmdlist: User pointer to a list of kgsl_ibdesc structures
- * @numcmds: Number of commands listed in cmdlist
- * @synclist: User pointer to a list of kgsl_cmd_syncpoint structures
- * @numsyncs: Number of sync points listed in synclist
- * @timestamp: On entry the a user defined timestamp, on exist the timestamp
- * assigned to the command batch
- *
- * This structure specifies a command to send to the GPU hardware. This is
- * similar to kgsl_issueibcmds expect that it doesn't support the legacy way to
- * submit IB lists and it adds sync points to block the IB until the
- * dependencies are satisified. This entry point is the new and preferred way
- * to submit commands to the GPU.
- */
-
-struct kgsl_submit_commands {
- unsigned int context_id;
- unsigned int flags;
- struct kgsl_ibdesc __user *cmdlist;
- unsigned int numcmds;
- struct kgsl_cmd_syncpoint __user *synclist;
- unsigned int numsyncs;
- unsigned int timestamp;
-/* private: reserved for future use */
- unsigned int __pad[4];
-};
-
-#define IOCTL_KGSL_SUBMIT_COMMANDS \
- _IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands)
-
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 2455212..fab9301 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -405,6 +405,33 @@
struct mdp_hist_lut_data hist_lut_cfg;
};
+/**
+ * enum mdss_mdp_blend_op - Different blend operations set by userspace
+ *
+ * @BLEND_OP_NOT_DEFINED: No blend operation defined for the layer.
+ * @BLEND_OP_OPAQUE: Apply a constant blend operation. The layer
+ * would appear opaque in case fg plane alpha is
+ * 0xff.
+ * @BLEND_OP_PREMULTIPLIED: Apply source over blend rule. Layer already has
+ * alpha pre-multiplication done. If fg plane alpha
+ * is less than 0xff, apply modulation as well. This
+ * operation is intended on layers having alpha
+ * channel.
+ * @BLEND_OP_COVERAGE: Apply source over blend rule. Layer is not alpha
+ * pre-multiplied. Apply pre-multiplication. If fg
+ * plane alpha is less than 0xff, apply modulation as
+ * well.
+ * @BLEND_OP_MAX: Used to track maximum blend operation possible by
+ * mdp.
+ */
+enum mdss_mdp_blend_op {
+ BLEND_OP_NOT_DEFINED = 0,
+ BLEND_OP_OPAQUE,
+ BLEND_OP_PREMULTIPLIED,
+ BLEND_OP_COVERAGE,
+ BLEND_OP_MAX,
+};
+
struct mdp_overlay {
struct msmfb_img src;
struct mdp_rect src_rect;
@@ -412,6 +439,7 @@
uint32_t z_order; /* stage number */
uint32_t is_fg; /* control alpha & transp */
uint32_t alpha;
+ uint32_t blend_op;
uint32_t transp_mask;
uint32_t flags;
uint32_t id;
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2c1fa11..2ca9900 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -23,6 +23,8 @@
uint32_t freq_control_mask;
int32_t core_limit_temp_degC;
int32_t core_temp_hysteresis_degC;
+ int32_t hotplug_temp_degC;
+ int32_t hotplug_temp_hysteresis_degC;
uint32_t core_control_mask;
int32_t vdd_rstr_temp_degC;
int32_t vdd_rstr_temp_hyst_degC;
diff --git a/include/linux/qpnp-revid.h b/include/linux/qpnp-revid.h
new file mode 100644
index 0000000..3cf9f1c
--- /dev/null
+++ b/include/linux/qpnp-revid.h
@@ -0,0 +1,111 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QPNP_REVID
+#define __QPNP_REVID
+
+#define PM8226_V2P1_REV1 0x00
+#define PM8226_V2P1_REV2 0x00
+#define PM8226_V2P1_REV3 0x01
+#define PM8226_V2P1_REV4 0x02
+#define PM8226_V2P1_TYPE 0x51
+#define PM8226_V2P1_SUBTYPE 0x04
+
+#define PM8226_V2P0_REV1 0x00
+#define PM8226_V2P0_REV2 0x00
+#define PM8226_V2P0_REV3 0x00
+#define PM8226_V2P0_REV4 0x02
+#define PM8226_V2P0_TYPE 0x51
+#define PM8226_V2P0_SUBTYPE 0x04
+
+#define PM8226_V1P0_REV1 0x00
+#define PM8226_V1P0_REV2 0x00
+#define PM8226_V1P0_REV3 0x00
+#define PM8226_V1P0_REV4 0x00
+#define PM8226_V1P0_TYPE 0x51
+#define PM8226_V1P0_SUBTYPE 0x04
+
+#define PM8941_V1P0_REV1 0x00
+#define PM8941_V1P0_REV2 0x00
+#define PM8941_V1P0_REV3 0x00
+#define PM8941_V1P0_REV4 0x01
+#define PM8941_V1P0_TYPE 0x51
+#define PM8941_V1P0_SUBTYPE 0x01
+
+#define PM8941_V2P0_REV1 0x00
+#define PM8941_V2P0_REV2 0x00
+#define PM8941_V2P0_REV3 0x00
+#define PM8941_V2P0_REV4 0x01
+#define PM8941_V2P0_TYPE 0x51
+#define PM8941_V2P0_SUBTYPE 0x01
+
+#define PM8941_V3P0_REV1 0x00
+#define PM8941_V3P0_REV2 0x00
+#define PM8941_V3P0_REV3 0x00
+#define PM8941_V3P0_REV4 0x03
+#define PM8941_V3P0_TYPE 0x51
+#define PM8941_V3P0_SUBTYPE 0x01
+
+#define PM8941_V3P1_REV1 0x00
+#define PM8941_V3P1_REV2 0x00
+#define PM8941_V3P1_REV3 0x01
+#define PM8941_V3P1_REV4 0x03
+#define PM8941_V3P1_TYPE 0x51
+#define PM8941_V3P1_SUBTYPE 0x01
+
+#define PM8110_V1P0_REV1 0x00
+#define PM8110_V1P0_REV2 0x00
+#define PM8110_V1P0_REV3 0x00
+#define PM8110_V1P0_REV4 0x01
+#define PM8110_V1P0_TYPE 0x51
+#define PM8110_V1P0_SUBTYPE 0x05
+
+#define PM8110_V1P1_REV1 0x00
+#define PM8110_V1P1_REV2 0x01
+#define PM8110_V1P1_REV3 0x00
+#define PM8110_V1P1_REV4 0x01
+#define PM8110_V1P1_TYPE 0x51
+#define PM8110_V1P1_SUBTYPE 0x05
+
+#define PM8110_V1P3_REV1 0x00
+#define PM8110_V1P3_REV2 0x03
+#define PM8110_V1P3_REV3 0x00
+#define PM8110_V1P3_REV4 0x01
+#define PM8110_V1P3_TYPE 0x51
+#define PM8110_V1P3_SUBTYPE 0x05
+
+#define PM8110_V2P0_REV1 0x00
+#define PM8110_V2P0_REV2 0x00
+#define PM8110_V2P0_REV3 0x00
+#define PM8110_V2P0_REV4 0x02
+#define PM8110_V2P0_TYPE 0x51
+#define PM8110_V2P0_SUBTYPE 0x05
+
+struct pmic_revid_data {
+ u8 rev1;
+ u8 rev2;
+ u8 rev3;
+ u8 rev4;
+ u8 pmic_type;
+ u8 pmic_subtype;
+};
+
+#ifdef CONFIG_QPNP_REVID
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node);
+#else
+static inline
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+ return NULL;
+}
+#endif
+#endif
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 4f39eaa..9a49c5e 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -218,6 +218,8 @@
* Uses a mapping table with 150K pullup.
* %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
* btm parameters.
+ * %SCALE_QRD_SKUAA_BATT_THERM: Conversion to temperature(decidegC) based on
+ * btm parametersi for SKUAA.
* %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
@@ -228,6 +230,7 @@
SCALE_XOTHERM,
SCALE_THERM_150K_PULLUP,
SCALE_QRD_BATT_THERM,
+ SCALE_QRD_SKUAA_BATT_THERM,
SCALE_NONE,
};
@@ -1121,6 +1124,23 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_qrd_skuaa_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC.
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
@@ -1366,7 +1386,13 @@
struct qpnp_vadc_chip *vadc, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
- struct qpnp_vadc_result *chan_rslt);
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(
+ struct qpnp_vadc_chip *vadc, int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *vadc,
int32_t adc_code,
diff --git a/include/linux/smsc3503.h b/include/linux/smsc_hub.h
similarity index 90%
rename from include/linux/smsc3503.h
rename to include/linux/smsc_hub.h
index 1e28a58..9c0afc0 100644
--- a/include/linux/smsc3503.h
+++ b/include/linux/smsc_hub.h
@@ -14,6 +14,12 @@
#ifndef __LINUX_SMSC3503_H__
#define __LINUX_SMSC3503_H__
+#define SMSC3503_ID 3503
+#define SMSC4604_ID 4604
+#define SMSC3503_I2C_ADDR 0x08
+#define SMSC4604_I2C_ADDR 0x2d
+#define SMSC_GSBI_I2C_BUS_ID 0
+
/*Serial interface Registers*/
#define SMSC3503_VENDORID 0x00 /*u16 read*/
#define SMSC3503_PRODUCTID 0x02 /*u16 read*/
@@ -42,6 +48,7 @@
#define OCSPINSEL (1<<5)
struct smsc_hub_platform_data {
+ u32 model_id;
int hub_reset;
int refclk_gpio;
int int_gpio;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f740640..1bb3b06 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -97,6 +97,27 @@
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
+struct sensor_threshold {
+ int temp;
+ enum thermal_trip_type trip;
+ int (*notify)(enum thermal_trip_type type, int temp, void *data);
+ void *data;
+ struct list_head list;
+};
+
+struct sensor_info {
+ uint32_t sensor_id;
+ struct thermal_zone_device *tz;
+ int threshold_min;
+ int threshold_max;
+ int max_idx;
+ int min_idx;
+ struct list_head sensor_list;
+ struct list_head threshold_list;
+ struct mutex lock;
+ struct work_struct work;
+};
+
struct thermal_zone_device {
int id;
char type[THERMAL_NAME_LENGTH];
@@ -116,6 +137,8 @@
struct mutex lock; /* protect cooling devices list */
struct list_head node;
struct delayed_work poll_queue;
+ struct sensor_threshold tz_threshold[2];
+ struct sensor_info sensor;
};
/* Adding event notification support elements */
#define THERMAL_GENL_FAMILY_NAME "thermal_event"
@@ -163,6 +186,12 @@
const struct thermal_cooling_device_ops *);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+int sensor_get_id(char *name);
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type trip, unsigned long temp);
+
#ifdef CONFIG_NET
extern int thermal_generate_netlink_event(u32 orig, enum events event);
#else
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 2805401..15391d8 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -122,6 +122,62 @@
SUB_MODULE_MAX,
};
+enum {
+ MSM_CAMERA_EFFECT_MODE_OFF,
+ MSM_CAMERA_EFFECT_MODE_MONO,
+ MSM_CAMERA_EFFECT_MODE_NEGATIVE,
+ MSM_CAMERA_EFFECT_MODE_SOLARIZE,
+ MSM_CAMERA_EFFECT_MODE_SEPIA,
+ MSM_CAMERA_EFFECT_MODE_POSTERIZE,
+ MSM_CAMERA_EFFECT_MODE_WHITEBOARD,
+ MSM_CAMERA_EFFECT_MODE_BLACKBOARD,
+ MSM_CAMERA_EFFECT_MODE_AQUA,
+ MSM_CAMERA_EFFECT_MODE_EMBOSS,
+ MSM_CAMERA_EFFECT_MODE_SKETCH,
+ MSM_CAMERA_EFFECT_MODE_NEON,
+ MSM_CAMERA_EFFECT_MODE_MAX
+};
+
+enum {
+ MSM_CAMERA_WB_MODE_AUTO,
+ MSM_CAMERA_WB_MODE_CUSTOM,
+ MSM_CAMERA_WB_MODE_INCANDESCENT,
+ MSM_CAMERA_WB_MODE_FLUORESCENT,
+ MSM_CAMERA_WB_MODE_WARM_FLUORESCENT,
+ MSM_CAMERA_WB_MODE_DAYLIGHT,
+ MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT,
+ MSM_CAMERA_WB_MODE_TWILIGHT,
+ MSM_CAMERA_WB_MODE_SHADE,
+ MSM_CAMERA_WB_MODE_OFF,
+ MSM_CAMERA_WB_MODE_MAX
+};
+
+enum {
+ MSM_CAMERA_SCENE_MODE_OFF,
+ MSM_CAMERA_SCENE_MODE_AUTO,
+ MSM_CAMERA_SCENE_MODE_LANDSCAPE,
+ MSM_CAMERA_SCENE_MODE_SNOW,
+ MSM_CAMERA_SCENE_MODE_BEACH,
+ MSM_CAMERA_SCENE_MODE_SUNSET,
+ MSM_CAMERA_SCENE_MODE_NIGHT,
+ MSM_CAMERA_SCENE_MODE_PORTRAIT,
+ MSM_CAMERA_SCENE_MODE_BACKLIGHT,
+ MSM_CAMERA_SCENE_MODE_SPORTS,
+ MSM_CAMERA_SCENE_MODE_ANTISHAKE,
+ MSM_CAMERA_SCENE_MODE_FLOWERS,
+ MSM_CAMERA_SCENE_MODE_CANDLELIGHT,
+ MSM_CAMERA_SCENE_MODE_FIREWORKS,
+ MSM_CAMERA_SCENE_MODE_PARTY,
+ MSM_CAMERA_SCENE_MODE_NIGHT_PORTRAIT,
+ MSM_CAMERA_SCENE_MODE_THEATRE,
+ MSM_CAMERA_SCENE_MODE_ACTION,
+ MSM_CAMERA_SCENE_MODE_AR,
+ MSM_CAMERA_SCENE_MODE_FACE_PRIORITY,
+ MSM_CAMERA_SCENE_MODE_BARCODE,
+ MSM_CAMERA_SCENE_MODE_HDR,
+ MSM_CAMERA_SCENE_MODE_MAX
+};
+
enum csid_cfg_type_t {
CSID_INIT,
CSID_CFG,
@@ -361,6 +417,12 @@
CFG_SET_SATURATION,
CFG_SET_CONTRAST,
CFG_SET_SHARPNESS,
+ CFG_SET_ISO,
+ CFG_SET_EXPOSURE_COMPENSATION,
+ CFG_SET_ANTIBANDING,
+ CFG_SET_BESTSHOT_MODE,
+ CFG_SET_EFFECT,
+ CFG_SET_WHITE_BALANCE,
CFG_SET_AUTOFOCUS,
CFG_CANCEL_AUTOFOCUS,
};
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index b18b16b..23b19b5 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -225,6 +225,7 @@
VFE_READ_DMI_16BIT,
VFE_READ_DMI_32BIT,
VFE_READ_DMI_64BIT,
+ GET_SOC_HW_VER,
};
struct msm_vfe_cfg_cmd2 {
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 6a031e6..bb2dad8 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -237,11 +237,18 @@
*/
static void pm_qos_work_fn(struct work_struct *work)
{
+ s32 new_value = PM_QOS_DEFAULT_VALUE;
struct pm_qos_request *req = container_of(to_delayed_work(work),
struct pm_qos_request,
work);
- pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
+ if (!req || !pm_qos_request_active(req))
+ return;
+
+ if (new_value != req->node.prio)
+ pm_qos_update_target(
+ pm_qos_array[req->pm_qos_class]->constraints,
+ &req->node, PM_QOS_UPDATE_REQ, new_value);
}
/**
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index b9868e1..aa74be4 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -126,6 +126,9 @@
if (nlmsg_len(nlh) < sizeof(*req))
return -EINVAL;
+ if (req->sdiag_family >= AF_MAX)
+ return -EINVAL;
+
hndl = sock_diag_lock_handler(req->sdiag_family);
if (hndl == NULL)
err = -ENOENT;
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 170dbe7..66b0094 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -126,6 +126,16 @@
ON_DEMAND_SUPPLIES_MAX,
};
+/*
+ * The delay list is per codec HW specification.
+ * Please add delay in the list in the future instead
+ * of magic number
+ */
+enum {
+ CODEC_DELAY_1_MS = 1000,
+ CODEC_DELAY_1_1_MS = 1100,
+};
+
struct hpf_work {
struct msm8x10_wcd_priv *msm8x10_wcd;
u32 decimator;
@@ -1148,13 +1158,8 @@
"ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
};
-static const char * const anc_mux_text[] = {
- "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
- "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
-};
-
-static const char * const anc1_fb_mux_text[] = {
- "ZERO", "EAR_HPH_L", "EAR_LINE_1",
+static const char * const adc2_mux_text[] = {
+ "ZERO", "INP2", "INP3"
};
static const char * const iir1_inp1_text[] = {
@@ -1212,6 +1217,9 @@
SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
rx_rdac4_text);
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -1242,6 +1250,9 @@
static const struct snd_kcontrol_new rx_dac4_mux =
SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
+static const struct snd_kcontrol_new tx_adc2_mux =
+ SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1370,7 +1381,8 @@
if (w->reg == MSM8X10_WCD_A_TX_1_EN)
init_bit_shift = 7;
- else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
+ else if ((w->reg == MSM8X10_WCD_A_TX_2_EN) ||
+ (w->reg == MSM8X10_WCD_A_TX_3_EN))
init_bit_shift = 6;
else {
dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1383,9 +1395,11 @@
msm8x10_wcd_codec_enable_adc_block(codec, 1);
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1 << init_bit_shift);
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
break;
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
break;
case SND_SOC_DAPM_POST_PMD:
msm8x10_wcd_codec_enable_adc_block(codec, 0);
@@ -1930,9 +1944,14 @@
{"DEC2 MUX", "ADC2", "ADC2"},
{"DEC2 MUX", NULL, "CDC_CONN"},
+ {"ADC2", NULL, "ADC2 MUX"},
+ {"ADC2 MUX", "INP2", "ADC2_INP2"},
+ {"ADC2 MUX", "INP3", "ADC2_INP3"},
+
/* ADC Connections */
{"ADC1", NULL, "AMIC1"},
- {"ADC2", NULL, "AMIC2"},
+ {"ADC2_INP2", NULL, "AMIC2"},
+ {"ADC2_INP3", NULL, "AMIC3"},
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -2406,9 +2425,17 @@
SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+ SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, MSM8X10_WCD_A_TX_3_EN, 7, 0,
+ msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
+ &tx_adc2_mux),
SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
7, 0),
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index b49b1e3..e1f1efc 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -52,6 +52,9 @@
static void __iomem *pcbcr;
static void __iomem *prcgr;
+static int msm_sec_mi2s_rx_ch = 1;
+static int msm_pri_mi2s_tx_ch = 1;
+
/*
* There is limitation for the clock root selection from
* either MI2S or DIG_CODEC.
@@ -182,10 +185,43 @@
return 0;
}
+static int msm_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s(): channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_sec_mi2s_rx_ch;
+
+ return 0;
+}
+
+static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s(), channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_pri_mi2s_tx_ch;
+
+ return 0;
+}
+
+
static const char *const btsco_rate_text[] = {"8000", "16000"};
static const struct soc_enum msm_btsco_enum[] = {
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static const char *const sec_mi2s_rx_ch_text[] = {"One", "Two"};
+static const char *const pri_mi2s_tx_ch_text[] = {"One", "Two"};
static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -215,6 +251,43 @@
return 0;
}
+static int msm_sec_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_sec_mi2s_rx_ch = %d\n", __func__,
+ msm_sec_mi2s_rx_ch);
+ ucontrol->value.integer.value[0] = msm_sec_mi2s_rx_ch - 1;
+ return 0;
+}
+
+static int msm_sec_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_sec_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_sec_mi2s_rx_ch = %d\n", __func__,
+ msm_sec_mi2s_rx_ch);
+ return 1;
+}
+
+static int msm_pri_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_pri_mi2s_tx_ch = %d\n", __func__,
+ msm_pri_mi2s_tx_ch);
+ ucontrol->value.integer.value[0] = msm_pri_mi2s_tx_ch - 1;
+ return 0;
+}
+
+static int msm_pri_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_pri_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_pri_mi2s_tx_ch = %d\n", __func__, msm_pri_mi2s_tx_ch);
+ return 1;
+}
+
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -353,9 +426,18 @@
return ret;
}
+static const struct soc_enum msm_snd_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, sec_mi2s_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, pri_mi2s_tx_ch_text),
+};
+
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
msm_btsco_rate_get, msm_btsco_rate_put),
+ SOC_ENUM_EXT("MI2S_RX Channels", msm_snd_enum[0],
+ msm_sec_mi2s_rx_ch_get, msm_sec_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1],
+ msm_pri_mi2s_tx_ch_get, msm_pri_mi2s_tx_ch_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -637,7 +719,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
.init = &msm_audrx_init,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_rx_be_hw_params_fixup,
.ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
},
@@ -650,7 +732,7 @@
.codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_tx_be_hw_params_fixup,
.ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
},
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 60dd522..c863497 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1890,20 +1890,20 @@
if (!common.apr_q6_cvs) {
pr_err("%s: apr_cvs is NULL\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocstrm_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVS cal size is 0\n", __func__);
-
+ ret = -EPERM;
goto done;
}
@@ -1932,7 +1932,7 @@
ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_reg_cal_cmd);
if (ret < 0) {
pr_err("%s: Error %d registering CVS cal\n", __func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvs_wait,
@@ -1940,7 +1940,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -1965,19 +1965,22 @@
if (!common.apr_q6_cvs) {
pr_err("%s: apr_cvs is NULL\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocstrm_cal(&cal_block);
- if (cal_block.cal_size == 0)
+ if (cal_block.cal_size == 0) {
+ pr_err("%s: CVS cal size is 0\n", __func__);
+ ret = -EPERM;
goto done;
+ }
cvs_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -1994,7 +1997,7 @@
ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_dereg_cal_cmd);
if (ret < 0) {
pr_err("%s: Error %d de-registering CVS cal\n", __func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvs_wait,
@@ -2002,7 +2005,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -2028,20 +2031,20 @@
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocproc_dev_cfg_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVP cal size is 0\n", __func__);
-
+ ret = -EPERM;
goto done;
}
@@ -2066,7 +2069,7 @@
if (ret < 0) {
pr_err("%s: Error %d registering CVP dev cfg cal\n",
__func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvp_wait,
@@ -2074,7 +2077,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -2099,19 +2102,22 @@
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocproc_dev_cfg_cal(&cal_block);
- if (cal_block.cal_size == 0)
+ if (cal_block.cal_size == 0) {
+ pr_err("%s: CVP cal size is 0\n", __func__);
+ ret = -EPERM;
goto done;
+ }
cvp_dereg_dev_cfg_cmd.hdr.hdr_field =
APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2131,7 +2137,7 @@
if (ret < 0) {
pr_err("%s: Error %d de-registering CVP dev cfg cal\n",
__func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvp_wait,
@@ -2139,7 +2145,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -2164,20 +2170,20 @@
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocproc_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVP cal size is 0\n", __func__);
-
+ ret = -EPERM;
goto done;
}
@@ -2206,7 +2212,7 @@
ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_reg_cal_cmd);
if (ret < 0) {
pr_err("%s: Error %d registering CVP cal\n", __func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvp_wait,
@@ -2214,7 +2220,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -2239,19 +2245,22 @@
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL.\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocproc_cal(&cal_block);
- if (cal_block.cal_size == 0)
+ if (cal_block.cal_size == 0) {
+ pr_err("%s: CVP vol cal size is 0\n", __func__);
+ ret = -EPERM;
goto done;
+ }
cvp_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2268,7 +2277,7 @@
ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_dereg_cal_cmd);
if (ret < 0) {
pr_err("%s: Error %d de-registering CVP cal\n", __func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvp_wait,
@@ -2276,7 +2285,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -2301,20 +2310,20 @@
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocvol_cal(&cal_block);
if (cal_block.cal_size == 0) {
pr_err("%s: CVP vol cal size is 0\n", __func__);
-
+ ret = -EPERM;
goto done;
}
@@ -2346,7 +2355,7 @@
(uint32_t *) &cvp_reg_vol_cal_cmd);
if (ret < 0) {
pr_err("%s: Error %d registering CVP vol cal\n", __func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvp_wait,
@@ -2354,7 +2363,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -2379,19 +2388,22 @@
if (!common.apr_q6_cvp) {
pr_err("%s: apr_cvp is NULL\n", __func__);
- ret = -EINVAL;
+ ret = -EPERM;
goto done;
}
if (!common.cal_mem_handle) {
- pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+ pr_err("%s: Cal mem handle is NULL\n", __func__);
+ ret = -EPERM;
goto done;
}
get_vocvol_cal(&cal_block);
- if (cal_block.cal_size == 0)
+ if (cal_block.cal_size == 0) {
+ pr_err("%s: CVP vol cal size is 0\n", __func__);
+ ret = -EPERM;
goto done;
+ }
cvp_dereg_vol_cal_cmd.hdr.hdr_field =
APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2411,7 +2423,7 @@
if (ret < 0) {
pr_err("%s: Error %d de-registering CVP vol cal\n",
__func__, ret);
-
+ ret = -EINVAL;
goto done;
}
ret = wait_event_timeout(v->cvp_wait,
@@ -2419,7 +2431,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: Command timeout\n", __func__);
-
+ ret = -EINVAL;
goto done;
}
@@ -2430,6 +2442,7 @@
int voc_register_vocproc_vol_table(void)
{
int result = 0;
+ int result2 = 0;
int i;
struct voice_data *v = NULL;
pr_debug("%s\n", __func__);
@@ -2440,17 +2453,17 @@
mutex_lock(&v->lock);
if (is_voc_state_active(v->voc_state)) {
- result = voice_send_cvp_register_vol_cal_cmd(v);
- if (result) {
+ result2 = voice_send_cvp_register_vol_cal_cmd(v);
+ if (result2 < 0) {
pr_err("%s: Failed to register vocvol table for session 0x%x!\n",
__func__, v->session_id);
- mutex_unlock(&v->lock);
- goto done;
+ result = result2;
+ /* Still try to register other sessions */
}
}
mutex_unlock(&v->lock);
}
-done:
+
mutex_unlock(&common.common_lock);
return result;
}
@@ -2458,6 +2471,7 @@
int voc_deregister_vocproc_vol_table(void)
{
int result = 0;
+ int success = 0;
int i;
struct voice_data *v = NULL;
pr_debug("%s\n", __func__);
@@ -2469,17 +2483,25 @@
mutex_lock(&v->lock);
if (is_voc_state_active(v->voc_state)) {
result = voice_send_cvp_deregister_vol_cal_cmd(v);
- if (result) {
+ if (result < 0) {
pr_err("%s: Failed to deregister vocvol table for session 0x%x!\n",
__func__, v->session_id);
mutex_unlock(&v->lock);
+ mutex_unlock(&common.common_lock);
+ if (success) {
+ pr_err("%s: Try to re-register all deregistered sessions!\n",
+ __func__);
+ voc_register_vocproc_vol_table();
+ }
goto done;
+ } else {
+ success = 1;
}
}
mutex_unlock(&v->lock);
}
-done:
mutex_unlock(&common.common_lock);
+done:
return result;
}