Merge "defconfig: msm: Enable zram for msm8610"
diff --git a/Documentation/arm/msm/msm_sharedmem.txt b/Documentation/arm/msm/msm_sharedmem.txt
new file mode 100644
index 0000000..d9c939e
--- /dev/null
+++ b/Documentation/arm/msm/msm_sharedmem.txt
@@ -0,0 +1,115 @@
+Introduction
+============
+
+This is a new platform driver for newly introduced UIO devices
+to facilitate clients in Userspace.
+
+Hardware description
+====================
+This driver does not implement any specific hardware driver.
+
+Software description
+====================
+
+Design
+======
+
+The goal of this driver is to ensure there is no security lapse in the
+Userspace clients' functionality. This new driver uses the existing
+UIO framework to facilitate the clients to be able to memory map their
+respective allotted shared memory address in the client's address space.
+
+ |
+ Userspace | Kernel space
+ +--------------+ +---------------+ +---------------+
+ | Client | | Shared | | shrdmem_uio |
+ | <-------> Memory <-------> driver |
+ +--------------+ +---------------+ +---------------+
+ |
+ |
+
+The shared memory (a transport buffer) address is unique for each
+individual client and is made available to the driver via device tree.
+
+For a given client the probe would be called once in the shrdmem_uio driver.
+This driver would parse the device tree and register a new UIO device with kernel
+available under /dev/uioX (where X would start from zero, being serially
+incremented for the next UIO device probed)
+
+The client in Userspace would be able to access the respective UIO device
+under the sysfs entry(/sys/class/uio/uioX) upon verifying the name and version
+of the device under this sysfs node. Once verified it could access the physical
+address under /sys/class/uio/uioX/maps/map0/addr
+
+The client would request for memory mapping which would be taken care of in the
+kernel space by the UIO framework. No explicit mmap() implementation required by
+the shrdmem_uio driver.
+
+Power Management
+================
+Does not implement any power management.
+
+SMP/multi-core
+==============
+
+The platform driver would be loaded/probed once per client.
+DTS files will be looked up for shared memory addresses and sizes for all the clients.
+The UIO char device will be created under /dev/uioX.
+
+This being one time activity for a given client it does not require SMP/multi-core safety.
+
+Security
+========
+
+The devices (/dev/uioX) would have permission checks for restricted access
+
+Performance
+===========
+
+None.
+
+Interface
+=========
+
+This driver does not export any APIs for kernel.
+Android user space can access the shared memory by mmaping it.
+
+Driver parameters
+=================
+
+None.
+
+Config options
+==============
+
+None.
+
+Dependencies
+============
+
+The only dependency is the kernel device tree files for the
+Userspace client details.
+
+User space utilities
+====================
+This driver communicates with the following user space clients/utilities:
+
+Remote File System:
+ - Based on Qualcomm Messaging Interface (QMI)
+ - This service enables the modules on the MSM modem processor to
+ read data from and write data to the embedded multimedia card (eMMC),
+ which is solely controlled by the applications processor.
+
+Remote File System Access (QMI_RFSA):
+ - Based on Qualcomm Messaging Interface (QMI)
+ - This service provides access from the Hexagon processor to a High-Level
+ Operating Sytem (HLOS) file system
+Other
+=====
+
+None.
+
+Known issues
+============
+
+None.
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 584a76d..7d8fe0a 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -93,10 +93,16 @@
set, the charger ovp status is monitored in software.
- qcom,ext-ovp-present Indicates if an external OVP exists which reduces the
overall input resistance of the charge path.
+- qcom,ibat-calibration-enabled Indicates if ibat calibration is enabled. This is
+ required for devices which have a ibat trim error
+ causing ibatmax to go out of spec.
- qcom,power-stage-reduced Indicates if power stage workaround is enabled. This work
around reduces the power stage segments while charging
under high load during low battery voltages. It's for
improving IADC accuracy while board has a bad layout.
+- qcom,use-external-rsense A boolean that controls whether BMS will use
+ an external sensor resistor instead of the default
+ RDS of the batfet.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/uio/msm_sharedmem.txt b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
new file mode 100644
index 0000000..5af50da
--- /dev/null
+++ b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
@@ -0,0 +1,13 @@
+msm_sharedmem provides the shared memory addresses for various clients in user-space
+
+Required properties:
+- compatible: Must be "qcom,sharedmem-uio"
+- reg : The address and size of the shared memory. The address/sizes may vary.
+- reg-names : indicates various client-names.
+
+Example:
+ msm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc80000 0x00180000>,
+ reg-names = "rmtfs";
+ };
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-2200mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-2200mah.dtsi
new file mode 100644
index 0000000..53aa781
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-2200mah.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-2200mah-data {
+ qcom,default-rbatt-mohm = <163>;
+ qcom,max-voltage-uv = <4200>;
+ qcom,fcc-mah = <2200>;
+ qcom,rbatt-capacitive-mohm = <0>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-id-kohm = <10>;
+ qcom,flat-ocv-threshold-uv = <3800000>;
+
+ qcom,fcc-temp-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-data = <2167 2179 2234 2178 2164>;
+ };
+
+ 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 = <4188 4184 4199 4176 4170>,
+ <4109 4124 4145 4124 4118>,
+ <4051 4082 4097 4077 4072>,
+ <3963 4024 4055 4034 4029>,
+ <3920 3971 4002 3993 3989>,
+ <3880 3932 3963 3957 3952>,
+ <3846 3892 3920 3913 3910>,
+ <3822 3859 3881 3873 3871>,
+ <3805 3834 3851 3845 3844>,
+ <3790 3813 3828 3823 3822>,
+ <3777 3796 3808 3805 3803>,
+ <3764 3784 3792 3790 3788>,
+ <3750 3775 3778 3777 3774>,
+ <3736 3766 3766 3761 3751>,
+ <3721 3752 3755 3745 3732>,
+ <3704 3733 3737 3729 3716>,
+ <3684 3707 3713 3707 3694>,
+ <3655 3686 3688 3682 3672>,
+ <3598 3661 3677 3671 3659>,
+ <3585 3655 3673 3669 3656>,
+ <3571 3644 3664 3663 3650>,
+ <3551 3626 3643 3648 3631>,
+ <3523 3598 3609 3618 3600>,
+ <3489 3561 3565 3578 3561>,
+ <3445 3514 3510 3529 3512>,
+ <3389 3453 3440 3468 3450>,
+ <3313 3372 3345 3386 3366>,
+ <3207 3252 3209 3262 3239>,
+ <3000 3000 3000 3000 3000>;
+ };
+
+ 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 = <1371 224 100 79 74>,
+ <1358 242 100 80 74>,
+ <1358 242 103 80 74>,
+ <1195 257 107 82 75>,
+ <1171 256 112 84 77>,
+ <1149 250 119 89 79>,
+ <1144 232 114 90 79>,
+ <1150 225 101 83 76>,
+ <1175 227 98 81 76>,
+ <1210 232 98 82 76>,
+ <1260 236 98 82 77>,
+ <1329 242 100 84 77>,
+ <1421 251 100 86 79>,
+ <1536 263 101 81 76>,
+ <1671 280 100 80 74>,
+ <1830 304 100 81 75>,
+ <2036 338 101 82 76>,
+ <2326 443 103 82 76>,
+ <2788 708 112 88 79>,
+ <2890 747 115 90 80>,
+ <2755 676 117 89 79>,
+ <2750 716 118 87 78>,
+ <2916 765 119 87 79>,
+ <3336 833 123 89 80>,
+ <4214 920 133 92 81>,
+ <5615 1031 151 96 83>,
+ <7923 1188 192 104 89>,
+ <13252 1886 585 137 122>,
+ <43764 20050 47711 3680 16847>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index b540063..0678559 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -209,7 +209,9 @@
qcom,resume-soc = <99>;
qcom,tchg-mins = <150>;
qcom,chg-vadc = <&pm8941_vadc>;
+ qcom,chg-iadc = <&pm8941_iadc>;
qcom,chg-adc_tm = <&pm8941_adc_tm>;
+ qcom,ibat-calibration-enabled;
qcom,chgr@1000 {
status = "disabled";
diff --git a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
index 76bd262..2e32ac4 100755
--- a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
@@ -85,25 +85,25 @@
goodix,button-map= <158 102 139>;
goodix,product-id = "915";
goodix,cfg-data0 = [
- 41 D0 02 00 05 05 35 01 01 0F
- 2D 06 50 32 03 05 00 00 00 00
- 00 00 05 18 1A 1E 14 8C 0E 0E
- 3F 3D 2A 09 00 00 00 99 04 1D
- 00 00 00 00 00 00 00 00 00 00
- 00 32 6E 94 D5 01 05 00 00 04
- CE 36 00 B5 3F 00 9E 4A 00 8B
- 57 00 7C 65 00 7C 10 38 68 00
- 56 50 35 66 66 27 00 00 00 00
+ 41 D0 02 00 05 05 35 11 01 0F
+ 2D 06 50 32 03 02 00 00 00 00
+ 00 00 05 18 1A 1E 14 8C 2E 0E
+ 59 5B B2 04 00 00 00 99 03 11
+ 00 1C 00 00 00 00 00 00 00 00
+ 00 53 A6 94 C5 01 05 00 00 08
+ 7F 59 00 71 66 00 64 75 00 58
+ 87 00 4E 9B 00 4E 10 38 68 00
+ 56 45 30 66 66 27 00 00 00 00
00 00 00 00 00 00 00 00 00 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 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 02 04 06 08 0A 0C 0F
+ 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 00 00
- 00 FF FF FF FF FF FF FF FF FF
- FF FF FF FF A3 01];
+ 20 21 22 24 26 28 29 2A FF FF
+ FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF 03 01];
goodix,cfg-data1 = [
41 D0 02 00 05 05 35 01 01 C3
2D 06 55 32 03 03 00 00 00 00
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index a28bb94..906e4a8 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -216,6 +216,13 @@
reg = <0xf991f000 0x1000>;
interrupts = <0 109 0>;
status = "disabled";
+
+ qcom,msm-bus,name = "blsp1_uart2";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
};
serial@f995e000 {
@@ -722,6 +729,24 @@
compatible = "qcom,bcl";
};
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_mdm";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index 85bd746..92d1a77 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -102,6 +102,10 @@
linux,default-trigger = "flashlight-trigger";
};
+ qcom,wdt@f9017000 {
+ qcom,bark-time = <13000>;
+ };
+
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
index 95a5da5..2547148 100644
--- a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
@@ -56,10 +56,26 @@
&dsi_hx8389b_qhd_vid {
qcom,cont-splash-enabled;
};
+
&soc {
i2c@f9925000 {
fsl@1c {
fsl,sensors-position = <7>;
};
};
-};
\ No newline at end of file
+};
+
+&qrd_batterydata {
+ qcom,rpull-up-kohm = <100>;
+ qcom,vref-batt-therm = <1800000>;
+
+ /include/ "batterydata-qrd-4v2-2200mah.dtsi"
+};
+
+&pm8110_bms {
+ qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+ qcom,battery-data = <&qrd_batterydata>;
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index fc9e24a..0281e45 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -257,6 +257,24 @@
qcom,streaming-func = "rndis";
};
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc60000 0x00020000>;
+ reg-names = "rfsa_mdm";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index e612df7..69e2529 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -283,6 +283,24 @@
<87 512 60000 960000>;
};
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_mdm";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index a492561..6c55566 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -65,6 +65,24 @@
reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
};
+ rmtfs_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd80000 0x00180000>;
+ reg-names = "rmtfs";
+ };
+
+ dsp_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_dsp";
+ };
+
+ mdm_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0fd60000 0x00020000>;
+ reg-names = "rfsa_mdm";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 818e052..c5aa51a 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -270,6 +270,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -396,6 +397,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index c1f2ca2..f4ee78d 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -271,6 +271,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -421,6 +422,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 97779fe..8366a41 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -246,6 +246,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -354,6 +355,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ZRAM=y
CONFIG_ZSMALLOC=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 64933c9..02db2f2 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -248,6 +248,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -378,6 +379,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ZRAM=y
CONFIG_ZSMALLOC=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index fb05a08..07bb88c 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -298,6 +298,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -435,6 +436,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8f6f52f..82bbdb7 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -306,6 +306,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
@@ -443,6 +444,8 @@
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index cf3fac0..c5b1deb 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -761,15 +761,22 @@
}
/*
- * Increment the L2 HFPLL regulator refcount if _this_ CPU's frequency
- * requires a corresponding target L2 frequency that needs the L2 to
- * run off of an HFPLL.
+ * Vote for the L2 HFPLL regulators if _this_ CPU's frequency requires
+ * a corresponding target L2 frequency that needs the L2 an HFPLL.
*/
- if (drv.l2_freq_tbl[acpu_level->l2_level].speed.src == HFPLL)
- l2_vreg_count++;
+ if (drv.l2_freq_tbl[acpu_level->l2_level].speed.src == HFPLL) {
+ ret = enable_l2_regulators();
+ if (ret) {
+ dev_err(drv.dev, "enable_l2_regulators() failed (%d)\n",
+ ret);
+ goto err_l2_regs;
+ }
+ }
return 0;
+err_l2_regs:
+ regulator_disable(sc->vreg[VREG_CORE].reg);
err_core_conf:
regulator_put(sc->vreg[VREG_CORE].reg);
err_core_get:
@@ -901,7 +908,7 @@
ret = -ENODEV;
goto err_table;
}
- dev_dbg(drv.dev, "CPU%d is running at an unknown rate. Defaulting to %lu KHz.\n",
+ dev_warn(drv.dev, "CPU%d is running at an unknown rate. Defaulting to %lu KHz.\n",
cpu, acpu_level->speed.khz);
} else {
dev_dbg(drv.dev, "CPU%d is running at %lu KHz\n", cpu,
@@ -1208,7 +1215,7 @@
l2_level = find_cur_l2_level();
if (!l2_level) {
l2_level = drv.l2_freq_tbl;
- dev_dbg(drv.dev, "L2 is running at an unknown rate. Defaulting to %lu KHz.\n",
+ dev_warn(drv.dev, "L2 is running at an unknown rate. Defaulting to %lu KHz.\n",
l2_level->speed.khz);
} else {
dev_dbg(drv.dev, "L2 is running at %lu KHz\n",
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 80a957f..7b13bbc 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -108,6 +108,11 @@
msm_thermal_device_init();
}
+static struct of_dev_auxdata msm_hsic_host_adata[] = {
+ OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+ {}
+};
+
static struct of_dev_auxdata msm8974_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
"msm_otg", NULL),
@@ -148,6 +153,8 @@
"qcrypto.0", NULL),
OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, \
"msm_hsic_host", NULL),
+ OF_DEV_AUXDATA("qcom,hsic-smsc-hub", 0, "msm_smsc_hub",
+ msm_hsic_host_adata),
{}
};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index a883e39..8f1da85 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -694,6 +694,7 @@
F_GCC( 56000000, gpll0, 1, 7, 75),
F_GCC( 58982400, gpll0, 1, 1536, 15625),
F_GCC( 60000000, gpll0, 10, 0, 0),
+ F_GCC( 63160000, gpll0, 9.5, 0, 0),
F_END
};
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 89d462c..5e00770 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -676,6 +676,7 @@
F( 960000, gcc_xo, 10, 1, 2),
F( 4800000, gcc_xo, 4, 0, 0),
F( 9600000, gcc_xo, 2, 0, 0),
+ F(12000000, gpll0, 10, 1, 5),
F(15000000, gpll0, 10, 1, 4),
F(19200000, gcc_xo, 1, 0, 0),
F(25000000, gpll0, 12, 1, 2),
@@ -782,6 +783,7 @@
F(56000000, gpll0, 1, 7, 75),
F(58982400, gpll0, 1, 1536, 15625),
F(60000000, gpll0, 10, 0, 0),
+ F(63160000, gpll0, 9.5, 0, 0),
F_END,
};
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
index 176dc32..2b529b0 100644
--- a/arch/arm/mach-msm/clock-krypton.c
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -515,6 +515,7 @@
F( 56000000, gpll0, 1, 7, 75),
F( 58982400, gpll0, 1, 1536, 15625),
F( 60000000, gpll0, 10, 0, 0),
+ F( 63160000, gpll0, 9.5, 0, 0),
F_END
};
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index bdda546..5aa6c93 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -589,17 +589,24 @@
};
static const struct proto_ops msm_ipc_proto_ops = {
- .owner = THIS_MODULE,
.family = AF_MSM_IPC,
+ .owner = THIS_MODULE,
+ .release = msm_ipc_router_close,
.bind = msm_ipc_router_bind,
.connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .getname = sock_no_getname,
+ .poll = msm_ipc_router_poll,
+ .ioctl = msm_ipc_router_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = sock_no_setsockopt,
+ .getsockopt = sock_no_getsockopt,
.sendmsg = msm_ipc_router_sendmsg,
.recvmsg = msm_ipc_router_recvmsg,
- .ioctl = msm_ipc_router_ioctl,
- .poll = msm_ipc_router_poll,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .release = msm_ipc_router_close,
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage,
};
static struct proto msm_ipc_proto = {
diff --git a/arch/arm/mach-msm/pil-msa.c b/arch/arm/mach-msm/pil-msa.c
index 3a26af9..76afe6c 100644
--- a/arch/arm/mach-msm/pil-msa.c
+++ b/arch/arm/mach-msm/pil-msa.c
@@ -233,18 +233,17 @@
if (drv->self_auth) {
ret = pil_msa_wait_for_mba_ready(drv);
if (ret)
- goto err_auth;
+ goto err_q6v5_reset;
}
drv->is_booted = true;
return 0;
-err_auth:
- pil_q6v5_shutdown(pil);
err_q6v5_reset:
pil_msa_pbl_disable_clks(drv);
err_clks:
+ writel_relaxed(1, drv->restart_reg);
pil_msa_pbl_power_down(drv);
err_power:
return ret;
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 0a50bcc..2d375ac 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -269,6 +269,7 @@
} else {
ion_phys_addr_t phys_addr;
size_t phys_len;
+ size_t va_len = 0;
pr_debug("%s: page is NULL\n", __func__);
ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
@@ -282,6 +283,12 @@
vma, (unsigned int)vma->vm_start,
(unsigned int)vma->vm_end, vma->vm_pgoff,
(unsigned long int)vma->vm_page_prot);
+ va_len = vma->vm_end - vma->vm_start;
+ if ((offset > phys_len) || (va_len > phys_len-offset)) {
+ pr_err("wrong offset size %ld, lens= %d, va_len=%d\n",
+ offset, phys_len, va_len);
+ return -EINVAL;
+ }
ret = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(phys_addr) + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in.c b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
index 0db4894..cf7548d 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -256,6 +256,7 @@
}
case AUDIO_GET_CONFIG: {
struct msm_audio_config config;
+ memset(&config, 0, sizeof(config));
config.buffer_size = pcm->buffer_size;
config.buffer_count = pcm->buffer_count;
config.sample_rate = pcm->sample_rate;
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
index 5faee21..f7bf1ae 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
@@ -1,5 +1,5 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -475,6 +475,7 @@
}
case AUDIO_GET_CONFIG: {
struct msm_audio_config config;
+ memset(&config, 0, sizeof(config));
config.buffer_size = pcm->buffer_size;
config.buffer_count = pcm->buffer_count;
config.sample_rate = pcm->sample_rate;
diff --git a/arch/arm/mach-msm/sensors_adsp.c b/arch/arm/mach-msm/sensors_adsp.c
index fab10b8..ad19e16 100644
--- a/arch/arm/mach-msm/sensors_adsp.c
+++ b/arch/arm/mach-msm/sensors_adsp.c
@@ -38,6 +38,7 @@
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
+#define CLASS_NAME "ssc"
#define DRV_NAME "sensors"
#define DRV_VERSION "1.00"
@@ -1079,7 +1080,7 @@
static int sensors_adsp_probe(struct platform_device *pdev)
{
int ret = 0;
- sns_ctl.dev_class = class_create(THIS_MODULE, DRV_NAME);
+ sns_ctl.dev_class = class_create(THIS_MODULE, CLASS_NAME);
if (sns_ctl.dev_class == NULL) {
pr_err("%s: class_create fail.\n", __func__);
goto res_err;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index e2864ec..02d76fc 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -650,14 +650,13 @@
different function.
config MSM_ADSPRPC
- tristate "Qualcomm ADSP RPC driver"
- depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
- default m
- help
- Provides a communication mechanism that allows for clients to
- make remote method invocations across processor boundary to
- applications DSP processor. Say M if you want to enable this
- module.
+ tristate "Qualcomm ADSP RPC driver"
+ depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
+ help
+ Provides a communication mechanism that allows for clients to
+ make remote method invocations across processor boundary to
+ applications DSP processor. Say M if you want to enable this
+ module.
config MMC_GENERIC_CSDIO
tristate "Generic sdio driver"
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 4507f80..0a093cc 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/of.h>
#include <linux/iommu.h>
+#include <linux/kref.h>
#ifndef ION_ADSPRPC_HEAP_ID
#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
@@ -152,9 +153,11 @@
struct class *class;
struct device *dev;
struct fastrpc_smmu smmu;
+ struct mutex smd_mutex;
dev_t dev_no;
spinlock_t wrlock;
spinlock_t hlock;
+ struct kref kref;
struct hlist_head htbl[RPC_HASH_SZ];
};
@@ -661,6 +664,7 @@
spin_lock_init(&me->hlock);
spin_lock_init(&me->wrlock);
init_completion(&me->work);
+ mutex_init(&me->smd_mutex);
for (i = 0; i < RPC_HASH_SZ; ++i)
INIT_HLIST_HEAD(&me->htbl[i]);
VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
@@ -687,23 +691,10 @@
if (me->smmu.domain_id >= 0)
me->smmu.enabled = enabled;
}
- VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
- SMD_APPS_QDSP, &me->chan,
- me, smd_event_handler));
- if (err)
- goto smd_bail;
- VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
- RPC_TIMEOUT));
- if (err)
- goto completion_bail;
}
return 0;
-completion_bail:
- smd_close(me->chan);
-smd_bail:
- ion_client_destroy(me->iclient);
ion_bail:
context_list_dtor(&me->clst);
context_list_bail:
@@ -1087,9 +1078,22 @@
return;
}
+static void fastrpc_channel_close(struct kref *kref)
+{
+ struct fastrpc_apps *me = &gfa;
+
+ smd_close(me->chan);
+ me->chan = 0;
+ mutex_unlock(&me->smd_mutex);
+ pr_info("'closed /dev/%s c %d 0'\n", DEVICE_NAME,
+ MAJOR(me->dev_no));
+}
+
static int fastrpc_device_release(struct inode *inode, struct file *file)
{
struct file_data *fdata = (struct file_data *)file->private_data;
+ struct fastrpc_apps *me = &gfa;
+
(void)fastrpc_release_current_dsp_process();
cleanup_current_dev();
if (fdata) {
@@ -1102,6 +1106,8 @@
kfree(map);
}
kfree(fdata);
+ kref_put_mutex(&me->kref, fastrpc_channel_close,
+ &me->smd_mutex);
}
return 0;
}
@@ -1109,6 +1115,25 @@
static int fastrpc_device_open(struct inode *inode, struct file *filp)
{
int err = 0;
+ struct fastrpc_apps *me = &gfa;
+
+ mutex_lock(&me->smd_mutex);
+ if (kref_get_unless_zero(&me->kref) == 0) {
+ VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
+ SMD_APPS_QDSP, &me->chan,
+ me, smd_event_handler));
+ if (err)
+ goto smd_bail;
+ VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
+ RPC_TIMEOUT));
+ if (err)
+ goto completion_bail;
+ kref_init(&me->kref);
+ pr_info("'opened /dev/%s c %d 0'\n", DEVICE_NAME,
+ MAJOR(me->dev_no));
+ }
+ mutex_unlock(&me->smd_mutex);
+
filp->private_data = 0;
if (0 != try_module_get(THIS_MODULE)) {
struct file_data *fdata = 0;
@@ -1130,10 +1155,19 @@
if (err) {
cleanup_current_dev();
kfree(fdata);
+ kref_put_mutex(&me->kref, fastrpc_channel_close,
+ &me->smd_mutex);
}
module_put(THIS_MODULE);
}
return err;
+
+completion_bail:
+ smd_close(me->chan);
+ me->chan = 0;
+smd_bail:
+ mutex_unlock(&me->smd_mutex);
+ return err;
}
@@ -1251,7 +1285,6 @@
VERIFY(err, !IS_ERR(me->dev));
if (err)
goto device_create_bail;
- pr_info("'created /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
return 0;
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 7778477..8037187 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -1949,6 +1949,12 @@
else
q_req->cryptlen = areq->cryptlen - authsize;
+ if ((q_req->cryptlen > ULONG_MAX - ivsize) ||
+ (q_req->cryptlen + ivsize > ULONG_MAX - areq->assoclen)) {
+ pr_err("Integer overflow on total aead req length.\n");
+ return -EINVAL;
+ }
+
totallen = q_req->cryptlen + ivsize + areq->assoclen;
pad_len = ALIGN(totallen, ADM_CE_BLOCK_SIZE) - totallen;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 4c05978..a4154c1 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -43,13 +43,17 @@
#define QCE_MAX_NUM_DSCR 0x500
#define QCE_SECTOR_SIZE 0x200
-static DEFINE_MUTEX(bam_register_cnt);
+static DEFINE_MUTEX(bam_register_lock);
struct bam_registration_info {
+ struct list_head qlist;
uint32_t handle;
uint32_t cnt;
+ uint32_t bam_mem;
+ void __iomem *bam_iobase;
+ bool support_cmd_dscr;
};
-static struct bam_registration_info bam_registry;
-static bool ce_bam_registered;
+static LIST_HEAD(qce50_bam_list);
+
/*
* CE HW device structure.
* Each engine has an instance of the structure.
@@ -58,11 +62,14 @@
*/
struct qce_device {
struct device *pdev; /* Handle to platform_device structure */
+ struct bam_registration_info *pbam;
unsigned char *coh_vmem; /* Allocated coherent virtual memory */
dma_addr_t coh_pmem; /* Allocated coherent physical memory */
int memsize; /* Memory allocated */
- int is_shared; /* CE HW is shared */
+ uint32_t bam_mem; /* bam physical address, from DT */
+ uint32_t bam_mem_size; /* bam io size, from DT */
+ int is_shared; /* CE HW is shared */
bool support_cmd_dscr;
bool support_hw_key;
@@ -2162,25 +2169,93 @@
sps_connect_info->desc.phys_base);
sps_free_endpoint(sps_pipe_info);
}
-/**
- * Initialize SPS HW connected with CE core
- *
- * This function register BAM HW resources with
- * SPS driver and then initialize 2 SPS endpoints
- *
- * This function should only be called once typically
- * during driver probe.
- *
- * @pce_dev - Pointer to qce_device structure
- *
- * @return - 0 if successful else negative value.
- *
- */
-static int qce_sps_init(struct qce_device *pce_dev)
+
+static void qce_sps_release_bam(struct qce_device *pce_dev)
+{
+ struct bam_registration_info *pbam;
+
+ mutex_lock(&bam_register_lock);
+ pbam = pce_dev->pbam;
+ if (pbam == NULL)
+ goto ret;
+
+ pbam->cnt--;
+ if (pbam->cnt > 0)
+ goto ret;
+
+ if (pce_dev->ce_sps.bam_handle) {
+ sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
+
+ pr_debug("deregister bam handle %x\n",
+ pce_dev->ce_sps.bam_handle);
+ pce_dev->ce_sps.bam_handle = 0;
+ }
+ iounmap(pbam->bam_iobase);
+ pr_debug("delete bam 0x%x\n", pbam->bam_mem);
+ list_del(&pbam->qlist);
+ kfree(pbam);
+
+ pce_dev->pbam = NULL;
+ret:
+ mutex_unlock(&bam_register_lock);
+}
+
+static int qce_sps_get_bam(struct qce_device *pce_dev)
{
int rc = 0;
struct sps_bam_props bam = {0};
- bool register_bam = false;
+ struct bam_registration_info *pbam = NULL;
+ struct bam_registration_info *p;
+ uint32_t bam_cfg = 0 ;
+
+
+ mutex_lock(&bam_register_lock);
+
+ list_for_each_entry(p, &qce50_bam_list, qlist) {
+ if (p->bam_mem == pce_dev->bam_mem) {
+ pbam = p; /* found */
+ break;
+ }
+ }
+
+ if (pbam) {
+ pr_debug("found bam 0x%x\n", pbam->bam_mem);
+ pbam->cnt++;
+ pce_dev->ce_sps.bam_handle = pbam->handle;
+ pce_dev->ce_sps.bam_mem = pbam->bam_mem;
+ pce_dev->ce_sps.bam_iobase = pbam->bam_iobase;
+ pce_dev->pbam = pbam;
+ pce_dev->support_cmd_dscr = pbam->support_cmd_dscr;
+ goto ret;
+ }
+
+ pbam = kzalloc(sizeof(struct bam_registration_info), GFP_KERNEL);
+ if (!pbam) {
+ pr_err("qce50 Memory allocation of bam FAIL, error %ld\n",
+ PTR_ERR(pbam));
+
+ rc = -ENOMEM;
+ goto ret;
+ }
+ pbam->cnt = 1;
+ pbam->bam_mem = pce_dev->bam_mem;
+ pbam->bam_iobase = ioremap_nocache(pce_dev->bam_mem,
+ pce_dev->bam_mem_size);
+ if (!pbam->bam_iobase) {
+ kfree(pbam);
+ rc = -ENOMEM;
+ pr_err("Can not map BAM io memory\n");
+ goto ret;
+ }
+ pce_dev->ce_sps.bam_mem = pbam->bam_mem;
+ pce_dev->ce_sps.bam_iobase = pbam->bam_iobase;
+ pbam->handle = 0;
+ pr_debug("allocate bam 0x%x\n", pbam->bam_mem);
+ bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
+ CRYPTO_BAM_CNFG_BITS_REG);
+ pbam->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
+ true : false;
+ pce_dev->support_cmd_dscr = pbam->support_cmd_dscr;
bam.phys_addr = pce_dev->ce_sps.bam_mem;
bam.virt_addr = pce_dev->ce_sps.bam_iobase;
@@ -2212,27 +2287,46 @@
pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
pr_debug("bam virtual base=0x%x\n", (u32)bam.virt_addr);
- mutex_lock(&bam_register_cnt);
- if (ce_bam_registered == false) {
- bam_registry.handle = 0;
- bam_registry.cnt = 0;
+ /* Register CE Peripheral BAM device to SPS driver */
+ rc = sps_register_bam_device(&bam, &pbam->handle);
+ if (rc) {
+ pr_err("sps_register_bam_device() failed! err=%d", rc);
+ rc = -EIO;
+ iounmap(pbam->bam_iobase);
+ kfree(pbam);
+ goto ret;
}
- if ((bam_registry.handle == 0) && (bam_registry.cnt == 0)) {
- /* Register CE Peripheral BAM device to SPS driver */
- rc = sps_register_bam_device(&bam, &bam_registry.handle);
- if (rc) {
- mutex_unlock(&bam_register_cnt);
- pr_err("sps_register_bam_device() failed! err=%d", rc);
- return -EIO;
- }
- bam_registry.cnt++;
- register_bam = true;
- ce_bam_registered = true;
- } else {
- bam_registry.cnt++;
- }
- mutex_unlock(&bam_register_cnt);
- pce_dev->ce_sps.bam_handle = bam_registry.handle;
+
+ pce_dev->pbam = pbam;
+ list_add_tail(&pbam->qlist, &qce50_bam_list);
+ pce_dev->ce_sps.bam_handle = pbam->handle;
+
+ret:
+ mutex_unlock(&bam_register_lock);
+
+ return rc;
+}
+/**
+ * Initialize SPS HW connected with CE core
+ *
+ * This function register BAM HW resources with
+ * SPS driver and then initialize 2 SPS endpoints
+ *
+ * This function should only be called once typically
+ * during driver probe.
+ *
+ * @pce_dev - Pointer to qce_device structure
+ *
+ * @return - 0 if successful else negative value.
+ *
+ */
+static int qce_sps_init(struct qce_device *pce_dev)
+{
+ int rc = 0;
+
+ rc = qce_sps_get_bam(pce_dev);
+ if (rc)
+ return rc;
pr_debug("BAM device registered. bam_handle=0x%x",
pce_dev->ce_sps.bam_handle);
@@ -2253,14 +2347,7 @@
sps_connect_consumer_err:
qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer);
sps_connect_producer_err:
- if (register_bam) {
- mutex_lock(&bam_register_cnt);
- sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
- ce_bam_registered = false;
- bam_registry.handle = 0;
- bam_registry.cnt = 0;
- mutex_unlock(&bam_register_cnt);
- }
+ qce_sps_release_bam(pce_dev);
return rc;
}
@@ -2280,17 +2367,7 @@
{
qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.consumer);
qce_sps_exit_ep_conn(pce_dev, &pce_dev->ce_sps.producer);
- mutex_lock(&bam_register_cnt);
- if ((bam_registry.handle != 0) && (bam_registry.cnt == 1)) {
- sps_deregister_bam_device(pce_dev->ce_sps.bam_handle);
- bam_registry.cnt = 0;
- bam_registry.handle = 0;
- }
- if ((bam_registry.handle != 0) && (bam_registry.cnt > 1))
- bam_registry.cnt--;
- mutex_unlock(&bam_register_cnt);
-
- iounmap(pce_dev->ce_sps.bam_iobase);
+ qce_sps_release_bam(pce_dev);
}
static void _aead_sps_producer_callback(struct sps_event_notify *notify)
@@ -4069,22 +4146,15 @@
resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"crypto-bam-base");
if (resource) {
- pce_dev->ce_sps.bam_mem = resource->start;
- pce_dev->ce_sps.bam_iobase = ioremap_nocache(resource->start,
- resource_size(resource));
- if (!pce_dev->ce_sps.bam_iobase) {
- rc = -ENOMEM;
- pr_err("Can not map BAM io memory\n");
- goto err_getting_bam_info;
- }
+ pce_dev->bam_mem = resource->start;
+ pce_dev->bam_mem_size = resource_size(resource);
} else {
pr_err("CRYPTO BAM mem unavailable.\n");
rc = -ENODEV;
goto err_getting_bam_info;
}
- pr_warn("ce_bam_phy_reg_base=0x%x ", pce_dev->ce_sps.bam_mem);
- pr_warn("ce_bam_virt_reg_base=0x%x\n",
- (uint32_t)pce_dev->ce_sps.bam_iobase);
+ pr_warn("ce_bam_phy_reg_base=0x%x ", pce_dev->bam_mem);
+
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
pce_dev->ce_sps.bam_irq = resource->start;
@@ -4250,7 +4320,6 @@
void *qce_open(struct platform_device *pdev, int *rc)
{
struct qce_device *pce_dev;
- uint32_t bam_cfg = 0 ;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -4293,15 +4362,9 @@
}
*rc = 0;
- bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
- CRYPTO_BAM_CNFG_BITS_REG);
- pce_dev->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
- true : false;
qce_init_ce_cfg_val(pce_dev);
- qce_setup_ce_sps_data(pce_dev);
qce_sps_init(pce_dev);
-
-
+ qce_setup_ce_sps_data(pce_dev);
qce_disable_clk(pce_dev);
return pce_dev;
@@ -4313,8 +4376,6 @@
dma_free_coherent(pce_dev->pdev, pce_dev->memsize,
pce_dev->coh_vmem, pce_dev->coh_pmem);
err_iobase:
- if (pce_dev->ce_sps.bam_iobase)
- iounmap(pce_dev->ce_sps.bam_iobase);
if (pce_dev->iobase)
iounmap(pce_dev->iobase);
err_pce_dev:
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 81a90fe..4845f11 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1339,7 +1339,7 @@
areq->cipher_op_req.vbuf.src[0].len))
return -EFAULT;
- k_align_src += areq->cipher_op_req.vbuf.src[0].len;
+ k_align_src += byteoffset + areq->cipher_op_req.vbuf.src[0].len;
for (i = 1; i < areq->cipher_op_req.entries; i++) {
user_src =
@@ -1602,11 +1602,6 @@
static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req,
struct qcedev_control *podev)
{
-
- if (req->encklen < 0) {
- pr_err("%s: Invalid key size: %d\n", __func__, req->encklen);
- return -EINVAL;
- }
/* if intending to use HW key make sure key fields are set
* correctly and HW key is indeed supported in target
*/
@@ -1701,6 +1696,13 @@
goto error;
}
}
+
+ if (req->data_len < req->byteoffset) {
+ pr_err("%s: req data length %u is less than byteoffset %u\n",
+ __func__, req->data_len, req->byteoffset);
+ goto error;
+ }
+
/* Ensure zer ivlen for ECB mode */
if (req->ivlen > 0) {
if ((req->mode == QCEDEV_AES_MODE_ECB) ||
@@ -1716,16 +1718,28 @@
}
}
/* Check for sum of all dst length is equal to data_len */
- for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++)
+ for (i = 0; (i < QCEDEV_MAX_BUFFERS) && (total < req->data_len); i++) {
+ if (req->vbuf.dst[i].len > ULONG_MAX - total) {
+ pr_err("%s: Integer overflow on total req dst vbuf length\n",
+ __func__);
+ goto error;
+ }
total += req->vbuf.dst[i].len;
+ }
if (total != req->data_len) {
pr_err("%s: Total (i=%d) dst(%d) buf size != data_len (%d)\n",
__func__, i, total, req->data_len);
goto error;
}
/* Check for sum of all src length is equal to data_len */
- for (i = 0, total = 0; i < req->entries; i++)
+ for (i = 0, total = 0; i < req->entries; i++) {
+ if (req->vbuf.src[i].len > ULONG_MAX - total) {
+ pr_err("%s: Integer overflow on total req src vbuf length\n",
+ __func__);
+ goto error;
+ }
total += req->vbuf.src[i].len;
+ }
if (total != req->data_len) {
pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
__func__, total, req->data_len);
@@ -1781,8 +1795,15 @@
}
/* Check for sum of all src length is equal to data_len */
- for (i = 0, total = 0; i < req->entries; i++)
+ for (i = 0, total = 0; i < req->entries; i++) {
+ if (req->data[i].len > ULONG_MAX - total) {
+ pr_err("%s: Integer overflow on total req buf length\n",
+ __func__);
+ goto sha_error;
+ }
total += req->data[i].len;
+ }
+
if (total != req->data_len) {
pr_err("%s: Total src(%d) buf size != data_len (%d)\n",
__func__, total, req->data_len);
@@ -2112,21 +2133,21 @@
int len = 0;
pstat = &_qcedev_stat;
- len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
+ len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm QCE dev driver %d Statistics:\n",
id + 1);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Encryption operation success : %d\n",
pstat->qcedev_enc_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Encryption operation fail : %d\n",
pstat->qcedev_enc_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Decryption operation success : %d\n",
pstat->qcedev_dec_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" Encryption operation fail : %d\n",
pstat->qcedev_dec_fail);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index ae57d6c..6606706 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -409,7 +409,7 @@
{
int i;
- for (i = 0; nbytes > 0; i++, sg = scatterwalk_sg_next(sg))
+ for (i = 0; nbytes > 0 && sg != NULL; i++, sg = scatterwalk_sg_next(sg))
nbytes -= sg->length;
return i;
@@ -628,98 +628,98 @@
int len = 0;
pstat = &_qcrypto_stat;
- len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
+ len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm crypto accelerator %d Statistics:\n",
id + 1);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK AES CIPHER encryption : %d\n",
pstat->ablk_cipher_aes_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK AES CIPHER decryption : %d\n",
pstat->ablk_cipher_aes_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK DES CIPHER encryption : %d\n",
pstat->ablk_cipher_des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK DES CIPHER decryption : %d\n",
pstat->ablk_cipher_des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK 3DES CIPHER encryption : %d\n",
pstat->ablk_cipher_3des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK 3DES CIPHER decryption : %d\n",
pstat->ablk_cipher_3des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK CIPHER operation success: %d\n",
pstat->ablk_cipher_op_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" ABLK CIPHER operation fail : %d\n",
pstat->ablk_cipher_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-AES encryption : %d\n",
pstat->aead_sha1_aes_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-AES decryption : %d\n",
pstat->aead_sha1_aes_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-DES encryption : %d\n",
pstat->aead_sha1_des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-DES decryption : %d\n",
pstat->aead_sha1_des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-3DES encryption : %d\n",
pstat->aead_sha1_3des_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD SHA1-3DES decryption : %d\n",
pstat->aead_sha1_3des_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD CCM-AES encryption : %d\n",
pstat->aead_ccm_aes_enc);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD CCM-AES decryption : %d\n",
pstat->aead_ccm_aes_dec);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation fail : %d\n",
pstat->aead_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD bad message : %d\n",
pstat->aead_bad_msg);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA1 digest : %d\n",
pstat->sha1_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA256 digest : %d\n",
pstat->sha256_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA operation fail : %d\n",
pstat->sha_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA operation success : %d\n",
pstat->sha_op_success);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA1 HMAC digest : %d\n",
pstat->sha1_hmac_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA256 HMAC digest : %d\n",
pstat->sha256_hmac_digest);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA HMAC operation fail : %d\n",
pstat->sha_hmac_op_fail);
- len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA HMAC operation success : %d\n",
pstat->sha_hmac_op_success);
return len;
@@ -1423,8 +1423,20 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
+
+ if ((MAX_ALIGN_SIZE*2 > ULONG_MAX - req->assoclen) ||
+ ((MAX_ALIGN_SIZE*2 + req->assoclen) >
+ ULONG_MAX - qreq.authsize) ||
+ ((MAX_ALIGN_SIZE*2 + req->assoclen +
+ qreq.authsize) >
+ ULONG_MAX - req->cryptlen)) {
+ pr_err("Integer overflow on aead req length.\n");
+ return -EINVAL;
+ }
+
rctx->data = kzalloc((req->cryptlen + qreq.assoclen +
- qreq.authsize + 64*2), GFP_ATOMIC);
+ qreq.authsize + MAX_ALIGN_SIZE*2),
+ GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld\n",
PTR_ERR(rctx->data));
@@ -1486,6 +1498,16 @@
* include assoicated data, ciphering data stream,
* generated MAC, and CCM padding.
*/
+ if ((MAX_ALIGN_SIZE * 2 > ULONG_MAX - req->assoclen) ||
+ ((MAX_ALIGN_SIZE * 2 + req->assoclen) >
+ ULONG_MAX - qreq.ivsize) ||
+ ((MAX_ALIGN_SIZE * 2 + req->assoclen
+ + qreq.ivsize)
+ > ULONG_MAX - req->cryptlen)) {
+ pr_err("Integer overflow on aead req length.\n");
+ return -EINVAL;
+ }
+
rctx->data = kzalloc(
(req->cryptlen +
req->assoclen +
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index efa3ad0..c79b3a3 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -438,7 +438,7 @@
static inline int __msm_destroy_session_streams(void *d1, void *d2)
{
struct msm_stream *stream = d1;
-
+ pr_err("%s: Destroyed here due to list is not empty\n", __func__);
INIT_LIST_HEAD(&stream->queued_list);
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 154ee87..7520ce5 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -100,6 +100,24 @@
return ret;
}
+static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev)
+{
+ unsigned long flags;
+ struct msm_get_bufs *bufs, *save;
+
+ spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
+ if (!list_empty(&buf_mngr_dev->buf_qhead)) {
+ list_for_each_entry_safe(bufs,
+ save, &buf_mngr_dev->buf_qhead, entry) {
+ pr_err("%s: Delete invalid bufs =%x\n", __func__,
+ (unsigned int)bufs);
+ list_del_init(&bufs->entry);
+ kfree(bufs);
+ }
+ }
+ spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
+}
+
static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
@@ -123,6 +141,9 @@
case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp);
break;
+ case MSM_SD_SHUTDOWN:
+ msm_buf_mngr_sd_shutdown(buf_mngr_dev);
+ break;
default:
return -ENOIOCTLCMD;
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 8fa8f8d..0fbaeca 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -251,6 +251,7 @@
unsigned long flags;
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
+ struct vb2_buffer *vb2_buf = NULL;
int rc = 0;
stream = msm_get_stream(session_id, stream_id);
@@ -258,6 +259,18 @@
return 0;
spin_lock_irqsave(&stream->stream_lock, flags);
if (vb) {
+ list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+ vb2_buf = &(msm_vb2->vb2_buf);
+ if (vb2_buf == vb)
+ break;
+ }
+ if (vb2_buf != vb) {
+ pr_err("%s:%d VB buffer is INVALID vb=%x, ses_id=%d, str_id=%d\n",
+ __func__, __LINE__, (unsigned int)vb,
+ session_id, stream_id);
+ rc = -EINVAL;
+ goto out;
+ }
msm_vb2 =
container_of(vb, struct msm_vb2_buffer, vb2_buf);
/* put buf before buf done */
@@ -268,10 +281,11 @@
} else
rc = -EINVAL;
} else {
- pr_err("%s: VB buffer is null\n", __func__);
+ pr_err("%s:%d VB buffer is NULL for ses_id=%d, str_id=%d\n",
+ __func__, __LINE__, session_id, stream_id);
rc = -EINVAL;
}
-
+out:
spin_unlock_irqrestore(&stream->stream_lock, flags);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 2124b13..69f0a3d 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -57,14 +57,12 @@
};
struct msm_cpp_timer_t {
- uint8_t used;
+ atomic_t used;
struct msm_cpp_timer_data_t data;
struct timer_list cpp_timer;
};
-struct msm_cpp_timer_t cpp_timers[2];
-static int del_timer_idx;
-static int set_timer_idx;
+struct msm_cpp_timer_t cpp_timer;
/* dump the frame command before writing to the hardware */
#define MSM_CPP_DUMP_FRM_CMD 0
@@ -596,24 +594,20 @@
if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
CPP_DBG("Frame done!!\n");
/* delete CPP timer */
- CPP_DBG("delete timer %d.\n",
- del_timer_idx);
- timer = &cpp_timers[del_timer_idx];
+ CPP_DBG("delete timer.\n");
+ timer = &cpp_timer;
+ atomic_set(&timer->used, 0);
del_timer(&timer->cpp_timer);
- timer->used = 0;
timer->data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
msm_cpp_notify_frame_done(cpp_dev);
} else if (msg_id ==
MSM_CPP_MSG_ID_FRAME_NACK) {
pr_err("NACK error from hw!!\n");
- CPP_DBG("delete timer %d.\n",
- del_timer_idx);
- timer = &cpp_timers[del_timer_idx];
+ CPP_DBG("delete timer.\n");
+ timer = &cpp_timer;
+ atomic_set(&timer->used, 0);
del_timer(&timer->cpp_timer);
- timer->used = 0;
timer->data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
msm_cpp_notify_frame_done(cpp_dev);
}
i += cmd_len + 2;
@@ -1077,97 +1071,62 @@
{
int ret;
uint32_t i = 0;
- struct msm_cpp_frame_info_t *this_frame =
- cpp_timers[del_timer_idx].data.processed_frame;
- struct msm_cpp_frame_info_t *second_frame = NULL;
+ struct msm_cpp_frame_info_t *this_frame = NULL;
- pr_err("cpp_timer_callback called idx:%d. (jiffies=%lu)\n",
- del_timer_idx, jiffies);
- if (!work || !this_frame) {
- pr_err("Invalid work:%p, this_frame:%p, del_idx:%d\n",
- work, this_frame, del_timer_idx);
+ pr_err("cpp_timer_callback called. (jiffies=%lu)\n",
+ jiffies);
+ if (!work) {
+ pr_err("Invalid work:%p\n", work);
return;
}
- pr_err("fatal: cpp_timer expired for identity=0x%x, frame_id=%03d",
- this_frame->identity, this_frame->frame_id);
- cpp_timers[del_timer_idx].used = 0;
- cpp_timers[del_timer_idx].data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
-
- if (cpp_timers[del_timer_idx].used == 1) {
- pr_err("deleting cpp_timer %d.\n", del_timer_idx);
- del_timer(&cpp_timers[del_timer_idx].cpp_timer);
- cpp_timers[del_timer_idx].used = 0;
- second_frame = cpp_timers[del_timer_idx].data.processed_frame;
- cpp_timers[del_timer_idx].data.processed_frame = NULL;
- del_timer_idx = 1 - del_timer_idx;
+ if (!atomic_read(&cpp_timer.used)) {
+ pr_err("Delayed trigger, IRQ serviced\n");
+ return;
}
- disable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
+ disable_irq(cpp_timer.data.cpp_dev->irq->start);
pr_err("Reloading firmware\n");
- cpp_load_fw(cpp_timers[del_timer_idx].data.cpp_dev, NULL);
+ cpp_load_fw(cpp_timer.data.cpp_dev, NULL);
pr_err("Firmware loading done\n");
- enable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
- msm_camera_io_w_mb(0x8, cpp_timers[del_timer_idx].data.cpp_dev->base +
+ enable_irq(cpp_timer.data.cpp_dev->irq->start);
+ msm_camera_io_w_mb(0x8, cpp_timer.data.cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_MASK);
msm_camera_io_w_mb(0xFFFF,
- cpp_timers[del_timer_idx].data.cpp_dev->base +
+ cpp_timer.data.cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_CLR);
- cpp_timers[set_timer_idx].data.processed_frame = this_frame;
- cpp_timers[set_timer_idx].used = 1;
- pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
- setup_timer(&cpp_timers[set_timer_idx].cpp_timer, cpp_timer_callback,
- (unsigned long)&cpp_timers[0]);
+ if (!atomic_read(&cpp_timer.used)) {
+ pr_err("Delayed trigger, IRQ serviced\n");
+ return;
+ }
+
+ this_frame = cpp_timer.data.processed_frame;
+ pr_err("ReInstalling cpp_timer\n");
+ setup_timer(&cpp_timer.cpp_timer, cpp_timer_callback,
+ (unsigned long)&cpp_timer);
pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
- ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ ret = mod_timer(&cpp_timer.cpp_timer,
jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
if (ret)
pr_err("error in mod_timer\n");
- set_timer_idx = 1 - set_timer_idx;
- pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
+ pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n",
this_frame->identity, this_frame->frame_id);
- msm_cpp_write(0x6, cpp_timers[set_timer_idx].data.cpp_dev->base);
+ msm_cpp_write(0x6, cpp_timer.data.cpp_dev->base);
msm_cpp_dump_frame_cmd(this_frame->cpp_cmd_msg,
this_frame->msg_len);
for (i = 0; i < this_frame->msg_len; i++)
msm_cpp_write(this_frame->cpp_cmd_msg[i],
- cpp_timers[set_timer_idx].data.cpp_dev->base);
-
-
- if (second_frame != NULL) {
- cpp_timers[set_timer_idx].data.processed_frame = second_frame;
- cpp_timers[set_timer_idx].used = 1;
- pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
- setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
- cpp_timer_callback, (unsigned long)&cpp_timers[0]);
- pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
- CPP_CMD_TIMEOUT_MS, jiffies);
- ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
- jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
- if (ret)
- pr_err("error in mod_timer\n");
-
- set_timer_idx = 1 - set_timer_idx;
- pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
- second_frame->identity, second_frame->frame_id);
- msm_cpp_write(0x6,
- cpp_timers[set_timer_idx].data.cpp_dev->base);
- msm_cpp_dump_frame_cmd(second_frame->cpp_cmd_msg,
- second_frame->msg_len);
- for (i = 0; i < second_frame->msg_len; i++)
- msm_cpp_write(second_frame->cpp_cmd_msg[i],
- cpp_timers[set_timer_idx].data.cpp_dev->base);
- }
+ cpp_timer.data.cpp_dev->base);
+ return;
}
void cpp_timer_callback(unsigned long data)
{
struct msm_cpp_work_t *work =
- cpp_timers[set_timer_idx].data.cpp_dev->work;
- queue_work(cpp_timers[set_timer_idx].data.cpp_dev->timer_wq,
+ cpp_timer.data.cpp_dev->work;
+ queue_work(cpp_timer.data.cpp_dev->timer_wq,
(struct work_struct *)work);
}
@@ -1184,21 +1143,19 @@
msm_enqueue(&cpp_dev->processing_q,
&frame_qcmd->list_frame);
- cpp_timers[set_timer_idx].data.processed_frame = process_frame;
- cpp_timers[set_timer_idx].used = 1;
+ cpp_timer.data.processed_frame = process_frame;
+ atomic_set(&cpp_timer.used, 1);
/* install timer for cpp timeout */
- CPP_DBG("Installing cpp_timer %d\n", set_timer_idx);
- setup_timer(&cpp_timers[set_timer_idx].cpp_timer,
- cpp_timer_callback, (unsigned long)&cpp_timers[0]);
+ CPP_DBG("Installing cpp_timer\n");
+ setup_timer(&cpp_timer.cpp_timer,
+ cpp_timer_callback, (unsigned long)&cpp_timer);
CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
- ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
+ ret = mod_timer(&cpp_timer.cpp_timer,
jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
if (ret)
pr_err("error in mod_timer\n");
- set_timer_idx = 1 - set_timer_idx;
-
msm_cpp_write(0x6, cpp_dev->base);
msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
process_frame->msg_len);
@@ -1285,8 +1242,8 @@
in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
&new_frame->input_buffer_info,
- ((new_frame->identity >> 16) & 0xFFFF),
- (new_frame->identity & 0xFFFF), &in_fd);
+ ((new_frame->input_buffer_info.identity >> 16) & 0xFFFF),
+ (new_frame->input_buffer_info.identity & 0xFFFF), &in_fd);
if (!in_phyaddr) {
pr_err("error gettting input physical address\n");
rc = -EINVAL;
@@ -1891,10 +1848,8 @@
INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
cpp_dev->cpp_open_cnt = 0;
cpp_dev->is_firmware_loaded = 0;
- cpp_timers[0].data.cpp_dev = cpp_dev;
- cpp_timers[1].data.cpp_dev = cpp_dev;
- cpp_timers[0].used = 0;
- cpp_timers[1].used = 0;
+ cpp_timer.data.cpp_dev = cpp_dev;
+ atomic_set(&cpp_timer.used, 0);
cpp_dev->fw_name_bin = NULL;
return rc;
ERROR3:
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 9f3a81c..a4d7f15 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -53,9 +53,11 @@
const char *flash_trigger_name[MAX_LED_TRIGGERS];
struct led_trigger *flash_trigger[MAX_LED_TRIGGERS];
uint32_t flash_op_current[MAX_LED_TRIGGERS];
+ uint32_t flash_max_current[MAX_LED_TRIGGERS];
const char *torch_trigger_name;
struct led_trigger *torch_trigger;
uint32_t torch_op_current;
+ uint32_t torch_max_current;
void *data;
uint32_t num_sources;
enum msm_camera_device_type_t flash_device_type;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 01d2c13..699142a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -51,6 +51,7 @@
int rc = 0;
struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data;
uint32_t i;
+ uint32_t curr_l, max_curr_l;
CDBG("called led_state %d\n", cfg->cfgtype);
if (!fctrl) {
@@ -68,18 +69,38 @@
break;
case MSM_CAMERA_LED_LOW:
- if (fctrl->torch_trigger)
+ if (fctrl->torch_trigger) {
+ max_curr_l = fctrl->torch_max_current;
+ if (cfg->led_current > 0 &&
+ cfg->led_current < max_curr_l) {
+ curr_l = cfg->led_current;
+ } else {
+ curr_l = fctrl->torch_op_current;
+ pr_err("LED current clamped to %d\n",
+ curr_l);
+ }
led_trigger_event(fctrl->torch_trigger,
- fctrl->torch_op_current);
+ curr_l);
+ }
break;
case MSM_CAMERA_LED_HIGH:
if (fctrl->torch_trigger)
led_trigger_event(fctrl->torch_trigger, 0);
for (i = 0; i < fctrl->num_sources; i++)
- if (fctrl->flash_trigger[i])
+ if (fctrl->flash_trigger[i]) {
+ max_curr_l = fctrl->flash_max_current[i];
+ if (cfg->led_current > 0 &&
+ cfg->led_current < max_curr_l) {
+ curr_l = cfg->led_current;
+ } else {
+ curr_l = fctrl->flash_op_current[i];
+ pr_err("LED current clamped to %d\n",
+ curr_l);
+ }
led_trigger_event(fctrl->flash_trigger[i],
- fctrl->flash_op_current[i]);
+ curr_l);
+ }
break;
case MSM_CAMERA_LED_INIT:
@@ -116,7 +137,7 @@
static int32_t msm_led_trigger_probe(struct platform_device *pdev)
{
- int32_t rc = 0, i = 0;
+ int32_t rc = 0, rc_1 = 0, i = 0;
struct device_node *of_node = pdev->dev.of_node;
struct device_node *flash_src_node = NULL;
uint32_t count = 0;
@@ -181,7 +202,10 @@
rc = of_property_read_u32(flash_src_node,
"qcom,current",
&fctrl.flash_op_current[i]);
- if (rc < 0) {
+ rc_1 = of_property_read_u32(flash_src_node,
+ "qcom,max-current",
+ &fctrl.flash_max_current[i]);
+ if ((rc < 0) || (rc_1 < 0)) {
pr_err("current: read failed\n");
of_node_put(flash_src_node);
continue;
@@ -229,7 +253,11 @@
rc = of_property_read_u32(flash_src_node,
"qcom,current",
&fctrl.torch_op_current);
- if (rc < 0) {
+ rc_1 = of_property_read_u32(flash_src_node,
+ "qcom,max-current",
+ &fctrl.torch_max_current);
+
+ if ((rc < 0) || (rc_1 < 0)) {
pr_err("current: read failed\n");
goto torch_failed;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c b/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
old mode 100644
new mode 100755
index 82e4b7c..9a422c0
--- a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
@@ -866,6 +866,42 @@
}
break;
}
+ case CFG_SET_SATURATION: {
+
+ break;
+ }
+ case CFG_SET_CONTRAST: {
+
+ break;
+ }
+ case CFG_SET_SHARPNESS: {
+
+ break;
+ }
+ case CFG_SET_ISO: {
+
+ break;
+ }
+ case CFG_SET_EXPOSURE_COMPENSATION: {
+
+ break;
+ }
+ case CFG_SET_EFFECT: {
+
+ break;
+ }
+ case CFG_SET_ANTIBANDING: {
+
+ break;
+ }
+ case CFG_SET_BESTSHOT_MODE: {
+
+ break;
+ }
+ case CFG_SET_WHITE_BALANCE: {
+
+ break;
+ }
default:
rc = -EFAULT;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 42460fa..808c283 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -765,6 +765,7 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
+ mutex_lock(&core->sync_lock);
list_for_each_entry(inst, &core->instances,
list) {
mutex_lock(&inst->lock);
@@ -786,6 +787,7 @@
msm_vidc_queue_v4l2_event(inst,
V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
+ mutex_unlock(&core->sync_lock);
} else {
dprintk(VIDC_ERR,
"Got SYS_ERR but unable to identify core");
@@ -813,6 +815,7 @@
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
+ mutex_lock(&core->sync_lock);
list_for_each_entry(inst, &core->instances, list) {
if (inst) {
msm_vidc_queue_v4l2_event(inst,
@@ -834,6 +837,7 @@
mutex_unlock(&inst->lock);
}
}
+ mutex_unlock(&core->sync_lock);
}
static void handle_session_close(enum command_response cmd, void *data)
@@ -3158,10 +3162,12 @@
int num_mbs_per_sec = 0;
if (inst->state == MSM_VIDC_OPEN_DONE) {
+ mutex_lock(&inst->core->sync_lock);
num_mbs_per_sec = msm_comm_get_load(inst->core,
MSM_VIDC_DECODER);
num_mbs_per_sec += msm_comm_get_load(inst->core,
MSM_VIDC_ENCODER);
+ mutex_unlock(&inst->core->sync_lock);
if (num_mbs_per_sec > inst->core->resources.max_load) {
dprintk(VIDC_ERR,
"H/w is overloaded. needed: %d max: %d\n",
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 31d03b6..9e25e42 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -3476,13 +3476,26 @@
radio->riva_data_req.cmd_params.start_addr = ctrl->value;
break;
case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
- radio->riva_data_req.cmd_params.length = ctrl->value;
+ if ((ctrl->value > 0) &&
+ (ctrl->value <= MAX_RIVA_PEEK_RSP_SIZE)) {
+ radio->riva_data_req.cmd_params.length = ctrl->value;
+ } else {
+ FMDERR("Length %d is more than the buffer size %d\n",
+ ctrl->value, MAX_RIVA_PEEK_RSP_SIZE);
+ retval = -EINVAL;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
- memcpy(radio->riva_data_req.data, (void *)ctrl->value,
- radio->riva_data_req.cmd_params.length);
- radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
- retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
+ if (radio->riva_data_req.cmd_params.length <= MAX_RIVA_PEEK_RSP_SIZE) {
+ memcpy(radio->riva_data_req.data, (void *)ctrl->value,
+ radio->riva_data_req.cmd_params.length);
+ radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
+ retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
+ } else {
+ FMDERR("Can not copy into driver's buffer. Length %d is more than"
+ "the buffer size %d\n", ctrl->value, MAX_RIVA_PEEK_RSP_SIZE);
+ retval = -EINVAL;
+ }
break;
case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
radio->ssbi_data_accs.start_addr = ctrl->value;
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 5952e52..6b9f2b3 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -3051,7 +3051,7 @@
int retval = 0;
int bytes_to_copy;
int bytes_copied = 0;
- int bytes_left = 0;
+ __u32 bytes_left = 0;
int chunk_index = 0;
char tx_data[XFR_REG_NUM];
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
@@ -3066,15 +3066,15 @@
chunk_index = 0;
bytes_copied = 0;
- bytes_left = min((int)(ctrl->controls[0]).size,
- MAX_PS_LENGTH);
+ bytes_left = min((ctrl->controls[0]).size,
+ (__u32)MAX_PS_LENGTH);
data = (ctrl->controls[0]).string;
/* send payload to FM hardware */
while (bytes_left) {
chunk_index++;
FMDBG("chunk is %d", chunk_index);
- bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+ bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
/*Clear the tx_data */
memset(tx_data, 0, XFR_REG_NUM);
if (copy_from_user(tx_data,
@@ -3116,12 +3116,12 @@
FMDBG("Passed RT String : %s\n",
(ctrl->controls[0]).string);
bytes_left =
- min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+ min((ctrl->controls[0]).size, (__u32)MAX_RT_LENGTH);
data = (ctrl->controls[0]).string;
/* send payload to FM hardware */
while (bytes_left) {
chunk_index++;
- bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+ bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
memset(tx_data, 0, XFR_REG_NUM);
if (copy_from_user(tx_data,
data + bytes_copied, bytes_to_copy))
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index a30607c..308abeb 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -494,6 +494,11 @@
}
spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
flags);
+
+ if (ptr_svc == NULL) {
+ pr_err("Listener Svc %d does not exist\n", lstnr);
+ return -EINVAL;
+ }
if (ptr_svc->svc.listener_id != lstnr) {
pr_warning("Service requested for does on exist\n");
return -ERESTARTSYS;
@@ -860,6 +865,10 @@
req_ptr, send_svc_ireq_ptr);
return -EINVAL;
}
+ if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
+ pr_err("Invalid req/resp buffer, exiting\n");
+ return -EINVAL;
+ }
send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
send_svc_ireq_ptr->key_type =
((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 0147e66..6f98dc7 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -385,26 +385,27 @@
static int __devinit smsc_hub_probe(struct platform_device *pdev)
{
int ret = 0;
- const struct smsc_hub_platform_data *pdata;
+ struct smsc_hub_platform_data *pdata;
struct device_node *node = pdev->dev.of_node;
struct i2c_adapter *i2c_adap;
struct i2c_board_info i2c_info;
+ struct of_dev_auxdata *hsic_host_auxdata;
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
- pdev->dev.platform_data = msm_hub_dt_to_pdata(pdev);
- if (IS_ERR(pdev->dev.platform_data))
- return PTR_ERR(pdev->dev.platform_data);
-
- dev_set_name(&pdev->dev, smsc_hub_driver.driver.name);
+ hsic_host_auxdata = dev_get_platdata(&pdev->dev);
+ pdata = msm_hub_dt_to_pdata(pdev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ } else {
+ pdata = pdev->dev.platform_data;
}
- if (!pdev->dev.platform_data) {
+ if (!pdata) {
dev_err(&pdev->dev, "No platform data\n");
return -ENODEV;
}
- pdata = pdev->dev.platform_data;
if (!pdata->hub_reset)
return -EINVAL;
@@ -413,7 +414,7 @@
return -ENOMEM;
smsc_hub->dev = &pdev->dev;
- smsc_hub->pdata = pdev->dev.platform_data;
+ smsc_hub->pdata = pdata;
smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
ret = PTR_ERR(smsc_hub->hub_vbus_reg);
@@ -494,7 +495,7 @@
i2c_put_adapter(i2c_adap);
i2c_add_fail:
- ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+ ret = of_platform_populate(node, NULL, hsic_host_auxdata, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
goto uninit_gpio;
@@ -523,7 +524,7 @@
{
const struct smsc_hub_platform_data *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = smsc_hub->pdata;
if (smsc_hub->client) {
i2c_unregister_device(smsc_hub->client);
smsc_hub->client = NULL;
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 10dea37..bd4ecf3 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -520,6 +520,7 @@
*/
regd = ath_world_regdomain(reg);
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy->country_ie_pref = NL80211_COUNTRY_IE_FOLLOW_POWER;
} else {
/*
* This gets applied in the case of the absence of CRDA,
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 33d11b1..13eeb78 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -142,6 +142,7 @@
#define MSM_PRONTO_PLL_BASE 0xfb21b1c0
#define PRONTO_PLL_STATUS_OFFSET 0x1c
+#define MSM_PRONTO_TXP_STATUS 0xfb08040c
#define MSM_PRONTO_TXP_PHY_ABORT 0xfb080488
#define MSM_PRONTO_BRDG_ERR_SRC 0xfb080fb0
@@ -339,6 +340,7 @@
void __iomem *pronto_ccpu_base;
void __iomem *pronto_saw2_base;
void __iomem *pronto_pll_base;
+ void __iomem *wlan_tx_status;
void __iomem *wlan_tx_phy_aborts;
void __iomem *wlan_brdg_err_source;
void __iomem *fiq_reg;
@@ -515,6 +517,10 @@
pr_info_ratelimited("%s: PRONTO_PMU_SOFT_RESET %08x\n",
__func__, reg);
+ reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_PMU_COM_GDSCR %08x\n",
@@ -563,10 +569,6 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
- reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
- reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
-
reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_PLL_STATUS %08x\n", __func__, reg);
@@ -664,6 +666,8 @@
reg = readl_relaxed(penv->wlan_brdg_err_source);
pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+ reg = readl_relaxed(penv->wlan_tx_status);
+ pr_info_ratelimited("%s: WLAN_TX_STATUS %08x\n", __func__, reg);
}
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
@@ -1965,7 +1969,12 @@
pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__);
goto fail_ioremap8;
}
-
+ penv->wlan_tx_status = ioremap(MSM_PRONTO_TXP_STATUS, SZ_8);
+ if (!penv->wlan_tx_status) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wlan TX STATUS failed\n", __func__);
+ goto fail_ioremap9;
+ }
}
penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
if (IS_ERR(penv->adc_tm_dev)) {
@@ -1991,6 +2000,9 @@
fail_pil:
if (penv->riva_ccu_base)
iounmap(penv->riva_ccu_base);
+ if (penv->wlan_tx_status)
+ iounmap(penv->wlan_tx_status);
+fail_ioremap9:
if (penv->wlan_brdg_err_source)
iounmap(penv->wlan_brdg_err_source);
fail_ioremap8:
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 5f0ba94..9ccb993 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -327,10 +327,9 @@
for(; lookup->compatible != NULL; lookup++) {
if (!of_device_is_compatible(np, lookup->compatible))
continue;
- if (of_address_to_resource(np, 0, &res))
- continue;
- if (res.start != lookup->phys_addr)
- continue;
+ if (!of_address_to_resource(np, 0, &res))
+ if (res.start != lookup->phys_addr)
+ continue;
pr_debug("%s: devname=%s\n", np->full_name, lookup->name);
return lookup;
}
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index b918110..4688514 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -152,6 +152,7 @@
POWER_SUPPLY_ATTR(current_max),
POWER_SUPPLY_ATTR(input_current_max),
POWER_SUPPLY_ATTR(input_current_trim),
+ POWER_SUPPLY_ATTR(input_current_settled),
POWER_SUPPLY_ATTR(current_now),
POWER_SUPPLY_ATTR(current_avg),
POWER_SUPPLY_ATTR(power_now),
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 9727787..8c03bbd 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -765,10 +765,22 @@
return get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL;
}
+#define BAT_PRES_BIT BIT(7)
static bool is_battery_present(struct qpnp_bms_chip *chip)
{
union power_supply_propval ret = {0,};
+ int rc;
+ u8 batt_pres;
+ /* first try to use the batt_pres register if given */
+ if (chip->batt_pres_addr) {
+ rc = qpnp_read_wrapper(chip, &batt_pres,
+ chip->batt_pres_addr, 1);
+ if (!rc && (batt_pres & BAT_PRES_BIT))
+ return true;
+ else
+ return false;
+ }
if (chip->batt_psy == NULL)
chip->batt_psy = power_supply_get_by_name("battery");
if (chip->batt_psy) {
@@ -2254,6 +2266,7 @@
(uint16_t)ocv_raw);
}
+#define BAD_SOC_THRESH -10
static int calculate_raw_soc(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
struct soc_params *params,
@@ -2270,7 +2283,7 @@
soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
(params->fcc_uah - params->uuc_uah));
- if (chip->first_time_calc_soc && soc < 0) {
+ if (chip->first_time_calc_soc && soc > BAD_SOC_THRESH && soc < 0) {
/*
* first time calcualtion and the pon ocv is too low resulting
* in a bad soc. Adjust ocv to get 0 soc
@@ -2295,7 +2308,7 @@
if (soc > 100)
soc = 100;
- if (soc < 0) {
+ if (soc > BAD_SOC_THRESH && soc < 0) {
pr_debug("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
remaining_usable_charge_uah,
params->ocv_charge_uah,
@@ -3488,7 +3501,7 @@
|| shutdown_soc_out_of_limit) {
chip->battery_removed = true;
chip->shutdown_soc_invalid = true;
- chip->shutdown_iavg_ma = 0;
+ chip->shutdown_iavg_ma = MIN_IAVG_MA;
pr_debug("Ignoring shutdown SoC: invalid = %d, offmode = %d, out_of_limit = %d\n",
invalid_stored_soc, offmode_battery_replaced,
shutdown_soc_out_of_limit);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a627ec2..5c50791 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -101,6 +101,7 @@
#define BUCK_VCHG_OV 0x77
#define BUCK_TEST_SMBC_MODES 0xE6
#define BUCK_CTRL_TRIM1 0xF1
+#define BUCK_CTRL_TRIM3 0xF3
#define SEC_ACCESS 0xD0
#define BAT_IF_VREF_BAT_THM_CTRL 0x4A
#define BAT_IF_BPD_CTRL 0x48
@@ -310,6 +311,9 @@
bool btc_disabled;
bool use_default_batt_values;
bool duty_cycle_100p;
+ bool ibat_calibration_enabled;
+ bool aicl_settled;
+ bool use_external_rsense;
unsigned int bpd_detection;
unsigned int max_bat_chg_current;
unsigned int warm_bat_chg_ma;
@@ -362,6 +366,7 @@
bool batfet_ext_en;
struct work_struct batfet_lcl_work;
struct qpnp_vadc_chip *vadc_dev;
+ struct qpnp_iadc_chip *iadc_dev;
struct qpnp_adc_tm_chip *adc_tm_dev;
struct mutex jeita_configure_lock;
spinlock_t usbin_health_monitor_lock;
@@ -421,6 +426,16 @@
return -EINVAL;
}
+static bool
+is_within_range(int value, int left, int right)
+{
+ if (left >= right && left >= value && value >= right)
+ return 1;
+ if (left <= right && left <= value && value <= right)
+ return 1;
+ return 0;
+}
+
static int
qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
u16 base, int count)
@@ -623,6 +638,22 @@
return (usbin_valid_rt_sts & USB_VALID_BIT) ? 1 : 0;
}
+static bool
+qpnp_chg_is_ibat_loop_active(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 buck_sts;
+
+ rc = qpnp_chg_read(chip, &buck_sts,
+ INT_RT_STS(chip->buck_base), 1);
+ if (rc) {
+ pr_err("failed to read buck RT status rc=%d\n", rc);
+ return 0;
+ }
+
+ return !!(buck_sts & IBAT_LOOP_IRQ);
+}
+
#define USB_VALID_MASK 0xC0
#define USB_COARSE_DET 0x10
#define USB_VALID_UVP_VALUE 0x00
@@ -1404,10 +1435,10 @@
(chip->usb_valid_check_ovp)) {
usbin_health =
qpnp_chg_check_usbin_health(chip);
- if (chip->usbin_health != usbin_health) {
+ if ((chip->usbin_health != usbin_health)
+ && (usbin_health == USBIN_OVP)) {
chip->usbin_health = usbin_health;
- if (usbin_health == USBIN_OVP)
- psy_health_sts =
+ psy_health_sts =
POWER_SUPPLY_HEALTH_OVERVOLTAGE;
power_supply_set_health_state(
chip->usb_psy,
@@ -1422,6 +1453,7 @@
}
qpnp_chg_usb_suspend_enable(chip, 1);
chip->prev_usb_max_ma = -EINVAL;
+ chip->aicl_settled = false;
} else {
/* when OVP clamped usbin, and then decrease
* the charger voltage to lower than the OVP
@@ -1432,10 +1464,10 @@
(chip->usb_valid_check_ovp)) {
usbin_health =
qpnp_chg_check_usbin_health(chip);
- if (chip->usbin_health != usbin_health) {
+ if ((chip->usbin_health != usbin_health)
+ && (usbin_health == USBIN_OK)) {
chip->usbin_health = usbin_health;
- if (usbin_health == USBIN_OK)
- psy_health_sts =
+ psy_health_sts =
POWER_SUPPLY_HEALTH_GOOD;
power_supply_set_health_state(
chip->usb_psy,
@@ -1656,6 +1688,7 @@
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
case POWER_SUPPLY_PROP_COOL_TEMP:
case POWER_SUPPLY_PROP_WARM_TEMP:
@@ -1769,6 +1802,7 @@
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
@@ -2243,6 +2277,9 @@
case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
val->intval = qpnp_chg_iusb_trim_get(chip);
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+ val->intval = chip->aicl_settled;
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
val->intval = qpnp_chg_vinmin_get(chip) * 1000;
break;
@@ -2349,6 +2386,24 @@
QPNP_CHG_I_MASK, temp, 1);
}
+static int
+qpnp_chg_ibatmax_get(struct qpnp_chg_chip *chip, int *chg_current)
+{
+ int rc;
+ u8 temp;
+
+ *chg_current = 0;
+ rc = qpnp_chg_read(chip, &temp, chip->chgr_base + CHGR_IBAT_MAX, 1);
+ if (rc) {
+ pr_err("failed read ibat_max rc=%d\n", rc);
+ return rc;
+ }
+
+ *chg_current = ((temp & QPNP_CHG_I_MASK) * QPNP_CHG_I_STEP_MA);
+
+ return 0;
+}
+
#define QPNP_CHG_TCHG_MASK 0x7F
#define QPNP_CHG_TCHG_MIN 4
#define QPNP_CHG_TCHG_MAX 512
@@ -2383,6 +2438,155 @@
chip->chgr_base + CHGR_VDD_SAFE, 1);
}
+#define IBAT_TRIM_TGT_MA 500
+#define IBAT_TRIM_OFFSET_MASK 0x7F
+#define IBAT_TRIM_GOOD_BIT BIT(7)
+#define IBAT_TRIM_LOW_LIM 20
+#define IBAT_TRIM_HIGH_LIM 114
+#define IBAT_TRIM_MEAN 64
+
+static void
+qpnp_chg_trim_ibat(struct qpnp_chg_chip *chip, u8 ibat_trim)
+{
+ int ibat_now_ma, ibat_diff_ma, rc;
+ struct qpnp_iadc_result i_result;
+ enum qpnp_iadc_channels iadc_channel;
+
+ iadc_channel = chip->use_external_rsense ?
+ EXTERNAL_RSENSE : INTERNAL_RSENSE;
+ rc = qpnp_iadc_read(chip->iadc_dev, iadc_channel, &i_result);
+ if (rc) {
+ pr_err("Unable to read bat rc=%d\n", rc);
+ return;
+ }
+
+ ibat_now_ma = i_result.result_ua / 1000;
+
+ if (qpnp_chg_is_ibat_loop_active(chip)) {
+ ibat_diff_ma = ibat_now_ma - IBAT_TRIM_TGT_MA;
+
+ if (abs(ibat_diff_ma) > 50) {
+ ibat_trim += (ibat_diff_ma / 20);
+ ibat_trim &= IBAT_TRIM_OFFSET_MASK;
+ /* reject new ibat_trim if it is outside limits */
+ if (!is_within_range(ibat_trim, IBAT_TRIM_LOW_LIM,
+ IBAT_TRIM_HIGH_LIM))
+ return;
+ }
+ ibat_trim |= IBAT_TRIM_GOOD_BIT;
+ rc = qpnp_chg_write(chip, &ibat_trim,
+ chip->buck_base + BUCK_CTRL_TRIM3, 1);
+ if (rc)
+ pr_err("failed to set IBAT_TRIM rc=%d\n", rc);
+
+ pr_debug("ibat_now=%dmA, itgt=%dmA, ibat_diff=%dmA, ibat_trim=%x\n",
+ ibat_now_ma, IBAT_TRIM_TGT_MA,
+ ibat_diff_ma, ibat_trim);
+ } else {
+ pr_debug("ibat loop not active - cannot calibrate ibat\n");
+ }
+}
+
+static int
+qpnp_chg_input_current_settled(struct qpnp_chg_chip *chip)
+{
+ int rc, ibat_max_ma;
+ u8 reg, chgr_sts, ibat_trim, i;
+
+ chip->aicl_settled = true;
+
+ /*
+ * Perform the ibat calibration.
+ * This is for devices which have a IBAT_TRIM error
+ * which can show IBAT_MAX out of spec.
+ */
+ if (!chip->ibat_calibration_enabled)
+ return 0;
+
+ if (chip->type != SMBB)
+ return 0;
+
+ rc = qpnp_chg_read(chip, ®,
+ chip->buck_base + BUCK_CTRL_TRIM3, 1);
+ if (rc) {
+ pr_err("failed to read BUCK_CTRL_TRIM3 rc=%d\n", rc);
+ return rc;
+ }
+ if (reg & IBAT_TRIM_GOOD_BIT) {
+ pr_debug("IBAT_TRIM_GOOD bit already set. Quitting!\n");
+ return 0;
+ }
+ ibat_trim = reg & IBAT_TRIM_OFFSET_MASK;
+
+ if (!is_within_range(ibat_trim, IBAT_TRIM_LOW_LIM,
+ IBAT_TRIM_HIGH_LIM)) {
+ pr_debug("Improper ibat_trim value=%x setting to value=%x\n",
+ ibat_trim, IBAT_TRIM_MEAN);
+ ibat_trim = IBAT_TRIM_MEAN;
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + BUCK_CTRL_TRIM3,
+ IBAT_TRIM_OFFSET_MASK, ibat_trim, 1);
+ if (rc) {
+ pr_err("failed to set ibat_trim to %x rc=%d\n",
+ IBAT_TRIM_MEAN, rc);
+ return rc;
+ }
+ }
+
+ rc = qpnp_chg_read(chip, &chgr_sts,
+ INT_RT_STS(chip->chgr_base), 1);
+ if (rc) {
+ pr_err("failed to read interrupt sts rc=%d\n", rc);
+ return rc;
+ }
+ if (!(chgr_sts & FAST_CHG_ON_IRQ)) {
+ pr_debug("Not in fastchg\n");
+ return rc;
+ }
+
+ /* save the ibat_max to restore it later */
+ rc = qpnp_chg_ibatmax_get(chip, &ibat_max_ma);
+ if (rc) {
+ pr_debug("failed to save ibatmax rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_ibatmax_set(chip, IBAT_TRIM_TGT_MA);
+ if (rc) {
+ pr_err("failed to set ibatmax rc=%d\n", rc);
+ return rc;
+ }
+
+ for (i = 0; i < 3; i++) {
+ /*
+ * ibat settling delay - to make sure the BMS controller
+ * has sufficient time to sample ibat for the configured
+ * ibat_max
+ */
+ msleep(20);
+ if (qpnp_chg_is_ibat_loop_active(chip))
+ qpnp_chg_trim_ibat(chip, ibat_trim);
+ else
+ pr_debug("ibat loop not active\n");
+
+ /* read the adjusted ibat_trim for further adjustments */
+ rc = qpnp_chg_read(chip, &ibat_trim,
+ chip->buck_base + BUCK_CTRL_TRIM3, 1);
+ if (rc) {
+ pr_err("failed to read BUCK_CTRL_TRIM3 rc=%d\n", rc);
+ break;
+ }
+ }
+
+ /* restore IBATMAX */
+ rc = qpnp_chg_ibatmax_set(chip, ibat_max_ma);
+ if (rc)
+ pr_err("failed to restore ibatmax rc=%d\n", rc);
+
+ return rc;
+}
+
+
#define BOOST_MIN_UV 4200000
#define BOOST_MAX_UV 5500000
#define BOOST_STEP_UV 50000
@@ -3377,6 +3581,9 @@
case POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM:
qpnp_chg_iusb_trim_set(chip, val->intval);
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+ qpnp_chg_input_current_settled(chip);
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
qpnp_chg_vinmin_set(chip, val->intval / 1000);
break;
@@ -4098,6 +4305,11 @@
return rc;
}
+ /* Get the use-external-rsense property */
+ chip->use_external_rsense = of_property_read_bool(
+ chip->spmi->dev.of_node,
+ "qcom,use-external-rsense");
+
/* Get the btc-disabled property */
chip->btc_disabled = of_property_read_bool(chip->spmi->dev.of_node,
"qcom,btc-disabled");
@@ -4130,17 +4342,21 @@
of_property_read_bool(chip->spmi->dev.of_node,
"qcom,power-stage-reduced");
+ chip->ibat_calibration_enabled =
+ of_property_read_bool(chip->spmi->dev.of_node,
+ "qcom,ibat-calibration-enabled");
+
of_get_property(chip->spmi->dev.of_node, "qcom,thermal-mitigation",
&(chip->thermal_levels));
if (chip->thermal_levels > sizeof(int)) {
- chip->thermal_mitigation = kzalloc(
+ chip->thermal_mitigation = devm_kzalloc(chip->dev,
chip->thermal_levels,
GFP_KERNEL);
if (chip->thermal_mitigation == NULL) {
pr_err("thermal mitigation kzalloc() failed.\n");
- return rc;
+ return -ENOMEM;
}
chip->thermal_levels /= sizeof(int);
@@ -4165,7 +4381,8 @@
struct spmi_resource *spmi_resource;
int rc = 0;
- chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ chip = devm_kzalloc(&spmi->dev,
+ sizeof(struct qpnp_chg_chip), GFP_KERNEL);
if (chip == NULL) {
pr_err("kzalloc() failed.\n");
return -ENOMEM;
@@ -4197,7 +4414,7 @@
/* Get all device tree properties */
rc = qpnp_charger_read_dt_props(chip);
if (rc)
- goto fail_chg_enable;
+ return rc;
/*
* Check if bat_if is set in DT and make sure VADC is present
@@ -4237,6 +4454,17 @@
goto fail_chg_enable;
}
+ if (subtype == SMBB_BAT_IF_SUBTYPE) {
+ chip->iadc_dev = qpnp_get_iadc(chip->dev,
+ "chg");
+ if (IS_ERR(chip->iadc_dev)) {
+ rc = PTR_ERR(chip->iadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("iadc property missing\n");
+ goto fail_chg_enable;
+ }
+ }
+
rc = qpnp_chg_load_battery_data(chip);
if (rc)
goto fail_chg_enable;
@@ -4509,9 +4737,6 @@
fail_chg_enable:
regulator_unregister(chip->otg_vreg.rdev);
regulator_unregister(chip->boost_vreg.rdev);
- kfree(chip->thermal_mitigation);
- kfree(chip);
- dev_set_drvdata(&spmi->dev, NULL);
return rc;
}
@@ -4524,15 +4749,27 @@
qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
&chip->adc_param);
}
- cancel_work_sync(&chip->adc_measure_work);
+
+ cancel_delayed_work_sync(&chip->aicl_check_work);
+ power_supply_unregister(&chip->dc_psy);
+ cancel_work_sync(&chip->soc_check_work);
+ cancel_delayed_work_sync(&chip->usbin_health_check);
+ cancel_delayed_work_sync(&chip->arb_stop_work);
cancel_delayed_work_sync(&chip->eoc_work);
+ cancel_work_sync(&chip->adc_disable_work);
+ cancel_work_sync(&chip->adc_measure_work);
+ power_supply_unregister(&chip->batt_psy);
+ cancel_work_sync(&chip->batfet_lcl_work);
+ cancel_work_sync(&chip->insertion_ocv_work);
+ cancel_work_sync(&chip->reduce_power_stage_work);
+ alarm_cancel(&chip->reduce_power_stage_alarm);
+
+ mutex_destroy(&chip->batfet_vreg_lock);
+ mutex_destroy(&chip->jeita_configure_lock);
regulator_unregister(chip->otg_vreg.rdev);
regulator_unregister(chip->boost_vreg.rdev);
- dev_set_drvdata(&spmi->dev, NULL);
- kfree(chip);
-
return 0;
}
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 00df613..3bf1ae0 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -38,9 +38,11 @@
#include <linux/regulator/consumer.h>
#define MAX_RAILS 5
+#define MAX_THRESHOLD 2
static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
+static uint32_t limited_max_freq = UINT_MAX;
+static uint32_t limited_min_freq;
static struct delayed_work check_temp_work;
static bool core_control_enabled;
static uint32_t cpus_offlined;
@@ -77,8 +79,10 @@
uint32_t cpu;
bool offline;
bool user_offline;
+ bool thresh_cleared;
const char *sensor_type;
- struct sensor_threshold thresh[2];
+ uint32_t sensor_id;
+ struct sensor_threshold thresh[MAX_THRESHOLD];
};
struct rail {
@@ -154,6 +158,25 @@
#define PSM_REG_MODE_FROM_ATTRIBS(attr) \
(container_of(attr, struct psm_rail, mode_attr));
+
+static int msm_thermal_cpufreq_callback(struct notifier_block *nfb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+
+ switch (event) {
+ case CPUFREQ_INCOMPATIBLE:
+ cpufreq_verify_within_limits(policy, limited_min_freq,
+ limited_max_freq);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block msm_thermal_cpufreq_notifier = {
+ .notifier_call = msm_thermal_cpufreq_callback,
+};
+
/* If freq table exists, then we can send freq request */
static int check_freq_table(void)
{
@@ -174,37 +197,26 @@
{
int cpu = 0;
int ret = 0;
- struct cpufreq_policy *policy = NULL;
if (!freq_table_get) {
ret = check_freq_table();
if (ret) {
- pr_err("%s:Fail to get freq table\n", __func__);
+ pr_err("%s:Fail to get freq table\n", KBUILD_MODNAME);
return ret;
}
}
/* If min is larger than allowed max */
- if (min != MSM_CPUFREQ_NO_LIMIT &&
- min > table[limit_idx_high].frequency)
- min = table[limit_idx_high].frequency;
+ min = min(min, table[limit_idx_high].frequency);
- for_each_possible_cpu(cpu) {
- ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
- if (ret) {
- pr_err("%s:Fail to set limits for cpu%d\n",
- __func__, cpu);
- return ret;
- }
+ limited_min_freq = min;
- if (cpu_online(cpu)) {
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
- continue;
- cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_L);
- cpufreq_cpu_put(policy);
- }
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
return ret;
}
@@ -599,27 +611,90 @@
{
int ret = 0;
- ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
- if (ret)
- return ret;
-
- limited_max_freq = max_freq;
- if (max_freq != MSM_CPUFREQ_NO_LIMIT)
+ if (max_freq != UINT_MAX)
pr_info("%s: Limiting cpu%d max frequency to %d\n",
KBUILD_MODNAME, cpu, max_freq);
else
pr_info("%s: Max frequency reset for cpu%d\n",
KBUILD_MODNAME, cpu);
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
+ }
+ put_online_cpus();
- if (cpu_online(cpu)) {
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (!policy)
- return ret;
- ret = cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_H);
- cpufreq_cpu_put(policy);
+ return ret;
+}
+
+static int set_and_activate_threshold(uint32_t sensor_id,
+ struct sensor_threshold *threshold)
+{
+ int ret = 0;
+
+ ret = sensor_set_trip(sensor_id, threshold);
+ if (ret != 0) {
+ pr_err("%s: Error in setting trip %d\n",
+ KBUILD_MODNAME, threshold->trip);
+ goto set_done;
}
+ ret = sensor_activate_trip(sensor_id, threshold, true);
+ if (ret != 0) {
+ pr_err("%s: Error in enabling trip %d\n",
+ KBUILD_MODNAME, threshold->trip);
+ goto set_done;
+ }
+
+set_done:
+ return ret;
+}
+
+static int set_threshold(uint32_t sensor_id,
+ struct sensor_threshold *threshold)
+{
+ struct tsens_device tsens_dev;
+ int i = 0, ret = 0;
+ long temp;
+
+ if ((!threshold) || check_sensor_id(sensor_id)) {
+ pr_err("%s: Invalid input\n", KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto set_threshold_exit;
+ }
+
+ tsens_dev.sensor_num = sensor_id;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (ret) {
+ pr_err("%s: Unable to read TSENS sensor %d\n",
+ KBUILD_MODNAME, tsens_dev.sensor_num);
+ goto set_threshold_exit;
+ }
+ while (i < MAX_THRESHOLD) {
+ switch (threshold[i].trip) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ if (threshold[i].temp >= temp) {
+ ret = set_and_activate_threshold(sensor_id,
+ &threshold[i]);
+ if (ret)
+ goto set_threshold_exit;
+ }
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ if (threshold[i].temp <= temp) {
+ ret = set_and_activate_threshold(sensor_id,
+ &threshold[i]);
+ if (ret)
+ goto set_threshold_exit;
+ }
+ break;
+ default:
+ break;
+ }
+ i++;
+ }
+set_threshold_exit:
return ret;
}
@@ -676,7 +751,7 @@
/* Call with core_control_mutex locked */
static int __ref update_offline_cores(int val)
{
- int cpu = 0;
+ uint32_t cpu = 0;
int ret = 0;
if (!core_control_enabled)
@@ -700,8 +775,7 @@
static __ref int do_hotplug(void *data)
{
int ret = 0;
- int cpu = 0;
- uint32_t mask = 0;
+ uint32_t cpu = 0, mask = 0;
if (!core_control_enabled)
return -EINVAL;
@@ -713,6 +787,11 @@
mutex_lock(&core_control_mutex);
for_each_possible_cpu(cpu) {
+ if (cpus[cpu].thresh_cleared) {
+ set_threshold(cpus[cpu].sensor_id,
+ cpus[cpu].thresh);
+ cpus[cpu].thresh_cleared = false;
+ }
if (cpus[cpu].offline || cpus[cpu].user_offline)
mask |= BIT(cpu);
}
@@ -835,7 +914,6 @@
static void __ref do_freq_control(long temp)
{
- int ret = 0;
int cpu = 0;
uint32_t max_freq = limited_max_freq;
@@ -855,7 +933,7 @@
limit_idx += msm_thermal_info.freq_step;
if (limit_idx >= limit_idx_high) {
limit_idx = limit_idx_high;
- max_freq = MSM_CPUFREQ_NO_LIMIT;
+ max_freq = UINT_MAX;
} else
max_freq = table[limit_idx].frequency;
}
@@ -863,17 +941,13 @@
if (max_freq == limited_max_freq)
return;
+ limited_max_freq = max_freq;
/* Update new limits */
for_each_possible_cpu(cpu) {
if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
continue;
- ret = update_cpu_max_freq(cpu, max_freq);
- if (ret)
- pr_debug(
- "%s: Unable to limit cpu%d max freq to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
+ update_cpu_max_freq(cpu, max_freq);
}
-
}
static void __ref check_temp(struct work_struct *work)
@@ -988,10 +1062,12 @@
default:
break;
}
- if (hotplug_task)
+ if (hotplug_task) {
+ cpu_node->thresh_cleared = true;
complete(&hotplug_notify_complete);
- else
+ } else {
pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+ }
return 0;
}
/* Adjust cpus offlined bit based on temperature reading. */
@@ -1005,8 +1081,7 @@
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);
+ tsens_dev.sensor_num = cpus[cpu].sensor_id;
if (tsens_get_temp(&tsens_dev, &temp)) {
pr_err("%s: Unable to read TSENS sensor %d\n",
KBUILD_MODNAME, tsens_dev.sensor_num);
@@ -1039,24 +1114,23 @@
return;
for_each_possible_cpu(cpu) {
+ cpus[cpu].cpu = (uint32_t)cpu;
+ cpus[cpu].thresh_cleared = false;
+ cpus[cpu].sensor_id =
+ sensor_get_id((char *)cpus[cpu].sensor_type);
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]);
-
+ set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh);
}
init_completion(&hotplug_notify_complete);
hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
@@ -1086,12 +1160,17 @@
cancel_delayed_work(&check_temp_work);
flush_scheduled_work();
- if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
+ if (limited_max_freq == UINT_MAX)
return;
- for_each_possible_cpu(cpu) {
- update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
+ limited_max_freq = UINT_MAX;
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
}
static int __ref set_enabled(const char *val, const struct kernel_param *kp)
@@ -1104,7 +1183,7 @@
hotplug_init();
} else
pr_info("%s: no action for enabled = %d\n",
- KBUILD_MODNAME, enabled);
+ KBUILD_MODNAME, enabled);
pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
@@ -1345,7 +1424,11 @@
return -EINVAL;
enabled = 1;
-
+ ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
+ CPUFREQ_POLICY_NOTIFIER);
+ if (ret)
+ pr_err("%s: cannot register cpufreq notifier\n",
+ KBUILD_MODNAME);
INIT_DELAYED_WORK(&check_temp_work, check_temp);
schedule_delayed_work(&check_temp_work, 0);
@@ -1659,7 +1742,7 @@
key = "qcom,freq-req";
rails[i].freq_req = of_property_read_bool(child_node, key);
if (rails[i].freq_req)
- rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
+ rails[i].min_level = 0;
else {
key = "qcom,min-level";
ret = of_property_read_u32(child_node, key,
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 8d9da6b..739696d 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -89,30 +89,21 @@
}
EXPORT_SYMBOL(sensor_get_id);
-static long get_min(struct sensor_info *sensor, long temp)
+static int __update_sensor_thresholds(struct sensor_info *sensor)
{
- long min = LONG_MIN;
- struct sensor_threshold *pos, *var;
-
- list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
- if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW)
- if (pos->temp < temp && pos->temp > min)
- min = pos->temp;
- }
-
- return min;
-}
-
-static void __update_sensor_thresholds(struct sensor_info *sensor)
-{
- long min = LONG_MIN;
- long max = LONG_MAX;
- long max_of_min = LONG_MIN;
- long min_of_max = LONG_MAX;
+ long max_of_low_thresh = LONG_MIN;
+ long min_of_high_thresh = LONG_MAX;
struct sensor_threshold *pos, *var;
enum thermal_trip_type type;
- int i;
- long curr_temp;
+ int i, ret = 0;
+
+ if (!sensor->tz->ops->set_trip_temp ||
+ !sensor->tz->ops->activate_trip_type ||
+ !sensor->tz->ops->get_trip_type ||
+ !sensor->tz->ops->get_trip_temp) {
+ ret = -ENODEV;
+ goto update_done;
+ }
for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
@@ -128,60 +119,85 @@
THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
}
- sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if (!pos->active)
+ continue;
if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) {
- if (pos->temp > max_of_min)
- max_of_min = pos->temp;
- if (pos->temp < curr_temp && pos->temp > min)
- min = pos->temp;
+ if (pos->temp > max_of_low_thresh)
+ max_of_low_thresh = pos->temp;
}
if (pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) {
- if (pos->temp < min_of_max)
- min_of_max = pos->temp;
- if (pos->temp > curr_temp && pos->temp < max)
- max = pos->temp;
+ if (pos->temp < min_of_high_thresh)
+ min_of_high_thresh = pos->temp;
}
}
- pr_debug("sensor %d: min of max: %ld max of min: %ld\n",
- sensor->sensor_id, max_of_min, min_of_max);
+ pr_debug("sensor %d: Thresholds: max of low: %ld min of high: %ld\n",
+ sensor->sensor_id, max_of_low_thresh,
+ min_of_high_thresh);
- /* If we haven't found a max and min bounding the curr_temp,
- * use the min of max and max of min instead.
- */
- if (max == LONG_MAX)
- max = min_of_max;
- if (min == LONG_MIN) {
- min = get_min(sensor, max);
- if (min == LONG_MIN)
- min = max_of_min;
+ if ((min_of_high_thresh != sensor->threshold_max) &&
+ (min_of_high_thresh != LONG_MAX)) {
+ ret = sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->max_idx, min_of_high_thresh);
+ if (ret) {
+ pr_err("sensor %d: Unable to set high threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
+ }
+ sensor->threshold_max = min_of_high_thresh;
+ }
+ ret = sensor->tz->ops->activate_trip_type(sensor->tz,
+ sensor->max_idx,
+ (min_of_high_thresh == LONG_MAX) ?
+ THERMAL_TRIP_ACTIVATION_DISABLED :
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (ret) {
+ pr_err("sensor %d: Unable to activate high threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
}
- if (sensor->tz->ops->set_trip_temp) {
- if (max != sensor->threshold_max) {
- sensor->tz->ops->set_trip_temp(sensor->tz,
- sensor->max_idx, max);
- sensor->threshold_max = max;
+ if ((max_of_low_thresh != sensor->threshold_min) &&
+ (max_of_low_thresh != LONG_MIN)) {
+ ret = sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->min_idx, max_of_low_thresh);
+ if (ret) {
+ pr_err("sensor %d: Unable to set low threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
}
- if (min != sensor->threshold_min) {
- sensor->tz->ops->set_trip_temp(sensor->tz,
- sensor->min_idx, min);
- sensor->threshold_min = min;
- }
+ sensor->threshold_min = max_of_low_thresh;
+ }
+ ret = sensor->tz->ops->activate_trip_type(sensor->tz,
+ sensor->min_idx,
+ (max_of_low_thresh == LONG_MIN) ?
+ THERMAL_TRIP_ACTIVATION_DISABLED :
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (ret) {
+ pr_err("sensor %d: Unable to activate low threshold %d",
+ sensor->sensor_id, ret);
+ goto update_done;
}
- pr_debug("sensor %d: curr_temp: %ld min: %ld max: %ld\n",
- sensor->sensor_id, curr_temp,
+ pr_debug("sensor %d: low: %ld high: %ld\n",
+ sensor->sensor_id,
sensor->threshold_min, sensor->threshold_max);
+
+update_done:
+ return ret;
}
static void sensor_update_work(struct work_struct *work)
{
struct sensor_info *sensor = container_of(work, struct sensor_info,
work);
+ int ret = 0;
mutex_lock(&sensor->lock);
- __update_sensor_thresholds(sensor);
+ ret = __update_sensor_thresholds(sensor);
+ if (ret)
+ pr_err("sensor %d: Error %d setting threshold\n",
+ sensor->sensor_id, ret);
mutex_unlock(&sensor->lock);
}
@@ -202,7 +218,7 @@
return 0;
list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
- if (pos->trip != trip)
+ if ((pos->trip != trip) || (!pos->active))
continue;
if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
(pos->temp <= tz->sensor.threshold_min) &&
@@ -210,6 +226,7 @@
((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
(pos->temp >= tz->sensor.threshold_max) &&
(pos->temp <= temp))) {
+ pos->active = 0;
pos->notify(trip, temp, pos->data);
}
}
@@ -220,6 +237,29 @@
}
EXPORT_SYMBOL(thermal_sensor_trip);
+int sensor_activate_trip(uint32_t sensor_id,
+ struct sensor_threshold *threshold, bool enable)
+{
+ struct sensor_info *sensor = get_sensor(sensor_id);
+ int ret = 0;
+
+ if (!sensor || !threshold) {
+ pr_err("Sensor %d: uninitialized data\n",
+ sensor_id);
+ ret = -ENODEV;
+ goto activate_trip_exit;
+ }
+
+ mutex_lock(&sensor->lock);
+ threshold->active = (enable) ? 1 : 0;
+ ret = __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+
+activate_trip_exit:
+ return ret;
+}
+EXPORT_SYMBOL(sensor_activate_trip);
+
int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
{
struct sensor_threshold *pos, *var;
@@ -241,8 +281,7 @@
INIT_LIST_HEAD(&threshold->list);
list_add(&threshold->list, &sensor->threshold_list);
}
-
- __update_sensor_thresholds(sensor);
+ threshold->active = 0; /* Do not allow active threshold right away */
mutex_unlock(&sensor->lock);
return 0;
@@ -254,6 +293,7 @@
{
struct sensor_threshold *pos, *var;
struct sensor_info *sensor = get_sensor(sensor_id);
+ int ret = 0;
if (!sensor)
return -ENODEV;
@@ -261,15 +301,16 @@
mutex_lock(&sensor->lock);
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
if (pos == threshold) {
+ pos->active = 0;
list_del(&pos->list);
break;
}
}
- __update_sensor_thresholds(sensor);
+ ret = __update_sensor_thresholds(sensor);
mutex_unlock(&sensor->lock);
- return 0;
+ return ret;
}
EXPORT_SYMBOL(sensor_cancel_trip);
@@ -283,36 +324,36 @@
return 0;
}
+static void get_trip_threshold(struct thermal_zone_device *tz, int trip,
+ struct sensor_threshold **threshold)
+{
+ enum thermal_trip_type type;
+
+ tz->ops->get_trip_type(tz, trip, &type);
+
+ if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+ *threshold = &tz->tz_threshold[0];
+ else if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+ *threshold = &tz->tz_threshold[1];
+ else
+ *threshold = NULL;
+}
+
int sensor_set_trip_temp(struct thermal_zone_device *tz,
int trip, long temp)
{
int ret = 0;
- enum thermal_trip_type type;
+ struct sensor_threshold *threshold = NULL;
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:
+ get_trip_threshold(tz, trip, &threshold);
+ if (threshold) {
+ threshold->temp = temp;
+ ret = sensor_set_trip(tz->sensor.sensor_id, threshold);
+ } else {
ret = tz->ops->set_trip_temp(tz, trip, temp);
- break;
}
return ret;
@@ -333,10 +374,12 @@
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;
+ tz->tz_threshold[0].notify = tz_notify_trip;
+ tz->tz_threshold[0].data = tz;
+ tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ tz->tz_threshold[1].notify = tz_notify_trip;
+ tz->tz_threshold[1].data = tz;
+ tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
list_add(&sensor->sensor_list, &sensor_info_list);
INIT_WORK(&sensor->work, sensor_update_work);
@@ -489,23 +532,40 @@
const char *buf, size_t count)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, result;
+ int trip, result = 0;
+ bool activate;
+ struct sensor_threshold *threshold = NULL;
- if (!tz->ops->activate_trip_type)
- return -EPERM;
+ if (!tz->ops->get_trip_type ||
+ !tz->ops->activate_trip_type) {
+ result = -EPERM;
+ goto trip_activate_exit;
+ }
- if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
- return -EINVAL;
-
- if (!strncmp(buf, "enabled", sizeof("enabled")))
- result = tz->ops->activate_trip_type(tz, trip,
- THERMAL_TRIP_ACTIVATION_ENABLED);
- else if (!strncmp(buf, "disabled", sizeof("disabled")))
- result = tz->ops->activate_trip_type(tz, trip,
- THERMAL_TRIP_ACTIVATION_DISABLED);
- else
+ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) {
result = -EINVAL;
+ goto trip_activate_exit;
+ }
+ if (!strcmp(buf, "enabled")) {
+ activate = true;
+ } else if (!strcmp(buf, "disabled")) {
+ activate = false;
+ } else {
+ result = -EINVAL;
+ goto trip_activate_exit;
+ }
+
+ get_trip_threshold(tz, trip, &threshold);
+ if (threshold)
+ result = sensor_activate_trip(tz->sensor.sensor_id,
+ threshold, activate);
+ else
+ result = tz->ops->activate_trip_type(tz, trip,
+ activate ? THERMAL_TRIP_ACTIVATION_ENABLED :
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+
+trip_activate_exit:
if (result)
return result;
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index a4a4f28..0ff8ad7 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -523,6 +523,10 @@
{
struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
+ if (port->suspended) {
+ pr_err("%s: System is in Suspend state\n", __func__);
+ return;
+ }
msm_hsl_port->imr |= UARTDM_ISR_TXLEV_BMSK;
msm_hsl_write(port, msm_hsl_port->imr,
regmap[msm_hsl_port->ver_id][UARTDM_IMR]);
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 6f3ea9b..ad66113 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -111,4 +111,11 @@
To compile this driver as a module, choose M here: the module
will be called uio_pruss.
+config UIO_MSM_SHAREDMEM
+ bool "MSM shared memory driver"
+ default n
+ help
+ Provides the clients with their respective alloted shared memory
+ addresses which are used as transport buffer.
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index d4dd9a5..c4d177a 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
obj-$(CONFIG_UIO_NETX) += uio_netx.o
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
+obj-$(CONFIG_UIO_MSM_SHAREDMEM) += msm_sharedmem.o
diff --git a/drivers/uio/msm_sharedmem.c b/drivers/uio/msm_sharedmem.c
new file mode 100644
index 0000000..438f002
--- /dev/null
+++ b/drivers/uio/msm_sharedmem.c
@@ -0,0 +1,87 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/uio_driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#define DRIVER_NAME "msm_sharedmem"
+
+static int msm_sharedmem_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct uio_info *info = NULL;
+ struct resource *clnt_res = NULL;
+
+ /* Get the addresses from platform-data */
+ if (!pdev->dev.of_node) {
+ pr_err("Node not found\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!clnt_res) {
+ pr_err("resource not found\n");
+ return -ENODEV;
+ }
+
+ info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->name = clnt_res->name;
+ info->version = "1.0";
+ info->mem[0].addr = clnt_res->start;
+ info->mem[0].size = resource_size(clnt_res);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+
+ /* Setup device */
+ ret = uio_register_device(&pdev->dev, info);
+ if (ret)
+ goto out;
+
+ dev_set_drvdata(&pdev->dev, info);
+ pr_debug("Device created for client '%s'\n", clnt_res->name);
+out:
+ return ret;
+}
+
+static int msm_sharedmem_remove(struct platform_device *pdev)
+{
+ struct uio_info *info = dev_get_drvdata(&pdev->dev);
+
+ uio_unregister_device(info);
+
+ return 0;
+}
+
+static struct of_device_id msm_sharedmem_of_match[] = {
+ {.compatible = "qcom,sharedmem-uio",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, msm_sharedmem_of_match);
+
+static struct platform_driver msm_sharedmem_driver = {
+ .probe = msm_sharedmem_probe,
+ .remove = msm_sharedmem_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_sharedmem_of_match,
+ },
+};
+
+module_platform_driver(msm_sharedmem_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 7d57f64..452e63a 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -1070,6 +1070,27 @@
return dsi_pan_node;
}
+static int msm_dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
+{
+ u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (enable) {
+ msm_dsi_ahb_ctrl(1);
+ msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &dsiclk_rate,
+ &byteclk_rate, &pclk_rate);
+ msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate,
+ byteclk_rate, pclk_rate);
+ msm_dsi_clk_enable();
+ } else {
+ msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
+ msm_dsi_clk_disable();
+ msm_dsi_ahb_ctrl(0);
+ }
+ return 0;
+}
+
static int __devinit msm_dsi_probe(struct platform_device *pdev)
{
struct dsi_interface intf;
@@ -1188,6 +1209,7 @@
intf.on = msm_dsi_on;
intf.off = msm_dsi_off;
intf.cont_on = msm_dsi_cont_on;
+ intf.clk_ctrl = msm_dsi_clk_ctrl;
intf.op_mode_config = msm_dsi_op_mode_config;
intf.tx = msm_dsi_cmds_tx;
intf.rx = msm_dsi_cmds_rx;
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 65cca0e..f3d0ad4 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -104,6 +104,18 @@
return rc;
}
+static int dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
+{
+ int rc = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (dsi_intf.clk_ctrl)
+ rc = dsi_intf.clk_ctrl(pdata, enable);
+
+ return rc;
+}
+
static int dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@@ -130,6 +142,9 @@
case MDSS_EVENT_CONT_SPLASH_BEGIN:
rc = dsi_splash_on(pdata);
break;
+ case MDSS_EVENT_PANEL_CLK_CTRL:
+ rc = dsi_clk_ctrl(pdata, (int)arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index e15f640..cb007e3 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -27,6 +27,7 @@
int (*on)(struct mdss_panel_data *pdata);
int (*off)(struct mdss_panel_data *pdata);
int (*cont_on)(struct mdss_panel_data *pdata);
+ int (*clk_ctrl)(struct mdss_panel_data *pdata, int enable);
void (*op_mode_config)(int mode, struct mdss_panel_data *pdata);
int (*tx)(struct mdss_panel_data *pdata,
struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index d642093..e4ae7ea 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -184,11 +184,11 @@
u32 mdp_interrupt = 0;
spin_lock(&mdata->irq_lock);
- if (!mdata->irq_mask) {
+ if (!mdata->irq_mask)
pr_err("spurious interrupt\n");
- spin_unlock(&mdata->irq_lock);
- return IRQ_HANDLED;
- }
+
+ clk_enable(mdp3_res->clocks[MDP3_CLK_AHB]);
+ clk_enable(mdp3_res->clocks[MDP3_CLK_CORE]);
mdp_interrupt = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_interrupt);
@@ -202,6 +202,10 @@
mdp_interrupt = mdp_interrupt >> 1;
i++;
}
+
+ clk_disable(mdp3_res->clocks[MDP3_CLK_AHB]);
+ clk_disable(mdp3_res->clocks[MDP3_CLK_CORE]);
+
spin_unlock(&mdata->irq_lock);
return IRQ_HANDLED;
@@ -281,8 +285,6 @@
spin_lock_irqsave(&mdp3_res->irq_lock, flag);
memset(mdp3_res->irq_ref_count, 0, sizeof(u32) * MDP3_MAX_INTR);
mdp3_res->irq_mask = 0;
- MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
- MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, 0xfffffff);
disable_irq_nosync(mdp3_res->irq);
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}
@@ -415,10 +417,10 @@
count = mdp3_res->clock_ref_count[clk_idx];
if (count == 1 && enable) {
pr_debug("clk=%d en=%d\n", clk_idx, enable);
- ret = clk_prepare_enable(clk);
+ ret = clk_enable(clk);
} else if (count == 0) {
pr_debug("clk=%d disable\n", clk_idx);
- clk_disable_unprepare(clk);
+ clk_disable(clk);
ret = 0;
} else if (count < 0) {
pr_err("clk=%d count=%d\n", clk_idx, count);
@@ -554,7 +556,7 @@
clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
}
-int mdp3_clk_enable(int enable)
+int mdp3_clk_enable(int enable, int dsi_clk)
{
int rc;
@@ -564,11 +566,62 @@
rc = mdp3_clk_update(MDP3_CLK_AHB, enable);
rc |= mdp3_clk_update(MDP3_CLK_CORE, enable);
rc |= mdp3_clk_update(MDP3_CLK_VSYNC, enable);
- rc |= mdp3_clk_update(MDP3_CLK_DSI, enable);
+ if (dsi_clk)
+ rc |= mdp3_clk_update(MDP3_CLK_DSI, enable);
mutex_unlock(&mdp3_res->res_mutex);
return rc;
}
+int mdp3_clk_prepare(void)
+{
+ int rc = 0;
+
+ mutex_lock(&mdp3_res->res_mutex);
+ mdp3_res->clk_prepare_count++;
+ if (mdp3_res->clk_prepare_count == 1) {
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+ if (rc < 0)
+ goto error0;
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+ if (rc < 0)
+ goto error1;
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+ if (rc < 0)
+ goto error2;
+ rc = clk_prepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+ if (rc < 0)
+ goto error3;
+ }
+ mutex_unlock(&mdp3_res->res_mutex);
+ return rc;
+
+error3:
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+error2:
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+error1:
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+error0:
+ mdp3_res->clk_prepare_count--;
+ mutex_unlock(&mdp3_res->res_mutex);
+ return rc;
+}
+
+void mdp3_clk_unprepare(void)
+{
+ mutex_lock(&mdp3_res->res_mutex);
+ mdp3_res->clk_prepare_count--;
+ if (mdp3_res->clk_prepare_count == 0) {
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_AHB]);
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_CORE]);
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+ clk_unprepare(mdp3_res->clocks[MDP3_CLK_DSI]);
+ } else if (mdp3_res->clk_prepare_count < 0) {
+ pr_err("mdp3 clk unprepare mismatch\n");
+ }
+ mutex_unlock(&mdp3_res->res_mutex);
+}
+
static int mdp3_irq_setup(void)
{
int ret;
@@ -1512,8 +1565,17 @@
static int mdp3_init(struct msm_fb_data_type *mfd)
{
int rc;
+
rc = mdp3_ctrl_init(mfd);
- rc |= mdp3_ppp_res_init(mfd);
+ if (rc) {
+ pr_err("mdp3 ctl init fail\n");
+ return rc;
+ }
+
+ rc = mdp3_ppp_res_init(mfd);
+ if (rc)
+ pr_err("mdp3 ppp res init fail\n");
+
return rc;
}
@@ -1671,6 +1733,11 @@
return mdp3_res->domains[MDP3_DMA_IOMMU_DOMAIN].domain_idx;
}
+int mdp3_get_cont_spash_en(void)
+{
+ return mdp3_res->cont_splash_en;
+}
+
int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
{
unsigned long splash_phys, phys;
@@ -1740,9 +1807,19 @@
pr_debug("mdp3__continuous_splash_on\n");
- rc = mdp3_clk_enable(1);
+ mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
+ MDP3_CLIENT_DMA_P);
+
+ rc = mdp3_clk_prepare();
+ if (rc) {
+ pr_err("fail to prepare clk\n");
+ return rc;
+ }
+
+ rc = mdp3_clk_enable(1, 1);
if (rc) {
pr_err("fail to enable clk\n");
+ mdp3_clk_unprepare();
return rc;
}
@@ -1776,11 +1853,15 @@
mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1;
else
mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
+
+ mdp3_res->cont_splash_en = 1;
return 0;
splash_on_err:
- if (mdp3_clk_enable(0))
+ if (mdp3_clk_enable(0, 1))
pr_err("%s: Unable to disable mdp3 clocks\n", __func__);
+
+ mdp3_clk_unprepare();
return rc;
}
@@ -1813,10 +1894,13 @@
static void mdp3_debug_enable_clock(int on)
{
- if (on)
- mdp3_clk_enable(1);
- else
- mdp3_clk_enable(0);
+ if (on) {
+ mdp3_clk_prepare();
+ mdp3_clk_enable(1, 0);
+ } else {
+ mdp3_clk_enable(0, 0);
+ mdp3_clk_unprepare();
+ }
}
static int mdp3_debug_init(struct platform_device *pdev)
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index e66b5ac..c0d630e 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -25,6 +25,8 @@
#include "mdp3_dma.h"
#include "mdss_fb.h"
+#define MDP_VSYNC_CLK_RATE 19200000
+
enum {
MDP3_CLK_AHB,
MDP3_CLK_CORE,
@@ -152,6 +154,9 @@
struct mdss_panel_cfg pan_cfg;
u32 splash_mem_addr;
u32 splash_mem_size;
+
+ int clk_prepare_count;
+ int cont_splash_en;
};
struct mdp3_img_data {
@@ -175,7 +180,9 @@
void mdp3_irq_register(void);
void mdp3_irq_deregister(void);
int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
-int mdp3_clk_enable(int enable);
+int mdp3_clk_enable(int enable, int dsi_clk);
+int mdp3_clk_prepare(void);
+void mdp3_clk_unprepare(void);
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
int mdp3_put_img(struct mdp3_img_data *data, int client);
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
@@ -187,6 +194,7 @@
int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
void mdp3_release_splash_memory(void);
int mdp3_create_sysfs_link(struct device *dev);
+int mdp3_get_cont_spash_en(void);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index b123ccb..14107c5 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -26,12 +26,15 @@
#include "mdp3_ppp.h"
#define MDP_CORE_CLK_RATE 100000000
-#define MDP_VSYNC_CLK_RATE 19200000
+#define VSYNC_EXPIRE_TICK 4
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
static int mdp3_histogram_stop(struct mdp3_session_data *session,
u32 block);
+static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable);
+static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable);
+static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd);
static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
{
@@ -88,6 +91,29 @@
return bufq->count;
}
+static void mdp3_dispatch_clk_off(struct work_struct *work)
+{
+ struct mdp3_session_data *session;
+
+ pr_debug("%s\n", __func__);
+ session = container_of(work, struct mdp3_session_data,
+ clk_off_work);
+ if (!session)
+ return;
+
+ mutex_lock(&session->lock);
+ if (session->vsync_enabled ||
+ atomic_read(&session->vsync_countdown) != 0) {
+ mutex_unlock(&session->lock);
+ pr_debug("Ignoring clk shut down\n");
+ return;
+ }
+
+ mdp3_ctrl_vsync_enable(session->mfd, 0);
+ mdp3_ctrl_clk_enable(session->mfd, 0);
+ mutex_unlock(&session->lock);
+}
+
void vsync_notify_handler(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
@@ -95,6 +121,22 @@
sysfs_notify_dirent(session->vsync_event_sd);
}
+void vsync_count_down(void *arg)
+{
+ struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+ /* We are counting down to turn off clocks */
+ atomic_dec(&session->vsync_countdown);
+ if (atomic_read(&session->vsync_countdown) == 0)
+ schedule_work(&session->clk_off_work);
+}
+
+void mdp3_ctrl_reset_countdown(struct mdp3_session_data *session,
+ struct msm_fb_data_type *mfd)
+{
+ if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_CMD)
+ atomic_set(&session->vsync_countdown, VSYNC_EXPIRE_TICK);
+}
+
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
{
struct mdp3_session_data *mdp3_session;
@@ -115,17 +157,37 @@
vsync_client.handler = vsync_notify_handler;
vsync_client.arg = mdp3_session;
arg = &vsync_client;
+ } else if (atomic_read(&mdp3_session->vsync_countdown)) {
+ /*
+ * Now that vsync is no longer needed we will
+ * shutdown dsi clocks as soon as cnt down == 0
+ * for cmd mode panels
+ */
+ vsync_client.handler = vsync_count_down;
+ vsync_client.arg = mdp3_session;
+ arg = &vsync_client;
+ enable = 1;
}
- mutex_lock(&mdp3_session->lock);
+ mdp3_clk_enable(1, 0);
mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
- if (enable && mdp3_session->status == 1 && !mdp3_session->intf->active)
+ mdp3_clk_enable(0, 0);
+
+ /*
+ * Need to fake vsync whenever dsi interface is not
+ * active or when dsi clocks are currently off
+ */
+ if (enable && mdp3_session->status == 1
+ && !mdp3_session->intf->active) {
mod_timer(&mdp3_session->vsync_timer,
jiffies + msecs_to_jiffies(mdp3_session->vsync_period));
- else if (!enable)
+ } else if (enable && !mdp3_session->clk_on) {
+ mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_clk_enable(mfd, 1);
+ } else if (!enable) {
del_timer(&mdp3_session->vsync_timer);
+ }
- mutex_unlock(&mdp3_session->lock);
return 0;
}
@@ -209,6 +271,33 @@
.attrs = vsync_fs_attrs,
};
+static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable)
+{
+ struct mdp3_session_data *session;
+ struct mdss_panel_data *panel;
+ int rc = 0;
+
+ pr_debug("mdp3_ctrl_clk_enable %d\n", enable);
+
+ session = mfd->mdp.private1;
+ panel = session->panel;
+
+ if (!panel->event_handler)
+ return 0;
+
+ if ((enable && session->clk_on == 0) ||
+ (!enable && session->clk_on == 1)) {
+ rc = panel->event_handler(panel,
+ MDSS_EVENT_PANEL_CLK_CTRL, (void *)enable);
+ rc |= mdp3_clk_enable(enable, 1);
+ } else {
+ pr_debug("enable = %d, clk_on=%d\n", enable, session->clk_on);
+ }
+
+ session->clk_on = enable;
+ return rc;
+}
+
static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status)
{
int rc = 0;
@@ -236,12 +325,24 @@
mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
MDP3_CLIENT_DMA_P);
- rc = mdp3_clk_enable(true);
- if (rc)
+ rc = mdp3_clk_prepare();
+ if (rc) {
+ pr_err("mdp3 clk prepare fail\n");
return rc;
+ }
+ rc = mdp3_clk_enable(1, 1);
+ if (rc) {
+ pr_err("mdp3 clk enable fail\n");
+ mdp3_clk_unprepare();
+ return rc;
+ }
} else {
- rc = mdp3_clk_enable(false);
+ rc = mdp3_clk_enable(0, 1);
+ if (rc)
+ pr_err("mdp3 clk disable fail\n");
+ else
+ mdp3_clk_unprepare();
}
return rc;
}
@@ -473,6 +574,7 @@
goto on_error;
}
+ mdp3_session->clk_on = 1;
pr_debug("mdp3_ctrl_on dma start\n");
if (mfd->fbi->screen_base) {
rc = mdp3_session->dma->start(mdp3_session->dma,
@@ -517,31 +619,36 @@
goto off_error;
}
+ mdp3_ctrl_clk_enable(mfd, 1);
+
mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
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");
-
-
mdp3_irq_deregister();
pr_debug("mdp3_ctrl_off stop clock\n");
- rc = mdp3_ctrl_res_req_clk(mfd, 0);
- if (rc)
- pr_err("mdp clock resource release failed\n");
+ if (mdp3_session->clk_on) {
+ rc = mdp3_clk_enable(0, 1);
+ if (rc)
+ pr_err("mdp clock resource release failed\n");
- pr_debug("mdp3_ctrl_off stop dsi controller\n");
- if (panel->event_handler)
- rc = panel->event_handler(panel, MDSS_EVENT_BLANK, NULL);
- if (rc)
- pr_err("fail to turn off the panel\n");
+ pr_debug("mdp3_ctrl_off stop dsi controller\n");
+ if (panel->event_handler)
+ rc = panel->event_handler(panel,
+ MDSS_EVENT_BLANK, NULL);
+ if (rc)
+ pr_err("fail to turn off the panel\n");
+ }
+ mdp3_clk_unprepare();
pr_debug("mdp3_ctrl_off release bus\n");
rc = mdp3_ctrl_res_req_bus(mfd, 0);
@@ -552,6 +659,9 @@
if (rc)
pr_err("fail to dettach MDP DMA SMMU\n");
+ mdp3_session->vsync_enabled = 0;
+ atomic_set(&mdp3_session->vsync_countdown, 0);
+ mdp3_session->clk_on = 0;
off_error:
mdp3_session->status = 0;
mdp3_bufq_deinit(&mdp3_session->bufq_out);
@@ -845,6 +955,8 @@
data = mdp3_bufq_pop(&mdp3_session->bufq_in);
if (data) {
+ mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_clk_enable(mfd, 1);
mdp3_session->dma->update(mdp3_session->dma,
(void *)data->addr,
mdp3_session->intf);
@@ -913,12 +1025,16 @@
}
if (mfd->fbi->screen_base) {
+ mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_clk_enable(mfd, 1);
mdp3_session->dma->update(mdp3_session->dma,
(void *)mfd->iova + offset,
mdp3_session->intf);
} else {
pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
+ mdp3_clk_enable(1, 0);
mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+ mdp3_clk_enable(0, 0);
}
if (mdp3_session->first_commit) {
@@ -1034,10 +1150,11 @@
if (session->histo_status) {
pr_err("mdp3_histogram_start already started\n");
- ret = -EBUSY;
- goto histogram_start_err;
+ mutex_unlock(&session->histo_lock);
+ return -EBUSY;
}
+ mdp3_clk_enable(1, 0);
ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET);
if (ret) {
pr_err("mdp3_histogram_start reset error\n");
@@ -1063,6 +1180,7 @@
session->histo_status = 1;
histogram_start_err:
+ mdp3_clk_enable(0, 0);
mutex_unlock(&session->histo_lock);
return ret;
}
@@ -1085,7 +1203,9 @@
goto histogram_stop_err;
}
+ mdp3_clk_enable(1, 0);
ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL);
+ mdp3_clk_enable(0, 0);
if (ret)
pr_err("mdp3_histogram_stop error\n");
@@ -1102,11 +1222,17 @@
int ret;
struct mdp3_dma_histogram_data *mdp3_histo;
+ pr_debug("%s\n", __func__);
if (!session->dma->get_histo) {
pr_err("mdp3_histogram_collect not supported\n");
return -EINVAL;
}
+ if (!session->clk_on) {
+ pr_debug("mdp/dsi clock off currently\n");
+ return -EPERM;
+ }
+
mutex_lock(&session->histo_lock);
if (!session->histo_status) {
@@ -1117,7 +1243,9 @@
mutex_unlock(&session->histo_lock);
+ mdp3_clk_enable(1, 0);
ret = session->dma->get_histo(session->dma);
+ mdp3_clk_enable(0, 0);
if (ret) {
pr_debug("mdp3_histogram_collect error = %d\n", ret);
return ret;
@@ -1199,7 +1327,9 @@
ccs.post_lv = data->csc_data.csc_post_lv;
mutex_lock(&session->lock);
+ mdp3_clk_enable(1, 0);
ret = session->dma->config_ccs(session->dma, &config, &ccs);
+ mdp3_clk_enable(0, 0);
mutex_unlock(&session->lock);
return ret;
}
@@ -1341,8 +1471,10 @@
return -EPERM;
}
+ mdp3_clk_enable(1, 0);
rc = mdp3_session->dma->config_lut(mdp3_session->dma, &lut_config,
&lut);
+ mdp3_clk_enable(0, 0);
if (rc)
pr_err("mdp3_ctrl_lut_update failed\n");
@@ -1386,7 +1518,10 @@
case MSMFB_VSYNC_CTRL:
case MSMFB_OVERLAY_VSYNC_CTRL:
if (!copy_from_user(&val, argp, sizeof(val))) {
+ mutex_lock(&mdp3_session->lock);
+ mdp3_session->vsync_enabled = val;
rc = mdp3_ctrl_vsync_enable(mfd, val);
+ mutex_unlock(&mdp3_session->lock);
} else {
pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
rc = -EFAULT;
@@ -1475,6 +1610,8 @@
}
memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
mutex_init(&mdp3_session->lock);
+ INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off);
+ atomic_set(&mdp3_session->vsync_countdown, 0);
mutex_init(&mdp3_session->histo_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
if (!mdp3_session->dma) {
@@ -1542,6 +1679,9 @@
mdp3_ctrl_off(mfd);
}
+ if (mdp3_get_cont_spash_en())
+ mdp3_session->clk_on = 1;
+
init_done:
if (IS_ERR_VALUE(rc))
kfree(mdp3_session);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 66ed3d5..8d7627e 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -48,11 +48,16 @@
struct mdp_overlay req_overlay;
struct mdp3_buffer_queue bufq_in;
struct mdp3_buffer_queue bufq_out;
+ struct work_struct clk_off_work;
int histo_status;
struct mutex histo_lock;
int lut_sel;
int cc_vect_sel;
bool first_commit;
+ int clk_on;
+
+ int vsync_enabled;
+ atomic_t vsync_countdown; /* Used to count down */
};
int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 89f3e27..3a2c94b 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -828,6 +828,9 @@
MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
mdp3_irq_disable(MDP3_INTR_LCDC_UNDERFLOW);
+ MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0);
+ MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, 0xfffffff);
+
init_completion(&dma->dma_comp);
dma->vsync_client.handler = NULL;
return ret;
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index 90ee357..8846ec5 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -221,6 +221,9 @@
#define MDP3_PPP_BG_UNPACK_PATTERN1 0x101D8
#define MDP3_PPP_BG_UNPACK_PATTERN2 0x101DC
+#define MDP3_TFETCH_SOLID_FILL 0x20004
+#define MDP3_TFETCH_FILL_COLOR 0x20040
+
#define MDP3_PPP_BLEND_PARAM 0x1014C
#define MDP3_PPP_BLEND_BG_ALPHA_SEL 0x70010
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index d16cb3f..6187db4 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -36,6 +36,8 @@
#define MDP_PPP_MAX_BPP 4
#define MDP_PPP_DYNAMIC_FACTOR 3
#define MDP_PPP_MAX_READ_WRITE 3
+#define ENABLE_SOLID_FILL 0x2
+#define DISABLE_SOLID_FILL 0x0
static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
[MDP_RGB_565] = true,
@@ -370,14 +372,14 @@
ib = (ab * 3) / 2;
}
mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
- rc = mdp3_clk_enable(on_off);
+ rc = mdp3_clk_enable(on_off, 0);
if (rc < 0) {
pr_err("%s: mdp3_clk_enable failed\n", __func__);
return rc;
}
rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
if (rc < 0) {
- mdp3_clk_enable(!on_off);
+ mdp3_clk_enable(!on_off, 0);
pr_err("%s: scale_set_quota failed\n", __func__);
return rc;
}
@@ -390,6 +392,23 @@
/* Wait for the pipe to clear */
do { } while (mdp3_ppp_pipe_wait() <= 0);
config_ppp_op_mode(blit_op);
+ if (blit_op->solid_fill) {
+ MDP3_REG_WRITE(0x10138, 0x10000000);
+ MDP3_REG_WRITE(0x1014c, 0xffffffff);
+ MDP3_REG_WRITE(0x101b8, 0);
+ MDP3_REG_WRITE(0x101bc, 0);
+ MDP3_REG_WRITE(0x1013c, 0);
+ MDP3_REG_WRITE(0x10140, 0);
+ MDP3_REG_WRITE(0x10144, 0);
+ MDP3_REG_WRITE(0x10148, 0);
+ MDP3_REG_WRITE(MDP3_TFETCH_FILL_COLOR,
+ blit_op->solid_fill_color);
+ MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL,
+ ENABLE_SOLID_FILL);
+ } else {
+ MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL,
+ DISABLE_SOLID_FILL);
+ }
mdp3_ppp_kickoff();
}
@@ -489,6 +508,26 @@
if (req->flags & MDP_BLUR)
blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
+
+ if (req->flags & MDP_SOLID_FILL) {
+ blit_op->solid_fill = true;
+
+ /* Avoid odd width, as it could hang ppp during solid fill */
+ blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
+ blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
+
+ /* Avoid RGBA format, as it could hang ppp during solid fill */
+ if (blit_op->src.color_fmt == MDP_RGBA_8888)
+ blit_op->src.color_fmt = MDP_RGBX_8888;
+ if (blit_op->dst.color_fmt == MDP_RGBA_8888)
+ blit_op->dst.color_fmt = MDP_RGBX_8888;
+ blit_op->solid_fill_color = (req->const_color.g & 0xFF)|
+ (req->const_color.b & 0xFF) << 8 |
+ (req->const_color.r & 0xFF) << 16 |
+ (req->const_color.alpha & 0xFF) << 24;
+ } else {
+ blit_op->solid_fill = false;
+ }
}
static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
@@ -791,9 +830,10 @@
}
is_bpp_4 = (ret == 4) ? 1 : 0;
- if ((is_bpp_4 && (remainder == 6 || remainder == 14)))
+ if ((is_bpp_4 && (remainder == 6 || remainder == 14)) &&
+ !(req->flags & MDP_SOLID_FILL))
ret = mdp3_ppp_blit_workaround(mfd, req, remainder,
- src_data, dst_data);
+ src_data, dst_data);
else
ret = mdp3_ppp_blit(mfd, req, src_data, dst_data);
return ret;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
index b4252ca..9753e94 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.h
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -332,6 +332,8 @@
struct ppp_img_desc bg;
struct ppp_blend blend;
uint32_t mdp_op; /* Operations */
+ uint32_t solid_fill_color;
+ bool solid_fill;
};
struct ppp_edge_rep {
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 890066e..03dbd4d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -398,7 +398,7 @@
if (dchdr->dlen > len) {
pr_err("%s: dtsi cmd=%x error, len=%d",
__func__, dchdr->dtype, dchdr->dlen);
- return -ENOMEM;
+ goto exit_free;
}
bp += sizeof(*dchdr);
len -= sizeof(*dchdr);
@@ -410,14 +410,13 @@
if (len != 0) {
pr_err("%s: dcs_cmd=%x len=%d error!",
__func__, buf[0], blen);
- kfree(buf);
- return -ENOMEM;
+ goto exit_free;
}
pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
GFP_KERNEL);
if (!pcmds->cmds)
- return -ENOMEM;
+ goto exit_free;
pcmds->cmd_cnt = cnt;
pcmds->buf = buf;
@@ -445,6 +444,10 @@
pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
return 0;
+
+exit_free:
+ kfree(buf);
+ return -ENOMEM;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 52ca42c..8d59107 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -359,6 +359,8 @@
#define MDSS_MDP_REG_WB_CSC_BASE 0x260
#define MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS 0x2B0
+#define MDSS_MDP_MAX_AD_AL 65535
+#define MDSS_MDP_MAX_AD_STR 255
#define MDSS_MDP_REG_AD_BYPASS 0x000
#define MDSS_MDP_REG_AD_CTRL_0 0x004
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index dc7b8b3..dfeec22 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -2291,6 +2291,7 @@
return ret;
}
+#define MDSS_MAX_HIST_BIN_SIZE 16777215
int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
{
u32 done_shift_bit;
@@ -2299,9 +2300,13 @@
int i, ret = 0;
u32 disp_num, dspp_num = 0;
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 frame_size;
struct mdss_mdp_pipe *pipe;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ if (!mdss_is_ready())
+ return -EPROBE_DEFER;
+
if ((PP_BLOCK(req->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(req->block) >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -2321,6 +2326,16 @@
ret = -EPERM;
goto hist_exit;
}
+
+ frame_size = (mdata->ctl_off[mixer_id[0]].width *
+ mdata->ctl_off[mixer_id[0]].height);
+ if (!frame_size ||
+ ((MDSS_MAX_HIST_BIN_SIZE / frame_size) < req->frame_cnt)) {
+ pr_err("%s, too many frames for given display size, %d",
+ __func__, req->frame_cnt);
+ ret = -EINVAL;
+ goto hist_exit;
+ }
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (PP_LOCAT(req->block) == MDSS_PP_SSPP_CFG) {
@@ -2987,6 +3002,11 @@
ret = -EINVAL;
goto error;
}
+ if (input->in.amb_light > MDSS_MDP_MAX_AD_AL) {
+ pr_warn("invalid input ambient light");
+ ret = -EINVAL;
+ goto error;
+ }
ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
pr_debug("ambient = %d", input->in.amb_light);
ad->ad_data = input->in.amb_light;
@@ -3001,6 +3021,11 @@
ret = -EINVAL;
goto error;
}
+ if (input->in.strength > MDSS_MDP_MAX_AD_STR) {
+ pr_warn("invalid input strength");
+ ret = -EINVAL;
+ goto error;
+ }
ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
pr_debug("strength = %d", input->in.strength);
ad->ad_data = input->in.strength;
@@ -3563,8 +3588,8 @@
return ret;
}
- if (cfg->size == 0) {
- pr_err("Invalid buffer size");
+ if (cfg->size == 0 || cfg->size > PAGE_SIZE) {
+ pr_err("Invalid buffer size %d", cfg->size);
return ret;
}
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 4bbd07a..8da837b 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -90,8 +90,8 @@
* unusual file system layouts.
*/
if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) {
- block_cluster = EXT4_B2C(sbi, (start -
- ext4_block_bitmap(sb, gdp)));
+ block_cluster = EXT4_B2C(sbi,
+ ext4_block_bitmap(sb, gdp) - start);
if (block_cluster < num_clusters)
block_cluster = -1;
else if (block_cluster == num_clusters) {
@@ -102,7 +102,7 @@
if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) {
inode_cluster = EXT4_B2C(sbi,
- start - ext4_inode_bitmap(sb, gdp));
+ ext4_inode_bitmap(sb, gdp) - start);
if (inode_cluster < num_clusters)
inode_cluster = -1;
else if (inode_cluster == num_clusters) {
@@ -114,7 +114,7 @@
itbl_blk = ext4_inode_table(sb, gdp);
for (i = 0; i < sbi->s_itb_per_group; i++) {
if (ext4_block_in_group(sb, itbl_blk + i, block_group)) {
- c = EXT4_B2C(sbi, start - itbl_blk + i);
+ c = EXT4_B2C(sbi, itbl_blk + i - start);
if ((c < num_clusters) || (c == inode_cluster) ||
(c == block_cluster) || (c == itbl_cluster))
continue;
diff --git a/include/linux/kref.h b/include/linux/kref.h
index aa5acc26..6f515f2 100644
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -18,6 +18,7 @@
#include <linux/bug.h>
#include <linux/atomic.h>
#include <linux/kernel.h>
+#include <linux/mutex.h>
struct kref {
atomic_t refcount;
@@ -94,6 +95,23 @@
return kref_sub(kref, 1, release);
}
+static inline int kref_put_mutex(struct kref *kref,
+ void (*release)(struct kref *kref),
+ struct mutex *lock)
+{
+ WARN_ON(release == NULL);
+ if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
+ mutex_lock(lock);
+ if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
+ mutex_unlock(lock);
+ return 0;
+ }
+ release(kref);
+ return 1;
+ }
+ return 0;
+}
+
/**
* kref_get_unless_zero - Increment refcount for object unless it is zero.
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index e6b7f69..803ebeb 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -169,6 +169,7 @@
#define MDP_BLUR 0x10
#define MDP_BLEND_FG_PREMULT 0x20000
#define MDP_IS_FG 0x40000
+#define MDP_SOLID_FILL 0x0000100
#define MDP_DEINTERLACE 0x80000000
#define MDP_SHARPENING 0x40000000
#define MDP_NO_DMA_BARRIER_START 0x20000000
@@ -254,11 +255,19 @@
#define MDP_BLIT_REQ_VERSION 2
+struct color {
+ uint32_t r;
+ uint32_t g;
+ uint32_t b;
+ uint32_t alpha;
+};
+
struct mdp_blit_req {
struct mdp_img src;
struct mdp_img dst;
struct mdp_rect src_rect;
struct mdp_rect dst_rect;
+ struct color const_color;
uint32_t alpha;
uint32_t transp_mask;
uint32_t flags;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 22b004e..0065203 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -105,6 +105,7 @@
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_POWER_NOW,
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index ed6d41b..faf98fe 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -102,6 +102,7 @@
enum thermal_trip_type trip;
int (*notify)(enum thermal_trip_type type, int temp, void *data);
void *data;
+ uint8_t active;
struct list_head list;
};
@@ -189,6 +190,8 @@
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 sensor_activate_trip(uint32_t sensor_id, struct sensor_threshold *threshold,
+ bool enable);
int thermal_sensor_trip(struct thermal_zone_device *tz,
enum thermal_trip_type trip, long temp);
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index cccf851..c48586e 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -571,6 +571,7 @@
struct msm_camera_led_cfg_t {
enum msm_camera_led_config_t cfgtype;
+ uint32_t led_current;
};
#define VIDIOC_MSM_SENSOR_CFG \
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index de42c38..ed4ffa2 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -90,6 +90,7 @@
uint32_t offset;
uint8_t native_buff;
uint8_t processed_divert;
+ uint32_t identity;
};
struct msm_cpp_stream_buff_info_t {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4ecadd8..7932ba1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1801,22 +1801,28 @@
* enum wiphy_flags - wiphy capability flags
*
* @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device
- * has its own custom regulatory domain and cannot identify the
- * ISO / IEC 3166 alpha2 it belongs to. When this is enabled
- * we will disregard the first regulatory hint (when the
- * initiator is %REGDOM_SET_BY_CORE).
- * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
- * ignore regulatory domain settings until it gets its own regulatory
- * domain via its regulatory_hint() unless the regulatory hint is
- * from a country IE. After its gets its own regulatory domain it will
- * only allow further regulatory domain settings to further enhance
- * compliance. For example if channel 13 and 14 are disabled by this
- * regulatory domain no user regulatory domain can enable these channels
- * at a later time. This can be used for devices which do not have
- * calibration information guaranteed for frequencies or settings
- * outside of its regulatory domain. If used in combination with
- * WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings
- * will be followed.
+ * has its own custom regulatory domain and cannot identify the
+ * ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ * we will disregard the first regulatory hint (when the
+ * initiator is %REGDOM_SET_BY_CORE). wiphys can set the custom
+ * regulatory domain using wiphy_apply_custom_regulatory()
+ * prior to wiphy registration.
+ * @WIPHY_FLAG_STRICT_REGULATORY: tells us that the wiphy for this device
+ * has regulatory domain that it wishes to be considered as the
+ * superset for regulatory rules. After this device gets its regulatory
+ * domain programmed further regulatory hints shall only be considered
+ * for this device to enhance regulatory compliance, forcing the
+ * device to only possibly use subsets of the original regulatory
+ * rules. For example if channel 13 and 14 are disabled by this
+ * device's regulatory domain no user specified regulatory hint which
+ * has these channels enabled would enable them for this wiphy,
+ * the device's original regulatory domain will be trusted as the
+ * base. You can program the superset of regulatory rules for this
+ * wiphy with regulatory_hint() for cards programmed with an
+ * ISO3166-alpha2 country code. wiphys that use regulatory_hint()
+ * will have their wiphy->regd programmed once the regulatory
+ * domain is set, and all other regulatory hints will be ignored
+ * until their own regulatory domain gets programmed.
* @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
* that passive scan flags and beaconing flags may not be lifted by
* cfg80211 due to regulatory beacon hints. For more information on beacon
@@ -1884,6 +1890,34 @@
};
/**
+ * enum nl80211_country_ie_pref - country IE processing preferences
+ *
+ * enumerates the different preferences a 802.11 card can advertize
+ * for parsing the country IEs. As per the current implementation
+ * country IEs are only used derive the apha2, the information
+ * for power settings that comes with the country IE is ignored
+ * and we use the power settings from regdb.
+ *
+ * @NL80211_COUNTRY_IE_FOLLOW_CORE - This is the default behaviour.
+ * It allows the core to update channel flags according to the
+ * ISO3166-alpha2 in the country IE. The applied power is -
+ * MIN(power specified by custom domain, power obtained from regdb)
+ * @NL80211_COUNTRY_IE_FOLLOW_POWER - for devices that have a
+ * preference that even though they may have programmed their own
+ * custom power setting prior to wiphy registration, they want
+ * to ensure their channel power settings are updated for this
+ * connection with the power settings derived from alpha2 of the
+ * country IE.
+ * @NL80211_COUNTRY_IE_IGNORE_CORE - for devices that have a preference to
+ * to ignore all country IE information processed by the core.
+ */
+enum nl80211_country_ie_pref {
+ NL80211_COUNTRY_IE_FOLLOW_CORE,
+ NL80211_COUNTRY_IE_FOLLOW_POWER,
+ NL80211_COUNTRY_IE_IGNORE_CORE,
+};
+
+/**
* struct ieee80211_iface_limit - limit on certain interface types
* @max: maximum number of interfaces of these types
* @types: interface types (bits)
@@ -2100,6 +2134,8 @@
*
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
* supports for ACL.
+ * @country_ie_pref: country IE processing preferences specified
+ * by enum nl80211_country_ie_pref
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2164,6 +2200,8 @@
*/
u32 probe_resp_offload;
+ u8 country_ie_pref;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
@@ -2691,6 +2729,30 @@
extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
/**
+ * regulatory_hint_user - hint to the wireless core a regulatory domain
+ * which the driver has received from an application
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ * should be in. If @rd is set this should be NULL. Note that if you
+ * set this to NULL you should still set rd->alpha2 to some accepted
+ * alpha2.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * the current regulatory domain as specified by trusted applications,
+ * it is the driver's responsibilty to estbalish which applications it
+ * trusts.
+ *
+ * The wiphy should be registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM or an -EINVAL.
+ *
+ * Return: 0 on success. -ENOMEM, -EINVAL.
+ */
+extern int regulatory_hint_user(const char *alpha2);
+
+/**
* wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
* @wiphy: the wireless device we want to process the regulatory domain on
* @regd: the custom regulatory domain to use for this wiphy
diff --git a/include/sound/soc.h b/include/sound/soc.h
index b1e536d..50d0471 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -561,6 +561,7 @@
#endif
struct snd_soc_jack {
+ struct mutex mutex;
struct snd_jack *jack;
struct snd_soc_codec *codec;
struct list_head pins;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b96094c..036f8ae 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -883,7 +883,19 @@
chan->max_antenna_gain = min(chan->orig_mag,
(int) MBI_TO_DBI(power_rule->max_antenna_gain));
chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
- chan->max_power = min(chan->max_power, chan->max_reg_power);
+ if (chan->orig_mpwr) {
+ /*
+ * Devices that use NL80211_COUNTRY_IE_FOLLOW_POWER will always
+ * follow the passed country IE power settings.
+ */
+ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+ wiphy->country_ie_pref & NL80211_COUNTRY_IE_FOLLOW_POWER)
+ chan->max_power = chan->max_reg_power;
+ else
+ chan->max_power = min(chan->orig_mpwr,
+ chan->max_reg_power);
+ } else
+ chan->max_power = chan->max_reg_power;
}
static void handle_band(struct wiphy *wiphy,
@@ -1295,6 +1307,8 @@
case NL80211_REGDOM_SET_BY_CORE:
return 0;
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ if (wiphy->country_ie_pref & NL80211_COUNTRY_IE_IGNORE_CORE)
+ return -EALREADY;
last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
@@ -1648,6 +1662,7 @@
return 0;
}
+EXPORT_SYMBOL(regulatory_hint_user);
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index e2aaaf5..017880c 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -22,8 +22,6 @@
bool reg_is_valid_request(const char *alpha2);
bool reg_supported_dfs_region(u8 dfs_region);
-int regulatory_hint_user(const char *alpha2);
-
int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
void reg_device_remove(struct wiphy *wiphy);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 52af21c..55fec32 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -2582,6 +2582,8 @@
*/
{MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
{MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+ {MSM8X10_WCD_A_RX_HPH_L_TEST, 0x01, 0x01},
+ {MSM8X10_WCD_A_RX_HPH_R_TEST, 0x01, 0x01},
/* Initialize gain registers to use register gain */
{MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c
index e5d5c32..b406feb 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.c
@@ -21,6 +21,8 @@
#define MSM_HDMI_PCM_RATES SNDRV_PCM_RATE_48000
+static int msm_hdmi_audio_codec_return_value;
+
struct msm_hdmi_audio_codec_rx_data {
struct platform_device *hdmi_core_pdev;
struct msm_hdmi_audio_codec_ops hdmi_ops;
@@ -54,8 +56,8 @@
int rc;
codec_data = snd_soc_codec_get_drvdata(codec);
- rc = codec_data->hdmi_ops.get_audio_edid_blk(codec_data->hdmi_core_pdev,
- &edid_blk);
+ rc = codec_data->hdmi_ops.get_audio_edid_blk(
+ codec_data->hdmi_core_pdev, &edid_blk);
if (!IS_ERR_VALUE(rc)) {
memcpy(ucontrol->value.bytes.data, edid_blk.audio_data_blk,
@@ -80,6 +82,24 @@
},
};
+static int msm_hdmi_audio_codec_rx_dai_startup(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_hdmi_audio_codec_rx_data *codec_data =
+ dev_get_drvdata(dai->codec->dev);
+
+ msm_hdmi_audio_codec_return_value =
+ codec_data->hdmi_ops.hdmi_cable_status(
+ codec_data->hdmi_core_pdev, 1);
+ if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) {
+ dev_err(dai->dev,
+ "%s() HDMI core is not ready\n", __func__);
+ }
+
+ return msm_hdmi_audio_codec_return_value;
+}
+
static int msm_hdmi_audio_codec_rx_dai_hw_params(
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -89,10 +109,17 @@
u32 level_shift = 0; /* 0dB */
bool down_mix = 0;
u32 num_channels = params_channels(params);
+ int rc = 0;
struct msm_hdmi_audio_codec_rx_data *codec_data =
dev_get_drvdata(dai->codec->dev);
+ if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) {
+ dev_err(dai->dev,
+ "%s() HDMI core is not ready\n", __func__);
+ return msm_hdmi_audio_codec_return_value;
+ }
+
switch (num_channels) {
case 2:
channel_allocation = 0;
@@ -108,19 +135,47 @@
return -EINVAL;
}
- dev_dbg(dai->dev, "%s() num_ch %u samplerate %u channel_allocation = %u\n",
+ dev_dbg(dai->dev,
+ "%s() num_ch %u samplerate %u channel_allocation = %u\n",
__func__, num_channels, params_rate(params),
channel_allocation);
- codec_data->hdmi_ops.audio_info_setup(codec_data->hdmi_core_pdev,
- params_rate(params), num_channels, channel_allocation,
- level_shift, down_mix);
+ rc = codec_data->hdmi_ops.audio_info_setup(
+ codec_data->hdmi_core_pdev,
+ params_rate(params), num_channels,
+ channel_allocation, level_shift, down_mix);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev,
+ "%s() HDMI core is not ready\n", __func__);
+ }
- return 0;
+ return rc;
+}
+
+static void msm_hdmi_audio_codec_rx_dai_shutdown(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int rc;
+
+ struct msm_hdmi_audio_codec_rx_data *codec_data =
+ dev_get_drvdata(dai->codec->dev);
+
+ rc = codec_data->hdmi_ops.hdmi_cable_status(
+ codec_data->hdmi_core_pdev, 0);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev,
+ "%s() HDMI core had problems releasing HDMI audio flag\n",
+ __func__);
+ }
+
+ return;
}
static struct snd_soc_dai_ops msm_hdmi_audio_codec_rx_dai_ops = {
+ .startup = msm_hdmi_audio_codec_rx_dai_startup,
.hw_params = msm_hdmi_audio_codec_rx_dai_hw_params,
+ .shutdown = msm_hdmi_audio_codec_rx_dai_shutdown
};
static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 6dc2ec0..c62f875 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -260,6 +260,8 @@
#define TAIKO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+#define TAIKO_SLIM_PGD_PORT_INT_TX_EN0 (TAIKO_SLIM_PGD_PORT_INT_EN0 + 2)
+
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -4884,6 +4886,46 @@
return ret;
}
+static void taiko_codec_enable_int_port(struct wcd9xxx_codec_dai_data *dai,
+ struct snd_soc_codec *codec)
+{
+ struct wcd9xxx_ch *ch;
+ int port_num = 0;
+ unsigned short reg = 0;
+ u8 val = 0;
+ if (!dai || !codec) {
+ pr_err("%s: Invalid params\n", __func__);
+ return;
+ }
+ list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+ if (ch->port >= TAIKO_RX_PORT_START_NUMBER) {
+ port_num = ch->port - TAIKO_RX_PORT_START_NUMBER;
+ reg = TAIKO_SLIM_PGD_PORT_INT_EN0 + (port_num / 8);
+ val = wcd9xxx_interface_reg_read(codec->control_data,
+ reg);
+ if (!(val & (1 << (port_num % 8)))) {
+ val |= (1 << (port_num % 8));
+ wcd9xxx_interface_reg_write(
+ codec->control_data, reg, val);
+ val = wcd9xxx_interface_reg_read(
+ codec->control_data, reg);
+ }
+ } else {
+ port_num = ch->port;
+ reg = TAIKO_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
+ val = wcd9xxx_interface_reg_read(codec->control_data,
+ reg);
+ if (!(val & (1 << (port_num % 8)))) {
+ val |= (1 << (port_num % 8));
+ wcd9xxx_interface_reg_write(codec->control_data,
+ reg, val);
+ val = wcd9xxx_interface_reg_read(
+ codec->control_data, reg);
+ }
+ }
+ }
+}
+
static int taiko_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -4910,6 +4952,7 @@
switch (event) {
case SND_SOC_DAPM_POST_PMU:
+ taiko_codec_enable_int_port(dai, codec);
(void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
@@ -4974,6 +5017,7 @@
/*Enable spkr VI clocks*/
snd_soc_update_bits(codec,
TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
+ taiko_codec_enable_int_port(dai, codec);
(void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
@@ -5021,6 +5065,7 @@
dai = &taiko_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
+ taiko_codec_enable_int_port(dai, codec);
(void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
@@ -5629,8 +5674,9 @@
unsigned long status = 0;
int i, j, port_id, k;
u32 bit;
- u8 val;
+ u8 val, int_val = 0;
bool tx, cleared;
+ unsigned short reg = 0;
for (i = TAIKO_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
i <= TAIKO_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
@@ -5645,12 +5691,28 @@
TAIKO_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
if (val & TAIKO_SLIM_IRQ_OVERFLOW)
pr_err_ratelimited(
- "%s: overflow error on %s port %d, value %x\n",
- __func__, (tx ? "TX" : "RX"), port_id, val);
+ "%s: overflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
if (val & TAIKO_SLIM_IRQ_UNDERFLOW)
pr_err_ratelimited(
- "%s: underflow error on %s port %d, value %x\n",
- __func__, (tx ? "TX" : "RX"), port_id, val);
+ "%s: underflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
+ if ((val & TAIKO_SLIM_IRQ_OVERFLOW) ||
+ (val & TAIKO_SLIM_IRQ_UNDERFLOW)) {
+ if (!tx)
+ reg = TAIKO_SLIM_PGD_PORT_INT_EN0 +
+ (port_id / 8);
+ else
+ reg = TAIKO_SLIM_PGD_PORT_INT_TX_EN0 +
+ (port_id / 8);
+ int_val = wcd9xxx_interface_reg_read(
+ codec->control_data, reg);
+ if (int_val & (1 << (port_id % 8))) {
+ int_val = int_val ^ (1 << (port_id % 8));
+ wcd9xxx_interface_reg_write(codec->control_data,
+ reg, int_val);
+ }
+ }
if (val & TAIKO_SLIM_IRQ_PORT_CLOSED) {
/*
* INT SOURCE register starts from RX to TX
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index ec99c5f..3d07f15 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -841,7 +841,8 @@
mbhc->zl = mbhc->zr = 0;
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
0, WCD9XXX_JACK_MASK);
- mbhc->hph_status = 0;
+ mbhc->hph_status &= ~(SND_JACK_HEADSET |
+ SND_JACK_LINEOUT);
}
/* Report insertion */
mbhc->hph_status |= jack_type;
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
index 3a055e2..5b12b9c 100644
--- a/sound/soc/msm/apq8074.c
+++ b/sound/soc/msm/apq8074.c
@@ -19,18 +19,22 @@
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
#include <linux/regulator/consumer.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
-#include <asm/mach-types.h>
-#include <mach/socinfo.h>
#include <sound/pcm_params.h>
+#include <asm/mach-types.h>
+#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
+
#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "qdsp6v2/q6core.h"
+#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9320.h"
-#include <linux/io.h>
#define DRV_NAME "apq8074-asoc-taiko"
@@ -82,6 +86,10 @@
#define NUM_OF_AUXPCM_GPIOS 4
+static void *adsp_state_notifier;
+
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
static inline int param_is_mask(int p)
{
return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -1230,6 +1238,101 @@
return true;
}
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int rc;
+ void *config_data;
+
+ pr_debug("%s: enter\n", __func__);
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm8974_adsp_state_callback(struct notifier_block *nb,
+ unsigned long value, void *priv)
+{
+ if (value == SUBSYS_BEFORE_SHUTDOWN) {
+ pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
+ __func__);
+ msm_afe_clear_config();
+ } else if (value == SUBSYS_AFTER_POWERUP) {
+ pr_debug("%s: ADSP is up\n", __func__);
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+ .notifier_call = msm8974_adsp_state_callback,
+ .priority = -INT_MAX,
+};
+
+static int msm8974_taiko_codec_up(struct snd_soc_codec *codec)
+{
+ int err;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (!q6core_is_adsp_ready()) {
+ pr_err("%s: ADSP Audio isn't ready\n", __func__);
+ } else {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ err = msm_afe_set_config(codec);
+ if (err)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, err);
+ return err;
+}
+
+static int apq8074_taiko_event_cb(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event codec_event)
+{
+ switch (codec_event) {
+ case WCD9XXX_CODEC_EVENT_CODEC_UP:
+ return msm8974_taiko_codec_up(codec);
+ break;
+ default:
+ pr_err("%s: UnSupported codec event %d\n",
+ __func__, codec_event);
+ return -EINVAL;
+ }
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -1291,19 +1394,9 @@
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
- config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
- err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ err = msm_afe_set_config(codec);
if (err) {
- pr_err("%s: Failed to set codec registers config %d\n",
- __func__, err);
- goto out;
- }
-
- config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
- err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
- if (err) {
- pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
- err);
+ pr_err("%s: Failed to set AFE config %d\n", __func__, err);
goto out;
}
@@ -1340,12 +1433,23 @@
err = taiko_hs_detect(codec, &mbhc_cfg);
if (err)
goto out;
- else
- return err;
} else {
err = -ENOMEM;
goto out;
}
+ adsp_state_notifier =
+ subsys_notif_register_notifier("adsp",
+ &adsp_state_notifier_block);
+ if (!adsp_state_notifier) {
+ pr_err("%s: Failed to register adsp state notifier\n",
+ __func__);
+ err = -EFAULT;
+ taiko_hs_detect_exit(codec);
+ goto out;
+ }
+
+ taiko_event_register(apq8074_taiko_event_cb, rtd->codec);
+ return 0;
out:
clk_put(codec_clk);
return err;
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 8187616..cc2fd50 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -718,11 +718,22 @@
int result = 0;
pr_debug("%s,\n", __func__);
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
+ goto done;
+ }
if (cal_size > MAX_COL_SIZE) {
pr_err("%s: col size is to big %d\n", __func__, cal_size);
result = -EINVAL;
goto done;
}
+ if (acdb_data.col_data[vocproc_type] == NULL) {
+ pr_err("%s: vocproc_type %d data not allocated!\n",
+ __func__, vocproc_type);
+ result = -EINVAL;
+ goto done;
+ }
if (copy_from_user(acdb_data.col_data[vocproc_type],
(void *)((uint8_t *)cal_block + sizeof(cal_size)),
cal_size)) {
@@ -746,6 +757,12 @@
result = -EINVAL;
goto done;
}
+ if (acdb_data.col_data[vocproc_type] == NULL) {
+ pr_err("%s: vocproc_type %d data not allocated!\n",
+ __func__, vocproc_type);
+ result = -EINVAL;
+ goto done;
+ }
cal_block->cal_size = acdb_data.
vocproc_col_cal[vocproc_type].cal_size;
@@ -1042,8 +1059,19 @@
return result;
}
-static void allocate_hw_delay_entries(void)
+static void deallocate_hw_delay_entries(void)
{
+ kfree(acdb_data.hw_delay_rx.delay_info);
+ kfree(acdb_data.hw_delay_tx.delay_info);
+
+ acdb_data.hw_delay_rx.delay_info = NULL;
+ acdb_data.hw_delay_tx.delay_info = NULL;
+}
+
+static int allocate_hw_delay_entries(void)
+{
+ int result = 0;
+
/* Allocate memory for hw delay entries */
acdb_data.hw_delay_rx.num_entries = 0;
acdb_data.hw_delay_tx.num_entries = 0;
@@ -1054,6 +1082,8 @@
if (acdb_data.hw_delay_rx.delay_info == NULL) {
pr_err("%s : Failed to allocate av sync delay entries rx\n",
__func__);
+ result = -ENOMEM;
+ goto done;
}
acdb_data.hw_delay_tx.delay_info =
kmalloc(sizeof(struct hw_delay_entry)*
@@ -1062,7 +1092,44 @@
if (acdb_data.hw_delay_tx.delay_info == NULL) {
pr_err("%s : Failed to allocate av sync delay entries tx\n",
__func__);
+ deallocate_hw_delay_entries();
+ result = -ENOMEM;
+ goto done;
}
+done:
+ return result;
+}
+
+static void deallocate_col_data(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ kfree(acdb_data.col_data[i]);
+ acdb_data.col_data[i] = NULL;
+ }
+}
+
+static int allocate_col_data(void)
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
+ if (acdb_data.col_data[i] == NULL) {
+ pr_err("%s: kmalloc column data failed, type = %d\n",
+ __func__, i);
+ deallocate_col_data();
+ result = -ENOMEM;
+ goto done;
+ }
+ acdb_data.vocproc_col_cal[i].cal_kvaddr =
+ (uint32_t)acdb_data.col_data[i];
+ }
+
+done:
+ return result;
}
static int unmap_cal_tables(void)
@@ -1111,7 +1178,6 @@
static int deregister_memory(void)
{
int result = 0;
- int i;
pr_debug("%s\n", __func__);
if (acdb_data.mem_len == 0)
@@ -1130,13 +1196,8 @@
acdb_data.ion_client = NULL;
acdb_data.ion_handle = NULL;
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- kfree(acdb_data.col_data[i]);
- acdb_data.col_data[i] = NULL;
- }
-
- kfree(acdb_data.hw_delay_tx.delay_info);
- kfree(acdb_data.hw_delay_rx.delay_info);
+ deallocate_col_data();
+ deallocate_hw_delay_entries();
done:
return result;
}
@@ -1144,13 +1205,26 @@
static int register_memory(void)
{
int result;
- int i;
ion_phys_addr_t paddr;
void *kvptr;
unsigned long kvaddr;
unsigned long mem_len;
pr_debug("%s\n", __func__);
+ result = allocate_col_data();
+ if (result) {
+ pr_err("%s: allocate_hw_delay_entries failed, rc = %d\n",
+ __func__, result);
+ goto err_done;
+ }
+
+ result = allocate_hw_delay_entries();
+ if (result) {
+ pr_err("%s: allocate_hw_delay_entries failed, rc = %d\n",
+ __func__, result);
+ goto err_col;
+ }
+
result = msm_audio_ion_import("audio_acdb_client",
&acdb_data.ion_client,
&acdb_data.ion_handle,
@@ -1160,15 +1234,7 @@
if (result) {
pr_err("%s: audio ION alloc failed, rc = %d\n",
__func__, result);
- goto err_ion_handle;
- }
-
- allocate_hw_delay_entries();
-
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
- acdb_data.vocproc_col_cal[i].cal_kvaddr =
- (uint32_t)acdb_data.col_data[i];
+ goto err_hw_delay;
}
kvaddr = (unsigned long)kvptr;
@@ -1181,7 +1247,11 @@
acdb_data.mem_len);
return result;
-err_ion_handle:
+err_hw_delay:
+ deallocate_hw_delay_entries();
+err_col:
+ deallocate_col_data();
+err_done:
acdb_data.mem_len = 0;
return result;
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index bc3f6a7..63bbbdd 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1922,7 +1922,7 @@
{
struct snd_soc_card *card = widget->dapm->card;
int ret;
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
ret = soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
mutex_unlock(&card->dapm_mutex);
return ret;
@@ -1970,7 +1970,7 @@
{
struct snd_soc_card *card = widget->dapm->card;
int ret;
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
mutex_unlock(&card->dapm_mutex);
return ret;
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 9eb96e5..60a401a 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -36,6 +36,7 @@
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack)
{
+ mutex_init(&jack->mutex);
jack->codec = codec;
INIT_LIST_HEAD(&jack->pins);
INIT_LIST_HEAD(&jack->jack_zones);
@@ -75,7 +76,7 @@
codec = jack->codec;
dapm = &codec->dapm;
- mutex_lock(&codec->mutex);
+ mutex_lock(&jack->mutex);
oldstatus = jack->status;
@@ -109,7 +110,7 @@
snd_jack_report(jack->jack, jack->status);
out:
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&jack->mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_jack_report);