Merge "ARM: dts: msm: change ambient light sensor maximum detection range"
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/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index d9a0d59..f969e2f 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,8 @@
- qcom,saw2-spm-cmd-wfi: The WFI command sequence
- qcom,saw2-spm-cmd-ret: The Retention command sequence
- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
+- qcom,saw2-spm-cmd-pc-no-rpm: The Power Collapse command sequence where APPS
+ proc won't inform the RPM.
- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
- qcom,L2-spm-is-apcs-master: Boolean indicates if the target uses L2 SAW to
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/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index e7eae76..714311e 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -86,6 +86,11 @@
for detection of dp line transition during VDD minimization.
- qcom,hsusb-otg-dmsehv-int: If present, indicates mpm interrupt to be configured
for detection of dm line transition during VDD minimization.
+- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
+ mode with device controller for better throughput. With this mode, USB Core
+ runs using PNOC clock and synchronous to it. Hence it is must to have proper
+ "qcom,msm_bus,vectors" to have high bus frequency. User shouldn't try to
+ enable this feature without proper bus voting.
Example HSUSB OTG controller device node :
usb@f9690000 {
@@ -176,12 +181,19 @@
- qcom,android-usb-cdrom : if this property is present then device creates
a new LUN as CD-ROM
- qcom,android-usb-internal-ums : if this property is present then device
- creates a new LUN as internal usb mass storage
+ creates a new LUN as internal usb mass storage.
+- qcom,streaming-func : add list of usb function name. If mention usb function
+ is being enable as part of USB composition, streaming mode is enable with
+ usb device controller to get better throughput. NOTE: Inverted CRC and
+ turnaround timeout is observed on enabling streaming. Hence it is required
+ to see these errors and number of erros on enabling this at USB level to make
+ final decision to enable this feature or not.
Example Android USB device node :
android_usb@fc42b0c8 {
compatible = "qcom,android-usb";
reg = <0xfc42b0c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis","mtp";
};
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-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 2ccb1fb..20e8a96 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -328,7 +328,7 @@
qcom,low-voltage-threshold = <3420000>;
qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
- qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,high-ocv-correction-limit-uv = <250>;
qcom,hold-soc-est = <3>;
qcom,bms-vadc = <&pm8110_vadc>;
qcom,bms-iadc = <&pm8110_iadc>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index b9bcd0c..6d506cc 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -206,7 +206,7 @@
qcom,batt-type = <0>;
qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
- qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,high-ocv-correction-limit-uv = <250>;
qcom,hold-soc-est = <3>;
qcom,low-voltage-threshold = <3420000>;
qcom,bms-vadc = <&pm8226_vadc>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index b540063..520decd 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -135,7 +135,7 @@
qcom,low-voltage-threshold = <3420000>;
qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
- qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,high-ocv-correction-limit-uv = <250>;
qcom,hold-soc-est = <3>;
qcom,bms-vadc = <&pm8941_vadc>;
qcom,bms-iadc = <&pm8941_iadc>;
@@ -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-1080p-cdp.dtsi b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
index e310c17..bb66538 100644
--- a/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
@@ -27,13 +27,23 @@
vcc_i2c-supply = <&pm8226_lvs1>;
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
- synaptics,button-map = <139 102 158>;
+ synaptics,display-coords = <0 0 1079 1919>;
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
};
};
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "synaptics_rmi4_i2c";
+ qcom,disp-maxx = <1079>;
+ qcom,disp-maxy = <1919>;
+ qcom,panel-maxx = <1079>;
+ qcom,panel-maxy = <2084>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
i2c@f9925000 { /* BLSP1 QUP3 */
nfc-nci@0e {
compatible = "qcom,nfc-nci";
diff --git a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
index e58c321..31624de 100644
--- a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
@@ -27,13 +27,23 @@
vcc_i2c-supply = <&pm8226_lvs1>;
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
- synaptics,button-map = <139 102 158>;
+ synaptics,display-coords = <0 0 1079 1919>;
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
};
};
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "synaptics_rmi4_i2c";
+ qcom,disp-maxx = <1079>;
+ qcom,disp-maxy = <1919>;
+ qcom,panel-maxx = <1079>;
+ qcom,panel-maxy = <2084>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
i2c@f9925000 { /* BLSP1 QUP3 */
nfc-nci@0e {
compatible = "qcom,nfc-nci";
diff --git a/arch/arm/boot/dts/msm8226-720p-cdp.dtsi b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
index 3ebe225..9a1eb36 100644
--- a/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
@@ -28,6 +28,7 @@
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
+ synaptics,fw-image-name = "PR1468813.img";
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
diff --git a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
index a4bd8fd..7f4f8fc 100644
--- a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
@@ -28,6 +28,7 @@
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
+ synaptics,fw-image-name = "PR1468813.img";
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 3e2507ff..e2891d1 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -36,7 +36,7 @@
qcom,mdss-wb-off = <0x00011100 0x00013100>;
qcom,mdss-intf-off = <0x00000000 0x00021300>;
qcom,mdss-rot-block-size = <64>;
- qcom,mdss-smp-mb-per-pipe = <2>;
+ qcom,mdss-smp-mb-per-pipe = <4>;
vdd-cx-supply = <&pm8226_s1_corner>;
qcom,vbif-settings = <0x004 0x00000001>,
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-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index eac0bb6..7ff97f6 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -28,6 +28,7 @@
synaptics,reset-gpio = <&msmgpio 16 0x00>;
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
+ synaptics,fw-image-name = "PR1468813.img";
synaptics,i2c-pull-up;
synaptics,power-down;
synaptics,disable-gpios;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 08ebf88..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 {
@@ -283,6 +290,7 @@
qcom,hsusb-otg-otg-control = <2>;
qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
+ qcom,ahb-async-bridge-bypass;
qcom,msm-bus,name = "usb";
qcom,msm-bus,num-cases = <3>;
@@ -297,6 +305,7 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis";
};
hsic_host: hsic@f9a00000 {
@@ -720,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-rumi.dts b/arch/arm/boot/dts/msm8610-rumi.dts
index 7f06485..c22b4f28 100644
--- a/arch/arm/boot/dts/msm8610-rumi.dts
+++ b/arch/arm/boot/dts/msm8610-rumi.dts
@@ -17,7 +17,7 @@
/ {
model = "Qualcomm MSM 8610 Rumi";
compatible = "qcom,msm8610-rumi", "qcom,msm8610", "qcom,rumi";
- qcom,msm-id = <147 15 0>;
+ qcom,board-id = <15 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 33176b9..531ee4b 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -17,7 +17,7 @@
/ {
model = "Qualcomm MSM 8610 Simulator";
compatible = "qcom,msm8610-sim", "qcom,msm8610", "qcom,sim";
- qcom,msm-id = <147 16 0>;
+ qcom,board-id = <16 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8610-v1-cdp.dts b/arch/arm/boot/dts/msm8610-v1-cdp.dts
index beb3976..5a70379 100644
--- a/arch/arm/boot/dts/msm8610-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-v1-cdp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610 CDP";
compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
- qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
- <163 1 0>, <164 1 0>, <166 1 0>;
+ qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v1-mtp.dts b/arch/arm/boot/dts/msm8610-v1-mtp.dts
index 82992a3..c8c8d09 100644
--- a/arch/arm/boot/dts/msm8610-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v1-mtp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610 MTP";
compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
- qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
- <163 8 0>, <164 8 0>, <166 8 0>;
+ qcom,board-id = <8 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 6296692..62aa0f4 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -56,10 +56,10 @@
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x8>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -99,6 +99,9 @@
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+ 11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
qcom,L2-spm-is-apcs-master;
};
@@ -125,28 +128,29 @@
qcom,latency-us = <500>;
qcom,ss-power = <410>;
qcom,energy-overhead = <603400>;
- qcom,time-overhead = <1200>;
+ qcom,time-overhead = <1410>;
};
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <520>;
- qcom,ss-power = <460>;
- qcom,energy-overhead = <704900>;
- qcom,time-overhead = <1300>;
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
};
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11700>;
+ qcom,latency-us = <12700>;
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
};
+
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8610-v2-cdp.dts b/arch/arm/boot/dts/msm8610-v2-cdp.dts
index a6d1d9c..447161f 100644
--- a/arch/arm/boot/dts/msm8610-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-cdp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610v2 CDP";
compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
- qcom,msm-id = <147 1 0x10001>, <165 1 0x10001>, <161 1 0x10001>, <162 1 0x10001>,
- <163 1 0x10001>, <164 1 0x10001>, <166 1 0x10001>;
+ qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
index 405a775..77f5276 100644
--- a/arch/arm/boot/dts/msm8610-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -19,8 +19,7 @@
/ {
model = "Qualcomm MSM 8610v2 MTP";
compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
- qcom,msm-id = <147 8 0x10001>, <165 8 0x10001>, <161 8 0x10001>, <162 8 0x10001>,
- <163 8 0x10001>, <164 8 0x10001>, <166 8 0x10001>;
+ qcom,board-id = <8 0>;
};
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 6c7f2f6..e401f7a 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -56,10 +56,10 @@
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x8>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -101,6 +101,9 @@
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+ 11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
qcom,L2-spm-is-apcs-master;
};
@@ -134,17 +137,27 @@
reg = <0x2>;
qcom,mode = "pc";
qcom,l2 = "l2_cache_gdhs";
- qcom,latency-us = <10700>;
- qcom,ss-power = <325>;
- qcom,energy-overhead = <441250>;
- qcom,time-overhead = <1020>;
+ qcom,latency-us = <11700>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <738750>;
+ qcom,time-overhead = <1410>;
};
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = "pc";
qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11700>;
+ qcom,latency-us = <12700>;
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
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 133757a..1619d1f 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -239,6 +239,7 @@
qcom,hsusb-otg-otg-control = <2>;
qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
+ qcom,ahb-async-bridge-bypass;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
@@ -253,6 +254,25 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ 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 {
@@ -422,7 +442,6 @@
compatible = "qcom,rpm-smd";
rpm-channel-name = "rpm_requests";
rpm-channel-type = <15>; /* SMD_APPS_RPM */
- rpm-standalone;
};
qcom,bcl {
@@ -853,8 +872,8 @@
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <1 618 0 0>,
- <1 618 0 800>;
+ <54 618 0 0>,
+ <54 618 0 800>;
};
qcom,msm-rtb {
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 0da5658..238f02c 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -81,6 +81,7 @@
qcom,mdss-has-bwc;
qcom,mdss-has-decimation;
qcom,mdss-ad-off = <0x0013100 0x00013300>;
+ vdd-cx-supply = <&pm8841_s2_corner>;
};
&mdss_hdmi_tx {
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 efdd8de..8366a41 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -79,7 +79,6 @@
CONFIG_ARM_ARCH_TIMER=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_ENABLE_VMALLOC_SAVING=y
@@ -247,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
@@ -355,7 +355,11 @@
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
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ASHMEM=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index c140a46..02db2f2 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -80,7 +80,6 @@
CONFIG_ARM_ARCH_TIMER=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_ENABLE_VMALLOC_SAVING=y
@@ -249,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
@@ -379,7 +379,11 @@
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
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ASHMEM=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/kernel/signal.c b/arch/arm/kernel/signal.c
index e000e5e..edb73b4 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -440,12 +440,18 @@
*/
thumb = handler & 1;
+#if __LINUX_ARM_ARCH__ >= 7
+ /*
+ * Clear the If-Then Thumb-2 execution state
+ * ARM spec requires this to be all 000s in ARM mode
+ * Snapdragon S4/Krait misbehaves on a Thumb=>ARM
+ * signal transition without this.
+ */
+ cpsr &= ~PSR_IT_MASK;
+#endif
+
if (thumb) {
cpsr |= PSR_T_BIT;
-#if __LINUX_ARM_ARCH__ >= 7
- /* clear the If-Then Thumb-2 execution state */
- cpsr &= ~PSR_IT_MASK;
-#endif
} else
cpsr &= ~PSR_T_BIT;
}
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S
index 650d592..94b0650 100644
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -14,27 +14,15 @@
.text
.align 5
- .word 0
-
-1: subs r2, r2, #4 @ 1 do we have enough
- blt 5f @ 1 bytes to align with?
- cmp r3, #2 @ 1
- strltb r1, [r0], #1 @ 1
- strleb r1, [r0], #1 @ 1
- strb r1, [r0], #1 @ 1
- add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
-/*
- * The pointer is now aligned and the length is adjusted. Try doing the
- * memset again.
- */
ENTRY(memset)
ands r3, r0, #3 @ 1 unaligned?
- bne 1b @ 1
+ mov ip, r0 @ preserve r0 as return value
+ bne 6f @ 1
/*
- * we know that the pointer in r0 is aligned to a word boundary.
+ * we know that the pointer in ip is aligned to a word boundary.
*/
- orr r1, r1, r1, lsl #8
+1: orr r1, r1, r1, lsl #8
orr r1, r1, r1, lsl #16
mov r3, r1
cmp r2, #16
@@ -43,29 +31,28 @@
#if ! CALGN(1)+0
/*
- * We need an extra register for this loop - save the return address and
- * use the LR
+ * We need 2 extra registers for this loop - use r8 and the LR
*/
- str lr, [sp, #-4]!
- mov ip, r1
+ stmfd sp!, {r8, lr}
+ mov r8, r1
mov lr, r1
2: subs r2, r2, #64
- stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
- stmgeia r0!, {r1, r3, ip, lr}
- stmgeia r0!, {r1, r3, ip, lr}
- stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia ip!, {r1, r3, r8, lr} @ 64 bytes at a time.
+ stmgeia ip!, {r1, r3, r8, lr}
+ stmgeia ip!, {r1, r3, r8, lr}
+ stmgeia ip!, {r1, r3, r8, lr}
bgt 2b
- ldmeqfd sp!, {pc} @ Now <64 bytes to go.
+ ldmeqfd sp!, {r8, pc} @ Now <64 bytes to go.
/*
* No need to correct the count; we're only testing bits from now on
*/
tst r2, #32
- stmneia r0!, {r1, r3, ip, lr}
- stmneia r0!, {r1, r3, ip, lr}
+ stmneia ip!, {r1, r3, r8, lr}
+ stmneia ip!, {r1, r3, r8, lr}
tst r2, #16
- stmneia r0!, {r1, r3, ip, lr}
- ldr lr, [sp], #4
+ stmneia ip!, {r1, r3, r8, lr}
+ ldmfd sp!, {r8, lr}
#else
@@ -74,54 +61,63 @@
* whole cache lines at once.
*/
- stmfd sp!, {r4-r7, lr}
+ stmfd sp!, {r4-r8, lr}
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
- mov ip, r1
+ mov r8, r1
mov lr, r1
cmp r2, #96
- tstgt r0, #31
+ tstgt ip, #31
ble 3f
- and ip, r0, #31
- rsb ip, ip, #32
- sub r2, r2, ip
- movs ip, ip, lsl #(32 - 4)
- stmcsia r0!, {r4, r5, r6, r7}
- stmmiia r0!, {r4, r5}
- tst ip, #(1 << 30)
- mov ip, r1
- strne r1, [r0], #4
+ and r8, ip, #31
+ rsb r8, r8, #32
+ sub r2, r2, r8
+ movs r8, r8, lsl #(32 - 4)
+ stmcsia ip!, {r4, r5, r6, r7}
+ stmmiia ip!, {r4, r5}
+ tst r8, #(1 << 30)
+ mov r8, r1
+ strne r1, [ip], #4
3: subs r2, r2, #64
- stmgeia r0!, {r1, r3-r7, ip, lr}
- stmgeia r0!, {r1, r3-r7, ip, lr}
+ stmgeia ip!, {r1, r3-r8, lr}
+ stmgeia ip!, {r1, r3-r8, lr}
bgt 3b
- ldmeqfd sp!, {r4-r7, pc}
+ ldmeqfd sp!, {r4-r8, pc}
tst r2, #32
- stmneia r0!, {r1, r3-r7, ip, lr}
+ stmneia ip!, {r1, r3-r8, lr}
tst r2, #16
- stmneia r0!, {r4-r7}
- ldmfd sp!, {r4-r7, lr}
+ stmneia ip!, {r4-r7}
+ ldmfd sp!, {r4-r8, lr}
#endif
4: tst r2, #8
- stmneia r0!, {r1, r3}
+ stmneia ip!, {r1, r3}
tst r2, #4
- strne r1, [r0], #4
+ strne r1, [ip], #4
/*
* When we get here, we've got less than 4 bytes to zero. We
* may have an unaligned pointer as well.
*/
5: tst r2, #2
- strneb r1, [r0], #1
- strneb r1, [r0], #1
+ strneb r1, [ip], #1
+ strneb r1, [ip], #1
tst r2, #1
- strneb r1, [r0], #1
+ strneb r1, [ip], #1
mov pc, lr
+
+6: subs r2, r2, #4 @ 1 do we have enough
+ blt 5b @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strltb r1, [ip], #1 @ 1
+ strleb r1, [ip], #1 @ 1
+ strb r1, [ip], #1 @ 1
+ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
+ b 1b
ENDPROC(memset)
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 60be20a..5117949 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -95,159 +95,7 @@
},
};
-static struct msm_bus_paths bw_level_tbl_v1[] __initdata = {
- [0] = BW_MBPS(600), /* At least 75 MHz on bus. */
- [1] = BW_MBPS(800), /* At least 100 MHz on bus. */
- [2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
- [3] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [4] = BW_MBPS(2224), /* At least 278 MHz on bus. */
- [5] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [6] = BW_MBPS(4448), /* At least 556 MHz on bus. */
- [7] = BW_MBPS(6400), /* At least 800 MHz on bus. */
-};
-
-static struct l2_level l2_freq_tbl_v1[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
- [1] = { { 345600, HFPLL, 2, 36 }, LVL_NOM, 950000, 1 },
- [2] = { { 422400, HFPLL, 2, 44 }, LVL_NOM, 950000, 1 },
- [3] = { { 499200, HFPLL, 2, 52 }, LVL_NOM, 950000, 2 },
- [4] = { { 576000, HFPLL, 1, 30 }, LVL_NOM, 950000, 3 },
- [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 950000, 3 },
- [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 950000, 3 },
- [7] = { { 806400, HFPLL, 1, 42 }, LVL_HIGH, 1050000, 4 },
- [8] = { { 883200, HFPLL, 1, 46 }, LVL_HIGH, 1050000, 4 },
- [9] = { { 960000, HFPLL, 1, 50 }, LVL_HIGH, 1050000, 4 },
- [10] = { { 1036800, HFPLL, 1, 54 }, LVL_HIGH, 1050000, 5 },
- [11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 5 },
- [12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 6 },
- [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 6 },
- [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 7 },
- [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 7 },
- [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
- { }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 835000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 845000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 860000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 835000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 845000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 860000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 835000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 855000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 835000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 855000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 825000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 825000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 835000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 855000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 870000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 885000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 900000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 925000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 940000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 950000, 506 },
- { 0, { 0 } }
-};
-
-static struct msm_bus_paths bw_level_tbl_v2[] __initdata = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(600), /* At least 75 MHz on bus. */
[1] = BW_MBPS(800), /* At least 100 MHz on bus. */
[2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
@@ -259,7 +107,7 @@
[8] = BW_MBPS(7448), /* At least 931 MHz on bus. */
};
-static struct l2_level l2_freq_tbl_v2[] __initdata = {
+static struct l2_level l2_freq_tbl[] __initdata = {
[0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
[1] = { { 345600, HFPLL, 2, 36 }, LVL_LOW, 950000, 1 },
[2] = { { 422400, HFPLL, 2, 44 }, LVL_LOW, 950000, 2 },
@@ -2440,15 +2288,6 @@
{ 0, { 0 } }
};
-static struct pvs_table pvs_v1[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
- /* 8974v1 1.7GHz Parts */
- [0][0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
- [0][0][1] = { acpu_freq_tbl_v1_pvs1, sizeof(acpu_freq_tbl_v1_pvs1) },
- [0][0][2] = { acpu_freq_tbl_v1_pvs2, sizeof(acpu_freq_tbl_v1_pvs2) },
- [0][0][3] = { acpu_freq_tbl_v1_pvs3, sizeof(acpu_freq_tbl_v1_pvs3) },
- [0][0][4] = { acpu_freq_tbl_v1_pvs4, sizeof(acpu_freq_tbl_v1_pvs4) },
-};
-
static struct pvs_table pvs_v2[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
/* 8974v2 2.0GHz Parts */
[0][0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
@@ -2560,8 +2399,8 @@
};
static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl_v2,
- .num_usecases = ARRAY_SIZE(bw_level_tbl_v2),
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
.name = "acpuclk-8974",
};
@@ -2570,68 +2409,23 @@
.scalable = scalable,
.scalable_size = sizeof(scalable),
.hfpll_data = &hfpll_data,
- .pvs_tables = pvs_v2,
- .l2_freq_tbl = l2_freq_tbl_v2,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl_v2),
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0xFC4B80B0,
.get_bin_info = get_krait_bin_format_b,
.stby_khz = 300000,
};
-static void __init apply_pro_bringup_workaround(void)
-{
- acpuclk_8974_params.pvs_tables = pvs_pro;
-}
-
-static void __init apply_v1_l2_workaround(void)
-{
- static struct l2_level resticted_l2_tbl[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 1050000, 0 },
- [1] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
- { }
- };
- struct acpu_level *l;
- int s, p, r;
-
- for (r = 0; r < NUM_PVS_REVS; r++)
- for (s = 0; s < NUM_SPEED_BINS; s++)
- for (p = 0; p < NUM_PVS; p++) {
- l = pvs_v1[r][s][p].table;
- for (; l && l->speed.khz; l++)
- l->l2_level = l->l2_level > 5 ? 1 : 0;
- }
-
- acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
- acpuclk_8974_params.l2_freq_tbl_size = sizeof(resticted_l2_tbl);
-}
-
#define cpu_is_msm8974pro() (cpu_is_msm8974pro_aa() || cpu_is_msm8974pro_ab() \
|| cpu_is_msm8974pro_ac())
static int __init acpuclk_8974_probe(struct platform_device *pdev)
{
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1
- && cpu_is_msm8974()) {
- acpuclk_8974_params.pvs_tables = pvs_v1;
- acpuclk_8974_params.l2_freq_tbl = l2_freq_tbl_v1;
- bus_scale_data.usecase = bw_level_tbl_v1;
- bus_scale_data.num_usecases = ARRAY_SIZE(bw_level_tbl_v1);
- acpuclk_8974_params.l2_freq_tbl_size = sizeof(l2_freq_tbl_v1);
-
- /*
- * 8974 hardware revisions older than v1.2 may experience L2
- * parity errors when running at some performance points between
- * 300MHz and 1497.6MHz (non-inclusive), or when vdd_mx is less
- * than 1.05V. Restrict L2 operation to safe performance points
- * on these devices.
- */
- if (SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
- apply_v1_l2_workaround();
- }
-
if (cpu_is_msm8974pro())
- apply_pro_bringup_workaround();
+ acpuclk_8974_params.pvs_tables = pvs_pro;
+ else
+ acpuclk_8974_params.pvs_tables = pvs_v2;
return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
}
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..da0e500 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
};
@@ -1278,6 +1279,7 @@
.en_mask = BIT(5),
.base = &virt_bases[GCC_BASE],
.c = {
+ .parent = &ce1_clk_src.c,
.dbg_name = "gcc_ce1_clk",
.ops = &clk_ops_vote,
CLK_INIT(gcc_ce1_clk.c),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 89d462c..5e312aa 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,
};
@@ -1283,6 +1285,7 @@
.en_mask = BIT(5),
.base = &virt_bases[GCC_BASE],
.c = {
+ .parent = &ce1_clk_src.c,
.dbg_name = "gcc_ce1_clk",
.ops = &clk_ops_vote,
CLK_INIT(gcc_ce1_clk.c),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 03fcb25..d41b52b 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -578,17 +578,6 @@
| BVAL(10, 8, s##_mm_source_val), \
}
-#define F_HDMI(f, s, div, m, n) \
- { \
- .freq_hz = (f), \
- .src_clk = &s##_clk_src, \
- .m_val = (m), \
- .n_val = ~((n)-(m)) * !!(n), \
- .d_val = ~(n),\
- .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
- | BVAL(10, 8, s##_mm_source_val), \
- }
-
#define F_MDSS(f, s, div, m, n) \
{ \
.freq_hz = (f), \
@@ -2200,6 +2189,7 @@
.en_mask = BIT(5),
.base = &virt_bases[GCC_BASE],
.c = {
+ .parent = &ce1_clk_src.c,
.dbg_name = "gcc_ce1_clk",
.ops = &clk_ops_vote,
CLK_INIT(gcc_ce1_clk.c),
@@ -2236,6 +2226,7 @@
.en_mask = BIT(2),
.base = &virt_bases[GCC_BASE],
.c = {
+ .parent = &ce2_clk_src.c,
.dbg_name = "gcc_ce2_clk",
.ops = &clk_ops_vote,
CLK_INIT(gcc_ce2_clk.c),
@@ -3253,60 +3244,19 @@
},
};
-static int hdmi_pll_clk_enable(struct clk *c)
-{
- return hdmi_pll_enable();
-}
-
-static void hdmi_pll_clk_disable(struct clk *c)
-{
- hdmi_pll_disable();
-}
-
-static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
-{
- return hdmi_pll_set_rate(rate);
-}
-
-static struct clk_ops clk_ops_hdmi_pll = {
- .enable = hdmi_pll_clk_enable,
- .disable = hdmi_pll_clk_disable,
- .set_rate = hdmi_pll_clk_set_rate,
-};
-
-static struct clk hdmipll_clk_src = {
- .parent = &cxo_clk_src.c,
- .dbg_name = "hdmipll_clk_src",
- .ops = &clk_ops_hdmi_pll,
- CLK_INIT(hdmipll_clk_src),
-};
-
static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
- /*
- * The zero rate is required since suspend/resume wipes out the HDMI PHY
- * registers. This entry allows the HDMI driver to switch the cached
- * rate to zero before suspend and back to the real rate after resume.
- */
- F_HDMI( 0, hdmipll, 1, 0, 0),
- F_HDMI( 25200000, hdmipll, 1, 0, 0),
- F_HDMI( 27000000, hdmipll, 1, 0, 0),
- F_HDMI( 27030000, hdmipll, 1, 0, 0),
- F_HDMI( 65000000, hdmipll, 1, 0, 0),
- F_HDMI( 74250000, hdmipll, 1, 0, 0),
- F_HDMI(108000000, hdmipll, 1, 0, 0),
- F_HDMI(148500000, hdmipll, 1, 0, 0),
- F_HDMI(268500000, hdmipll, 1, 0, 0),
- F_HDMI(297000000, hdmipll, 1, 0, 0),
+ F_MM(148500000, hdmipll, 1, 0, 0),
F_END
};
static struct rcg_clk extpclk_clk_src = {
.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
.freq_tbl = ftbl_mdss_extpclk_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = ftbl_mdss_extpclk_clk,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "extpclk_clk_src",
+ .parent = &hdmipll_clk_src.c,
.ops = &clk_ops_rcg_hdmi,
VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
CLK_INIT(extpclk_clk_src.c),
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/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 4488869..62ecfa8 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -774,27 +774,35 @@
*/
static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
{
- struct clk_freq_tbl *nf;
struct rcg_clk *rcg = to_rcg_clk(c);
+ struct clk_freq_tbl *nf = rcg->freq_tbl;
int rc;
- for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
- if (nf->freq_hz == FREQ_END) {
- rc = -EINVAL;
- goto out;
- }
-
rc = clk_set_rate(nf->src_clk, rate);
if (rc < 0)
goto out;
set_rate_hid(rcg, nf);
rcg->current_freq = nf;
- c->parent = nf->src_clk;
out:
return rc;
}
+static struct clk *rcg_hdmi_clk_get_parent(struct clk *c)
+{
+ struct rcg_clk *rcg = to_rcg_clk(c);
+ struct clk_freq_tbl *freq = rcg->freq_tbl;
+ u32 cmd_rcgr_regval;
+
+ /* Is there a pending configuration? */
+ cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
+ if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
+ return NULL;
+
+ rcg->current_freq->freq_hz = clk_get_rate(c->parent);
+
+ return freq->src_clk;
+}
#define ENABLE_REG(x) (*(x)->base + (x)->enable_reg)
#define SELECT_REG(x) (*(x)->base + (x)->select_reg)
@@ -987,7 +995,7 @@
.list_rate = rcg_clk_list_rate,
.round_rate = rcg_clk_round_rate,
.handoff = rcg_clk_handoff,
- .get_parent = rcg_clk_get_parent,
+ .get_parent = rcg_hdmi_clk_get_parent,
};
struct clk_ops clk_ops_branch = {
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index cf2df18..343a6c6 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -167,23 +167,71 @@
(!(readl_relaxed(gdsc_base) & BIT(0)));
}
-void hdmi_pll_disable(void)
+/* Auto PLL calibaration */
+static int mdss_ahb_clk_enable(int enable)
{
- clk_enable(mdss_ahb_clk);
+ int rc = 0;
+
+ /* todo: Ideally, we should enable/disable GDSC whenever we are
+ * attempting to enable/disable MDSS AHB clock.
+ * For now, just return error if GDSC is not enabled.
+ */
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return -EPERM;
+ }
+
+ if (enable)
+ rc = clk_prepare_enable(mdss_ahb_clk);
+ else
+ clk_disable_unprepare(mdss_ahb_clk);
+
+ return rc;
+}
+
+static void hdmi_vco_disable(struct clk *c)
+{
+ u32 rc;
+
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return;
+ }
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return;
+ }
+
REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
udelay(5);
REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+
clk_disable(mdss_ahb_clk);
hdmi_pll_on = 0;
-} /* hdmi_pll_disable */
+} /* hdmi_vco_disable */
-int hdmi_pll_enable(void)
+static int hdmi_vco_enable(struct clk *c)
{
u32 status;
+ u32 rc;
u32 max_reads, timeout_us;
- clk_enable(mdss_ahb_clk);
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return -EPERM;
+ }
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
/* Global Enable */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
/* Power up power gen */
@@ -208,7 +256,7 @@
status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
__func__, status);
- hdmi_pll_disable();
+ hdmi_vco_disable(c);
clk_disable(mdss_ahb_clk);
return -EINVAL;
}
@@ -222,7 +270,7 @@
status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
pr_err("%s: hdmi phy status=%x failed to Lock\n",
__func__, status);
- hdmi_pll_disable();
+ hdmi_vco_disable(c);
clk_disable(mdss_ahb_clk);
return -EINVAL;
}
@@ -232,25 +280,173 @@
hdmi_pll_on = 1;
return 0;
-} /* hdmi_pll_enable */
+} /* hdmi_vco_enable */
-int hdmi_pll_set_rate(unsigned long rate)
+static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk)
+{
+ return container_of(clk, struct hdmi_pll_vco_clk, c);
+}
+
+static void hdmi_phy_pll_calculator(u32 vco_freq)
+{
+ u32 ref_clk = 19200000;
+ u32 sdm_mode = 1;
+ u32 ref_clk_multiplier = sdm_mode == 1 ? 2 : 1;
+ u32 int_ref_clk_freq = ref_clk * ref_clk_multiplier;
+ u32 fbclk_pre_div = 1;
+ u32 ssc_mode = 0;
+ u32 kvco = 270;
+ u32 vdd = 95;
+ u32 ten_power_six = 1000000;
+ u32 ssc_ds_ppm = ssc_mode ? 5000 : 0;
+ u32 sdm_res = 16;
+ u32 ssc_tri_step = 32;
+ u32 ssc_freq = 2;
+ u64 ssc_ds = vco_freq * ssc_ds_ppm;
+ u32 div_in_freq = vco_freq / fbclk_pre_div;
+ u64 dc_offset = (div_in_freq / int_ref_clk_freq - 1) *
+ ten_power_six * 10;
+ u32 ssc_kdiv = (int_ref_clk_freq / ssc_freq) -
+ ten_power_six;
+ u64 sdm_freq_seed;
+ u32 ssc_tri_inc;
+ u64 fb_div_n;
+
+ u32 val;
+
+ pr_debug("%s: vco_freq = %u\n", __func__, vco_freq);
+
+ do_div(ssc_ds, (u64)ten_power_six);
+
+ fb_div_n = (u64)div_in_freq * (u64)ten_power_six * 10;
+ do_div(fb_div_n, int_ref_clk_freq);
+
+ sdm_freq_seed = ((fb_div_n - dc_offset - ten_power_six * 10) *
+ (1 << sdm_res) * 10) + 5;
+ do_div(sdm_freq_seed, ((u64)ten_power_six * 100));
+
+ ssc_tri_inc = (u32)ssc_ds;
+ ssc_tri_inc = (ssc_tri_inc / int_ref_clk_freq) * (1 << 16) /
+ ssc_tri_step;
+
+ val = (ref_clk_multiplier == 2 ? 1 : 0) +
+ ((fbclk_pre_div == 2 ? 1 : 0) * 16);
+ pr_debug("%s: HDMI_UNI_PLL_REFCLK_CFG = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+
+ REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CHFPUMP_CFG);
+ REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_PWRGEN_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+ REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+
+ do_div(dc_offset, (u64)ten_power_six * 10);
+ val = sdm_mode == 0 ? 64 + dc_offset : 0;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG0 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+
+ val = 64 + dc_offset;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG1 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+
+ val = sdm_freq_seed & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG2 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+
+ val = (sdm_freq_seed >> 8) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG3 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+
+ val = (sdm_freq_seed >> 16) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SDM_CFG4 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+
+ val = (ssc_mode == 0 ? 128 : 0) + (ssc_kdiv / ten_power_six);
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG0 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG0);
+
+ val = ssc_tri_inc & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG1 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG1);
+
+ val = (ssc_tri_inc >> 8) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG2 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG2);
+
+ pr_debug("%s: HDMI_UNI_PLL_SSC_CFG3 = 0x%x\n", __func__, ssc_tri_step);
+ REG_W(ssc_tri_step, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG3);
+
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x0A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG0);
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG1);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG4);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG5);
+
+ val = (kvco * vdd * 10000) / 6;
+ val += 500000;
+ val /= ten_power_six;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG6 = 0x%x\n", __func__, val);
+ REG_W(val & 0xFF, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG6);
+
+ val = (kvco * vdd * 10000) / 6;
+ val -= ten_power_six;
+ val /= ten_power_six;
+ val = (val >> 8) & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG7 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG7);
+
+ val = (ref_clk * 5) / ten_power_six;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG8 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+
+ val = ((ref_clk * 5) / ten_power_six) >> 8;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG9 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+
+ vco_freq /= ten_power_six;
+ val = vco_freq & 0xFF;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG10 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+
+ val = vco_freq >> 8;
+ pr_debug("%s: HDMI_UNI_PLL_CAL_CFG11 = 0x%x\n", __func__, val);
+ REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+} /* hdmi_phy_pll_calculator */
+
+static int hdmi_vco_set_rate(struct clk *c, unsigned long rate)
{
unsigned int set_power_dwn = 0;
+ int rc = 0;
+
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
if (hdmi_pll_on) {
- hdmi_pll_disable();
+ hdmi_vco_disable(c);
set_power_dwn = 1;
}
- clk_enable(mdss_ahb_clk);
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
pr_debug("%s: rate=%ld\n", __func__, rate);
+
switch (rate) {
case 0:
- /* This case is needed for suspend/resume. */
- break;
+ break;
- case 25200000:
+ case 756000000:
/* 640x480p60 */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -267,7 +463,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -295,7 +490,7 @@
udelay(200);
break;
- case 27000000:
+ case 810000000:
/* 576p50/576i50 case */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -312,7 +507,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0X1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -340,7 +534,7 @@
udelay(200);
break;
- case 27030000:
+ case 810900000:
/* 480p60/480i60 case */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -357,7 +551,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -384,7 +577,7 @@
REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
udelay(200);
break;
- case 65000000:
+ case 650000000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -400,7 +593,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -427,7 +619,7 @@
REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
udelay(200);
break;
- case 74250000:
+ case 742500000:
/*
* 720p60/720p50/1080i60/1080i50
* 1080p24/1080p30/1080p25 case
@@ -447,7 +639,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -475,7 +666,7 @@
udelay(200);
break;
- case 108000000:
+ case 1080000000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -491,7 +682,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -519,51 +709,7 @@
udelay(200);
break;
- case 148500000:
- REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
- REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
- REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
- REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
- REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
- REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
- REG_W(0x56, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
- REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
- REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
- REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
- REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
- REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
- REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
- REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
- REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
- udelay(50);
-
- REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
- REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
- REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
- REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
- REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
- REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
- REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
- REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
- REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
- REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
- REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
- udelay(200);
- break;
-
- case 268500000:
+ case 1342500000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -579,7 +725,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -607,7 +752,7 @@
udelay(200);
break;
- case 297000000:
+ case 1485000000:
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -623,7 +768,6 @@
REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
- REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -652,40 +796,68 @@
break;
default:
- pr_err("%s: not supported rate=%ld\n", __func__, rate);
+ pr_debug("%s: Use pll settings calculator for rate=%ld\n",
+ __func__, rate);
+
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ hdmi_phy_pll_calculator(rate);
+ REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(50);
+
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+ REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+ REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+
+ if (rate < 825000000) {
+ REG_W(0x01, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ } else if (rate >= 825000000 && rate < 1342500000) {
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ } else {
+ REG_W(0x06, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+ REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+ }
+
+ REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+ REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+ REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+
+ if (rate < 825000000)
+ REG_W(0x01, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+ else
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+
+ REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+ REG_W(0x62, hdmi_phy_base + HDMI_PHY_BIST_PATN0);
+ REG_W(0x03, hdmi_phy_base + HDMI_PHY_BIST_PATN1);
+ REG_W(0x69, hdmi_phy_base + HDMI_PHY_BIST_PATN2);
+ REG_W(0x02, hdmi_phy_base + HDMI_PHY_BIST_PATN3);
+
+ udelay(200);
+
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG1);
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG0);
}
/* Make sure writes complete before disabling iface clock */
mb();
- clk_disable(mdss_ahb_clk);
+ mdss_ahb_clk_enable(0);
if (set_power_dwn)
- hdmi_pll_enable();
+ hdmi_vco_enable(c);
+
+ vco->rate = rate;
+ vco->rate_set = true;
return 0;
} /* hdmi_pll_set_rate */
-/* Auto PLL calibaration */
-int mdss_ahb_clk_enable(int enable)
-{
- int rc = 0;
-
- /* todo: Ideally, we should enable/disable GDSC whenever we are
- * attempting to enable/disable MDSS AHB clock.
- * For now, just return error if GDSC is not enabled.
- */
- if (!mdss_gdsc_enabled())
- return -EPERM;
-
- if (enable)
- rc = clk_prepare_enable(mdss_ahb_clk);
- else
- clk_disable_unprepare(mdss_ahb_clk);
-
- return rc;
-}
-
int set_byte_mux_sel(struct mux_clk *clk, int sel)
{
pr_debug("%s: byte mux set to %s mode\n", __func__,
@@ -1649,6 +1821,271 @@
},
};
+/* HDMI PLL DIV CLK */
+
+static unsigned long hdmi_vco_get_rate(struct clk *c)
+{
+ unsigned long freq = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+ return freq;
+ }
+
+ freq = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG11) << 8 |
+ DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG10);
+
+ switch (freq) {
+ case 742:
+ freq = 742500000;
+ break;
+ case 810:
+ if (DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_SDM_CFG3) == 0x18)
+ freq = 810000000;
+ else
+ freq = 810900000;
+ break;
+ case 1342:
+ freq = 1342500000;
+ break;
+ default:
+ freq *= 1000000;
+ }
+
+ mdss_ahb_clk_enable(0);
+
+ return freq;
+}
+
+static long hdmi_vco_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ pr_debug("%s: rrate=%ld\n", __func__, rrate);
+
+ return rrate;
+}
+
+static int hdmi_vco_prepare(struct clk *c)
+{
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+ int ret = 0;
+
+ pr_debug("%s: rate=%ld\n", __func__, vco->rate);
+
+ if (!vco->rate_set && vco->rate)
+ ret = hdmi_vco_set_rate(c, vco->rate);
+
+ if (!ret)
+ ret = clk_prepare(mdss_ahb_clk);
+
+ return ret;
+}
+
+static void hdmi_vco_unprepare(struct clk *c)
+{
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+
+ vco->rate_set = false;
+
+ clk_unprepare(mdss_ahb_clk);
+}
+
+static int hdmi_pll_lock_status(void)
+{
+ u32 status;
+ int pll_locked = 0;
+ int rc;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return 0;
+ }
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((hdmi_phy_base + HDMI_PHY_STATUS),
+ status, ((status & BIT(0)) == 1),
+ PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+ pr_debug("%s: HDMI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pll_locked = 0;
+ } else {
+ pll_locked = 1;
+ }
+ mdss_ahb_clk_enable(0);
+
+ return pll_locked;
+}
+
+static enum handoff hdmi_vco_handoff(struct clk *c)
+{
+ enum handoff ret = HANDOFF_DISABLED_CLK;
+
+ if (hdmi_pll_lock_status()) {
+ c->rate = hdmi_vco_get_rate(c);
+ ret = HANDOFF_ENABLED_CLK;
+ }
+
+ pr_debug("%s: done, ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static struct clk_ops hdmi_vco_clk_ops = {
+ .enable = hdmi_vco_enable,
+ .set_rate = hdmi_vco_set_rate,
+ .get_rate = hdmi_vco_get_rate,
+ .round_rate = hdmi_vco_round_rate,
+ .prepare = hdmi_vco_prepare,
+ .unprepare = hdmi_vco_unprepare,
+ .disable = hdmi_vco_disable,
+ .handoff = hdmi_vco_handoff,
+};
+
+static struct hdmi_pll_vco_clk hdmi_vco_clk = {
+ .min_rate = 600000000,
+ .max_rate = 1800000000,
+ .c = {
+ .dbg_name = "hdmi_vco_clk",
+ .ops = &hdmi_vco_clk_ops,
+ CLK_INIT(hdmi_vco_clk.c),
+ },
+};
+
+static struct div_clk hdmipll_div1_clk = {
+ .div = 1,
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div1_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div1_clk.c),
+ },
+};
+
+static struct div_clk hdmipll_div2_clk = {
+ .div = 2,
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div2_clk.c),
+ },
+};
+
+static struct div_clk hdmipll_div4_clk = {
+ .div = 4,
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div4_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div4_clk.c),
+ },
+};
+
+static struct div_clk hdmipll_div6_clk = {
+ .div = 6,
+ .c = {
+ .parent = &hdmi_vco_clk.c,
+ .dbg_name = "hdmipll_div6_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(hdmipll_div6_clk.c),
+ },
+};
+
+static int hdmipll_set_mux_sel(struct mux_clk *clk, int mux_sel)
+{
+ int rc;
+
+ if (!mdss_gdsc_enabled()) {
+ pr_err("%s: mdss GDSC is not enabled\n", __func__);
+ return -EPERM;
+ }
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+ return rc;
+ }
+
+ pr_debug("%s: mux_sel=%d\n", __func__, mux_sel);
+ DSS_REG_W(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG, mux_sel);
+
+ clk_disable(mdss_ahb_clk);
+
+ return 0;
+}
+
+static int hdmipll_get_mux_sel(struct mux_clk *clk)
+{
+ int mux_sel = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+ return mux_sel;
+ }
+
+ mux_sel = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG);
+ mux_sel &= 0x03;
+ pr_debug("%s: mux_sel=%d\n", __func__, mux_sel);
+
+ mdss_ahb_clk_enable(0);
+
+ return mux_sel;
+}
+
+static struct clk_mux_ops hdmipll_mux_ops = {
+ .set_mux_sel = hdmipll_set_mux_sel,
+ .get_mux_sel = hdmipll_get_mux_sel,
+};
+
+static struct clk_ops hdmi_mux_ops;
+
+static int hdmi_mux_prepare(struct clk *c)
+{
+ int ret = 0;
+
+ if (c && c->ops && c->ops->set_rate)
+ ret = c->ops->set_rate(c, c->rate);
+
+ return ret;
+}
+
+static struct mux_clk hdmipll_mux_clk = {
+ MUX_SRC_LIST(
+ { &hdmipll_div1_clk.c, 0 },
+ { &hdmipll_div2_clk.c, 1 },
+ { &hdmipll_div4_clk.c, 2 },
+ { &hdmipll_div6_clk.c, 3 },
+ ),
+ .ops = &hdmipll_mux_ops,
+ .c = {
+ .parent = &hdmipll_div1_clk.c,
+ .dbg_name = "hdmipll_mux_clk",
+ .ops = &hdmi_mux_ops,
+ CLK_INIT(hdmipll_mux_clk.c),
+ },
+};
+
+struct div_clk hdmipll_clk_src = {
+ .div = 5,
+ .c = {
+ .parent = &hdmipll_mux_clk.c,
+ .dbg_name = "hdmipll_clk_src",
+ .ops = &clk_ops_div,
+ CLK_INIT(hdmipll_clk_src.c),
+ },
+};
+
void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
{
BUG_ON(ahb_clk == NULL);
@@ -1682,5 +2119,8 @@
byte_mux_clk_ops = clk_ops_gen_mux;
byte_mux_clk_ops.prepare = mux_prepare;
+
+ hdmi_mux_ops = clk_ops_gen_mux;
+ hdmi_mux_ops.prepare = hdmi_mux_prepare;
}
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index 9fd3026..b1d5b45 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -22,9 +22,15 @@
void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
void mdss_clk_ctrl_post_init(void);
-int hdmi_pll_enable(void);
-void hdmi_pll_disable(void);
-int hdmi_pll_set_rate(unsigned long rate);
+
+struct hdmi_pll_vco_clk {
+ unsigned long rate; /* current vco rate */
+ unsigned long min_rate; /* min vco rate */
+ unsigned long max_rate; /* max vco rate */
+ bool rate_set;
+
+ struct clk c;
+};
struct lpfr_cfg {
unsigned long vco_rate;
@@ -57,4 +63,6 @@
extern struct mux_clk byte_mux_8226;
extern struct div_clk byte_clk_src_8226;
+extern struct div_clk hdmipll_clk_src;
+
#endif
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 7c06268..c480e56 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -112,8 +112,8 @@
continue;
state = &msm_cpuidle_driver.states[state_count];
- snprintf(state->name, CPUIDLE_NAME_LEN, cstate->name);
- snprintf(state->desc, CPUIDLE_DESC_LEN, cstate->desc);
+ snprintf(state->name, CPUIDLE_NAME_LEN, "%s", cstate->name);
+ snprintf(state->desc, CPUIDLE_DESC_LEN, "%s", cstate->desc);
state->flags = 0;
state->exit_latency = 0;
state->power_usage = 0;
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
index ff3da11..3973044 100644
--- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
@@ -30,6 +30,7 @@
bool down_mix);
int (*get_audio_edid_blk) (struct platform_device *pdev,
struct msm_hdmi_audio_edid_blk *blk);
+ int (*hdmi_cable_status) (struct platform_device *pdev, u32 vote);
};
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 20a5249..1d5e0d9 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -553,7 +553,8 @@
ida_simple_remove(&domain_nums, data->domain_num);
for (i = 0; i < data->npools; ++i)
- gen_pool_destroy(data->pools[i].gpool);
+ if (data->pools[i].gpool)
+ gen_pool_destroy(data->pools[i].gpool);
kfree(data->pools);
kfree(data);
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/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
deleted file mode 100644
index 8aacb56..0000000
--- a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
+++ /dev/null
@@ -1,1731 +0,0 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/msm_audio.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <mach/qdsp6v2/audio_dev_ctl.h>
-#include <mach/debug_mm.h>
-#include <mach/qdsp6v2/q6voice.h>
-#include <sound/apr_audio.h>
-#include <sound/q6adm.h>
-
-#ifndef MAX
-#define MAX(x, y) (((x) > (y)) ? (x) : (y))
-#endif
-
-
-static DEFINE_MUTEX(session_lock);
-static struct workqueue_struct *msm_reset_device_work_queue;
-static void reset_device_work(struct work_struct *work);
-static DECLARE_WORK(msm_reset_device_work, reset_device_work);
-
-struct audio_dev_ctrl_state {
- struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
- u32 num_dev;
- atomic_t opened;
- struct msm_snddev_info *voice_rx_dev;
- struct msm_snddev_info *voice_tx_dev;
- wait_queue_head_t wait;
-};
-
-static struct audio_dev_ctrl_state audio_dev_ctrl;
-struct event_listner event;
-
-struct session_freq {
- int freq;
- int evt;
-};
-
-struct audio_routing_info {
- unsigned short mixer_mask[MAX_SESSIONS];
- unsigned short audrec_mixer_mask[MAX_SESSIONS];
- struct session_freq dec_freq[MAX_SESSIONS];
- struct session_freq enc_freq[MAX_SESSIONS];
- unsigned int copp_list[MAX_SESSIONS][AFE_MAX_PORTS];
- int voice_tx_dev_id;
- int voice_rx_dev_id;
- int voice_tx_sample_rate;
- int voice_rx_sample_rate;
- signed int voice_tx_vol;
- signed int voice_rx_vol;
- int tx_mute;
- int rx_mute;
- int voice_state;
- struct mutex copp_list_mutex;
- struct mutex adm_mutex;
-};
-
-static struct audio_routing_info routing_info;
-
-struct audio_copp_topology {
- struct mutex lock;
- int session_cnt;
- int session_id[MAX_SESSIONS];
- int topolog_id[MAX_SESSIONS];
-};
-static struct audio_copp_topology adm_tx_topology_tbl;
-
-int msm_reset_all_device(void)
-{
- int rc = 0;
- int dev_id = 0;
- struct msm_snddev_info *dev_info = NULL;
-
- for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info)) {
- pr_err("%s:pass invalid dev_id\n", __func__);
- rc = PTR_ERR(dev_info);
- return rc;
- }
- if (!dev_info->opened)
- continue;
- pr_debug("%s:Resetting device %d active on COPP %d"
- "with %lld as routing\n", __func__,
- dev_id, dev_info->copp_id, dev_info->sessions);
- broadcast_event(AUDDEV_EVT_REL_PENDING,
- dev_id,
- SESSION_IGNORE);
- rc = dev_info->dev_ops.close(dev_info);
- if (rc < 0) {
- pr_err("%s:Snd device failed close!\n", __func__);
- return rc;
- } else {
- dev_info->opened = 0;
- broadcast_event(AUDDEV_EVT_DEV_RLS,
- dev_id,
- SESSION_IGNORE);
-
- if (dev_info->copp_id == VOICE_PLAYBACK_TX)
- voice_start_playback(0);
- }
- dev_info->sessions = 0;
- }
- msm_clear_all_session();
- return 0;
-}
-EXPORT_SYMBOL(msm_reset_all_device);
-
-static void reset_device_work(struct work_struct *work)
-{
- msm_reset_all_device();
-}
-
-int reset_device(void)
-{
- queue_work(msm_reset_device_work_queue, &msm_reset_device_work);
- return 0;
-}
-EXPORT_SYMBOL(reset_device);
-
-int msm_set_copp_id(int session_id, int copp_id)
-{
- int rc = 0;
- int index;
-
- if (session_id < 1 || session_id > 8)
- return -EINVAL;
- if (afe_validate_port(copp_id) < 0)
- return -EINVAL;
-
- index = afe_get_port_index(copp_id);
- if (index < 0 || index > AFE_MAX_PORTS)
- return -EINVAL;
- pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
- session_id, copp_id, index);
- mutex_lock(&routing_info.copp_list_mutex);
- if (routing_info.copp_list[session_id][index] == COPP_IGNORE)
- routing_info.copp_list[session_id][index] = copp_id;
- mutex_unlock(&routing_info.copp_list_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_set_copp_id);
-
-int msm_clear_copp_id(int session_id, int copp_id)
-{
- int rc = 0;
- int index = afe_get_port_index(copp_id);
-
- if (session_id < 1 || session_id > 8)
- return -EINVAL;
- pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
- session_id, copp_id, index);
- mutex_lock(&routing_info.copp_list_mutex);
- if (routing_info.copp_list[session_id][index] == copp_id)
- routing_info.copp_list[session_id][index] = COPP_IGNORE;
-#ifdef CONFIG_MSM8X60_RTAC
- rtac_remove_adm_device(copp_id, session_id);
-#endif
- mutex_unlock(&routing_info.copp_list_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_clear_copp_id);
-
-int msm_clear_session_id(int session_id)
-{
- int rc = 0;
- int i = 0;
- if (session_id < 1 || session_id > 8)
- return -EINVAL;
- pr_debug("%s: session[%d]\n", __func__, session_id);
- mutex_lock(&routing_info.adm_mutex);
- mutex_lock(&routing_info.copp_list_mutex);
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[session_id][i] != COPP_IGNORE) {
- rc = adm_close(routing_info.copp_list[session_id][i]);
- if (rc < 0) {
- pr_err("%s: adm close fail port[%d] rc[%d]\n",
- __func__,
- routing_info.copp_list[session_id][i],
- rc);
- continue;
- }
-#ifdef CONFIG_MSM8X60_RTAC
- rtac_remove_adm_device(
- routing_info.copp_list[session_id][i], session_id);
-#endif
- routing_info.copp_list[session_id][i] = COPP_IGNORE;
- rc = 0;
- }
- }
- mutex_unlock(&routing_info.copp_list_mutex);
- mutex_unlock(&routing_info.adm_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_clear_session_id);
-
-int msm_clear_all_session()
-{
- int rc = 0;
- int i = 0, j = 0;
- pr_info("%s:\n", __func__);
- mutex_lock(&routing_info.adm_mutex);
- mutex_lock(&routing_info.copp_list_mutex);
- for (j = 1; j < MAX_SESSIONS; j++) {
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[j][i] != COPP_IGNORE) {
- rc = adm_close(
- routing_info.copp_list[j][i]);
- if (rc < 0) {
- pr_err("%s: adm close fail copp[%d]"
- "session[%d] rc[%d]\n",
- __func__,
- routing_info.copp_list[j][i],
- j, rc);
- continue;
- }
- routing_info.copp_list[j][i] = COPP_IGNORE;
- rc = 0;
- }
- }
- }
- mutex_unlock(&routing_info.copp_list_mutex);
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-EXPORT_SYMBOL(msm_clear_all_session);
-
-int msm_get_voice_state(void)
-{
- pr_debug("voice state %d\n", routing_info.voice_state);
- return routing_info.voice_state;
-}
-EXPORT_SYMBOL(msm_get_voice_state);
-
-int msm_set_voice_mute(int dir, int mute, u32 session_id)
-{
- pr_debug("dir %x mute %x\n", dir, mute);
- if (dir == DIR_TX) {
- routing_info.tx_mute = mute;
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
- routing_info.voice_tx_dev_id, session_id);
- } else
- return -EPERM;
- return 0;
-}
-EXPORT_SYMBOL(msm_set_voice_mute);
-
-int msm_set_voice_vol(int dir, s32 volume, u32 session_id)
-{
- if (dir == DIR_TX) {
- routing_info.voice_tx_vol = volume;
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
- routing_info.voice_tx_dev_id,
- session_id);
- } else if (dir == DIR_RX) {
- routing_info.voice_rx_vol = volume;
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
- routing_info.voice_rx_dev_id,
- session_id);
- } else
- return -EINVAL;
- return 0;
-}
-EXPORT_SYMBOL(msm_set_voice_vol);
-
-void msm_snddev_register(struct msm_snddev_info *dev_info)
-{
- mutex_lock(&session_lock);
- if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
- audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
- /* roughly 0 DB for digital gain
- * If default gain is not desirable, it is expected that
- * application sets desired gain before activating sound
- * device
- */
- dev_info->dev_volume = 75;
- dev_info->sessions = 0x0;
- dev_info->usage_count = 0;
- audio_dev_ctrl.num_dev++;
- } else
- pr_err("%s: device registry max out\n", __func__);
- mutex_unlock(&session_lock);
-}
-EXPORT_SYMBOL(msm_snddev_register);
-
-int msm_snddev_devcount(void)
-{
- return audio_dev_ctrl.num_dev;
-}
-EXPORT_SYMBOL(msm_snddev_devcount);
-
-int msm_snddev_query(int dev_id)
-{
- if (dev_id <= audio_dev_ctrl.num_dev)
- return 0;
- return -ENODEV;
-}
-EXPORT_SYMBOL(msm_snddev_query);
-
-int msm_snddev_is_set(int popp_id, int copp_id)
-{
- return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
-}
-EXPORT_SYMBOL(msm_snddev_is_set);
-
-unsigned short msm_snddev_route_enc(int enc_id)
-{
- if (enc_id >= MAX_SESSIONS)
- return -EINVAL;
- return routing_info.audrec_mixer_mask[enc_id];
-}
-EXPORT_SYMBOL(msm_snddev_route_enc);
-
-unsigned short msm_snddev_route_dec(int popp_id)
-{
- if (popp_id >= MAX_SESSIONS)
- return -EINVAL;
- return routing_info.mixer_mask[popp_id];
-}
-EXPORT_SYMBOL(msm_snddev_route_dec);
-
-/*To check one->many case*/
-int msm_check_multicopp_per_stream(int session_id,
- struct route_payload *payload)
-{
- int i = 0;
- int flag = 0;
- pr_debug("%s: session_id=%d\n", __func__, session_id);
- mutex_lock(&routing_info.copp_list_mutex);
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[session_id][i] == COPP_IGNORE)
- continue;
- else {
- pr_debug("Device enabled\n");
- payload->copp_ids[flag++] =
- routing_info.copp_list[session_id][i];
- }
- }
- mutex_unlock(&routing_info.copp_list_mutex);
- if (flag > 1) {
- pr_debug("Multiple copp per stream case num_copps=%d\n", flag);
- } else {
- pr_debug("Stream routed to single copp\n");
- }
- payload->num_copps = flag;
- return flag;
-}
-
-int msm_snddev_set_dec(int popp_id, int copp_id, int set,
- int rate, int mode)
-{
- int rc = 0, i = 0, num_copps;
- struct route_payload payload;
-
- if ((popp_id >= MAX_SESSIONS) || (popp_id <= 0)) {
- pr_err("%s: Invalid session id %d\n", __func__, popp_id);
- return 0;
- }
-
- mutex_lock(&routing_info.adm_mutex);
- if (set) {
- rc = adm_open(copp_id, ADM_PATH_PLAYBACK, rate, mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
- rc = -EINVAL;
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
- }
- msm_set_copp_id(popp_id, copp_id);
- pr_debug("%s:Session id=%d copp_id=%d\n",
- __func__, popp_id, copp_id);
- memset(payload.copp_ids, COPP_IGNORE,
- (sizeof(unsigned int) * AFE_MAX_PORTS));
- num_copps = msm_check_multicopp_per_stream(popp_id, &payload);
- /* Multiple streams per copp is handled, one stream at a time */
- rc = adm_matrix_map(popp_id, ADM_PATH_PLAYBACK, num_copps,
- payload.copp_ids, copp_id);
- if (rc < 0) {
- pr_err("%s: matrix map failed rc[%d]\n",
- __func__, rc);
- adm_close(copp_id);
- rc = -EINVAL;
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
- }
-#ifdef CONFIG_MSM8X60_RTAC
- for (i = 0; i < num_copps; i++)
- rtac_add_adm_device(payload.copp_ids[i], popp_id);
-#endif
- } else {
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[popp_id][i] == copp_id) {
- rc = adm_close(copp_id);
- if (rc < 0) {
- pr_err("%s: adm close fail copp[%d]"
- "rc[%d]\n",
- __func__, copp_id, rc);
- rc = -EINVAL;
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
- }
- msm_clear_copp_id(popp_id, copp_id);
- break;
- }
- }
- }
-
- if (copp_id == VOICE_PLAYBACK_TX) {
- /* Signal uplink playback. */
- rc = voice_start_playback(set);
- }
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_set_dec);
-
-
-static int check_tx_copp_topology(int session_id)
-{
- int cnt;
- int ret_val = -ENOENT;
-
- cnt = adm_tx_topology_tbl.session_cnt;
- if (cnt) {
- do {
- if (adm_tx_topology_tbl.session_id[cnt-1]
- == session_id)
- ret_val = cnt-1;
- } while (--cnt);
- }
-
- return ret_val;
-}
-
-static int add_to_tx_topology_lists(int session_id, int topology)
-{
- int idx = 0, tbl_idx;
- int ret_val = -ENOSPC;
-
- mutex_lock(&adm_tx_topology_tbl.lock);
-
- tbl_idx = check_tx_copp_topology(session_id);
- if (tbl_idx == -ENOENT) {
- while (adm_tx_topology_tbl.session_id[idx++])
- ;
- tbl_idx = idx-1;
- }
-
- if (tbl_idx < MAX_SESSIONS) {
- adm_tx_topology_tbl.session_id[tbl_idx] = session_id;
- adm_tx_topology_tbl.topolog_id[tbl_idx] = topology;
- adm_tx_topology_tbl.session_cnt++;
-
- ret_val = 0;
- }
- mutex_unlock(&adm_tx_topology_tbl.lock);
- return ret_val;
-}
-
-static void remove_from_tx_topology_lists(int session_id)
-{
- int tbl_idx;
-
- mutex_lock(&adm_tx_topology_tbl.lock);
- tbl_idx = check_tx_copp_topology(session_id);
- if (tbl_idx != -ENOENT) {
-
- adm_tx_topology_tbl.session_cnt--;
- adm_tx_topology_tbl.session_id[tbl_idx] = 0;
- adm_tx_topology_tbl.topolog_id[tbl_idx] = 0;
- }
- mutex_unlock(&adm_tx_topology_tbl.lock);
-}
-
-int auddev_cfg_tx_copp_topology(int session_id, int cfg)
-{
- int ret = 0;
-
- if (cfg == DEFAULT_COPP_TOPOLOGY)
- remove_from_tx_topology_lists(session_id);
- else {
- switch (cfg) {
- case VPM_TX_SM_ECNS_COPP_TOPOLOGY:
- case VPM_TX_DM_FLUENCE_COPP_TOPOLOGY:
- ret = add_to_tx_topology_lists(session_id, cfg);
- break;
-
- default:
- ret = -ENODEV;
- break;
- }
- }
- return ret;
-}
-
-int msm_snddev_set_enc(int popp_id, int copp_id, int set,
- int rate, int mode)
-{
- int topology;
- int tbl_idx;
- int rc = 0, i = 0;
- mutex_lock(&routing_info.adm_mutex);
- if (set) {
- mutex_lock(&adm_tx_topology_tbl.lock);
- tbl_idx = check_tx_copp_topology(popp_id);
- if (tbl_idx == -ENOENT)
- topology = DEFAULT_COPP_TOPOLOGY;
- else {
- topology = adm_tx_topology_tbl.topolog_id[tbl_idx];
- rate = 16000;
- }
- mutex_unlock(&adm_tx_topology_tbl.lock);
- rc = adm_open(copp_id, ADM_PATH_LIVE_REC, rate, mode, topology);
- if (rc < 0) {
- pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
- rc = -EINVAL;
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
- (unsigned int *)&copp_id, copp_id);
- if (rc < 0) {
- pr_err("%s: matrix map failed rc[%d]\n", __func__, rc);
- adm_close(copp_id);
- rc = -EINVAL;
- goto fail_cmd;
- }
- msm_set_copp_id(popp_id, copp_id);
-#ifdef CONFIG_MSM8X60_RTAC
- rtac_add_adm_device(copp_id, popp_id);
-#endif
-
- } else {
- for (i = 0; i < AFE_MAX_PORTS; i++) {
- if (routing_info.copp_list[popp_id][i] == copp_id) {
- rc = adm_close(copp_id);
- if (rc < 0) {
- pr_err("%s: adm close fail copp[%d]"
- "rc[%d]\n",
- __func__, copp_id, rc);
- rc = -EINVAL;
- goto fail_cmd;
- }
- msm_clear_copp_id(popp_id, copp_id);
- break;
- }
- }
- }
-fail_cmd:
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_set_enc);
-
-int msm_device_is_voice(int dev_id)
-{
- if ((dev_id == routing_info.voice_rx_dev_id)
- || (dev_id == routing_info.voice_tx_dev_id))
- return 0;
- else
- return -EINVAL;
-}
-EXPORT_SYMBOL(msm_device_is_voice);
-
-int msm_set_voc_route(struct msm_snddev_info *dev_info,
- int stream_type, int dev_id)
-{
- int rc = 0;
- u64 session_mask = 0;
-
- mutex_lock(&session_lock);
- switch (stream_type) {
- case AUDIO_ROUTE_STREAM_VOICE_RX:
- if (audio_dev_ctrl.voice_rx_dev)
- audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFFFF;
-
- if (!(dev_info->capability & SNDDEV_CAP_RX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
- audio_dev_ctrl.voice_rx_dev = dev_info;
- if (audio_dev_ctrl.voice_rx_dev) {
- session_mask =
- ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
- ((int)AUDDEV_CLNT_VOC-1));
- audio_dev_ctrl.voice_rx_dev->sessions |=
- session_mask;
- }
- routing_info.voice_rx_dev_id = dev_id;
- break;
- case AUDIO_ROUTE_STREAM_VOICE_TX:
- if (audio_dev_ctrl.voice_tx_dev)
- audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFFFF;
-
- if (!(dev_info->capability & SNDDEV_CAP_TX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
-
- audio_dev_ctrl.voice_tx_dev = dev_info;
- if (audio_dev_ctrl.voice_rx_dev) {
- session_mask =
- ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
- ((int)AUDDEV_CLNT_VOC-1));
- audio_dev_ctrl.voice_tx_dev->sessions |=
- session_mask;
- }
- routing_info.voice_tx_dev_id = dev_id;
- break;
- default:
- rc = -EINVAL;
- }
- mutex_unlock(&session_lock);
- return rc;
-}
-EXPORT_SYMBOL(msm_set_voc_route);
-
-void msm_release_voc_thread(void)
-{
- wake_up(&audio_dev_ctrl.wait);
-}
-EXPORT_SYMBOL(msm_release_voc_thread);
-
-int msm_snddev_get_enc_freq(session_id)
-{
- return routing_info.enc_freq[session_id].freq;
-}
-EXPORT_SYMBOL(msm_snddev_get_enc_freq);
-
-int msm_get_voc_freq(int *tx_freq, int *rx_freq)
-{
- *tx_freq = routing_info.voice_tx_sample_rate;
- *rx_freq = routing_info.voice_rx_sample_rate;
- return 0;
-}
-EXPORT_SYMBOL(msm_get_voc_freq);
-
-int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
-{
- int rc = 0;
-
- if (!rx_id || !tx_id)
- return -EINVAL;
-
- mutex_lock(&session_lock);
- if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
- rc = -ENODEV;
- mutex_unlock(&session_lock);
- return rc;
- }
-
- *rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
- *tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
-
- mutex_unlock(&session_lock);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_get_voc_route);
-
-struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
-{
- struct msm_snddev_info *info;
-
- if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
- info = ERR_PTR(-ENODEV);
- goto error;
- }
-
- info = audio_dev_ctrl.devs[dev_id];
-error:
- return info;
-
-}
-EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
-
-int snddev_voice_set_volume(int vol, int path)
-{
- if (audio_dev_ctrl.voice_rx_dev
- && audio_dev_ctrl.voice_tx_dev) {
- if (path)
- audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
- else
- audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
- } else
- return -ENODEV;
- return 0;
-}
-EXPORT_SYMBOL(snddev_voice_set_volume);
-
-static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
- void __user *arg)
-{
- int rc = 0;
- u32 index;
- struct msm_snd_device_list work_list;
- struct msm_snd_device_info *work_tbl;
-
- if (copy_from_user(&work_list, arg, sizeof(work_list))) {
- rc = -EFAULT;
- goto error;
- }
-
- if (work_list.num_dev > dev_ctrl->num_dev) {
- rc = -EINVAL;
- goto error;
- }
-
- work_tbl = kmalloc(work_list.num_dev *
- sizeof(struct msm_snd_device_info), GFP_KERNEL);
- if (!work_tbl) {
- rc = -ENOMEM;
- goto error;
- }
-
- for (index = 0; index < dev_ctrl->num_dev; index++) {
- work_tbl[index].dev_id = index;
- work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
- strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
- 64);
- }
-
- if (copy_to_user((void *) (work_list.list), work_tbl,
- work_list.num_dev * sizeof(struct msm_snd_device_info)))
- rc = -EFAULT;
- kfree(work_tbl);
-error:
- return rc;
-}
-
-
-int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
- void (*listner)(u32 evt_id,
- union auddev_evt_data *evt_payload,
- void *private_data),
- void *private_data)
-{
- int rc;
- struct msm_snd_evt_listner *callback = NULL;
- struct msm_snd_evt_listner *new_cb;
-
- new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
- if (!new_cb) {
- pr_err("No memory to add new listener node\n");
- return -ENOMEM;
- }
-
- mutex_lock(&session_lock);
- new_cb->cb_next = NULL;
- new_cb->auddev_evt_listener = listner;
- new_cb->evt_id = evt_id;
- new_cb->clnt_type = clnt_type;
- new_cb->clnt_id = clnt_id;
- new_cb->private_data = private_data;
- if (event.cb == NULL) {
- event.cb = new_cb;
- new_cb->cb_prev = NULL;
- } else {
- callback = event.cb;
- for (; ;) {
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- callback->cb_next = new_cb;
- new_cb->cb_prev = callback;
- }
- event.num_listner++;
- mutex_unlock(&session_lock);
- rc = 0;
- return rc;
-}
-EXPORT_SYMBOL(auddev_register_evt_listner);
-
-int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
-{
- struct msm_snd_evt_listner *callback = event.cb;
- struct msm_snddev_info *info;
- u64 session_mask = 0;
- int i = 0;
-
- mutex_lock(&session_lock);
- while (callback != NULL) {
- if ((callback->clnt_type == clnt_type)
- && (callback->clnt_id == clnt_id))
- break;
- callback = callback->cb_next;
- }
- if (callback == NULL) {
- mutex_unlock(&session_lock);
- return -EINVAL;
- }
-
- if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
- event.cb = NULL;
- else if (callback->cb_next == NULL)
- callback->cb_prev->cb_next = NULL;
- else if (callback->cb_prev == NULL) {
- callback->cb_next->cb_prev = NULL;
- event.cb = callback->cb_next;
- } else {
- callback->cb_prev->cb_next = callback->cb_next;
- callback->cb_next->cb_prev = callback->cb_prev;
- }
- kfree(callback);
-
- session_mask = (((u64)0x1) << clnt_id) << (MAX_BIT_PER_CLIENT * \
- ((int)clnt_type-1));
- for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
- info = audio_dev_ctrl.devs[i];
- info->sessions &= ~session_mask;
- }
- mutex_unlock(&session_lock);
- return 0;
-}
-EXPORT_SYMBOL(auddev_unregister_evt_listner);
-
-int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
-{
- int i = 0;
- struct msm_snddev_info *info;
- u64 session_mask = 0;
-
- if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_DEC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_ENC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
-
- session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
- ((int)clnt_type-1));
-
- for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
- info = audio_dev_ctrl.devs[i];
- if ((info->sessions & session_mask)
- && (info->capability & capability)) {
- if (!(info->sessions & ~(session_mask)))
- info->set_sample_rate = 0;
- }
- }
- if (clnt_type == AUDDEV_CLNT_DEC)
- routing_info.dec_freq[session_id].freq
- = 0;
- else if (clnt_type == AUDDEV_CLNT_ENC)
- routing_info.enc_freq[session_id].freq
- = 0;
- else if (capability == SNDDEV_CAP_TX)
- routing_info.voice_tx_sample_rate = 0;
- else
- routing_info.voice_rx_sample_rate = 48000;
- return 0;
-}
-
-int msm_snddev_request_freq(int *freq, u32 session_id,
- u32 capability, u32 clnt_type)
-{
- int i = 0;
- int rc = 0;
- struct msm_snddev_info *info;
- u32 set_freq;
- u64 session_mask = 0;
- u64 clnt_type_mask = 0;
-
- pr_debug(": clnt_type 0x%08x\n", clnt_type);
-
- if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_DEC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
- if ((clnt_type == AUDDEV_CLNT_ENC)
- && (session_id >= MAX_SESSIONS))
- return -EINVAL;
- session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
- ((int)clnt_type-1));
- clnt_type_mask = (0xFFFF << (MAX_BIT_PER_CLIENT * (clnt_type-1)));
- if (!(*freq == 8000) && !(*freq == 11025) &&
- !(*freq == 12000) && !(*freq == 16000) &&
- !(*freq == 22050) && !(*freq == 24000) &&
- !(*freq == 32000) && !(*freq == 44100) &&
- !(*freq == 48000))
- return -EINVAL;
-
- for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
- info = audio_dev_ctrl.devs[i];
- if ((info->sessions & session_mask)
- && (info->capability & capability)) {
- rc = 0;
- if ((info->sessions & ~clnt_type_mask)
- && ((*freq != 8000) && (*freq != 16000)
- && (*freq != 48000))) {
- if (clnt_type == AUDDEV_CLNT_ENC) {
- routing_info.enc_freq[session_id].freq
- = 0;
- return -EPERM;
- } else if (clnt_type == AUDDEV_CLNT_DEC) {
- routing_info.dec_freq[session_id].freq
- = 0;
- return -EPERM;
- }
- }
- if (*freq == info->set_sample_rate) {
- rc = info->set_sample_rate;
- continue;
- }
- set_freq = MAX(*freq, info->set_sample_rate);
-
-
- if (clnt_type == AUDDEV_CLNT_DEC) {
- routing_info.dec_freq[session_id].evt = 1;
- routing_info.dec_freq[session_id].freq
- = set_freq;
- } else if (clnt_type == AUDDEV_CLNT_ENC) {
- routing_info.enc_freq[session_id].evt = 1;
- routing_info.enc_freq[session_id].freq
- = set_freq;
- } else if (capability == SNDDEV_CAP_TX)
- routing_info.voice_tx_sample_rate = set_freq;
-
- rc = set_freq;
- info->set_sample_rate = set_freq;
- *freq = info->set_sample_rate;
-
- if (info->opened) {
- broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
- SESSION_IGNORE);
- set_freq = info->dev_ops.set_freq(info,
- set_freq);
- broadcast_event(AUDDEV_EVT_DEV_RDY, i,
- SESSION_IGNORE);
- }
- }
- pr_debug("info->set_sample_rate = %d\n", info->set_sample_rate);
- pr_debug("routing_info.enc_freq.freq = %d\n",
- routing_info.enc_freq[session_id].freq);
- }
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_request_freq);
-
-int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain)
-{
- int rc;
- struct msm_snddev_info *dev_info;
-
- pr_debug("dev_id %d enable %d\n", dev_id, enable);
-
- dev_info = audio_dev_ctrl_find_dev(dev_id);
-
- if (IS_ERR(dev_info)) {
- pr_err("bad dev_id %d\n", dev_id);
- rc = -EINVAL;
- } else if (!dev_info->dev_ops.enable_sidetone) {
- pr_debug("dev %d no sidetone support\n", dev_id);
- rc = -EPERM;
- } else
- rc = dev_info->dev_ops.enable_sidetone(dev_info, enable, gain);
-
- return rc;
-}
-EXPORT_SYMBOL(msm_snddev_enable_sidetone);
-
-int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
- int channel_mode)
-{
- int rc = 0;
- unsigned int port_id[2];
- port_id[0] = VOICE_RECORD_TX;
- port_id[1] = VOICE_RECORD_RX;
-
- pr_debug("%s: popp_id %d, rec_mode %d, rate %d, channel_mode %d\n",
- __func__, popp_id, rec_mode, rate, channel_mode);
-
- mutex_lock(&routing_info.adm_mutex);
-
- if (rec_mode == VOC_REC_UPLINK) {
- rc = afe_start_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[0], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
- &port_id[0], port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM matrix map %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[0]);
-
- } else if (rec_mode == VOC_REC_DOWNLINK) {
- rc = afe_start_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[1], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
- &port_id[1], port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM matrix map %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[1]);
-
- } else if (rec_mode == VOC_REC_BOTH) {
- rc = afe_start_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[0], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[0]);
-
- rc = afe_start_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port start\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- rc = adm_open(port_id[1], ADM_PATH_LIVE_REC, rate, channel_mode,
- DEFAULT_COPP_TOPOLOGY);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM open %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 2,
- &port_id[0], port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM matrix map\n",
- __func__, rc);
-
- goto fail_cmd;
- }
-
- msm_set_copp_id(popp_id, port_id[1]);
- } else {
- pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
-
- goto fail_cmd;
- }
-
- rc = voice_start_record(rec_mode, 1);
-
-fail_cmd:
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-
-int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode)
-{
- int rc = 0;
- uint32_t port_id[2];
- port_id[0] = VOICE_RECORD_TX;
- port_id[1] = VOICE_RECORD_RX;
-
- pr_debug("%s: popp_id %d, rec_mode %d\n", __func__, popp_id, rec_mode);
-
- mutex_lock(&routing_info.adm_mutex);
-
- rc = voice_start_record(rec_mode, 0);
- if (rc < 0) {
- pr_err("%s: Error %d stopping record\n", __func__, rc);
-
- goto fail_cmd;
- }
-
- if (rec_mode == VOC_REC_UPLINK) {
- rc = adm_close(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[0]);
-
- rc = afe_stop_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
-
- } else if (rec_mode == VOC_REC_DOWNLINK) {
- rc = adm_close(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[1]);
-
- rc = afe_stop_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
- } else if (rec_mode == VOC_REC_BOTH) {
- rc = adm_close(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[0]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[0]);
-
- rc = afe_stop_pseudo_port(port_id[0]);
- if (rc < 0) {
- pr_err("%s: Error %d in Tx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
-
- rc = adm_close(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in ADM close %d\n",
- __func__, rc, port_id[1]);
-
- goto fail_cmd;
- }
-
- msm_clear_copp_id(popp_id, port_id[1]);
-
- rc = afe_stop_pseudo_port(port_id[1]);
- if (rc < 0) {
- pr_err("%s: Error %d in Rx pseudo port stop\n",
- __func__, rc);
- goto fail_cmd;
- }
- } else {
- pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
-
- goto fail_cmd;
- }
-
-fail_cmd:
- mutex_unlock(&routing_info.adm_mutex);
- return rc;
-}
-
-static long audio_dev_ctrl_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int rc = 0;
- struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
-
- mutex_lock(&session_lock);
- switch (cmd) {
- case AUDIO_GET_NUM_SND_DEVICE:
- rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
- break;
- case AUDIO_GET_SND_DEVICES:
- rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
- break;
- case AUDIO_ENABLE_SND_DEVICE: {
- struct msm_snddev_info *dev_info;
- u32 dev_id;
-
- if (get_user(dev_id, (u32 __user *) arg)) {
- rc = -EFAULT;
- break;
- }
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info))
- rc = PTR_ERR(dev_info);
- else {
- rc = dev_info->dev_ops.open(dev_info);
- if (!rc)
- dev_info->opened = 1;
- wake_up(&audio_dev_ctrl.wait);
- }
- break;
-
- }
-
- case AUDIO_DISABLE_SND_DEVICE: {
- struct msm_snddev_info *dev_info;
- u32 dev_id;
-
- if (get_user(dev_id, (u32 __user *) arg)) {
- rc = -EFAULT;
- break;
- }
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info))
- rc = PTR_ERR(dev_info);
- else {
- rc = dev_info->dev_ops.close(dev_info);
- dev_info->opened = 0;
- }
- break;
- }
-
- case AUDIO_ROUTE_STREAM: {
- struct msm_audio_route_config route_cfg;
- struct msm_snddev_info *dev_info;
-
- if (copy_from_user(&route_cfg, (void __user *) arg,
- sizeof(struct msm_audio_route_config))) {
- rc = -EFAULT;
- break;
- }
- pr_debug("%s: route cfg %d %d type\n", __func__,
- route_cfg.dev_id, route_cfg.stream_type);
- dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
- if (IS_ERR(dev_info)) {
- pr_err("%s: pass invalid dev_id\n", __func__);
- rc = PTR_ERR(dev_info);
- break;
- }
-
- switch (route_cfg.stream_type) {
-
- case AUDIO_ROUTE_STREAM_VOICE_RX:
- if (!(dev_info->capability & SNDDEV_CAP_RX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
- dev_ctrl->voice_rx_dev = dev_info;
- break;
- case AUDIO_ROUTE_STREAM_VOICE_TX:
- if (!(dev_info->capability & SNDDEV_CAP_TX) |
- !(dev_info->capability & SNDDEV_CAP_VOICE)) {
- rc = -EINVAL;
- break;
- }
- dev_ctrl->voice_tx_dev = dev_info;
- break;
- }
- break;
- }
-
- default:
- rc = -EINVAL;
- }
- mutex_unlock(&session_lock);
- return rc;
-}
-
-static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
-{
- pr_debug("open audio_dev_ctrl\n");
- atomic_inc(&audio_dev_ctrl.opened);
- file->private_data = &audio_dev_ctrl;
- return 0;
-}
-
-static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
-{
- pr_debug("release audio_dev_ctrl\n");
- atomic_dec(&audio_dev_ctrl.opened);
- return 0;
-}
-
-static const struct file_operations audio_dev_ctrl_fops = {
- .owner = THIS_MODULE,
- .open = audio_dev_ctrl_open,
- .release = audio_dev_ctrl_release,
- .unlocked_ioctl = audio_dev_ctrl_ioctl,
-};
-
-
-struct miscdevice audio_dev_ctrl_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "msm_audio_dev_ctrl",
- .fops = &audio_dev_ctrl_fops,
-};
-
-/* session id is 64 bit routing mask per device
- * 0-15 for voice clients
- * 16-31 for Decoder clients
- * 32-47 for Encoder clients
- * 48-63 Do not care
- */
-void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id)
-{
- int clnt_id = 0, i;
- union auddev_evt_data *evt_payload;
- struct msm_snd_evt_listner *callback;
- struct msm_snddev_info *dev_info = NULL;
- u64 session_mask = 0;
- static int pending_sent;
-
- pr_debug(": evt_id = %d\n", evt_id);
-
- if ((evt_id != AUDDEV_EVT_START_VOICE)
- && (evt_id != AUDDEV_EVT_END_VOICE)
- && (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
- && (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
- dev_info = audio_dev_ctrl_find_dev(dev_id);
- if (IS_ERR(dev_info)) {
- pr_err("%s: pass invalid dev_id(%d)\n",
- __func__, dev_id);
- return;
- }
- }
-
- if (event.cb != NULL)
- callback = event.cb;
- else
- return;
- mutex_lock(&session_lock);
-
- if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- routing_info.voice_state = dev_id;
-
- evt_payload = kzalloc(sizeof(union auddev_evt_data),
- GFP_KERNEL);
-
- if (evt_payload == NULL) {
- pr_err("broadcast_event: cannot allocate memory\n");
- mutex_unlock(&session_lock);
- return;
- }
- for (; ;) {
- if (!(evt_id & callback->evt_id)) {
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- clnt_id = callback->clnt_id;
- memset(evt_payload, 0, sizeof(union auddev_evt_data));
-
- if ((evt_id == AUDDEV_EVT_START_VOICE)
- || (evt_id == AUDDEV_EVT_END_VOICE)
- || evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG)
- goto skip_check;
- if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
- goto aud_cal;
-
- session_mask = (((u64)0x1) << clnt_id)
- << (MAX_BIT_PER_CLIENT * \
- ((int)callback->clnt_type-1));
-
- if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
- (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
- pr_debug("AUDDEV_EVT_STREAM_VOL_CHG or\
- AUDDEV_EVT_VOICE_STATE_CHG\n");
- goto volume_strm;
- }
-
- pr_debug("dev_info->sessions = %llu\n", dev_info->sessions);
-
- if ((!session_id && !(dev_info->sessions & session_mask)) ||
- (session_id && ((dev_info->sessions & session_mask) !=
- session_id))) {
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
- goto voc_events;
-
-volume_strm:
- if (callback->clnt_type == AUDDEV_CLNT_DEC) {
- pr_debug("AUDDEV_CLNT_DEC\n");
- if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
- pr_debug("clnt_id = %d, session_id = %llu\n",
- clnt_id, session_id);
- if (session_mask != session_id)
- goto sent_dec;
- else
- evt_payload->session_vol =
- msm_vol_ctl.volume;
- } else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
- if (routing_info.dec_freq[clnt_id].evt) {
- routing_info.dec_freq[clnt_id].evt
- = 0;
- goto sent_dec;
- } else if (routing_info.dec_freq[clnt_id].freq
- == dev_info->set_sample_rate)
- goto sent_dec;
- else {
- evt_payload->freq_info.sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.dev_type
- = dev_info->capability;
- evt_payload->freq_info.acdb_dev_id
- = dev_info->acdb_id;
- }
- } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else
- evt_payload->routing_id = dev_info->copp_id;
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
-sent_dec:
- if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
- (evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
- routing_info.dec_freq[clnt_id].freq
- = dev_info->set_sample_rate;
-
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- if (callback->clnt_type == AUDDEV_CLNT_ENC) {
- pr_debug("AUDDEV_CLNT_ENC\n");
- if (evt_id == AUDDEV_EVT_FREQ_CHG) {
- if (routing_info.enc_freq[clnt_id].evt) {
- routing_info.enc_freq[clnt_id].evt
- = 0;
- goto sent_enc;
- } else {
- evt_payload->freq_info.sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.dev_type
- = dev_info->capability;
- evt_payload->freq_info.acdb_dev_id
- = dev_info->acdb_id;
- }
- } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else
- evt_payload->routing_id = dev_info->copp_id;
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
-sent_enc:
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
-aud_cal:
- if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
- pr_debug("AUDDEV_CLNT_AUDIOCAL\n");
- if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else if (!dev_info->sessions)
- goto sent_aud_cal;
- else {
- evt_payload->audcal_info.dev_id =
- dev_info->copp_id;
- evt_payload->audcal_info.acdb_id =
- dev_info->acdb_id;
- evt_payload->audcal_info.dev_type =
- (dev_info->capability & SNDDEV_CAP_TX) ?
- SNDDEV_CAP_TX : SNDDEV_CAP_RX;
- evt_payload->audcal_info.sample_rate =
- dev_info->set_sample_rate ?
- dev_info->set_sample_rate :
- dev_info->sample_rate;
- }
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
-
-sent_aud_cal:
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
-skip_check:
-voc_events:
- if (callback->clnt_type == AUDDEV_CLNT_VOC) {
- pr_debug("AUDDEV_CLNT_VOC\n");
- if (evt_id == AUDDEV_EVT_DEV_RLS) {
- if (!pending_sent)
- goto sent_voc;
- else
- pending_sent = 0;
- }
- if (evt_id == AUDDEV_EVT_REL_PENDING)
- pending_sent = 1;
-
- if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
- evt_payload->voc_vm_info.voice_session_id =
- session_id;
-
- if (dev_info->capability & SNDDEV_CAP_TX) {
- evt_payload->voc_vm_info.dev_type =
- SNDDEV_CAP_TX;
- evt_payload->voc_vm_info.acdb_dev_id =
- dev_info->acdb_id;
- evt_payload->
- voc_vm_info.dev_vm_val.mute =
- routing_info.tx_mute;
- } else {
- evt_payload->voc_vm_info.dev_type =
- SNDDEV_CAP_RX;
- evt_payload->voc_vm_info.acdb_dev_id =
- dev_info->acdb_id;
- evt_payload->
- voc_vm_info.dev_vm_val.vol =
- routing_info.voice_rx_vol;
- }
- } else if ((evt_id == AUDDEV_EVT_START_VOICE)
- || (evt_id == AUDDEV_EVT_END_VOICE)) {
- memset(evt_payload, 0,
- sizeof(union auddev_evt_data));
-
- evt_payload->voice_session_id = session_id;
- } else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
- if (routing_info.voice_tx_sample_rate
- != dev_info->set_sample_rate) {
- routing_info.voice_tx_sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.sample_rate
- = dev_info->set_sample_rate;
- evt_payload->freq_info.dev_type
- = dev_info->capability;
- evt_payload->freq_info.acdb_dev_id
- = dev_info->acdb_id;
- } else
- goto sent_voc;
- } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
- evt_payload->voice_state =
- routing_info.voice_state;
- else {
- evt_payload->voc_devinfo.dev_type =
- (dev_info->capability & SNDDEV_CAP_TX) ?
- SNDDEV_CAP_TX : SNDDEV_CAP_RX;
- evt_payload->voc_devinfo.acdb_dev_id =
- dev_info->acdb_id;
- evt_payload->voc_devinfo.dev_port_id =
- dev_info->copp_id;
- evt_payload->voc_devinfo.dev_sample =
- dev_info->set_sample_rate ?
- dev_info->set_sample_rate :
- dev_info->sample_rate;
- evt_payload->voc_devinfo.dev_id = dev_id;
- if (dev_info->capability & SNDDEV_CAP_RX) {
- for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
- i++) {
- evt_payload->
- voc_devinfo.max_rx_vol[i] =
- dev_info->max_voc_rx_vol[i];
- evt_payload
- ->voc_devinfo.min_rx_vol[i] =
- dev_info->min_voc_rx_vol[i];
- }
- }
- }
- callback->auddev_evt_listener(
- evt_id,
- evt_payload,
- callback->private_data);
- if (evt_id == AUDDEV_EVT_DEV_RLS)
- dev_info->sessions &= ~(0xFFFF);
-sent_voc:
- if (callback->cb_next == NULL)
- break;
- else {
- callback = callback->cb_next;
- continue;
- }
- }
- }
- kfree(evt_payload);
- mutex_unlock(&session_lock);
-}
-EXPORT_SYMBOL(broadcast_event);
-
-
-void mixer_post_event(u32 evt_id, u32 id)
-{
-
- pr_debug("evt_id = %d\n", evt_id);
- switch (evt_id) {
- case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
- broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_DEV_RDY:
- broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_DEV_RLS:
- broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_REL_PENDING:
- broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
- broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
- SESSION_IGNORE);
- break;
- case AUDDEV_EVT_STREAM_VOL_CHG:
- broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
- SESSION_IGNORE);
- break;
- case AUDDEV_EVT_START_VOICE:
- broadcast_event(AUDDEV_EVT_START_VOICE,
- id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_END_VOICE:
- broadcast_event(AUDDEV_EVT_END_VOICE,
- id, SESSION_IGNORE);
- break;
- case AUDDEV_EVT_FREQ_CHG:
- broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
- break;
- default:
- break;
- }
-}
-EXPORT_SYMBOL(mixer_post_event);
-
-static int __init audio_dev_ctrl_init(void)
-{
- init_waitqueue_head(&audio_dev_ctrl.wait);
-
- event.cb = NULL;
- msm_reset_device_work_queue = create_workqueue("reset_device");
- if (msm_reset_device_work_queue == NULL)
- return -ENOMEM;
- atomic_set(&audio_dev_ctrl.opened, 0);
- audio_dev_ctrl.num_dev = 0;
- audio_dev_ctrl.voice_tx_dev = NULL;
- audio_dev_ctrl.voice_rx_dev = NULL;
- routing_info.voice_state = VOICE_STATE_INVALID;
-
- mutex_init(&adm_tx_topology_tbl.lock);
- mutex_init(&routing_info.copp_list_mutex);
- mutex_init(&routing_info.adm_mutex);
-
- memset(routing_info.copp_list, COPP_IGNORE,
- (sizeof(unsigned int) * MAX_SESSIONS * AFE_MAX_PORTS));
- return misc_register(&audio_dev_ctrl_misc);
-}
-
-static void __exit audio_dev_ctrl_exit(void)
-{
- destroy_workqueue(msm_reset_device_work_queue);
-}
-module_init(audio_dev_ctrl_init);
-module_exit(audio_dev_ctrl_exit);
-
-MODULE_DESCRIPTION("MSM 8K Audio Device Control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index a1463bc..5bdd10a 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -179,6 +179,16 @@
pr_err("%s[%p]: pause cmd failed rc=%d\n",
__func__, audio, rc);
+ if (rc == 0) {
+ /* Send suspend only if pause was successful */
+ rc = q6asm_cmd(audio->ac, CMD_SUSPEND);
+ if (rc < 0)
+ pr_err("%s[%p]: suspend cmd failed rc=%d\n",
+ __func__, audio, rc);
+ } else
+ pr_err("%s[%p]: not sending suspend since pause failed\n",
+ __func__, audio);
+
} else
pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
return rc;
@@ -1189,6 +1199,7 @@
case AUDIO_GET_STATS: {
struct msm_audio_stats stats;
uint64_t timestamp;
+ memset(&stats, 0, sizeof(struct msm_audio_stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
rc = q6asm_get_session_time(audio->ac, ×tamp);
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
deleted file mode 100644
index c6def46..0000000
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/uaccess.h>
-#include <linux/dma-mapping.h>
-#include <linux/msm_audio.h>
-#include <mach/msm_hdmi_audio.h>
-#include <mach/audio_dma_msm8k.h>
-#include <sound/dai.h>
-#include <mach/qdsp6v2/q6core.h>
-
-#define DMA_ALLOC_BUF_SZ (SZ_4K * 16)
-
-#define HDMI_AUDIO_FIFO_WATER_MARK 4
-
-struct audio_buffer {
- dma_addr_t phys;
- void *data;
- uint32_t size;
- uint32_t used; /* 1 = CPU is waiting for DMA to consume this buf */
- uint32_t actual_size; /* actual number of bytes read by DMA */
-};
-
-struct lpa_if {
- struct mutex lock;
- struct msm_audio_config cfg;
- struct audio_buffer audio_buf[6];
- int cpu_buf; /* next buffer the CPU will touch */
- int dma_buf; /* next buffer the DMA will touch */
- u8 *buffer;
- dma_addr_t buffer_phys;
- u32 dma_ch;
- wait_queue_head_t wait;
- u32 config;
- u32 dma_period_sz;
- unsigned int num_periods;
-};
-
-static struct lpa_if *lpa_if_ptr;
-
-static unsigned int dma_buf_index;
-
-static irqreturn_t lpa_if_irq(int intrsrc, void *data)
-{
- struct lpa_if *lpa_if = data;
- int dma_ch = 0;
- unsigned int pending;
-
- if (lpa_if)
- dma_ch = lpa_if->dma_ch;
- else {
- pr_err("invalid lpa_if\n");
- return IRQ_NONE;
- }
-
- pending = (intrsrc
- & (UNDER_CH(dma_ch) | PER_CH(dma_ch) | ERR_CH(dma_ch)));
-
- if (pending & UNDER_CH(dma_ch))
- pr_err("under run\n");
- if (pending & ERR_CH(dma_ch))
- pr_err("DMA %x Master Error\n", dma_ch);
-
- if (pending & PER_CH(dma_ch)) {
-
- lpa_if->audio_buf[lpa_if->dma_buf].used = 0;
-
- pr_debug("dma_buf %d used %d\n", lpa_if->dma_buf,
- lpa_if->audio_buf[lpa_if->dma_buf].used);
- lpa_if->dma_buf++;
- lpa_if->dma_buf = lpa_if->dma_buf % lpa_if->cfg.buffer_count;
-
- if (lpa_if->dma_buf == lpa_if->cpu_buf)
- pr_err("Err:both dma_buf and cpu_buf are on same index\n");
- wake_up(&lpa_if->wait);
- }
- return IRQ_HANDLED;
-}
-
-
-int lpa_if_start(struct lpa_if *lpa_if)
-{
- pr_debug("buf1 0x%x, buf2 0x%x dma_ch %d\n",
- (unsigned int)lpa_if->audio_buf[0].data,
- (unsigned int)lpa_if->audio_buf[1].data, lpa_if->dma_ch);
-
- dai_start_hdmi(lpa_if->dma_ch);
-
- hdmi_audio_enable(1, HDMI_AUDIO_FIFO_WATER_MARK);
-
- hdmi_audio_packet_enable(1);
- return 0;
-}
-
-int lpa_if_config(struct lpa_if *lpa_if)
-{
- struct dai_dma_params dma_params;
-
- dma_params.src_start = lpa_if->buffer_phys;
- dma_params.buffer = lpa_if->buffer;
- dma_params.buffer_size = lpa_if->dma_period_sz * lpa_if->num_periods;
- dma_params.period_size = lpa_if->dma_period_sz;
- dma_params.channels = 2;
-
- lpa_if->dma_ch = 4;
- dai_set_params(lpa_if->dma_ch, &dma_params);
-
- register_dma_irq_handler(lpa_if->dma_ch, lpa_if_irq, (void *)lpa_if);
-
- mb();
- pr_debug("lpa_if 0x%08x buf_vir 0x%08x buf_phys 0x%08x "
- "config %u\n", (u32)lpa_if, (u32) (lpa_if->buffer),
- lpa_if->buffer_phys, lpa_if->config);
-
- pr_debug("user_buf_cnt %u user_buf_size %u\n",
- lpa_if->cfg.buffer_count, lpa_if->cfg.buffer_size);
-
- lpa_if->config = 1;
-
- lpa_if_start(lpa_if);
-
- return 0;
-}
-
-
-static long lpa_if_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct lpa_if *lpa_if = file->private_data;
- int rc = 0;
- unsigned int i;
- pr_debug("cmd %u\n", cmd);
-
- mutex_lock(&lpa_if->lock);
-
- switch (cmd) {
- case AUDIO_START:
- pr_debug("AUDIO_START\n");
-
- if (dma_buf_index == 2) {
- if (!lpa_if->config) {
- rc = lpa_if_config(lpa_if);
- if (rc)
- pr_err("lpa_if_config failed\n");
- }
- } else {
- pr_err("did not receved two buffer for "
- "AUDIO_STAR\n");
- rc = -EPERM;
- }
- break;
-
- case AUDIO_STOP:
- pr_debug("AUDIO_STOP\n");
- break;
-
- case AUDIO_FLUSH:
- pr_debug("AUDIO_FLUSH\n");
- break;
-
-
- case AUDIO_GET_CONFIG:
- pr_debug("AUDIO_GET_CONFIG\n");
- if (copy_to_user((void *)arg, &lpa_if->cfg,
- sizeof(struct msm_audio_config))) {
- rc = -EFAULT;
- }
- break;
- case AUDIO_SET_CONFIG: {
- /* Setting default rate as 48khz */
- unsigned int cur_sample_rate =
- HDMI_SAMPLE_RATE_48KHZ;
- struct msm_audio_config config;
-
- pr_debug("AUDIO_SET_CONFIG\n");
- if (copy_from_user(&config, (void *)arg, sizeof(config))) {
- rc = -EFAULT;
- break;
- }
- lpa_if->dma_period_sz = config.buffer_size;
- if ((lpa_if->dma_period_sz * lpa_if->num_periods) >
- DMA_ALLOC_BUF_SZ) {
- pr_err("Dma buffer size greater than allocated size\n");
- return -EINVAL;
- }
- pr_debug("Dma_period_sz %d\n", lpa_if->dma_period_sz);
- if (lpa_if->dma_period_sz < (2 * SZ_4K))
- lpa_if->num_periods = 6;
- pr_debug("No. of Periods %d\n", lpa_if->num_periods);
-
- lpa_if->cfg.buffer_count = lpa_if->num_periods;
- lpa_if->cfg.buffer_size = lpa_if->dma_period_sz *
- lpa_if->num_periods;
-
- for (i = 0; i < lpa_if->cfg.buffer_count; i++) {
- lpa_if->audio_buf[i].phys =
- lpa_if->buffer_phys + i * lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].data =
- lpa_if->buffer + i * lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].size = lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].used = 0;
- }
-
- pr_debug("Sample rate %d\n", config.sample_rate);
- switch (config.sample_rate) {
- case 48000:
- cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
- break;
- case 44100:
- cur_sample_rate = HDMI_SAMPLE_RATE_44_1KHZ;
- break;
- case 32000:
- cur_sample_rate = HDMI_SAMPLE_RATE_32KHZ;
- break;
- case 88200:
- cur_sample_rate = HDMI_SAMPLE_RATE_88_2KHZ;
- break;
- case 96000:
- cur_sample_rate = HDMI_SAMPLE_RATE_96KHZ;
- break;
- case 176400:
- cur_sample_rate = HDMI_SAMPLE_RATE_176_4KHZ;
- break;
- case 192000:
- cur_sample_rate = HDMI_SAMPLE_RATE_192KHZ;
- break;
- default:
- cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
- }
- if (cur_sample_rate != hdmi_msm_audio_get_sample_rate())
- hdmi_msm_audio_sample_rate_reset(cur_sample_rate);
- else
- pr_debug("Previous sample rate and current"
- "sample rate are same\n");
- break;
- }
- default:
- pr_err("UnKnown Ioctl\n");
- rc = -EINVAL;
- }
-
- mutex_unlock(&lpa_if->lock);
-
- return rc;
-}
-
-
-static int lpa_if_open(struct inode *inode, struct file *file)
-{
- pr_debug("\n");
-
- file->private_data = lpa_if_ptr;
- dma_buf_index = 0;
- lpa_if_ptr->cpu_buf = 2;
- lpa_if_ptr->dma_buf = 0;
- lpa_if_ptr->num_periods = 4;
-
- core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
- mb();
-
- return 0;
-}
-
-static inline int rt_policy(int policy)
-{
- if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
- return 1;
- return 0;
-}
-
-static inline int task_has_rt_policy(struct task_struct *p)
-{
- return rt_policy(p->policy);
-}
-static ssize_t lpa_if_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
-{
- struct lpa_if *lpa_if = file->private_data;
- struct audio_buffer *ab;
- const char __user *start = buf;
- int xfer, rc;
- struct sched_param s = { .sched_priority = 1 };
- int old_prio = current->rt_priority;
- int old_policy = current->policy;
- int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
-
- /* just for this write, set us real-time */
- if (!task_has_rt_policy(current)) {
- struct cred *new = prepare_creds();
- cap_raise(new->cap_effective, CAP_SYS_NICE);
- commit_creds(new);
- if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
- pr_err("sched_setscheduler failed\n");
- }
- mutex_lock(&lpa_if->lock);
-
- if (dma_buf_index < 2) {
-
- ab = lpa_if->audio_buf + dma_buf_index;
-
- if (copy_from_user(ab->data, buf, count)) {
- pr_err("copy from user failed\n");
- rc = 0;
- goto end;
-
- }
- mb();
- pr_debug("prefill: count %u audio_buf[%u].size %u\n",
- count, dma_buf_index, ab->size);
-
- ab->used = 1;
- dma_buf_index++;
- rc = count;
- goto end;
- }
-
- if (lpa_if->config != 1) {
- pr_err("AUDIO_START did not happen\n");
- rc = 0;
- goto end;
- }
-
- while (count > 0) {
-
- ab = lpa_if->audio_buf + lpa_if->cpu_buf;
-
- rc = wait_event_timeout(lpa_if->wait, (ab->used == 0), 10 * HZ);
- if (!rc) {
- pr_err("wait_event_timeout failed\n");
- rc = buf - start;
- goto end;
- }
-
- xfer = count;
-
- if (xfer > lpa_if->dma_period_sz)
- xfer = lpa_if->dma_period_sz;
-
- if (copy_from_user(ab->data, buf, xfer)) {
- pr_err("copy from user failed\n");
- rc = buf - start;
- goto end;
- }
-
- mb();
- buf += xfer;
- count -= xfer;
- ab->used = 1;
-
- pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
- xfer, ab->size, ab->used, lpa_if->cpu_buf);
- lpa_if->cpu_buf++;
- lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count;
- }
- rc = buf - start;
-end:
- mutex_unlock(&lpa_if->lock);
- /* restore old scheduling policy */
- if (!rt_policy(old_policy)) {
- struct sched_param v = { .sched_priority = old_prio };
- if ((sched_setscheduler(current, old_policy, &v)) < 0)
- pr_err("sched_setscheduler failed\n");
- if (likely(!cap_nice)) {
- struct cred *new = prepare_creds();
- cap_lower(new->cap_effective, CAP_SYS_NICE);
- commit_creds(new);
- }
- }
- return rc;
-}
-
-static int lpa_if_release(struct inode *inode, struct file *file)
-{
- struct lpa_if *lpa_if = file->private_data;
-
- hdmi_audio_packet_enable(0);
-
- wait_for_dma_cnt_stop(lpa_if->dma_ch);
-
- hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK);
-
- if (lpa_if->config) {
- unregister_dma_irq_handler(lpa_if->dma_ch);
- dai_stop_hdmi(lpa_if->dma_ch);
- lpa_if->config = 0;
- }
- core_req_bus_bandwith(AUDIO_IF_BUS_ID, 0, 0);
-
- if (hdmi_msm_audio_get_sample_rate() != HDMI_SAMPLE_RATE_48KHZ)
- hdmi_msm_audio_sample_rate_reset(HDMI_SAMPLE_RATE_48KHZ);
-
- return 0;
-}
-
-static const struct file_operations lpa_if_fops = {
- .owner = THIS_MODULE,
- .open = lpa_if_open,
- .write = lpa_if_write,
- .release = lpa_if_release,
- .unlocked_ioctl = lpa_if_ioctl,
-};
-
-struct miscdevice lpa_if_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "msm_lpa_if_out",
- .fops = &lpa_if_fops,
-};
-
-static int __init lpa_if_init(void)
-{
- int rc;
-
- lpa_if_ptr = kzalloc(sizeof(struct lpa_if), GFP_KERNEL);
- if (!lpa_if_ptr) {
- pr_info("No mem for lpa-if\n");
- return -ENOMEM;
- }
-
- mutex_init(&lpa_if_ptr->lock);
- init_waitqueue_head(&lpa_if_ptr->wait);
-
- lpa_if_ptr->buffer = dma_alloc_coherent(NULL, DMA_ALLOC_BUF_SZ,
- &(lpa_if_ptr->buffer_phys), GFP_KERNEL);
- if (!lpa_if_ptr->buffer) {
- pr_err("dma_alloc_coherent failed\n");
- kfree(lpa_if_ptr);
- return -ENOMEM;
- }
-
- pr_info("lpa_if_ptr 0x%08x buf_vir 0x%08x buf_phy 0x%08x "
- " buf_zise %u\n", (u32)lpa_if_ptr,
- (u32)(lpa_if_ptr->buffer), lpa_if_ptr->buffer_phys,
- DMA_ALLOC_BUF_SZ);
-
- rc = misc_register(&lpa_if_misc);
- if (rc < 0) {
- pr_err("misc_register failed\n");
-
- dma_free_coherent(NULL, DMA_ALLOC_BUF_SZ, lpa_if_ptr->buffer,
- lpa_if_ptr->buffer_phys);
- kfree(lpa_if_ptr);
- }
- return rc;
-}
-
-device_initcall(lpa_if_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 0a50bcc..fc6de64 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,
@@ -321,6 +328,11 @@
ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
{
int rc = 0;
+ if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ rc = -EINVAL;
+ goto err;
+ }
/* client is already created for legacy and given*/
/* name should be audio_acdb_client or Audio_Dec_Client,
bufsz should be 0 and fd shouldn't be 0 as of now
@@ -331,14 +343,16 @@
if (IS_ERR_OR_NULL((void *)(*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
- goto err_ion_handle;
- }
+ rc = -EINVAL;
+ goto err_destroy_client;
+ }
if (ionflag != NULL) {
rc = ion_handle_get_flags(client, *handle, ionflag);
if (rc) {
pr_err("%s: could not get flags for the handle\n",
__func__);
+ rc = -EINVAL;
goto err_ion_handle;
}
}
@@ -347,6 +361,7 @@
if (rc) {
pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
+ rc = -EINVAL;
goto err_ion_handle;
}
@@ -354,6 +369,7 @@
*vaddr = ion_map_kernel(client, *handle);
if (IS_ERR_OR_NULL((void *)*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ rc = -EINVAL;
goto err_ion_handle;
}
@@ -364,8 +380,12 @@
err_ion_handle:
ion_free(client, *handle);
- return -EINVAL;
-
+err_destroy_client:
+ msm_audio_ion_client_destroy(client);
+ client = NULL;
+ *handle = NULL;
+err:
+ return rc;
}
int msm_audio_ion_free_legacy(struct ion_client *client,
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/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index 923e647..faf774f 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -1266,14 +1266,16 @@
{
struct device *dev = &pdev->dev;
struct rpm_regulator *reg;
+ struct rpm_vreg *rpm_vreg;
reg = platform_get_drvdata(pdev);
if (reg) {
- rpm_vreg_lock(reg->rpm_vreg);
+ rpm_vreg = reg->rpm_vreg;
+ rpm_vreg_lock(rpm_vreg);
regulator_unregister(reg->rdev);
list_del(®->list);
kfree(reg);
- rpm_vreg_unlock(reg->rpm_vreg);
+ rpm_vreg_unlock(rpm_vreg);
} else {
dev_err(dev, "%s: drvdata missing\n", __func__);
return -EINVAL;
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/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 34ae4e6..ac6ccf3 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -885,8 +885,9 @@
MLM(VMALLOC_START, VMALLOC_END),
MLM(PAGE_OFFSET, (unsigned long)high_memory));
#endif
-#ifdef CONFIG_HIGHMEM
+
printk(KERN_NOTICE
+#ifdef CONFIG_HIGHMEM
" pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
#endif
#ifdef CONFIG_MODULES
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 1d12b07..9a1a2eb 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -85,6 +85,7 @@
}
#ifdef CONFIG_SMP
thread->vfpstate.hard.cpu = NR_CPUS;
+ vfp_current_hw_state[cpu] = NULL;
#endif
}
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..921b80c 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;
}
@@ -1242,7 +1276,7 @@
VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
if (err)
goto cdev_init_bail;
- me->class = class_create(THIS_MODULE, "chardrv");
+ me->class = class_create(THIS_MODULE, "fastrpc");
VERIFY(err, !IS_ERR(me->class));
if (err)
goto class_create_bail;
@@ -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/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 19ff6f4..f7c0d24 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1485,26 +1485,25 @@
return err;
}
if (pkt_type == CALLBACK_DATA_TYPE) {
- if (payload_size > itemsize) {
+ if (payload_size > driver->itemsize) {
pr_err("diag: Dropping packet, packet payload size crosses 4KB limit. Current payload size %d\n",
payload_size);
driver->dropped_count++;
return -EBADMSG;
}
- mutex_lock(&driver->diagchar_mutex);
buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
if (!buf_copy) {
driver->dropped_count++;
- mutex_unlock(&driver->diagchar_mutex);
return -ENOMEM;
}
err = copy_from_user(buf_copy, buf + 4, payload_size);
if (err) {
pr_err("diag: copy failed for user space data\n");
- ret = -EIO;
- goto fail_free_copy;
+ diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
+ return -EIO;
}
/* Check for proc_type */
remote_proc = diag_get_remote(*(int *)buf_copy);
@@ -1513,7 +1512,9 @@
wait_event_interruptible(driver->wait_q,
(driver->in_busy_pktdata == 0));
ret = diag_process_apps_pkt(buf_copy, payload_size);
- goto fail_free_copy;
+ diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
+ return ret;
}
/* The packet is for the remote processor */
token_offset = 4;
@@ -1526,7 +1527,7 @@
1 + payload_size);
send.terminate = 1;
-
+ mutex_lock(&driver->diagchar_mutex);
if (!buf_hdlc)
buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
POOL_TYPE_HDLC);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index ba3ecc2..447cb39 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -2480,7 +2480,7 @@
driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
driver->poolsize_hdlc : buf_tbl_size;
driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
- driver->supports_apps_hdlc_encoding = 0;
+ driver->supports_apps_hdlc_encoding = 1;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
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/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index b5945da..728e90c 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -772,6 +772,9 @@
#define SP0_ICL1_MISSES 0x1A
#define SP_FS_CFLOW_INSTRUCTIONS 0x0C
+/* COUNTABLE FOR TSE PERFCOUNTER */
+#define TSE_INPUT_PRIM_NUM 0x0
+
/* VBIF PERFCOUNTER ENA/CLR values */
#define VBIF_PERF_CNT_0 BIT(0)
#define VBIF_PERF_CNT_1 BIT(1)
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 8f48440..0ee54d0 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -362,7 +362,7 @@
unsigned int replay_for_snapshot;
};
-#define FT_DETECT_REGS_COUNT 12
+#define FT_DETECT_REGS_COUNT 14
struct log_field {
bool show;
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 5778e9e..f316664 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3863,7 +3863,9 @@
* USP L1 instruction miss request.
* Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it
* counts USP flow control instruction execution.
- * we will use this to augment our hang detection
+ * Set TSE to count TSE_INPUT_PRIM_NUM, it counts
+ * number of input primitives in TSE.
+ * we will use above countables for our hang detection
*/
if (adreno_dev->fast_hang_detect) {
adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
@@ -3878,6 +3880,10 @@
SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10],
PERFCOUNTER_FLAG_KERNEL);
ft_detect_regs[11] = ft_detect_regs[10] + 1;
+ adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_TSE,
+ TSE_INPUT_PRIM_NUM, &ft_detect_regs[12],
+ PERFCOUNTER_FLAG_KERNEL);
+ ft_detect_regs[13] = ft_detect_regs[12] + 1;
}
adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 6cd1f68..2eb5300 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -59,6 +59,9 @@
struct sg_table *table;
};
+static void kgsl_put_process_private(struct kgsl_device *device,
+ struct kgsl_process_private *private);
+
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
/**
@@ -409,14 +412,19 @@
*/
static int
kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
- struct kgsl_process_private *process)
+ struct kgsl_device_private *dev_priv)
{
int ret;
+ struct kgsl_process_private *process = dev_priv->process_priv;
+
+ ret = kref_get_unless_zero(&process->refcount);
+ if (!ret)
+ return -EBADF;
while (1) {
if (idr_pre_get(&process->mem_idr, GFP_KERNEL) == 0) {
ret = -ENOMEM;
- goto err;
+ goto err_put_proc_priv;
}
spin_lock(&process->mem_lock);
@@ -427,9 +435,10 @@
if (ret == 0)
break;
else if (ret != -EAGAIN)
- goto err;
+ goto err_put_proc_priv;
}
entry->priv = process;
+ entry->dev_priv = dev_priv;
spin_lock(&process->mem_lock);
ret = kgsl_mem_entry_track_gpuaddr(process, entry);
@@ -437,14 +446,17 @@
idr_remove(&process->mem_idr, entry->id);
spin_unlock(&process->mem_lock);
if (ret)
- goto err;
+ goto err_put_proc_priv;
/* map the memory after unlocking if gpuaddr has been assigned */
if (entry->memdesc.gpuaddr) {
ret = kgsl_mmu_map(process->pagetable, &entry->memdesc);
if (ret)
kgsl_mem_entry_detach_process(entry);
}
-err:
+ return ret;
+
+err_put_proc_priv:
+ kgsl_put_process_private(dev_priv->device, process);
return ret;
}
@@ -467,6 +479,7 @@
entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
spin_unlock(&entry->priv->mem_lock);
+ kgsl_put_process_private(entry->dev_priv->device, entry->priv);
entry->priv = NULL;
}
@@ -813,11 +826,6 @@
*/
static void kgsl_destroy_process_private(struct kref *kref)
{
-
- struct kgsl_mem_entry *entry = NULL;
- int next = 0;
-
-
struct kgsl_process_private *private = container_of(kref,
struct kgsl_process_private, refcount);
@@ -841,20 +849,6 @@
if (private->debug_root)
debugfs_remove_recursive(private->debug_root);
- while (1) {
- spin_lock(&private->mem_lock);
- entry = idr_get_next(&private->mem_idr, &next);
- spin_unlock(&private->mem_lock);
- if (entry == NULL)
- break;
- kgsl_mem_entry_put(entry);
- /*
- * Always start back at the beginning, to
- * ensure all entries are removed,
- * like list_for_each_entry_safe.
- */
- next = 0;
- }
idr_destroy(&private->mem_idr);
kgsl_mmu_putpagetable(private->pagetable);
@@ -1004,6 +998,7 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_device *device = dev_priv->device;
struct kgsl_context *context;
+ struct kgsl_mem_entry *entry;
int next = 0;
filep->private_data = NULL;
@@ -1024,6 +1019,25 @@
next = next + 1;
}
+ next = 0;
+ while (1) {
+ spin_lock(&private->mem_lock);
+ entry = idr_get_next(&private->mem_idr, &next);
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL)
+ break;
+ /*
+ * If the free pending flag is not set it means that user space
+ * did not free it's reference to this entry, in that case
+ * free a reference to this entry, other references are from
+ * within kgsl so they will be freed eventually by kgsl
+ */
+ if (entry->dev_priv == dev_priv && !entry->pending_free) {
+ entry->pending_free = 1;
+ kgsl_mem_entry_put(entry);
+ }
+ next = next + 1;
+ }
/*
* Clean up any to-be-freed entries that belong to this
* process and this device. This is done after the context
@@ -2246,7 +2260,7 @@
/* echo back flags */
param->flags = entry->memdesc.flags;
- result = kgsl_mem_entry_attach_process(entry, private);
+ result = kgsl_mem_entry_attach_process(entry, dev_priv);
if (result)
goto error_attach;
@@ -2534,7 +2548,7 @@
if (result)
return result;
- result = kgsl_mem_entry_attach_process(entry, private);
+ result = kgsl_mem_entry_attach_process(entry, dev_priv);
if (result != 0)
goto err;
@@ -2567,7 +2581,7 @@
if (result != 0)
goto err;
- result = kgsl_mem_entry_attach_process(entry, private);
+ result = kgsl_mem_entry_attach_process(entry, dev_priv);
if (result != 0)
goto err;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 42d3b3e..3f4dde7 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -197,6 +197,7 @@
struct kgsl_process_private *priv;
/* Initialized to 0, set to 1 when entry is marked for freeing */
int pending_free;
+ struct kgsl_device_private *dev_priv;
};
#ifdef CONFIG_MSM_KGSL_MMU_PAGE_FAULT
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index 17127a8..8516ea5 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -674,17 +674,9 @@
{
int ret = -EIO;
unsigned int delay;
-
- mutex_lock(&als_enable_mutex);
- if (lpi->als_enable) {
- dev_err(&lpi->i2c_client->dev, "%s: already enabled\n",
- __func__);
- ret = 0;
- } else {
- ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
- }
-
+ mutex_lock(&als_enable_mutex);
+ ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
mutex_unlock(&als_enable_mutex);
delay = atomic_read(&lpi->ls_poll_delay);
@@ -1565,7 +1557,7 @@
__func__, lpi->ls_cmd);
if (pdata->ls_cmd == 0) {
- lpi->ls_cmd = CM36283_ALS_IT_160ms | CM36283_ALS_GAIN_2;
+ lpi->ls_cmd = CM36283_ALS_IT_80ms | CM36283_ALS_GAIN_2;
}
lp_info = lpi;
@@ -1582,17 +1574,17 @@
mutex_init(&ps_get_adc_mutex);
- //SET LUX STEP FACTOR HERE
- // if adc raw value one step = 5/100 = 1/20 = 0.05 lux
- // the following will set the factor 0.05 = 1/20
- // and lpi->golden_adc = 1;
- // set als_kadc = (ALS_CALIBRATED <<16) | 20;
+ /*
+ * SET LUX STEP FACTOR HERE
+ * if adc raw value one step = 5/100 = 1/20 = 0.05 lux
+ * the following will set the factor 0.05 = 1/20
+ * and lpi->golden_adc = 1;
+ * set als_kadc = (ALS_CALIBRATED << 16) | 20;
+ */
- als_kadc = (ALS_CALIBRATED <<16) | 20;
- lpi->golden_adc = 1;
-
- //ls calibrate always set to 1
- lpi->ls_calibrate = 1;
+ als_kadc = (ALS_CALIBRATED << 16) | 10;
+ lpi->golden_adc = 100;
+ lpi->ls_calibrate = 0;
lightsensor_set_kvalue(lpi);
ret = lightsensor_update_table(lpi);
@@ -2009,27 +2001,40 @@
struct cm36283_info *lpi = lp_info;
if (lpi->als_enable) {
- lightsensor_disable(lpi);
+ if (lightsensor_disable(lpi))
+ goto out;
lpi->als_enable = 1;
}
- cm36283_power_set(lpi, 0);
+ if (cm36283_power_set(lpi, 0))
+ goto out;
return 0;
+
+out:
+ dev_err(&lpi->i2c_client->dev, "%s:failed during resume operation.\n",
+ __func__);
+ return -EIO;
}
static int cm36283_resume(struct device *dev)
{
struct cm36283_info *lpi = lp_info;
- cm36283_power_set(lpi, 1);
+ if (cm36283_power_set(lpi, 1))
+ goto out;
if (lpi->als_enable) {
- cm36283_setup(lpi);
- lightsensor_setup(lpi);
- psensor_setup(lpi);
- lightsensor_enable(lpi);
+ ls_initial_cmd(lpi);
+ psensor_initial_cmd(lpi);
+ if (lightsensor_enable(lpi))
+ goto out;
}
return 0;
+
+out:
+ dev_err(&lpi->i2c_client->dev, "%s:failed during resume operation.\n",
+ __func__);
+ return -EIO;
}
#endif
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index f879d78..94cc943 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -415,19 +415,16 @@
}
}
- tj9->enable = true;
return 0;
fail:
kxtj9_device_power_off(tj9);
- tj9->enable = false;
return err;
}
static void kxtj9_disable(struct kxtj9_data *tj9)
{
kxtj9_device_power_off(tj9);
- tj9->enable = false;
}
@@ -496,18 +493,21 @@
if (error)
return error;
mutex_lock(&input_dev->mutex);
- disable_irq(client->irq);
- if (data == 0)
+ if (data == 0) {
+ disable_irq(client->irq);
kxtj9_disable(tj9);
- else if (data == 1)
- kxtj9_enable(tj9);
- else {
+ tj9->enable = false;
+ } else if (data == 1) {
+ if (!kxtj9_enable(tj9)) {
+ enable_irq(client->irq);
+ tj9->enable = true;
+ }
+ } else {
dev_err(&tj9->client->dev,
"Invalid value of input, input=%ld\n", data);
}
- enable_irq(client->irq);
mutex_unlock(&input_dev->mutex);
return count;
@@ -555,7 +555,8 @@
/* Lock the device to prevent races with open/close (and itself) */
mutex_lock(&input_dev->mutex);
- disable_irq(client->irq);
+ if (tj9->enable)
+ disable_irq(client->irq);
/*
* Set current interval to the greater of the minimum interval or
@@ -563,9 +564,10 @@
*/
tj9->last_poll_interval = max(interval, tj9->pdata.min_interval);
- kxtj9_update_odr(tj9, tj9->last_poll_interval);
-
- enable_irq(client->irq);
+ if (tj9->enable) {
+ kxtj9_update_odr(tj9, tj9->last_poll_interval);
+ enable_irq(client->irq);
+ }
mutex_unlock(&input_dev->mutex);
return count;
@@ -857,6 +859,8 @@
goto err_destroy_input;
}
+ disable_irq(tj9->client->irq);
+
err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);
if (err) {
dev_err(&client->dev, "sysfs create failed: %d\n", err);
@@ -923,7 +927,7 @@
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_dev->users && tj9->enable)
kxtj9_disable(tj9);
mutex_unlock(&input_dev->mutex);
@@ -939,7 +943,7 @@
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_dev->users && tj9->enable)
kxtj9_enable(tj9);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index a325d54..91aa928 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -53,6 +53,7 @@
#define MMA8X5X_BUF_SIZE 7
#define MMA_SHUTTEDDOWN (1 << 31)
+#define MMA_STATE_MASK (~MMA_SHUTTEDDOWN)
struct sensor_regulator {
struct regulator *vreg;
@@ -349,7 +350,7 @@
struct input_polled_dev *poll_dev = pdata->poll_dev;
struct mma8x5x_data_axis data;
mutex_lock(&pdata->data_lock);
- if (pdata->active == MMA_STANDBY) {
+ if ((pdata->active & MMA_STATE_MASK) == MMA_STANDBY) {
poll_dev->poll_interval = POLL_STOP_TIME;
/* if standby ,set as 10s to slow the poll. */
goto out;
diff --git a/drivers/input/touchscreen/cyttsp-i2c-qc.c b/drivers/input/touchscreen/cyttsp-i2c-qc.c
index 6c4e6b7..2b1360e 100644
--- a/drivers/input/touchscreen/cyttsp-i2c-qc.c
+++ b/drivers/input/touchscreen/cyttsp-i2c-qc.c
@@ -2873,6 +2873,21 @@
return rc;
}
+static void cyttsp_release_all(struct cyttsp *ts)
+{
+ int id;
+
+ for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+ input_mt_slot(ts->input, id);
+ input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, 0);
+ }
+
+ input_report_key(ts->input, BTN_TOUCH, 0);
+ input_report_key(ts->input, BTN_TOOL_FINGER, 0);
+
+ input_sync(ts->input);
+}
+
/* Function to manage power-on resume */
static int cyttsp_resume(struct device *dev)
{
@@ -2978,6 +2993,8 @@
else
disable_irq(ts->client->irq);
+ cyttsp_release_all(ts);
+
if (!(retval < CY_OK)) {
if (ts->platform_data->use_sleep &&
(ts->platform_data->power_state == CY_ACTIVE_STATE)) {
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index f366364..9a4301e 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -717,7 +717,9 @@
if (r_buf[0] != info.upgrade_id_1
|| r_buf[1] != info.upgrade_id_2) {
- dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i);
+ dev_err(&client->dev, "Upgrade ID mismatch(%d), IC=0x%x 0x%x, info=0x%x 0x%x\n",
+ i, r_buf[0], r_buf[1],
+ info.upgrade_id_1, info.upgrade_id_2);
} else
break;
}
@@ -743,6 +745,10 @@
else
is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
+ dev_dbg(&client->dev, "bootloader type=%d, r_buf=0x%x, family_id=0x%x\n",
+ is_5336_new_bootloader, r_buf[0], ts_data->family_id);
+ /* is_5336_new_bootloader = FT_BLOADER_VERSION_GZF; */
+
/* erase app and panel paramenter area */
w_buf[0] = FT_ERASE_APP_REG;
ft5x06_i2c_write(client, w_buf, 1);
@@ -1537,7 +1543,7 @@
goto free_reset_gpio;
}
- data->family_id = reg_value;
+ data->family_id = pdata->family_id;
err = request_threaded_irq(client->irq, NULL,
ft5x06_ts_interrupt, pdata->irqflags,
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 7282c2e..e4e3aca 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -352,7 +352,6 @@
(data->options_firmware_id == (1 << OPTION_BUILD_INFO));
if (img->is_contain_build_info) {
- img->firmware_id = extract_uint(data->firmware_id);
img->package_id = (data->pkg_id_msb << 8) |
data->pkg_id_lsb;
img->package_revision_id = (data->pkg_id_rev_msb << 8) |
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index d21b6c1..ea3fe2c 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -67,10 +67,10 @@
#define F11_STD_CTRL_LEN 10
#define F11_STD_DATA_LEN 12
-#define NORMAL_OPERATION (0 << 0)
-#define SENSOR_SLEEP (1 << 0)
-#define NO_SLEEP_OFF (0 << 2)
-#define NO_SLEEP_ON (1 << 2)
+#define NORMAL_OPERATION 0
+#define SENSOR_SLEEP 1
+#define NO_SLEEP_OFF 0
+#define NO_SLEEP_ON 1
enum device_status {
STATUS_NO_ERROR = 0x00,
@@ -111,6 +111,13 @@
static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
+static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data);
+
+static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data);
+
+static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
+ *rmi4_data);
+
#ifdef CONFIG_PM
static int synaptics_rmi4_suspend(struct device *dev);
@@ -2051,6 +2058,30 @@
return 0;
}
+/*
+* This function checks whether the fhandler already existis in the
+* support_fn_list or not.
+* If it exists then return 1 as found or return 0 as not found.
+*
+* Called by synaptics_rmi4_query_device().
+*/
+static int synaptics_rmi4_check_fn_list(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int found = 0;
+ struct synaptics_rmi4_fn *new_fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ if (!list_empty(&rmi->support_fn_list))
+ list_for_each_entry(new_fhandler, &rmi->support_fn_list, link)
+ if (new_fhandler->fn_number == fhandler->fn_number)
+ found = 1;
+
+ return found;
+}
+
/**
* synaptics_rmi4_query_device()
*
@@ -2066,7 +2097,7 @@
*/
static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
{
- int retval;
+ int retval, found;
unsigned char ii;
unsigned char page_number;
unsigned char intr_count = 0;
@@ -2080,8 +2111,6 @@
rmi = &(rmi4_data->rmi4_mod_info);
- INIT_LIST_HEAD(&rmi->support_fn_list);
-
/* Scan the page description tables of the pages to service */
for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
@@ -2096,7 +2125,7 @@
return retval;
fhandler = NULL;
-
+ found = 0;
if (rmi_fd.fn_number == 0) {
dev_dbg(&rmi4_data->i2c_client->dev,
"%s: Reached end of PDT\n",
@@ -2215,8 +2244,28 @@
intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
if (fhandler && rmi_fd.intr_src_count) {
- list_add_tail(&fhandler->link,
+ /* Want to check whether the fhandler already
+ exists in the support_fn_list or not.
+ If not found then add it to the list, otherwise
+ free the memory allocated to it.
+ */
+ found = synaptics_rmi4_check_fn_list(rmi4_data,
+ fhandler);
+
+ if (!found) {
+ list_add_tail(&fhandler->link,
&rmi->support_fn_list);
+ } else {
+ if (fhandler->fn_number ==
+ SYNAPTICS_RMI4_F1A)
+ synaptics_rmi4_f1a_kfree(
+ fhandler);
+ else {
+ kfree(fhandler->data);
+ kfree(fhandler->extra);
+ }
+ kfree(fhandler);
+ }
}
}
}
@@ -2851,6 +2900,8 @@
init_waitqueue_head(&rmi4_data->wait);
mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
+ INIT_LIST_HEAD(&rmi->support_fn_list);
+
retval = synaptics_rmi4_query_device(rmi4_data);
if (retval < 0) {
dev_err(&client->dev,
@@ -2987,6 +3038,9 @@
goto err_sysfs;
}
}
+
+ synaptics_rmi4_sensor_wake(rmi4_data);
+
retval = synaptics_rmi4_irq_enable(rmi4_data, true);
if (retval < 0) {
dev_err(&client->dev,
@@ -2995,6 +3049,12 @@
goto err_sysfs;
}
+ retval = synaptics_rmi4_check_configuration(rmi4_data);
+ if (retval < 0) {
+ dev_err(&client->dev, "Failed to check configuration\n");
+ return retval;
+ }
+
return retval;
err_sysfs:
@@ -3175,6 +3235,12 @@
return;
}
+ if (device_ctrl.nosleep == NO_SLEEP_OFF &&
+ device_ctrl.sleep_mode == NORMAL_OPERATION) {
+ rmi4_data->sensor_sleep = false;
+ return;
+ }
+
device_ctrl.sleep_mode = NORMAL_OPERATION;
device_ctrl.nosleep = NO_SLEEP_OFF;
@@ -3558,6 +3624,22 @@
static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
};
#endif
+#else
+static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data)
+{
+ return;
+};
+
+static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ return;
+};
+
+static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
+ *rmi4_data)
+{
+ return 0;
+};
#endif
static const struct i2c_device_id synaptics_rmi4_id_table[] = {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 4f3094a..9c92a7b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1153,8 +1153,14 @@
* since for burst case, write masters already skip
* all frames.
*/
+ if (stream_info->stream_src == RDI_INTF_0 ||
+ stream_info->stream_src == RDI_INTF_1 ||
+ stream_info->stream_src == RDI_INTF_2)
+ wait_for_complete = 1;
+ else {
msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
stream_info->state = INACTIVE;
+ }
} else {
wait_for_complete = 1;
}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index 0a0fa04..5d34265 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -337,6 +337,11 @@
__LINE__, hw_cmd_p->offset, max_size);
return -EFAULT;
}
+ if (hw_cmd_p->offset & 0x3) {
+ JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__,
+ __LINE__, hw_cmd_p->offset);
+ return -EFAULT;
+ }
switch (hw_cmd_p->type) {
case MSM_JPEG_HW_CMD_TYPE_READ:
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index 80ff9e5..dffdab3 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -669,6 +669,8 @@
JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
return -EFAULT;
}
+ } else {
+ return is_copy_to_user;
}
return 0;
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/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
index 484dd69..336c922 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -669,7 +669,9 @@
}
gpio_set_value_cansleep(
ctrl->gpio_conf->gpio_num_info->gpio_num
- [power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+ [power_setting->seq_val],
+ ctrl->gpio_conf->gpio_num_info->gpio_num
+ [power_setting->config_val]);
break;
case SENSOR_VREG:
if (power_setting->seq_val >= CAM_VREG_MAX) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 0083378..03145c8 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1797,6 +1797,8 @@
(struct msm_sensor_ctrl_t *)data;
struct msm_camera_cci_client *cci_client = NULL;
uint32_t session_id;
+ unsigned long mount_pos;
+
s_ctrl->pdev = pdev;
s_ctrl->dev = &pdev->dev;
CDBG("%s called data %p\n", __func__, data);
@@ -1862,6 +1864,11 @@
s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
s_ctrl->msm_sd.sd.entity.name =
s_ctrl->msm_sd.sd.name;
+ mount_pos = s_ctrl->sensordata->sensor_init_params->position;
+ mount_pos = mount_pos << 8;
+ mount_pos = mount_pos |
+ (s_ctrl->sensordata->sensor_init_params->sensor_mount_angle / 90);
+ s_ctrl->msm_sd.sd.entity.flags = mount_pos;
rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
@@ -1880,6 +1887,8 @@
{
int rc = 0;
uint32_t session_id;
+ unsigned long mount_pos;
+
CDBG("%s %s_i2c_probe called\n", __func__, client->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
pr_err("%s %s i2c_check_functionality failed\n",
@@ -1976,6 +1985,12 @@
s_ctrl->msm_sd.sd.entity.name =
s_ctrl->msm_sd.sd.name;
+ mount_pos = s_ctrl->sensordata->sensor_init_params->position;
+ mount_pos = mount_pos << 8;
+ mount_pos = mount_pos |
+ (s_ctrl->sensordata->sensor_init_params->sensor_mount_angle / 90);
+ s_ctrl->msm_sd.sd.entity.flags = mount_pos;
+
rc = camera_init_v4l2(&s_ctrl->sensor_i2c_client->client->dev,
&session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
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_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 7bd6443..ca92e73 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -28,41 +28,6 @@
SMEM_SECURE = ION_FLAG_SECURE,
};
-/* NOTE: if you change this enum you MUST update the
- * "buffer-type-tz-usage-table" for any affected target
- * in arch/arm/boot/dts/<arch>.dtsi
- */
-enum hal_buffer {
- HAL_BUFFER_INPUT = 0x1,
- HAL_BUFFER_OUTPUT = 0x2,
- HAL_BUFFER_OUTPUT2 = 0x4,
- HAL_BUFFER_EXTRADATA_INPUT = 0x8,
- HAL_BUFFER_EXTRADATA_OUTPUT = 0x10,
- HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20,
- HAL_BUFFER_INTERNAL_SCRATCH = 0x40,
- HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80,
- HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100,
- HAL_BUFFER_INTERNAL_PERSIST = 0x200,
- HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
- HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
-};
-
-struct msm_smem {
- int mem_type;
- size_t size;
- void *kvaddr;
- unsigned long device_addr;
- u32 flags;
- void *smem_priv;
- enum hal_buffer buffer_type;
-};
-
-enum smem_cache_ops {
- SMEM_CACHE_CLEAN,
- SMEM_CACHE_INVALIDATE,
- SMEM_CACHE_CLEAN_INVALIDATE,
-};
-
void *msm_smem_new_client(enum smem_type mtype,
struct msm_vidc_platform_resources *res);
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
@@ -73,7 +38,6 @@
enum smem_cache_ops);
struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
enum hal_buffer buffer_type);
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
int msm_smem_get_domain_partition(void *clt, u32 flags, enum hal_buffer
buffer_type, int *domain_num, int *partition_num);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index efa195e..9dd4e93 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -971,6 +971,14 @@
rc = -EINVAL;
goto err_invalid_fmt;
}
+ if (!(get_hal_codec_type(fmt->fourcc) &
+ inst->core->dec_codec_supported)) {
+ dprintk(VIDC_ERR,
+ "Codec(0x%x) not supported\n",
+ get_hal_codec_type(fmt->fourcc));
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
inst->fmts[fmt->type] = fmt;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 6ed94e4..25917c1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -356,7 +356,7 @@
struct v4l2_plane *p, enum hal_buffer buffer_type)
{
struct msm_smem *handle = NULL;
- handle = msm_smem_user_to_kernel(inst->mem_client,
+ handle = msm_comm_smem_user_to_kernel(inst,
p->reserved[0],
p->reserved[1],
buffer_type);
@@ -365,7 +365,7 @@
"%s: Failed to get device buffer address\n", __func__);
return NULL;
}
- if (msm_smem_cache_operations(inst->mem_client, handle,
+ if (msm_comm_smem_cache_operations(inst, handle,
SMEM_CACHE_CLEAN))
dprintk(VIDC_WARN,
"CACHE Clean failed: %d, %d, %d\n",
@@ -584,7 +584,7 @@
dprintk(VIDC_DBG,
"[UNMAP] - handle[%d] = %p fd[%d] = %d",
i, temp->handle[i], i, temp->fd[i]);
- msm_smem_free(inst->mem_client,
+ msm_comm_smem_free(inst,
temp->handle[i]);
}
@@ -660,7 +660,7 @@
for (i = 0; i < binfo->num_planes; i++) {
if (binfo->handle[i]) {
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
binfo->handle[i], SMEM_CACHE_INVALIDATE);
if (rc) {
dprintk(VIDC_ERR,
@@ -745,7 +745,7 @@
list_del(&bi->list);
for (i = 0; i < bi->num_planes; i++) {
if (bi->handle[i])
- msm_smem_free(inst->mem_client,
+ msm_comm_smem_free(inst,
bi->handle[i]);
}
kfree(bi);
@@ -824,7 +824,7 @@
if ((inst->fmts[OUTPUT_PORT]->fourcc ==
V4L2_PIX_FMT_HEVC_HYBRID) && binfo->handle[i] &&
(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
binfo->handle[i], SMEM_CACHE_INVALIDATE);
if (rc) {
dprintk(VIDC_ERR,
@@ -835,7 +835,7 @@
if (binfo->handle[i] &&
(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
binfo->handle[i], SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_ERR,
@@ -970,6 +970,57 @@
fsize->stepwise.step_height = capability->height.step_size;
return 0;
}
+
+struct msm_smem *msm_vidc_smem_alloc(void *instance,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel)
+{
+ return msm_comm_smem_alloc((struct msm_vidc_inst *)instance,
+ size, align, flags, buffer_type, map_kernel);
+
+}
+
+void msm_vidc_smem_free(void *instance, struct msm_smem *mem)
+{
+ msm_comm_smem_free((struct msm_vidc_inst *)instance, mem);
+}
+
+int msm_vidc_smem_cache_operations(void *instance, struct msm_smem *mem,
+ enum smem_cache_ops cache_ops)
+{
+ return msm_comm_smem_cache_operations(
+ (struct msm_vidc_inst *)instance, mem, cache_ops);
+}
+
+struct msm_smem *msm_vidc_smem_user_to_kernel(void *instance, int fd,
+ u32 offset, enum hal_buffer buffer_type)
+{
+ return msm_comm_smem_user_to_kernel(
+ (struct msm_vidc_inst *)instance,
+ fd, offset, buffer_type);
+}
+
+int msm_vidc_smem_get_domain_partition(void *instance, u32 flags,
+ enum hal_buffer buffer_type, int *domain_num,
+ int *partition_num)
+{
+ return msm_comm_smem_get_domain_partition(
+ (struct msm_vidc_inst *)instance,
+ flags, buffer_type, domain_num, partition_num);
+}
+
+void *msm_vidc_smem_get_client(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !inst->mem_client) {
+ dprintk(VIDC_ERR, "%s: invalid instance or client = %p %p\n",
+ __func__, inst, inst->mem_client);
+ return NULL;
+ }
+
+ return inst->mem_client;
+}
static void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write)
{
@@ -1189,7 +1240,7 @@
list);
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -1200,7 +1251,7 @@
list);
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -1211,14 +1262,14 @@
list);
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
}
if (inst->extradata_handle) {
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, inst->extradata_handle);
+ msm_comm_smem_free(inst, inst->extradata_handle);
mutex_lock(&inst->lock);
}
mutex_unlock(&inst->lock);
@@ -1247,8 +1298,7 @@
for (i = 0; (i < bi->num_planes)
&& (i < VIDEO_MAX_PLANES); i++) {
if (bi->handle[i])
- msm_smem_free(inst->mem_client,
- bi->handle[i]);
+ msm_comm_smem_free(inst, bi->handle[i]);
}
kfree(bi);
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 42460fa..f456246 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -277,14 +277,17 @@
dprintk(VIDC_ERR, "Wrong device_id received\n");
return;
}
- dprintk(VIDC_DBG, "index = %d\n", index);
- dprintk(VIDC_DBG, "ptr = %p\n", &(core->completions[index]));
- complete(&(core->completions[index]));
sys_init_msg = response->data;
if (!sys_init_msg) {
dprintk(VIDC_ERR, "sys_init_done message not proper\n");
return;
}
+ core->enc_codec_supported = sys_init_msg->enc_codec_supported;
+ core->dec_codec_supported = sys_init_msg->dec_codec_supported;
+ dprintk(VIDC_DBG, "supported_codecs: enc = 0x%x, dec = 0x%x\n",
+ core->enc_codec_supported, core->dec_codec_supported);
+ dprintk(VIDC_DBG, "ptr[%d] = %p\n", index, &(core->completions[index]));
+ complete(&(core->completions[index]));
}
static void handle_session_release_buf_done(enum command_response cmd,
@@ -765,6 +768,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 +790,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 +818,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 +840,7 @@
mutex_unlock(&inst->lock);
}
}
+ mutex_unlock(&core->sync_lock);
}
static void handle_session_close(enum command_response cmd, void *data)
@@ -1594,7 +1601,7 @@
return domain;
}
-static enum hal_video_codec get_hal_codec_type(int fourcc)
+enum hal_video_codec get_hal_codec_type(int fourcc)
{
enum hal_video_codec codec;
dprintk(VIDC_DBG, "codec is 0x%x", fourcc);
@@ -1994,7 +2001,7 @@
if (output_buf->buffer_size) {
for (i = 0; i < output_buf->buffer_count_actual;
i++) {
- handle = msm_smem_alloc(inst->mem_client,
+ handle = msm_comm_smem_alloc(inst,
buffer_size, 1, smem_flags,
buffer_type, 0);
if (!handle) {
@@ -2003,7 +2010,7 @@
rc = -ENOMEM;
goto err_no_mem;
}
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
handle, SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN,
@@ -2048,7 +2055,7 @@
fail_set_buffers:
kfree(binfo);
fail_kzalloc:
- msm_smem_free(inst->mem_client, handle);
+ msm_comm_smem_free(inst, handle);
err_no_mem:
return rc;
}
@@ -2085,7 +2092,7 @@
if (scratch_buf->buffer_size) {
for (i = 0; i < scratch_buf->buffer_count_actual;
i++) {
- handle = msm_smem_alloc(inst->mem_client,
+ handle = msm_comm_smem_alloc(inst,
scratch_buf->buffer_size, 1, smem_flags,
buffer_type, 0);
if (!handle) {
@@ -2094,7 +2101,7 @@
rc = -ENOMEM;
goto err_no_mem;
}
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
handle, SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN,
@@ -2130,7 +2137,7 @@
fail_set_buffers:
kfree(binfo);
fail_kzalloc:
- msm_smem_free(inst->mem_client, handle);
+ msm_comm_smem_free(inst, handle);
err_no_mem:
return rc;
}
@@ -2172,7 +2179,7 @@
if (persist_buf->buffer_size) {
for (i = 0; i < persist_buf->buffer_count_actual; i++) {
- handle = msm_smem_alloc(inst->mem_client,
+ handle = msm_comm_smem_alloc(inst,
persist_buf->buffer_size, 1, smem_flags,
buffer_type, 0);
if (!handle) {
@@ -2181,7 +2188,7 @@
rc = -ENOMEM;
goto err_no_mem;
}
- rc = msm_smem_cache_operations(inst->mem_client,
+ rc = msm_comm_smem_cache_operations(inst,
handle, SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN,
@@ -2217,7 +2224,7 @@
fail_set_buffers:
kfree(binfo);
fail_kzalloc:
- msm_smem_free(inst->mem_client, handle);
+ msm_comm_smem_free(inst, handle);
err_no_mem:
return rc;
}
@@ -2586,7 +2593,7 @@
}
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -2657,7 +2664,7 @@
}
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -2728,7 +2735,7 @@
}
list_del(&buf->list);
mutex_unlock(&inst->lock);
- msm_smem_free(inst->mem_client, buf->handle);
+ msm_comm_smem_free(inst, buf->handle);
kfree(buf);
mutex_lock(&inst->lock);
}
@@ -3158,10 +3165,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",
@@ -3334,3 +3343,85 @@
change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
return rc;
}
+
+static inline int power_on_for_smem(struct msm_vidc_inst *inst)
+{
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: invalid inst handle\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+ rc = call_hfi_op(hdev, power_enable, hdev->hfi_device_data);
+ if (rc)
+ dprintk(VIDC_ERR, "%s: failed to power on fw\n", __func__);
+ return rc;
+}
+
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return NULL;
+ }
+ if (power_on_for_smem(inst))
+ return NULL;
+
+ return msm_smem_alloc(inst->mem_client, size, align,
+ flags, buffer_type, map_kernel);
+}
+
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem)
+{
+ if (!inst || !mem) {
+ dprintk(VIDC_ERR,
+ "%s: invalid params: %p %p\n", __func__, inst, mem);
+ return;
+ }
+ if (power_on_for_smem(inst))
+ return;
+
+ return msm_smem_free(inst->mem_client, mem);
+}
+
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+ struct msm_smem *mem, enum smem_cache_ops cache_ops)
+{
+ if (!inst || !mem) {
+ dprintk(VIDC_ERR,
+ "%s: invalid params: %p %p\n", __func__, inst, mem);
+ return -EINVAL;
+ }
+ return msm_smem_cache_operations(inst->mem_client, mem, cache_ops);
+}
+
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+ int fd, u32 offset, enum hal_buffer buffer_type)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return NULL;
+ }
+ if (power_on_for_smem(inst))
+ return NULL;
+
+ return msm_smem_user_to_kernel(inst->mem_client,
+ fd, offset, buffer_type);
+}
+
+int msm_comm_smem_get_domain_partition(struct msm_vidc_inst *inst,
+ u32 flags, enum hal_buffer buffer_type,
+ int *domain_num, int *partition_num)
+{
+ if (!inst || !domain_num || !partition_num) {
+ dprintk(VIDC_ERR, "%s: invalid params: %p %p %p\n",
+ __func__, inst, domain_num, partition_num);
+ return -EINVAL;
+ }
+ return msm_smem_get_domain_partition(inst->mem_client, flags,
+ buffer_type, domain_num, partition_num);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 195fa7e..e2f7b61 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -52,5 +52,16 @@
int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
-
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel);
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem);
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+ struct msm_smem *mem, enum smem_cache_ops cache_ops);
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+ int fd, u32 offset, enum hal_buffer buffer_type);
+int msm_comm_smem_get_domain_partition(struct msm_vidc_inst *inst,
+ u32 flags, enum hal_buffer buffer_type,
+ int *domain_num, int *partition_num);
+enum hal_video_codec get_hal_codec_type(int fourcc);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 2b1471c..e4f920f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -207,6 +207,8 @@
struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
enum msm_vidc_hfi_type hfi_type;
struct msm_vidc_platform_resources resources;
+ u32 enc_codec_supported;
+ u32 dec_codec_supported;
};
struct msm_vidc_inst {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 916df1d..a8178f7 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -29,6 +29,7 @@
#include "venus_hfi.h"
#include "vidc_hfi_io.h"
#include "msm_vidc_debug.h"
+#include <linux/iopoll.h>
#define FIRMWARE_SIZE 0X00A00000
#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
@@ -75,6 +76,10 @@
u32 spare; /*reserved for future, should be zero*/
};
+static int venus_hfi_power_enable(void *dev);
+
+static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device);
+
static void venus_hfi_dump_packet(u8 *packet)
{
u32 c = 0, packet_size = *(u32 *)packet;
@@ -402,21 +407,24 @@
return rc;
}
-static int venus_hfi_alloc(void *mem, void *clnt, u32 size, u32 align,
- u32 flags, u32 usage)
+static int venus_hfi_alloc(struct venus_hfi_device *dev, void *mem,
+ u32 size, u32 align, u32 flags, u32 usage)
{
- struct vidc_mem_addr *vmem;
- struct msm_smem *alloc;
+ struct vidc_mem_addr *vmem = NULL;
+ struct msm_smem *alloc = NULL;
int rc = 0;
- if (!mem || !clnt || !size) {
+ if (!dev || !dev->hal_client || !mem || !size) {
dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
+
vmem = (struct vidc_mem_addr *)mem;
dprintk(VIDC_INFO, "start to alloc: size:%d, Flags: %d", size, flags);
- alloc = msm_smem_alloc(clnt, size, align, flags, usage, 1);
+ venus_hfi_power_enable(dev);
+
+ alloc = msm_smem_alloc(dev->hal_client, size, align, flags, usage, 1);
dprintk(VIDC_DBG, "Alloc done");
if (!alloc) {
dprintk(VIDC_ERR, "Alloc failed\n");
@@ -425,7 +433,7 @@
}
dprintk(VIDC_DBG, "venus_hfi_alloc:ptr=%p,size=%d",
alloc->kvaddr, size);
- rc = msm_smem_cache_operations(clnt, alloc,
+ rc = msm_smem_cache_operations(dev->hal_client, alloc,
SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_WARN, "Failed to clean cache\n");
@@ -440,9 +448,14 @@
return rc;
}
-static void venus_hfi_free(struct smem_client *clnt, struct msm_smem *mem)
+static void venus_hfi_free(struct venus_hfi_device *dev, struct msm_smem *mem)
{
- msm_smem_free(clnt, mem);
+ if (!dev || !mem) {
+ dprintk(VIDC_ERR, "invalid param %p %p\n", dev, mem);
+ return;
+ }
+ venus_hfi_power_enable(dev);
+ msm_smem_free(dev->hal_client, mem);
}
static void venus_hfi_write_register(struct venus_hfi_device *device, u32 reg,
@@ -865,6 +878,34 @@
static DECLARE_COMPLETION(pc_prep_done);
+static int venus_hfi_halt_axi(struct venus_hfi_device *device)
+{
+ u32 reg;
+ int rc = 0;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid input: %p\n", device);
+ return -EINVAL;
+ }
+ if (venus_hfi_clk_gating_off(device)) {
+ dprintk(VIDC_ERR, "Failed to turn off clk gating\n");
+ return -EIO;
+ }
+ /* Halt AXI and AXI OCMEM VBIF Access */
+ reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
+ reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+ venus_hfi_write_register(device, VENUS_VBIF_AXI_HALT_CTRL0, reg, 0);
+
+ /* Request for AXI bus port halt */
+ rc = readl_poll_timeout((u32)device->hal_data->register_base_addr
+ + VENUS_VBIF_AXI_HALT_CTRL1,
+ reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+ POLL_INTERVAL_US,
+ VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+ if (rc)
+ dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+ return rc;
+}
+
static inline int venus_hfi_power_off(struct venus_hfi_device *device)
{
int rc = 0;
@@ -972,6 +1013,22 @@
return rc;
}
+static int venus_hfi_power_enable(void *dev)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = dev;
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return -EINVAL;
+ }
+ mutex_lock(&device->clk_pwr_lock);
+ if (!device->power_enabled)
+ rc = venus_hfi_power_on(device);
+ mutex_unlock(&device->clk_pwr_lock);
+
+ return rc;
+}
+
static void venus_hfi_pm_hndlr(struct work_struct *work);
static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr);
@@ -1057,30 +1114,32 @@
dprintk(VIDC_ERR, "cannot write to shared Q's");
goto err_q_null;
}
- mutex_lock(&device->clk_pwr_lock);
- result = venus_hfi_clk_gating_off(device);
- if (result) {
- dprintk(VIDC_ERR, "%s : Clock enable failed\n",
- __func__);
- goto err_q_write;
- }
- result = venus_hfi_scale_clocks(device, device->clk_load);
- if (result) {
- dprintk(VIDC_ERR, "Clock scaling failed\n");
- goto err_q_write;
- }
if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ result = venus_hfi_clk_gating_off(device);
+ if (result) {
+ dprintk(VIDC_ERR, "%s : Clock enable failed\n",
+ __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto err_q_write;
+ }
+ result = venus_hfi_scale_clocks(device, device->clk_load);
+ if (result) {
+ dprintk(VIDC_ERR, "Clock scaling failed\n");
+ mutex_unlock(&device->clk_pwr_lock);
+ goto err_q_write;
+ }
if (rx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
result = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full");
}
err_q_write:
- mutex_unlock(&device->clk_pwr_lock);
err_q_null:
mutex_unlock(&device->write_lock);
return result;
@@ -1104,26 +1163,27 @@
goto read_error_null;
}
q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
- mutex_lock(&device->clk_pwr_lock);
- rc = venus_hfi_clk_gating_off(device);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
- goto read_error;
- }
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto read_error;
+ }
if (tx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_INFO, "venus_hfi_iface_msgq_read:queue_empty");
rc = -ENODATA;
}
read_error:
- mutex_unlock(&device->clk_pwr_lock);
read_error_null:
mutex_unlock(&device->read_lock);
return rc;
@@ -1146,27 +1206,28 @@
rc = -ENODATA;
goto dbg_error_null;
}
- mutex_lock(&device->clk_pwr_lock);
- rc = venus_hfi_clk_gating_off(device);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
- goto dbg_error;
- }
q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto dbg_error;
+ }
if (tx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_INFO, "venus_hfi_iface_dbgq_read:queue_empty");
rc = -ENODATA;
}
dbg_error:
- mutex_unlock(&device->clk_pwr_lock);
dbg_error_null:
mutex_unlock(&device->read_lock);
return rc;
@@ -1213,10 +1274,10 @@
(unsigned long)(mem_map[i].virtual_addr),
domain, partition, SZ_4K);
}
- venus_hfi_free(device->hal_client, device->qdss.mem_data);
+ venus_hfi_free(device, device->qdss.mem_data);
}
- venus_hfi_free(device->hal_client, device->iface_q_table.mem_data);
- venus_hfi_free(device->hal_client, device->sfr.mem_data);
+ venus_hfi_free(device, device->iface_q_table.mem_data);
+ venus_hfi_free(device, device->sfr.mem_data);
for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
device->iface_queues[i].q_hdr = NULL;
@@ -1251,7 +1312,7 @@
for (i = 0; i < num_entries; i++) {
rc = msm_iommu_map_contig_buffer(venus_qdss_entries[i][0],
- domain, 1 , venus_qdss_entries[i][1],
+ domain, partition, venus_qdss_entries[i][1],
SZ_4K, 0, &iova);
if (rc) {
dprintk(VIDC_ERR,
@@ -1292,8 +1353,8 @@
int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
int domain, partition;
mem_addr = &dev->mem_addr;
- rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, QUEUE_SIZE, 1, 0,
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ QUEUE_SIZE, 1, 0,
HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
@@ -1319,8 +1380,8 @@
venus_hfi_set_queue_hdr_defaults(iface_q->q_hdr);
}
- rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, QDSS_SIZE, 1, 0,
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ QDSS_SIZE, 1, 0,
HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_WARN,
@@ -1332,8 +1393,8 @@
dev->qdss.mem_size = QDSS_SIZE;
dev->qdss.mem_data = mem_addr->mem_data;
}
- rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, SFR_SIZE, 1, 0,
+ rc = venus_hfi_alloc(dev, (void *) mem_addr,
+ SFR_SIZE, 1, 0,
HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work");
@@ -1398,7 +1459,7 @@
if (rc) {
dprintk(VIDC_ERR,
"IOMMU mapping failed, Freeing qdss memdata");
- venus_hfi_free(dev->hal_client, dev->qdss.mem_data);
+ venus_hfi_free(dev, dev->qdss.mem_data);
dev->qdss.mem_data = NULL;
}
if (!IS_ERR_OR_NULL(dev->qdss.align_device_addr))
@@ -1567,20 +1628,59 @@
return 0;
}
+static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
+{
+ struct hfi_queue_header *queue;
+ struct vidc_iface_q_info *q_info;
+ u32 write_ptr, read_ptr;
+ u32 rc = 0;
+ q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+ if (!q_info)
+ dprintk(VIDC_ERR, "cannot read shared Q's");
+ queue = (struct hfi_queue_header *) q_info->q_hdr;
+ if (!queue) {
+ dprintk(VIDC_ERR, "queue not present");
+ return -ENOENT;
+ }
+ write_ptr = (u32)queue->qhdr_write_idx;
+ read_ptr = (u32)queue->qhdr_read_idx;
+ rc = read_ptr - write_ptr;
+ return rc;
+}
+
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
+{
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return;
+ }
+ if (!device->clocks_enabled) {
+ dprintk(VIDC_DBG, "Clocks are already disabled");
+ goto already_disabled;
+ }
+ venus_hfi_clk_disable(device);
+ if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
+ msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
+ dprintk(VIDC_DBG, "PM work already scheduled\n");
+already_disabled:
+ device->clocks_enabled = 0;
+}
+
static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
{
u32 intr_status = 0;
- int rc = 0;
+ int rc = 0, ctrl_status;
if (!device->callback)
return;
+
+ mutex_lock(&device->write_lock);
mutex_lock(&device->clk_pwr_lock);
rc = venus_hfi_clk_gating_off(device);
if (rc) {
dprintk(VIDC_ERR,
"%s : Clock enable failed\n", __func__);
- mutex_unlock(&device->clk_pwr_lock);
- return;
+ goto err_clk_gating_off;
}
intr_status = venus_hfi_read_register(
device,
@@ -1603,8 +1703,23 @@
VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
venus_hfi_write_register(device,
VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
- mutex_unlock(&device->clk_pwr_lock);
+ rc = venus_hfi_is_cmd_pending(device);
+ ctrl_status = venus_hfi_read_register(
+ device,
+ VIDC_CPU_CS_SCIACMDARG0);
+ dprintk(VIDC_INFO,
+ "CLEAR INTERRUPT - cmd_pending %d, ctrl_status 0x%x\n",
+ rc, ctrl_status);
+ if ((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
+ && !rc) {
+ dprintk(VIDC_DBG, "SYS_IDLE interrupt, disable clocks\n");
+ venus_hfi_clk_gating_on(device);
+ }
+
dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
+err_clk_gating_off:
+ mutex_unlock(&device->clk_pwr_lock);
+ mutex_unlock(&device->write_lock);
}
static int venus_hfi_core_set_resource(void *device,
@@ -2321,26 +2436,6 @@
device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
}
-static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
-{
- struct hfi_queue_header *queue;
- struct vidc_iface_q_info *q_info;
- u32 write_ptr, read_ptr;
- u32 rc = 0;
- q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
- if (!q_info)
- dprintk(VIDC_ERR, "cannot read shared Q's");
- queue = (struct hfi_queue_header *) q_info->q_hdr;
- if (!queue) {
- dprintk(VIDC_ERR, "queue not present");
- return -ENOENT;
- }
- write_ptr = (u32)queue->qhdr_write_idx;
- read_ptr = (u32)queue->qhdr_read_idx;
- rc = read_ptr - write_ptr;
- return rc;
-}
-
static int venus_hfi_core_pc_prep(void *device)
{
struct hfi_cmd_sys_pc_prep_packet pkt;
@@ -2408,24 +2503,6 @@
mutex_unlock(&device->clk_pwr_lock);
}
-static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
-{
- if (!device) {
- dprintk(VIDC_ERR, "Invalid params: %p\n", device);
- return;
- }
- if (!device->clocks_enabled) {
- dprintk(VIDC_DBG, "Clocks are already disabled");
- goto already_disabled;
- }
- venus_hfi_clk_disable(device);
- if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
- msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
- dprintk(VIDC_DBG, "PM work already scheduled\n");
-already_disabled:
- device->clocks_enabled = 0;
-}
-
static int venus_hfi_try_clk_gating(struct venus_hfi_device *device)
{
int rc = 0;
@@ -2506,10 +2583,12 @@
(struct hfi_msg_sys_debug_packet *) packet;
dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
}
- if (rc == HFI_MSG_SYS_IDLE)
+ if (rc == HFI_MSG_SYS_IDLE) {
+ dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n");
rc = venus_hfi_try_clk_gating(device);
- else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
- dprintk(VIDC_DBG, "Received HFI_MSG_SYS_PC_PREP_DONE");
+ } else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_PC_PREP_DONE\n");
rc = venus_hfi_try_clk_gating(device);
if (rc)
dprintk(VIDC_ERR,
@@ -3258,15 +3337,21 @@
if (device->resources.fw.cookie) {
flush_workqueue(device->vidc_workq);
flush_workqueue(device->venus_pm_workq);
+ subsystem_put(device->resources.fw.cookie);
+ venus_hfi_interface_queues_release(dev);
+ /* IOMMU operations need to be done before AXI halt.*/
+ venus_hfi_iommu_detach(device);
+ /* Halt the AXI to make sure there are no pending transactions.
+ * Clocks should be unprepared after making sure axi is halted.
+ */
+ if(venus_hfi_halt_axi(device))
+ dprintk(VIDC_WARN, "Failed to halt AXI\n");
venus_hfi_disable_clks(device);
mutex_lock(&device->clk_pwr_lock);
- subsystem_put(device->resources.fw.cookie);
regulator_disable(device->gdsc);
device->power_enabled = 0;
--device->pwr_cnt;
mutex_unlock(&device->clk_pwr_lock);
- venus_hfi_interface_queues_release(dev);
- venus_hfi_iommu_detach(device);
device->resources.fw.cookie = NULL;
}
}
@@ -3559,6 +3644,7 @@
hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
hdev->capability_check = venus_hfi_capability_check;
hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
+ hdev->power_enable = venus_hfi_power_enable;
}
int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index cc07806..be9eae0 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1129,6 +1129,7 @@
u32 *max_width, u32 *max_height);
int (*session_clean)(void *sess);
int (*get_core_capabilities)(void);
+ int (*power_enable)(void *dev);
};
typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index 6377fbf..176db4a 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -131,6 +131,15 @@
#define VIDC_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0xC08)
#define VIDC_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0xC10)
#define VIDC_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0xC18)
+#define VENUS_VBIF_AXI_HALT_CTRL0 (VIDC_VBIF_BASE_OFFS + 0x208)
+#define VENUS_VBIF_AXI_HALT_CTRL1 (VIDC_VBIF_BASE_OFFS + 0x20C)
+
+#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0)
+#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0)
+#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
(VIDC_WRAPPER_BASE_OFFS + 0x20)
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 31d03b6..a554749 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -496,8 +496,15 @@
static void iris_q_event(struct iris_device *radio,
enum iris_evt_t event)
{
- struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
+ struct kfifo *data_b;
unsigned char evt = event;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ data_b = &radio->data_buf[IRIS_BUF_EVENTS];
if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
wake_up_interruptible(&radio->event_queue);
}
@@ -582,8 +589,6 @@
skb_queue_head_init(&hdev->cmd_q);
skb_queue_head_init(&hdev->raw_q);
- if (!radio)
- FMDERR(":radio is null");
radio->fm_hdev = hdev;
@@ -674,6 +679,10 @@
struct iris_device *radio = video_get_drvdata(video_get_dev());
__u16 opcode = 0;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
HCI_FM_SET_INTERNAL_TONE_GENRATOR);
return radio_hci_send_cmd(hdev, opcode,
@@ -1144,7 +1153,7 @@
return radio_hci_send_cmd(hdev, opcode, 0, NULL);
}
-static int radio_hci_err(__u16 code)
+static int radio_hci_err(__u32 code)
{
switch (code) {
case 0:
@@ -1642,6 +1651,11 @@
__u8 status = *((__u8 *) skb->data);
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
if ((radio->mode == FM_TURNING_OFF) && (status == 0)) {
iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
radio_hci_req_complete(hdev, status);
@@ -1659,6 +1673,10 @@
struct hci_fm_conf_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
if (rsp->status)
return;
@@ -1672,6 +1690,11 @@
struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
if (rsp->status)
return;
memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
@@ -1685,6 +1708,11 @@
struct hci_fm_conf_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
if (rsp->status) {
radio_hci_req_complete(hdev, rsp->status);
return;
@@ -1707,6 +1735,11 @@
struct hci_fm_conf_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
if (rsp->status)
return;
@@ -1722,6 +1755,11 @@
struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
if (rsp->status)
return;
@@ -1733,6 +1771,12 @@
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
struct hci_fm_station_rsp *rsp = (void *)skb->data;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
radio->fm_st_rsp = *(rsp);
/* Tune is always succesful */
@@ -1772,9 +1816,16 @@
static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
struct sk_buff *skb)
{
+ struct v4l2_capability *v4l_cap;
struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- struct v4l2_capability *v4l_cap = radio->g_cap;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ v4l_cap = radio->g_cap;
if (rsp->status)
return;
@@ -1789,8 +1840,13 @@
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
- radio->st_dbg_param = *(rsp);
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
+ radio->st_dbg_param = *(rsp);
if (radio->st_dbg_param.status)
return;
@@ -1800,7 +1856,13 @@
static void iris_q_evt_data(struct iris_device *radio,
char *data, int len, int event)
{
- struct kfifo *data_b = &radio->data_buf[event];
+ struct kfifo *data_b;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+ data_b = &radio->data_buf[event];
if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
wake_up_interruptible(&radio->event_queue);
}
@@ -1837,6 +1899,11 @@
__u8 status = *((__u8 *) skb->data);
__u8 len;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
+
if (status)
return;
len = skb->data[1];
@@ -1917,6 +1984,11 @@
{
struct iris_device *radio = video_get_drvdata(video_get_dev());
u8 status = skb->data[0];
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
if (status) {
FMDERR("status = %d", status);
return;
@@ -2050,6 +2122,10 @@
int i;
struct iris_device *radio = video_get_drvdata(video_get_dev());
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
sizeof(struct hci_ev_tune_status));
iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
@@ -2092,6 +2168,10 @@
int abs_freq;
int len;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
FMDERR("Memory allocation failed");
@@ -2150,6 +2230,10 @@
radio = video_get_drvdata(video_get_dev());
index = RDSGRP_DATA_OFFSET;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return;
+ }
for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
temp.rdsBlk[blocknum].rdsLsb =
(skb->data[index]);
@@ -2556,9 +2640,15 @@
static int iris_search(struct iris_device *radio, int on, int dir)
{
int retval = 0;
- enum search_t srch = radio->g_search_mode & SRCH_MODE;
- radio->search_on = on;
+ enum search_t srch;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
+ srch = radio->g_search_mode & SRCH_MODE;
+ radio->search_on = on;
if (on) {
switch (srch) {
case SCAN_FOR_STRONG:
@@ -2600,6 +2690,12 @@
int rds_grps_proc = 0x00;
int retval = 0;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
if (radio->power_mode != power_mode) {
if (power_mode) {
@@ -2638,6 +2734,12 @@
static int iris_recv_set_region(struct iris_device *radio, int req_region)
{
int retval;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
radio->region = req_region;
retval = hci_set_fm_recv_conf(
@@ -2651,6 +2753,11 @@
static int iris_trans_set_region(struct iris_device *radio, int req_region)
{
int retval;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
radio->region = req_region;
retval = hci_set_fm_trans_conf(
@@ -2664,6 +2771,11 @@
{
int retval;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
retval = hci_fm_tune_station(&freq, radio->fm_hdev);
if (retval < 0)
FMDERR("Error while setting the frequency : %d\n", retval);
@@ -2693,6 +2805,11 @@
char cal_mode = 0x00;
int retval = 0x00;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
cal_mode = PROCS_CALIB_MODE;
radio->mode = FM_CALIB;
retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
@@ -2727,6 +2844,11 @@
struct hci_fm_def_data_rd_req rd;
int lsb, msb;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
break;
@@ -3012,6 +3134,11 @@
struct iris_device *radio = video_get_drvdata(video_devdata(file));
struct hci_fm_def_data_rd_req default_data_rd;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
switch ((ctrl->controls[0]).id) {
case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
data = (ctrl->controls[0]).string;
@@ -3041,6 +3168,10 @@
struct iris_device *radio = video_get_drvdata(video_devdata(file));
char *data = NULL;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
switch ((ctrl->controls[0]).id) {
case V4L2_CID_RDS_TX_PS_NAME:
FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
@@ -3164,6 +3295,11 @@
char sinr_th, sinr;
__u8 intf_det_low_th, intf_det_high_th, intf_det_out;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
switch (ctrl->id) {
case V4L2_CID_PRIVATE_IRIS_TX_TONE:
radio->tone_freq = ctrl->value;
@@ -3476,13 +3612,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;
@@ -3833,6 +3982,10 @@
/* Pass the mode of SPUR_CLK */
default_data.mode = CKK_SPUR;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
temp = radio->spur_table_size;
for (cnt = 0; cnt < (temp / 5); cnt++) {
offset = 0;
@@ -3903,6 +4056,10 @@
int retval;
struct iris_device *radio = video_get_drvdata(video_devdata(file));
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
if (tuner->index > 0) {
FMDERR("Invalid Tuner Index");
return -EINVAL;
@@ -3946,6 +4103,12 @@
{
struct iris_device *radio = video_get_drvdata(video_devdata(file));
int retval = 0;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -3997,6 +4160,10 @@
int retval = -1;
freq->frequency = freq->frequency / TUNE_PARAM;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
if (freq->type != V4L2_TUNER_RADIO)
return -EINVAL;
@@ -4124,6 +4291,11 @@
{
struct iris_device *radio;
radio = video_get_drvdata(video_devdata(file));
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
@@ -4135,6 +4307,11 @@
{
int retval;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
radio->mute_mode.soft_mute = CTRL_ON;
retval = hci_set_fm_mute_mode(&radio->mute_mode,
radio->fm_hdev);
@@ -4172,7 +4349,14 @@
static int initialise_trans(struct iris_device *radio)
{
- int retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
+ int retval;
+
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
+ retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
if (retval < 0)
FMDERR("get frequency failed %d\n", retval);
@@ -4183,6 +4367,11 @@
{
int retval = 1;
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
+
if (radio->mode == FM_OFF || radio->mode == FM_RECV)
retval = 0;
@@ -4325,6 +4514,10 @@
int i;
struct iris_device *radio = platform_get_drvdata(pdev);
+ if (radio == NULL) {
+ FMDERR(":radio is null");
+ return -EINVAL;
+ }
video_unregister_device(radio->videodev);
for (i = 0; i < IRIS_BUF_MAX; i++)
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index e0a99e2..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))
@@ -4466,8 +4466,8 @@
struct marimba_fm_platform_data *tavarua_pdata;
struct tavarua_device *radio;
- int retval;
- int i;
+ int retval = 0;
+ int i = 0, j = 0;
FMDBG("%s: probe called\n", __func__);
/* private data allocation */
radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
@@ -4480,6 +4480,7 @@
tavarua_pdata = pdev->dev.platform_data;
radio->pdata = tavarua_pdata;
radio->dev = &pdev->dev;
+ radio->wqueue = NULL;
platform_set_drvdata(pdev, radio);
/* video device allocation */
@@ -4509,15 +4510,16 @@
if (kfifo_alloc_rc!=0) {
printk(KERN_ERR "%s: failed allocating buffers %d\n",
__func__, kfifo_alloc_rc);
- goto err_bufs;
+ retval = -ENOMEM;
+ goto err_all;
}
}
/* initializing the device count */
atomic_set(&radio->users, 1);
radio->xfr_in_progress = 0;
radio->xfr_bytes_left = 0;
- for (i = 0; i < TAVARUA_XFR_MAX; i++)
- radio->pending_xfrs[i] = 0;
+ for (j = 0; j < TAVARUA_XFR_MAX; j++)
+ radio->pending_xfrs[j] = 0;
/* init transmit data */
radio->tx_mode = TAVARUA_TX_RT;
@@ -4548,11 +4550,14 @@
/*Start the worker thread for event handling and register read_int_stat
as worker function*/
radio->wqueue = create_singlethread_workqueue("kfmradio");
- if (!radio->wqueue)
- return -ENOMEM;
+ if (!radio->wqueue) {
+ retval = -ENOMEM;
+ goto err_all;
+ }
/* register video device */
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (retval != 0) {
printk(KERN_WARNING DRIVER_NAME
": Could not register video device\n");
goto err_all;
@@ -4562,9 +4567,11 @@
err_all:
video_device_release(radio->videodev);
-err_bufs:
- for (; i > -1; i--)
+ if (radio->wqueue)
+ destroy_workqueue(radio->wqueue);
+ for (i--; i >= 0; i--) {
kfifo_free(&radio->data_buf[i]);
+ }
err_radio:
kfree(radio);
err_initial:
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index a30607c..2162294 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -91,7 +91,6 @@
static struct class *driver_class;
static dev_t qseecom_device_no;
-static struct cdev qseecom_cdev;
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
@@ -162,6 +161,7 @@
uint32_t qsee_perf_client;
struct qseecom_clk qsee;
struct qseecom_clk ce_drv;
+ struct cdev cdev;
};
struct qseecom_client_handle {
@@ -251,6 +251,12 @@
break;
}
spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+ if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
+ pr_err("Service id: %u is not found\n", listener_id);
+ return NULL;
+ }
+
return entry;
}
@@ -449,6 +455,11 @@
}
/* Get the physical address of the ION BUF */
ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+ if (len < req.sb_len) {
+ pr_err("Requested length (0x%x) is > allocated (0x%x)\n",
+ req.sb_len, len);
+ return -EINVAL;
+ }
/* Populate the structure for sending scm call to load image */
data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
data->client.ihandle);
@@ -494,6 +505,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 +876,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;
@@ -1063,8 +1083,6 @@
if (ret)
return ret;
- pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
- req.resp_len, req.resp_buf);
return ret;
}
@@ -1254,8 +1272,7 @@
ret = __qseecom_update_cmd_buf(&req, true, data, false);
if (ret)
return ret;
- pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
- req.resp_len, req.resp_buf);
+
return ret;
}
@@ -1273,6 +1290,11 @@
struct qseecom_registered_listener_list *this_lstnr;
this_lstnr = __qseecom_find_svc(data->listener.id);
+ if (!this_lstnr) {
+ pr_err("Invalid listener ID\n");
+ return -ENODATA;
+ }
+
while (1) {
if (wait_event_freezable(this_lstnr->rcv_req_wq,
__qseecom_listener_has_rcvd_req(data,
@@ -3330,7 +3352,7 @@
if (IS_ERR(driver_class)) {
rc = -ENOMEM;
pr_err("class_create failed %d\n", rc);
- goto unregister_chrdev_region;
+ goto exit_unreg_chrdev_region;
}
class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
@@ -3338,16 +3360,16 @@
if (!class_dev) {
pr_err("class_device_create failed %d\n", rc);
rc = -ENOMEM;
- goto class_destroy;
+ goto exit_destroy_class;
}
- cdev_init(&qseecom_cdev, &qseecom_fops);
- qseecom_cdev.owner = THIS_MODULE;
+ cdev_init(&qseecom.cdev, &qseecom_fops);
+ qseecom.cdev.owner = THIS_MODULE;
- rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
+ rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
if (rc < 0) {
pr_err("cdev_add failed %d\n", rc);
- goto err;
+ goto exit_destroy_device;
}
INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
@@ -3363,7 +3385,7 @@
&qsee_not_legacy, sizeof(qsee_not_legacy));
if (rc) {
pr_err("Failed to retrieve QSEOS version information %d\n", rc);
- goto err;
+ goto exit_del_cdev;
}
if (qsee_not_legacy) {
uint32_t feature = 10;
@@ -3373,14 +3395,14 @@
&qseecom.qsee_version, sizeof(qseecom.qsee_version));
if (rc) {
pr_err("Failed to get QSEE version info %d\n", rc);
- goto err;
+ goto exit_del_cdev;
}
qseecom.qseos_version = QSEOS_VERSION_14;
} else {
pr_err("QSEE legacy version is not supported:");
pr_err("Support for TZ1.3 and earlier is deprecated\n");
rc = -EINVAL;
- goto err;
+ goto exit_del_cdev;
}
qseecom.commonlib_loaded = false;
qseecom.pdev = class_dev;
@@ -3389,7 +3411,7 @@
if (qseecom.ion_clnt == NULL) {
pr_err("Ion client cannot be created\n");
rc = -ENOMEM;
- goto err;
+ goto exit_del_cdev;
}
/* register client for bus scaling */
@@ -3401,7 +3423,7 @@
pr_err("Fail to get disk-encrypt pipe pair information.\n");
qseecom.ce_info.disk_encrypt_pipe = 0xff;
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
} else {
pr_warn("bam_pipe_pair=0x%x",
qseecom.ce_info.disk_encrypt_pipe);
@@ -3413,7 +3435,7 @@
pr_err("Fail to get qsee ce hw instance information.\n");
qseecom.ce_info.qsee_ce_hw_instance = 0xff;
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
} else {
pr_warn("qsee-ce-hw-instance=0x%x",
qseecom.ce_info.qsee_ce_hw_instance);
@@ -3425,7 +3447,7 @@
pr_err("Fail to get hlos ce hw instance information.\n");
qseecom.ce_info.hlos_ce_hw_instance = 0xff;
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
} else {
pr_warn("hlos-ce-hw-instance=0x%x",
qseecom.ce_info.hlos_ce_hw_instance);
@@ -3436,13 +3458,13 @@
ret = __qseecom_init_clk(CLK_QSEE);
if (ret)
- goto err;
+ goto exit_destroy_ion_client;
if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
ret = __qseecom_init_clk(CLK_CE_DRV);
if (ret) {
__qseecom_deinit_clk(CLK_QSEE);
- goto err;
+ goto exit_destroy_ion_client;
}
} else {
struct qseecom_clk *qclk;
@@ -3472,7 +3494,7 @@
} else {
pr_err("Fail to get secure app region info\n");
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
}
rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
&resp, sizeof(resp));
@@ -3480,7 +3502,7 @@
pr_err("send secapp reg fail %d resp.res %d\n",
rc, resp.result);
rc = -EINVAL;
- goto err;
+ goto exit_destroy_ion_client;
}
}
} else {
@@ -3494,11 +3516,16 @@
if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
return 0;
-err:
+
+exit_destroy_ion_client:
+ ion_client_destroy(qseecom.ion_clnt);
+exit_del_cdev:
+ cdev_del(&qseecom.cdev);
+exit_destroy_device:
device_destroy(driver_class, qseecom_device_no);
-class_destroy:
+exit_destroy_class:
class_destroy(driver_class);
-unregister_chrdev_region:
+exit_unreg_chrdev_region:
unregister_chrdev_region(qseecom_device_no, 1);
return rc;
}
@@ -3509,69 +3536,64 @@
unsigned long flags = 0;
int ret = 0;
- if (pdev->dev.platform_data != NULL)
- msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
-
spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
- kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
- struct qseecom_registered_kclient_list, list);
- if (list_empty(&kclient->list)) {
- spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
- flags);
- return 0;
- }
+
list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
- list) {
- if (kclient)
- list_del(&kclient->list);
- break;
- }
- spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+ list) {
+ if (!kclient)
+ goto exit_irqrestore;
+ /* Break the loop if client handle is NULL */
+ if (!kclient->handle)
+ goto exit_free_kclient;
- while (kclient->handle != NULL) {
+ if (list_empty(&kclient->list))
+ goto exit_free_kc_handle;
+
+ list_del(&kclient->list);
ret = qseecom_unload_app(kclient->handle->dev);
- if (ret == 0) {
+ if (!ret) {
kzfree(kclient->handle->dev);
kzfree(kclient->handle);
kzfree(kclient);
}
- spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
- kclient = list_entry(
- (&qseecom.registered_kclient_list_head)->next,
- struct qseecom_registered_kclient_list, list);
- if (list_empty(&kclient->list)) {
- spin_unlock_irqrestore(
- &qseecom.registered_kclient_list_lock, flags);
- return 0;
- }
- list_for_each_entry(kclient,
- &qseecom.registered_kclient_list_head, list) {
- if (kclient)
- list_del(&kclient->list);
- break;
- }
- spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
- flags);
- if (!kclient) {
- ret = 0;
- break;
- }
}
- if (qseecom.qseos_version > QSEEE_VERSION_00)
+
+exit_free_kc_handle:
+ kzfree(kclient->handle);
+exit_free_kclient:
+ kzfree(kclient);
+exit_irqrestore:
+ spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+
+ if (qseecom.qseos_version > QSEEE_VERSION_00)
qseecom_unload_commonlib_image();
if (qseecom.qsee_perf_client)
msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
0);
+ if (pdev->dev.platform_data != NULL)
+ msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
+
/* register client for bus scaling */
if (pdev->dev.of_node) {
__qseecom_deinit_clk(CLK_QSEE);
if (qseecom.qsee.instance != qseecom.ce_drv.instance)
__qseecom_deinit_clk(CLK_CE_DRV);
}
+
+ ion_client_destroy(qseecom.ion_clnt);
+
+ cdev_del(&qseecom.cdev);
+
+ device_destroy(driver_class, qseecom_device_no);
+
+ class_destroy(driver_class);
+
+ unregister_chrdev_region(qseecom_device_no, 1);
+
return ret;
-};
+}
static struct of_device_id qseecom_match[] = {
{
@@ -3597,10 +3619,7 @@
static void __devexit qseecom_exit(void)
{
- device_destroy(driver_class, qseecom_device_no);
- class_destroy(driver_class);
- unregister_chrdev_region(qseecom_device_no, 1);
- ion_client_destroy(qseecom.ion_clnt);
+ platform_driver_unregister(&qseecom_plat_driver);
}
MODULE_LICENSE("GPL v2");
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/mmc/core/bus.c b/drivers/mmc/core/bus.c
index eb5d365..421774f 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -414,14 +414,12 @@
#endif
mmc_init_context_info(card->host);
- if (mmc_use_core_runtime_pm(card->host)) {
- ret = pm_runtime_set_active(&card->dev);
- if (ret)
- pr_err("%s: %s: failed setting runtime active: ret: %d\n",
- mmc_hostname(card->host), __func__, ret);
- else if (!mmc_card_sdio(card))
- pm_runtime_enable(&card->dev);
- }
+ ret = pm_runtime_set_active(&card->dev);
+ if (ret)
+ pr_err("%s: %s: failed setting runtime active: ret: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ else if (!mmc_card_sdio(card) && mmc_use_core_runtime_pm(card->host))
+ pm_runtime_enable(&card->dev);
ret = device_add(&card->dev);
if (ret)
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
index 14dd313..45ec5c2 100644
--- a/drivers/mmc/core/cd-gpio.c
+++ b/drivers/mmc/core/cd-gpio.c
@@ -111,8 +111,12 @@
{
struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
+ if (!cd || !gpio_is_valid(cd->gpio))
+ return;
+
free_irq(host->hotplug.irq, host);
gpio_free(cd->gpio);
+ cd->gpio = -EINVAL;
kfree(cd);
}
EXPORT_SYMBOL(mmc_cd_gpio_free);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index edd6a5d..c7fa876 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -78,7 +78,7 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
- if (!mmc_use_core_runtime_pm(host))
+ if (!mmc_use_core_pm(host))
return 0;
if (!pm_runtime_suspended(dev)) {
@@ -95,7 +95,7 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
- if (!mmc_use_core_runtime_pm(host))
+ if (!mmc_use_core_pm(host))
return 0;
if (!pm_runtime_suspended(dev)) {
@@ -686,14 +686,13 @@
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
- if (mmc_use_core_runtime_pm(host)) {
- err = pm_runtime_set_active(&host->class_dev);
- if (err)
- pr_err("%s: %s: failed setting runtime active: err: %d\n",
- mmc_hostname(host), __func__, err);
- else
- pm_runtime_enable(&host->class_dev);
- }
+ err = pm_runtime_set_active(&host->class_dev);
+ if (err)
+ pr_err("%s: %s: failed setting runtime active: err: %d\n",
+ mmc_hostname(host), __func__, err);
+ else if (mmc_use_core_runtime_pm(host))
+ pm_runtime_enable(&host->class_dev);
+
err = device_add(&host->class_dev);
if (err)
return err;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index b93eaf4..e391a06 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -317,6 +317,7 @@
bool tuning_done;
bool calibration_done;
u8 saved_tuning_phase;
+ atomic_t controller_clock;
};
enum vdd_io_level {
@@ -2213,6 +2214,50 @@
return sel_clk;
}
+static int sdhci_msm_enable_controller_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int rc = 0;
+
+ if (atomic_read(&msm_host->controller_clock))
+ return 0;
+
+ sdhci_msm_bus_voting(host, 1);
+
+ if (!IS_ERR(msm_host->pclk)) {
+ rc = clk_prepare_enable(msm_host->pclk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the pclk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto remove_vote;
+ }
+ }
+
+ rc = clk_prepare_enable(msm_host->clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the host-clk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_pclk;
+ }
+
+ atomic_set(&msm_host->controller_clock, 1);
+ pr_debug("%s: %s: enabled controller clock\n",
+ mmc_hostname(host->mmc), __func__);
+ goto out;
+
+disable_pclk:
+ if (!IS_ERR(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+remove_vote:
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+out:
+ return rc;
+}
+
+
+
static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -2223,36 +2268,32 @@
pr_debug("%s: request to enable clocks\n",
mmc_hostname(host->mmc));
- sdhci_msm_bus_voting(host, 1);
+ /*
+ * The bus-width or the clock rate might have changed
+ * after controller clocks are enbaled, update bus vote
+ * in such case.
+ */
+ if (atomic_read(&msm_host->controller_clock))
+ sdhci_msm_bus_voting(host, 1);
+
+ rc = sdhci_msm_enable_controller_clock(host);
+ if (rc)
+ goto remove_vote;
if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
rc = clk_prepare_enable(msm_host->bus_clk);
if (rc) {
pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto remove_vote;
+ goto disable_controller_clk;
}
}
- if (!IS_ERR(msm_host->pclk)) {
- rc = clk_prepare_enable(msm_host->pclk);
- if (rc) {
- pr_err("%s: %s: failed to enable the pclk with error %d\n",
- mmc_hostname(host->mmc), __func__, rc);
- goto disable_bus_clk;
- }
- }
- rc = clk_prepare_enable(msm_host->clk);
- if (rc) {
- pr_err("%s: %s: failed to enable the host-clk with error %d\n",
- mmc_hostname(host->mmc), __func__, rc);
- goto disable_pclk;
- }
if (!IS_ERR(msm_host->ff_clk)) {
rc = clk_prepare_enable(msm_host->ff_clk);
if (rc) {
pr_err("%s: %s: failed to enable the ff_clk with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto disable_clk;
+ goto disable_bus_clk;
}
}
if (!IS_ERR(msm_host->sleep_clk)) {
@@ -2280,6 +2321,7 @@
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+ atomic_set(&msm_host->controller_clock, 0);
sdhci_msm_bus_voting(host, 0);
}
atomic_set(&msm_host->clks_on, enable);
@@ -2287,15 +2329,15 @@
disable_ff_clk:
if (!IS_ERR_OR_NULL(msm_host->ff_clk))
clk_disable_unprepare(msm_host->ff_clk);
-disable_clk:
- if (!IS_ERR_OR_NULL(msm_host->clk))
- clk_disable_unprepare(msm_host->clk);
-disable_pclk:
- if (!IS_ERR_OR_NULL(msm_host->pclk))
- clk_disable_unprepare(msm_host->pclk);
disable_bus_clk:
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+disable_controller_clk:
+ if (!IS_ERR_OR_NULL(msm_host->clk))
+ clk_disable_unprepare(msm_host->clk);
+ if (!IS_ERR_OR_NULL(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+ atomic_set(&msm_host->controller_clock, 0);
remove_vote:
if (msm_host->msm_bus_vote.client_handle)
sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
@@ -2558,6 +2600,7 @@
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,
.disable_data_xfer = sdhci_msm_disable_data_xfer,
+ .enable_controller_clock = sdhci_msm_enable_controller_clock,
};
static int __devinit sdhci_msm_probe(struct platform_device *pdev)
@@ -2637,6 +2680,7 @@
if (ret)
goto bus_clk_disable;
}
+ atomic_set(&msm_host->controller_clock, 1);
/* Setup SDC MMC clock */
msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");
@@ -2840,6 +2884,7 @@
msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
+ msm_host->mmc->caps2 |= MMC_CAP2_CORE_PM;
msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
if (msm_host->pdata->nonremovable)
@@ -2896,7 +2941,7 @@
if (ret)
pr_err("%s: %s: pm_runtime_set_active failed: err: %d\n",
mmc_hostname(host->mmc), __func__, ret);
- else
+ else if (mmc_use_core_runtime_pm(host->mmc))
pm_runtime_enable(&pdev->dev);
/* Successful initialization */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 513ddfb..830223d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1577,6 +1577,7 @@
unsigned long flags;
int vdd_bit = -1;
u8 ctrl;
+ int ret;
mutex_lock(&host->ios_mutex);
if (host->flags & SDHCI_DEVICE_DEAD) {
@@ -1589,6 +1590,29 @@
if (ios->clock)
sdhci_set_clock(host, ios->clock);
+ /*
+ * The controller clocks may be off during power-up and we may end up
+ * enabling card clock before giving power to the card. Hence, during
+ * MMC_POWER_UP enable the controller clock and turn-on the regulators.
+ * The mmc_power_up would provide the necessary delay before turning on
+ * the clocks to the card.
+ */
+ if (ios->power_mode & MMC_POWER_UP) {
+ if (host->ops->enable_controller_clock) {
+ ret = host->ops->enable_controller_clock(host);
+ if (ret) {
+ pr_err("%s: enabling controller clock: failed: %d\n",
+ mmc_hostname(host->mmc), ret);
+ } else {
+ vdd_bit = sdhci_set_power(host, ios->vdd);
+
+ if (host->vmmc && vdd_bit != -1)
+ mmc_regulator_set_ocr(host->mmc,
+ host->vmmc,
+ vdd_bit);
+ }
+ }
+ }
spin_lock_irqsave(&host->lock, flags);
if (!host->clock) {
spin_unlock_irqrestore(&host->lock, flags);
@@ -1597,14 +1621,16 @@
}
spin_unlock_irqrestore(&host->lock, flags);
- if (ios->power_mode & (MMC_POWER_UP | MMC_POWER_ON))
+ if (!host->ops->enable_controller_clock && (ios->power_mode &
+ (MMC_POWER_UP |
+ MMC_POWER_ON))) {
vdd_bit = sdhci_set_power(host, ios->vdd);
- if (host->vmmc && vdd_bit != -1)
- mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+ if (host->vmmc && vdd_bit != -1)
+ mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+ }
spin_lock_irqsave(&host->lock, flags);
-
if (host->ops->platform_send_init_74_clocks)
host->ops->platform_send_init_74_clocks(host, ios->power_mode);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 3db99c4..db4806d 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -295,6 +295,7 @@
unsigned int (*get_max_segments)(void);
void (*platform_bus_voting)(struct sdhci_host *host, u32 enable);
void (*disable_data_xfer)(struct sdhci_host *host);
+ int (*enable_controller_clock)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
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..0eab568 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
@@ -154,6 +155,7 @@
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE (4*1024)
#define WCNSS_VERSION_LEN 30
+#define WCNSS_MAX_BUILD_VER_LEN 256
/* message types */
#define WCNSS_CTRL_MSG_START 0x01000000
@@ -166,6 +168,8 @@
#define WCNSS_CALDATA_DNLD_REQ (WCNSS_CTRL_MSG_START + 6)
#define WCNSS_CALDATA_DNLD_RSP (WCNSS_CTRL_MSG_START + 7)
#define WCNSS_VBATT_LEVEL_IND (WCNSS_CTRL_MSG_START + 8)
+#define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9)
+#define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10)
#define VALID_VERSION(version) \
@@ -339,10 +343,10 @@
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;
- int ssr_boot;
int nv_downloaded;
unsigned char *fw_cal_data;
unsigned char *user_cal_data;
@@ -515,6 +519,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 +571,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 +668,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);
@@ -755,8 +761,6 @@
case SMD_EVENT_CLOSE:
pr_debug("wcnss: closing WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
- /* This SMD is closed only during SSR */
- penv->ssr_boot = true;
penv->nv_downloaded = 0;
break;
@@ -1348,6 +1352,17 @@
goto exit;
}
+ if (penv->fw_cal_available) {
+ /* ignore cal upload from SSR */
+ smd_read(penv->smd_ch, NULL, calhdr.frag_size);
+ penv->fw_cal_exp_frag++;
+ if (calhdr.msg_flags & LAST_FRAGMENT) {
+ penv->fw_cal_exp_frag = 0;
+ goto exit;
+ }
+ return;
+ }
+
if (0 == calhdr.frag_number) {
if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
pr_err("wcnss: Invalid cal data size %d",
@@ -1411,7 +1426,9 @@
int len = 0;
int rc = 0;
unsigned char buf[sizeof(struct wcnss_version)];
+ unsigned char build[WCNSS_MAX_BUILD_VER_LEN+1];
struct smd_msg_hdr *phdr;
+ struct smd_msg_hdr smd_msg;
struct wcnss_version *pversion;
int hw_type;
unsigned char fw_status = 0;
@@ -1468,6 +1485,12 @@
break;
case WCNSS_PRONTO_HW:
+ smd_msg.msg_type = WCNSS_BUILD_VER_REQ;
+ smd_msg.msg_len = sizeof(smd_msg);
+ rc = wcnss_smd_tx(&smd_msg, smd_msg.msg_len);
+ if (rc < 0)
+ pr_err("wcnss: smd tx failed: %s\n", __func__);
+
/* supported only if pronto major >= 1 and minor >= 4 */
if ((pversion->major >= 1) && (pversion->minor >= 4)) {
pr_info("wcnss: schedule dnld work for pronto\n");
@@ -1482,6 +1505,21 @@
}
break;
+ case WCNSS_BUILD_VER_RSP:
+ if (len > WCNSS_MAX_BUILD_VER_LEN) {
+ pr_err("wcnss: invalid build version data from wcnss %d\n",
+ len);
+ return;
+ }
+ rc = smd_read(penv->smd_ch, build, len);
+ if (rc < len) {
+ pr_err("wcnss: incomplete data read from smd\n");
+ return;
+ }
+ build[len] = 0;
+ pr_info("wcnss: build version %s\n", build);
+ break;
+
case WCNSS_NVBIN_DNLD_RSP:
penv->nv_downloaded = true;
fw_status = wcnss_fw_status();
@@ -1498,7 +1536,6 @@
break;
case WCNSS_CALDATA_UPLD_REQ:
- penv->fw_cal_available = 0;
extract_cal_data(len);
break;
@@ -1748,21 +1785,12 @@
while (!penv->user_cal_available && retry++ < 5)
msleep(500);
}
-
- /* only cal data is sent during ssr (if available) */
- if (penv->fw_cal_available && penv->ssr_boot) {
- pr_info_ratelimited("wcnss: cal download during SSR, using fw cal");
- wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, false);
- return;
-
- } else if (penv->user_cal_available && penv->ssr_boot) {
- pr_info_ratelimited("wcnss: cal download during SSR, using user cal");
- wcnss_caldata_dnld(penv->user_cal_data,
- penv->user_cal_rcvd, false);
- return;
+ if (penv->fw_cal_available) {
+ pr_info_ratelimited("wcnss: cal download, using fw cal");
+ wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, true);
} else if (penv->user_cal_available) {
- pr_info_ratelimited("wcnss: cal download during cold boot, using user cal");
+ pr_info_ratelimited("wcnss: cal download, using user cal");
wcnss_caldata_dnld(penv->user_cal_data,
penv->user_cal_rcvd, true);
}
@@ -1965,7 +1993,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 +2024,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/of_batterydata.c b/drivers/of/of_batterydata.c
index b0d40f1..32aae74 100644
--- a/drivers/of/of_batterydata.c
+++ b/drivers/of/of_batterydata.c
@@ -228,7 +228,7 @@
OF_PROP_READ(batt_data->rbatt_capacitive_mohm,
"rbatt-capacitive-mohm", node, rc, false);
OF_PROP_READ(batt_data->flat_ocv_threshold_uv,
- "flat-ocv-threshold", node, rc, true);
+ "flat-ocv-threshold-uv", node, rc, true);
OF_PROP_READ(batt_data->max_voltage_uv,
"max-voltage-uv", node, rc, true);
OF_PROP_READ(batt_data->cutoff_uv, "v-cutoff-uv", node, rc, true);
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..3fe1ca8 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) {
@@ -922,14 +934,67 @@
}
}
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+#define UV_PER_SPIN 50000
+static int find_ocv_for_pc(struct qpnp_bms_chip *chip, int batt_temp, int pc)
+{
+ int new_pc;
+ int batt_temp_degc = batt_temp / 10;
+ int ocv_mv;
+ int delta_mv = 5;
+ int max_spin_count;
+ int count = 0;
+ int sign, new_sign;
+
+ ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
+
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_mv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_mv);
+ max_spin_count = 1 + (chip->max_voltage_uv - chip->v_cutoff_uv)
+ / UV_PER_SPIN;
+ sign = SIGN(pc - new_pc);
+
+ while (abs(new_pc - pc) != 0 && count < max_spin_count) {
+ /*
+ * If the newly interpolated pc is larger than the lookup pc,
+ * the ocv should be reduced and vice versa
+ */
+ new_sign = SIGN(pc - new_pc);
+ /*
+ * If the sign has changed, then we have passed the lookup pc.
+ * reduce the ocv step size to get finer results.
+ *
+ * If we have already reduced the ocv step size and still
+ * passed the lookup pc, just stop and use the current ocv.
+ * This can only happen if the batterydata profile is
+ * non-monotonic anyways.
+ */
+ if (new_sign != sign) {
+ if (delta_mv > 1)
+ delta_mv = 1;
+ else
+ break;
+ }
+ sign = new_sign;
+
+ ocv_mv = ocv_mv + delta_mv * sign;
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp_degc, ocv_mv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n",
+ new_pc, ocv_mv);
+ count++;
+ }
+
+ return ocv_mv * 1000;
+}
+
#define OCV_RAW_UNINITIALIZED 0xFFFF
#define MIN_OCV_UV 2000000
static int read_soc_params_raw(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
int batt_temp)
{
- int warm_reset;
- int rc;
+ int warm_reset, rc;
mutex_lock(&chip->bms_output_lock);
@@ -977,8 +1042,8 @@
chip->done_charging = false;
/* if we just finished charging, reset CC and fake 100% */
chip->ocv_reading_at_100 = raw->last_good_ocv_raw;
- chip->last_ocv_uv = chip->max_voltage_uv;
- raw->last_good_ocv_uv = chip->max_voltage_uv;
+ chip->last_ocv_uv = find_ocv_for_pc(chip, batt_temp, 100);
+ raw->last_good_ocv_uv = chip->last_ocv_uv;
raw->cc = 0;
raw->shdw_cc = 0;
reset_cc(chip, CLEAR_CC | CLEAR_SHDW_CC);
@@ -1355,60 +1420,6 @@
return pc;
}
-#define SIGN(x) ((x) < 0 ? -1 : 1)
-#define UV_PER_SPIN 50000
-static int find_ocv_for_pc(struct qpnp_bms_chip *chip, int batt_temp, int pc)
-{
- int new_pc;
- int batt_temp_degc = batt_temp / 10;
- int ocv_mv;
- int delta_mv = 5;
- int max_spin_count;
- int count = 0;
- int sign, new_sign;
-
- ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
-
- new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_mv);
- pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_mv);
- max_spin_count = 1 + (chip->max_voltage_uv - chip->v_cutoff_uv)
- / UV_PER_SPIN;
- sign = SIGN(pc - new_pc);
-
- while (abs(new_pc - pc) != 0 && count < max_spin_count) {
- /*
- * If the newly interpolated pc is larger than the lookup pc,
- * the ocv should be reduced and vice versa
- */
- new_sign = SIGN(pc - new_pc);
- /*
- * If the sign has changed, then we have passed the lookup pc.
- * reduce the ocv step size to get finer results.
- *
- * If we have already reduced the ocv step size and still
- * passed the lookup pc, just stop and use the current ocv.
- * This can only happen if the batterydata profile is
- * non-monotonic anyways.
- */
- if (new_sign != sign) {
- if (delta_mv > 1)
- delta_mv = 1;
- else
- break;
- }
- sign = new_sign;
-
- ocv_mv = ocv_mv + delta_mv * sign;
- new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
- batt_temp_degc, ocv_mv);
- pr_debug("test revlookup pc = %d for ocv = %d\n",
- new_pc, ocv_mv);
- count++;
- }
-
- return ocv_mv * 1000;
-}
-
static int get_current_time(unsigned long *now_tm_sec)
{
struct rtc_time tm;
@@ -1677,10 +1688,13 @@
rc = qpnp_write_wrapper(chip, &temp, chip->base + IAVG_STORAGE_REG, 1);
- /* don't store soc if temperature is below 5degC */
+ /* store an invalid soc if temperature is below 5degC */
if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
qpnp_masked_write_base(chip, chip->soc_storage_addr,
SOC_STORAGE_MASK, (soc + 1) << 1);
+ else
+ qpnp_masked_write_base(chip, chip->soc_storage_addr,
+ SOC_STORAGE_MASK, SOC_STORAGE_MASK);
}
static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
@@ -1817,8 +1831,15 @@
chip->catch_up_time_sec,
soc, chip->last_soc);
- soc_change = min((int)abs(chip->last_soc - soc),
- time_since_last_change_sec / SOC_CHANGE_PER_SEC);
+ /* if the battery is close to cutoff allow more change */
+ if (wake_lock_active(&chip->low_voltage_wake_lock))
+ soc_change = min((int)abs(chip->last_soc - soc),
+ time_since_last_change_sec);
+ else
+ soc_change = min((int)abs(chip->last_soc - soc),
+ time_since_last_change_sec
+ / SOC_CHANGE_PER_SEC);
+
if (chip->last_soc_unbound) {
chip->last_soc_unbound = false;
} else {
@@ -1994,7 +2015,7 @@
}
}
-#define NO_ADJUST_HIGH_SOC_THRESHOLD 90
+#define NO_ADJUST_HIGH_SOC_THRESHOLD 98
static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
int soc, int batt_temp)
{
@@ -2050,9 +2071,10 @@
* because we might pull it low
* and cause a bad user experience
*/
- if (soc_est == soc
- || soc_est > chip->adjust_soc_low_threshold
- || soc >= NO_ADJUST_HIGH_SOC_THRESHOLD)
+ if (!wake_lock_active(&chip->low_voltage_wake_lock) &&
+ (soc_est == soc
+ || soc_est > chip->adjust_soc_low_threshold
+ || soc >= NO_ADJUST_HIGH_SOC_THRESHOLD))
goto out;
if (chip->last_soc_est == -EINVAL)
@@ -2097,8 +2119,11 @@
pr_debug("new delta ocv = %d\n", delta_ocv_uv);
}
- if (wake_lock_active(&chip->low_voltage_wake_lock))
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ /* when in the cutoff region, do not correct upwards */
+ delta_ocv_uv = max(0, delta_ocv_uv);
goto skip_limits;
+ }
if (chip->last_ocv_uv > chip->flat_ocv_threshold_uv)
correction_limit_uv = chip->high_ocv_correction_limit_uv;
@@ -2254,6 +2279,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 +2296,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 +2321,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 +3514,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..095fddf 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,
@@ -1420,8 +1451,9 @@
qpnp_chg_set_appropriate_vddmax(chip);
chip->chg_done = false;
}
- qpnp_chg_usb_suspend_enable(chip, 1);
+ qpnp_chg_usb_suspend_enable(chip, 0);
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,
@@ -2133,7 +2167,8 @@
if (ret.intval <= 2 && !chip->use_default_batt_values &&
get_prop_batt_present(chip)) {
- qpnp_chg_usb_suspend_enable(chip, 1);
+ if (ret.intval == 2)
+ qpnp_chg_usb_suspend_enable(chip, 1);
qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
} else {
qpnp_chg_usb_suspend_enable(chip, 0);
@@ -2243,6 +2278,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 +2387,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 +2439,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 +3582,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 +4306,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 +4343,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 +4382,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 +4415,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 +4455,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 +4738,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 +4750,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/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 91d94b5..83fa657 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -32,6 +32,7 @@
#include <linux/lzo.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
+#include <linux/ratelimit.h>
#include "zram_drv.h"
@@ -39,6 +40,12 @@
static int zram_major;
static struct zram *zram_devices;
+/*
+ * We don't need to see memory allocation errors more than once every 1
+ * second to know that a problem is occurring.
+ */
+#define ALLOC_ERROR_LOG_RATE_MS 1000
+
/* Module params (documentation at end) */
static unsigned int num_devices = 1;
@@ -221,7 +228,8 @@
goto free_buffer;
}
- meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
+ meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM |
+ __GFP_NOWARN);
if (!meta->mem_pool) {
pr_err("Error creating memory pool\n");
goto free_table;
@@ -399,6 +407,7 @@
struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
struct zram_meta *meta = zram->meta;
+ static unsigned long zram_rs_time;
page = bvec->bv_page;
src = meta->compress_buffer;
@@ -472,8 +481,10 @@
handle = zs_malloc(meta->mem_pool, clen);
if (!handle) {
- pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
- index, clen);
+ if (printk_timed_ratelimit(&zram_rs_time,
+ ALLOC_ERROR_LOG_RATE_MS))
+ pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
+ index, clen);
ret = -ENOMEM;
goto out;
}
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index 97a3acf..508a19f 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -32,7 +32,7 @@
* Pages that compress to size greater than this are stored
* uncompressed in memory.
*/
-static const size_t max_zpage_size = PAGE_SIZE / 4 * 3;
+static const size_t max_zpage_size = PAGE_SIZE / 10 * 9;
/*
* NOTE: max_zpage_size must be less than or equal to:
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 1a67537..523b937 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -472,7 +472,7 @@
set_page_private(page, 0);
page->mapping = NULL;
page->freelist = NULL;
- page_mapcount_reset(page);
+ reset_page_mapcount(page);
}
static void free_zspage(struct page *first_page)
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 00df613..39cfa33 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;
@@ -69,6 +71,7 @@
static bool psm_enabled;
static bool psm_nodes_called;
static bool psm_probed;
+static bool hotplug_enabled;
static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
@@ -77,8 +80,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 +159,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 +198,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 +612,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 +752,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 +776,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 +788,12 @@
mutex_lock(&core_control_mutex);
for_each_possible_cpu(cpu) {
+ if (hotplug_enabled &&
+ 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 +916,6 @@
static void __ref do_freq_control(long temp)
{
- int ret = 0;
int cpu = 0;
uint32_t max_freq = limited_max_freq;
@@ -855,7 +935,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 +943,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 +1064,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. */
@@ -1001,15 +1079,18 @@
long temp = 0;
int cpu = 0;
+ if (!hotplug_enabled)
+ return 0;
+
mutex_lock(&core_control_mutex);
for_each_possible_cpu(cpu) {
if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
continue;
- tsens_dev.sensor_num = sensor_get_id(\
- (char *)cpus[cpu].sensor_type);
+ 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);
+ mutex_unlock(&core_control_mutex);
return -EINVAL;
}
@@ -1038,26 +1119,29 @@
if (hotplug_task)
return;
+ if (!hotplug_enabled)
+ goto init_kthread;
+
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_kthread:
init_completion(&hotplug_notify_complete);
hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
if (IS_ERR(hotplug_task)) {
@@ -1086,12 +1170,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 +1193,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 +1434,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 +1752,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,
@@ -1764,6 +1857,11 @@
int ret = 0;
int cpu = 0;
+ if (num_possible_cpus() > 1) {
+ core_control_enabled = 1;
+ hotplug_enabled = 1;
+ }
+
key = "qcom,core-limit-temp";
ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
if (ret)
@@ -1782,19 +1880,20 @@
key = "qcom,hotplug-temp";
ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
if (ret)
- goto read_node_fail;
+ goto hotplug_node_fail;
key = "qcom,hotplug-temp-hysteresis";
ret = of_property_read_u32(node, key,
&data->hotplug_temp_hysteresis_degC);
if (ret)
- goto read_node_fail;
+ goto hotplug_node_fail;
key = "qcom,cpu-sensors";
cpu_cnt = of_property_count_strings(node, key);
if (cpu_cnt != num_possible_cpus()) {
pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
- goto read_node_fail;
+ ret = -EINVAL;
+ goto hotplug_node_fail;
}
for_each_possible_cpu(cpu) {
@@ -1804,12 +1903,9 @@
ret = of_property_read_string_index(node, key, cpu,
&cpus[cpu].sensor_type);
if (ret)
- goto read_node_fail;
+ goto hotplug_node_fail;
}
- if (num_possible_cpus() > 1)
- core_control_enabled = 1;
-
read_node_fail:
if (ret) {
dev_info(&pdev->dev,
@@ -1819,6 +1915,16 @@
}
return ret;
+
+hotplug_node_fail:
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ KBUILD_MODNAME, node->full_name, key);
+ hotplug_enabled = 0;
+ }
+
+ return ret;
}
static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
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.c b/drivers/tty/serial/msm_serial_hs.c
index a243a05..078929b 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -155,7 +155,6 @@
struct tasklet_struct tlet;
struct msm_hs_sps_ep_conn_data prod;
};
-
enum buffer_states {
NONE_PENDING = 0x0,
FIFO_OVERRUN = 0x1,
@@ -219,6 +218,7 @@
struct msm_bus_scale_pdata *bus_scale_table;
bool rx_discard_flush_issued;
int rx_count_callback;
+ bool rx_bam_inprogress;
unsigned int *reg_ptr;
};
@@ -998,6 +998,14 @@
mutex_lock(&msm_uport->clk_mutex);
msm_hs_write(uport, UART_DM_IMR, 0);
+ /* Clear the Rx Ready Ctl bit - This ensures that
+ * flow control lines stop the other side from sending
+ * data while we change the parameters
+ */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+
/*
* Disable Rx channel of UARTDM
* DMA Rx Stall happens if enqueue and flush of Rx command happens
@@ -1071,18 +1079,6 @@
/* write parity/bits per char/stop bit configuration */
msm_hs_write(uport, UART_DM_MR2, data);
- /* Configure HW flow control */
- data = msm_hs_read(uport, UART_DM_MR1);
-
- data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
-
- if (c_cflag & CRTSCTS) {
- data |= UARTDM_MR1_CTS_CTL_BMSK;
- data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
- }
-
- msm_hs_write(uport, UART_DM_MR1, data);
-
uport->ignore_status_mask = termios->c_iflag & INPCK;
uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
uport->ignore_status_mask |= termios->c_iflag & IGNBRK;
@@ -1106,6 +1102,10 @@
*/
mb();
if (is_blsp_uart(msm_uport)) {
+ if (msm_uport->rx_bam_inprogress)
+ ret = wait_event_timeout(msm_uport->rx.wait,
+ msm_uport->rx_bam_inprogress == false,
+ RX_FLUSH_COMPLETE_TIMEOUT);
ret = sps_disconnect(sps_pipe_handle);
if (ret)
pr_err("%s(): sps_disconnect failed\n",
@@ -1127,6 +1127,20 @@
}
}
+ /* Configure HW flow control
+ * UART Core would see status of CTS line when it is sending data
+ * to remote uart to confirm that it can receive or not.
+ * UART Core would trigger RFR if it is not having any space with
+ * RX FIFO.
+ */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
+ if (c_cflag & CRTSCTS) {
+ data |= UARTDM_MR1_CTS_CTL_BMSK;
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ }
+ msm_hs_write(uport, UART_DM_MR1, data);
+
msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
mb();
mutex_unlock(&msm_uport->clk_mutex);
@@ -1358,10 +1372,13 @@
msm_uport->rx.flush = FLUSH_NONE;
if (is_blsp_uart(msm_uport)) {
+ msm_uport->rx_bam_inprogress = true;
sps_pipe_handle = rx->prod.pipe_handle;
/* Queue transfer request to SPS */
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, flags);
+ msm_uport->rx_bam_inprogress = false;
+ wake_up(&msm_uport->rx.wait);
} else {
msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
&msm_uport->rx.xfer);
@@ -1531,10 +1548,13 @@
if (!msm_uport->rx.buffer_pending) {
if (is_blsp_uart(msm_uport)) {
msm_uport->rx.flush = FLUSH_NONE;
+ msm_uport->rx_bam_inprogress = true;
sps_pipe_handle = rx->prod.pipe_handle;
/* Queue transfer request to SPS */
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
+ msm_uport->rx_bam_inprogress = false;
+ wake_up(&msm_uport->rx.wait);
} else {
msm_hs_start_rx_locked(uport);
}
@@ -2832,9 +2852,9 @@
/* Now save the sps pipe handle */
ep->pipe_handle = sps_pipe_handle;
pr_debug("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
- "desc_fifo.phys_base=0x%x\n",
+ "desc_fifo.phys_base=0x%llx\n",
is_producer ? "READ" : "WRITE",
- (u32)sps_pipe_handle, sps_config->desc.phys_base);
+ (u32) sps_pipe_handle, (u64) sps_config->desc.phys_base);
return 0;
get_config_err:
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/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 554cce8..97592c4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2288,8 +2288,12 @@
if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
(mdwc->ext_xceiv.otg_capability || !init)) {
mdwc->ext_xceiv.bsv = val->intval;
+ /*
+ * set debouncing delay to 120msec. Otherwise battery
+ * charging CDP complaince test fails if delay > 120ms.
+ */
queue_delayed_work(system_nrt_wq,
- &mdwc->resume_work, 20);
+ &mdwc->resume_work, 12);
if (!init)
init = true;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 9599936..cacd635 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -93,6 +93,19 @@
return 0;
}
+static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp)
+{
+ struct dwc3 *dwc = dotg->dwc;
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ if (susp)
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ else
+ reg &= ~(DWC3_GUSB2PHYCFG_SUSPHY);
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
/**
* dwc3_otg_set_host_power - Enable port power control for host operation
*
@@ -194,6 +207,7 @@
* remove_hcd, But we may not use standard set_host method
* anymore.
*/
+ dwc3_otg_set_hsphy_auto_suspend(dotg, true);
dwc3_otg_set_host_regs(dotg);
/*
* FIXME If micro A cable is disconnected during system suspend,
@@ -242,6 +256,7 @@
ext_xceiv->ext_block_reset)
ext_xceiv->ext_block_reset(ext_xceiv, true);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, false);
dwc3_otg_set_peripheral_regs(dotg);
/* re-init core and OTG registers as block reset clears these */
@@ -309,12 +324,14 @@
ext_xceiv->ext_block_reset)
ext_xceiv->ext_block_reset(ext_xceiv, false);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, true);
dwc3_otg_set_peripheral_regs(dotg);
usb_gadget_vbus_connect(otg->gadget);
} else {
dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
__func__, otg->gadget->name);
usb_gadget_vbus_disconnect(otg->gadget);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, false);
}
return 0;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 38c4b86..ad3a3a9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2623,13 +2623,10 @@
}
}
- /*
- * Notify suspend only to gadget driver, but not resume. Resume is
- * notified as part of wakeup event in dwc3_gadget_wakeup_interrupt().
- */
if (next == DWC3_LINK_STATE_U0) {
if (dwc->link_state == DWC3_LINK_STATE_U3) {
dbg_event(0xFF, "RESUME", 0);
+ dwc->gadget_driver->resume(&dwc->gadget);
}
} else if (next == DWC3_LINK_STATE_U3) {
dbg_event(0xFF, "SUSPEND", 0);
@@ -2920,7 +2917,11 @@
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
- dwc3_gadget_usb2_phy_suspend(dwc, true);
+ /*
+ * Clear autosuspend bit in dwc3 register for USB2. It will be
+ * enabled before setting run/stop bit.
+ */
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_gadget_usb3_phy_suspend(dwc, true);
}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6765078..877b944 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1770,7 +1770,7 @@
struct fsg_common *common;
int err;
int i;
- const char *name[2];
+ const char *name[3];
config = kzalloc(sizeof(struct mass_storage_function_config),
GFP_KERNEL);
@@ -2181,6 +2181,22 @@
}
}
+static inline void check_streaming_func(struct usb_gadget *gadget,
+ struct android_usb_platform_data *pdata,
+ char *name)
+{
+ int i;
+
+ for (i = 0; i < pdata->streaming_func_count; i++) {
+ if (!strcmp(name,
+ pdata->streaming_func[i])) {
+ pr_debug("set streaming_enabled to true\n");
+ gadget->streaming_enabled = true;
+ break;
+ }
+ }
+}
+
static int android_enable_function(struct android_dev *dev,
struct android_configuration *conf,
char *name)
@@ -2188,6 +2204,9 @@
struct android_usb_function **functions = dev->functions;
struct android_usb_function *f;
struct android_usb_function_holder *f_holder;
+ struct android_usb_platform_data *pdata = dev->pdata;
+ struct usb_gadget *gadget = dev->cdev->gadget;
+
while ((f = *functions++)) {
if (!strcmp(name, f->name)) {
if (f->android_dev && f->android_dev != dev)
@@ -2205,6 +2224,13 @@
f_holder->f = f;
list_add_tail(&f_holder->enabled_list,
&conf->enabled_functions);
+ pr_debug("func:%s is enabled.\n", f->name);
+ /*
+ * compare enable function with streaming func
+ * list and based on the same request streaming.
+ */
+ check_streaming_func(gadget, pdata, f->name);
+
return 0;
}
}
@@ -2577,6 +2603,10 @@
{
struct android_dev *dev = cdev_to_android_dev(c->cdev);
+ if (c->cdev->gadget->streaming_enabled) {
+ c->cdev->gadget->streaming_enabled = false;
+ pr_debug("setting streaming_enabled to false.\n");
+ }
android_unbind_enabled_functions(dev, c);
}
@@ -2745,8 +2775,10 @@
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- dev->suspended = 1;
- schedule_work(&dev->work);
+ if (!dev->suspended) {
+ dev->suspended = 1;
+ schedule_work(&dev->work);
+ }
spin_unlock_irqrestore(&cdev->lock, flags);
composite_suspend(gadget);
@@ -2759,8 +2791,10 @@
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- dev->suspended = 0;
- schedule_work(&dev->work);
+ if (dev->suspended) {
+ dev->suspended = 0;
+ schedule_work(&dev->work);
+ }
spin_unlock_irqrestore(&cdev->lock, flags);
composite_resume(gadget);
@@ -2895,7 +2929,7 @@
struct android_usb_platform_data *pdata;
struct android_dev *android_dev;
struct resource *res;
- int ret = 0;
+ int ret = 0, i, len = 0;
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
@@ -2912,6 +2946,33 @@
"qcom,android-usb-cdrom");
pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,
"qcom,android-usb-internal-ums");
+ len = of_property_count_strings(pdev->dev.of_node,
+ "qcom,streaming-func");
+ if (len > MAX_STREAMING_FUNCS) {
+ pr_err("Invalid number of functions used.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i++) {
+ const char *name = NULL;
+
+ of_property_read_string_index(pdev->dev.of_node,
+ "qcom,streaming-func", i, &name);
+ if (!name)
+ continue;
+
+ if (sizeof(name) > FUNC_NAME_LEN) {
+ pr_err("Function name is bigger than allowed.\n");
+ continue;
+ }
+
+ strlcpy(pdata->streaming_func[i], name,
+ sizeof(pdata->streaming_func[i]));
+ pr_debug("name of streaming function:%s\n",
+ pdata->streaming_func[i]);
+ }
+
+ pdata->streaming_func_count = len;
} else {
pdata = pdev->dev.platform_data;
}
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index a9c073b..f1e4220 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -271,6 +271,10 @@
1 << (pdata->log2_itc-1);
is_l1_supported = pdata->l1_supported;
+ /* Set ahb2ahb bypass flag if it is requested. */
+ if (pdata->enable_ahb2ahb_bypass)
+ ci13xxx_msm_udc_driver.flags |=
+ CI13XXX_ENABLE_AHB2AHB_BYPASS;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 3f8d924..6a92684 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -70,10 +70,6 @@
#include <mach/usb_trace.h>
#include "ci13xxx_udc.h"
-/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
-static unsigned int streaming;
-module_param(streaming, uint, S_IRUGO | S_IWUSR);
-
/******************************************************************************
* DEFINE
*****************************************************************************/
@@ -392,20 +388,32 @@
static int hw_device_state(u32 dma)
{
struct ci13xxx *udc = _udc;
+ struct usb_gadget *gadget = &udc->gadget;
if (dma) {
- if (streaming || !(udc->udc_driver->flags &
- CI13XXX_DISABLE_STREAMING))
+ if (gadget->streaming_enabled || !(udc->udc_driver->flags &
+ CI13XXX_DISABLE_STREAMING)) {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
- else
+ pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+ } else {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
+ pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+ }
hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
if (udc->udc_driver->notify_event)
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_CONNECT_EVENT);
+ /* Set BIT(31) to enable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+ pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
+
/* interrupt, error, port change, reset, sleep/suspend */
hw_cwrite(CAP_USBINTR, ~0,
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
@@ -413,6 +421,12 @@
} else {
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
hw_cwrite(CAP_USBINTR, ~0, 0);
+ /* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+ pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
}
return 0;
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f90ea86..47fe138 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -136,6 +136,7 @@
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_ZERO_ITC BIT(4)
#define CI13XXX_IS_OTG BIT(5)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS BIT(6)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
@@ -197,6 +198,9 @@
/* TESTMODE */
#define TESTMODE_FORCE BIT(0)
+/* AHB_MODE */
+#define AHB2AHB_BYPASS BIT(31)
+
/* USBCMD */
#define USBCMD_RS BIT(0)
#define USBCMD_RST BIT(1)
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 22e2a25..ccd48ca 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -464,12 +464,7 @@
pr_err("unable to allocate dev");
return -ENOMEM;
}
- dev->pdev = platform_device_alloc("diag_bridge", devid);
- if (!dev->pdev) {
- pr_err("unable to allocate platform device");
- kfree(dev);
- return -ENOMEM;
- }
+
__dev[devid] = dev;
dev->id = devid;
@@ -498,7 +493,13 @@
usb_set_intfdata(ifc, dev);
diag_bridge_debugfs_init();
- platform_device_add(dev->pdev);
+ dev->pdev = platform_device_register_simple("diag_bridge", devid,
+ NULL, 0);
+ if (IS_ERR(dev->pdev)) {
+ pr_err("unable to allocate platform device");
+ ret = PTR_ERR(dev->pdev);
+ goto error;
+ }
dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 276bbb0..45fbfa8 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -470,6 +470,20 @@
int ret;
struct msm_otg_platform_data *pdata = motg->pdata;
+ /*
+ * AHB2AHB Bypass mode shouldn't be enable before doing
+ * async clock reset. If it is enable, disable the same.
+ */
+ val = readl_relaxed(USB_AHBMODE);
+ if (val & AHB2AHB_BYPASS) {
+ pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
+ __func__, val);
+ val &= ~AHB2AHB_BYPASS_BIT_MASK;
+ writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
+ pr_err("%s(): AHBMODE: %x\n", __func__,
+ readl_relaxed(USB_AHBMODE));
+ }
+
ret = msm_otg_link_clk_reset(motg, 1);
if (ret)
return ret;
@@ -1275,7 +1289,8 @@
else if (motg->chg_type == USB_CDP_CHARGER)
charger_type = POWER_SUPPLY_TYPE_USB_CDP;
else if (motg->chg_type == USB_DCP_CHARGER ||
- motg->chg_type == USB_PROPRIETARY_CHARGER)
+ motg->chg_type == USB_PROPRIETARY_CHARGER ||
+ motg->chg_type == USB_FLOATED_CHARGER)
charger_type = POWER_SUPPLY_TYPE_USB_DCP;
else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
motg->chg_type == USB_ACA_A_CHARGER ||
@@ -3834,6 +3849,8 @@
ci_pdata.log2_itc = otg_pdata->log2_itc;
ci_pdata.usb_core_id = 0;
ci_pdata.l1_supported = otg_pdata->l1_supported;
+ ci_pdata.enable_ahb2ahb_bypass =
+ otg_pdata->enable_ahb2ahb_bypass;
retval = platform_device_add_data(pdev, &ci_pdata,
sizeof(ci_pdata));
if (retval)
@@ -4164,6 +4181,8 @@
pdata->l1_supported = of_property_read_bool(node,
"qcom,hsusb-l1-supported");
+ pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
+ "qcom,ahb-async-bridge-bypass");
return pdata;
}
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 5c3960d..f26570d 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -166,6 +166,9 @@
int tooff = 0, fromoff = 0;
int size;
+ if (!to || !from)
+ return -EINVAL;
+
if (to->start > from->start)
fromoff = to->start - from->start;
else
@@ -177,9 +180,12 @@
return -EINVAL;
size *= sizeof(u16);
- memcpy(to->red+tooff, from->red+fromoff, size);
- memcpy(to->green+tooff, from->green+fromoff, size);
- memcpy(to->blue+tooff, from->blue+fromoff, size);
+ if (from->red && to->red)
+ memcpy(to->red+tooff, from->red+fromoff, size);
+ if (from->green && to->green)
+ memcpy(to->green+tooff, from->green+fromoff, size);
+ if (from->blue && to->blue)
+ memcpy(to->blue+tooff, from->blue+fromoff, size);
if (from->transp && to->transp)
memcpy(to->transp+tooff, from->transp+fromoff, size);
return 0;
@@ -190,23 +196,31 @@
int tooff = 0, fromoff = 0;
int size;
+ if (!to || !from)
+ return -EINVAL;
+
if (to->start > from->start)
fromoff = to->start - from->start;
else
tooff = from->start - to->start;
+ if ((to->len <= tooff) || (from->len <= fromoff))
+ return -EINVAL;
+
size = to->len - tooff;
+
if (size > (int) (from->len - fromoff))
size = from->len - fromoff;
- if (size <= 0)
- return -EINVAL;
size *= sizeof(u16);
- if (copy_to_user(to->red+tooff, from->red+fromoff, size))
- return -EFAULT;
- if (copy_to_user(to->green+tooff, from->green+fromoff, size))
- return -EFAULT;
- if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
- return -EFAULT;
+ if (from->red && to->red)
+ if (copy_to_user(to->red+tooff, from->red+fromoff, size))
+ return -EFAULT;
+ if (from->green && to->green)
+ if (copy_to_user(to->green+tooff, from->green+fromoff, size))
+ return -EFAULT;
+ if (from->blue && to->blue)
+ if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
+ return -EFAULT;
if (from->transp && to->transp)
if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
return -EFAULT;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index d6a664a..6b84107 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1113,6 +1113,10 @@
if (copy_from_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
ret = fb_set_user_cmap(&cmap, info);
+ if (ret) {
+ if (info)
+ fb_dealloc_cmap(&info->cmap);
+ }
break;
case FBIOGETCMAP:
if (copy_from_user(&cmap, argp, sizeof(cmap)))
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 7d57f64..e8fe7e3 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -546,7 +546,12 @@
cm = cmds;
for (i = 0; i < cnt; i++) {
dsi_buf_init(tp);
- dsi_cmd_dma_add(tp, cm);
+ rc = dsi_cmd_dma_add(tp, cm);
+ if (!rc) {
+ pr_err("%s: dsi_cmd_dma_add fail\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
rc = msm_dsi_cmd_dma_tx(tp);
if (IS_ERR_VALUE(rc)) {
pr_err("%s: failed to call cmd_dma_tx\n", __func__);
@@ -634,27 +639,35 @@
pkt_size = len;
max_pktsize[0] = pkt_size;
dsi_buf_init(tp);
- dsi_cmd_dma_add(tp, pkt_size_cmd);
+ rc = dsi_cmd_dma_add(tp, pkt_size_cmd);
+ if (!rc) {
+ pr_err("%s: dsi_cmd_dma_add failed\n", __func__);
+ rp->len = 0;
+ goto msm_dsi_cmds_rx_err;
+ }
rc = msm_dsi_cmd_dma_tx(tp);
if (IS_ERR_VALUE(rc)) {
- msm_dsi_disable_irq();
- pr_err("%s: dma_tx failed\n", __func__);
+ pr_err("%s: msm_dsi_cmd_dma_tx failed\n", __func__);
rp->len = 0;
- goto end;
+ goto msm_dsi_cmds_rx_err;
}
pr_debug("%s: Max packet size sent\n", __func__);
}
dsi_buf_init(tp);
- dsi_cmd_dma_add(tp, cmds);
+ rc = dsi_cmd_dma_add(tp, cmds);
+ if (!rc) {
+ pr_err("%s: dsi_cmd_dma_add failed\n", __func__);
+ rp->len = 0;
+ goto msm_dsi_cmds_rx_err;
+ }
/* transmit read comamnd to client */
- msm_dsi_cmd_dma_tx(tp);
+ rc = msm_dsi_cmd_dma_tx(tp);
if (IS_ERR_VALUE(rc)) {
- msm_dsi_disable_irq();
- pr_err("%s: dma_tx failed\n", __func__);
+ pr_err("%s: msm_dsi_cmd_dma_tx failed\n", __func__);
rp->len = 0;
- goto end;
+ goto msm_dsi_cmds_rx_err;
}
/*
* once cmd_dma_done interrupt received,
@@ -672,8 +685,6 @@
msm_dsi_cmd_dma_rx(rp, cnt);
- msm_dsi_disable_irq();
-
if (pdata->panel_info.mipi.no_max_pkt_size) {
/*
* remove extra 2 bytes from previous
@@ -689,6 +700,7 @@
switch (cmd) {
case DTYPE_ACK_ERR_RESP:
pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
+ rp->len = 0;
break;
case DTYPE_GEN_READ1_RESP:
case DTYPE_DCS_READ1_RESP:
@@ -705,14 +717,17 @@
rp->len -= diff; /* align bytes */
break;
default:
- pr_debug("%s: Unknown cmd received\n", __func__);
+ pr_warn("%s: Unknown cmd received\n", __func__);
+ rp->len = 0;
break;
}
if (video_mode)
MIPI_OUTP(ctrl_base + DSI_CTRL,
dsi_ctrl); /* restore */
-end:
+
+msm_dsi_cmds_rx_err:
+ msm_dsi_disable_irq();
return rp->len;
}
@@ -1070,6 +1085,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 +1224,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..a64a6b4 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.r & 0xFF) << 8 |
+ (req->const_color.b & 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_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 211b540..96d8be0 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -98,8 +98,10 @@
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
- if (!mfd)
+ if (!mfd) {
pr_err("%s mfd NULL\n", __func__);
+ return;
+ }
mfd->no_update.value = NOTIFY_TYPE_NO_UPDATE;
complete(&mfd->no_update.comp);
}
@@ -107,9 +109,10 @@
static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
unsigned long *argp)
{
- int ret, notify, to_user;
+ int ret;
+ unsigned long notify = 0x0, to_user = 0x0;
- ret = copy_from_user(¬ify, argp, sizeof(int));
+ ret = copy_from_user(¬ify, argp, sizeof(unsigned long));
if (ret) {
pr_err("%s:ioctl failed\n", __func__);
return ret;
@@ -122,12 +125,12 @@
INIT_COMPLETION(mfd->update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
- to_user = mfd->update.value;
+ to_user = (unsigned int)mfd->update.value;
} else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
- to_user = mfd->no_update.value;
+ to_user = (unsigned int)mfd->no_update.value;
} else {
if (mfd->panel_power_on) {
INIT_COMPLETION(mfd->power_off_comp);
@@ -139,7 +142,7 @@
if (ret == 0)
ret = -ETIMEDOUT;
else if (ret > 0)
- ret = copy_to_user(argp, &to_user, sizeof(int));
+ ret = copy_to_user(argp, &to_user, sizeof(unsigned long));
return ret;
}
@@ -1173,9 +1176,12 @@
struct mdss_fb_proc_info *pinfo = NULL, *temp_pinfo = NULL;
int ret = 0;
int pid = current->tgid;
+ bool unknown_pid = true, release_needed = false;
+ struct task_struct *task = current->group_leader;
if (!mfd->ref_cnt) {
- pr_info("try to close unopened fb %d!\n", mfd->index);
+ pr_info("try to close unopened fb %d! from %s\n", mfd->index,
+ task->comm);
return -EINVAL;
}
@@ -1187,12 +1193,15 @@
if (!release_all && (pinfo->pid != pid))
continue;
- pr_debug("found process entry pid=%d ref=%d\n", pinfo->pid,
- pinfo->ref_cnt);
+ unknown_pid = false;
+
+ pr_debug("found process %s pid=%d mfd->ref=%d pinfo->ref=%d\n",
+ task->comm, mfd->ref_cnt, pinfo->pid, pinfo->ref_cnt);
do {
if (mfd->ref_cnt < pinfo->ref_cnt)
- pr_warn("WARN:mfd->ref_cnt < pinfo->ref_cnt\n");
+ pr_warn("WARN:mfd->ref=%d < pinfo->ref=%d\n",
+ mfd->ref_cnt, pinfo->ref_cnt);
else
mfd->ref_cnt--;
@@ -1201,14 +1210,37 @@
} while (release_all && pinfo->ref_cnt);
if (pinfo->ref_cnt == 0) {
- if (mfd->mdp.release_fnc) {
- ret = mfd->mdp.release_fnc(mfd);
- if (ret)
- pr_err("error releasing fb%d pid=%d\n",
- mfd->index, pinfo->pid);
- }
list_del(&pinfo->list);
kfree(pinfo);
+ release_needed = !release_all;
+ }
+
+ if (!release_all)
+ break;
+ }
+
+ if (release_needed) {
+ pr_debug("known process %s pid=%d mfd->ref=%d\n",
+ task->comm, pid, mfd->ref_cnt);
+
+ if (mfd->mdp.release_fnc) {
+ ret = mfd->mdp.release_fnc(mfd, false);
+ if (ret)
+ pr_err("error releasing fb%d pid=%d\n",
+ mfd->index, pid);
+ }
+ } else if (unknown_pid || release_all) {
+ pr_warn("unknown process %s pid=%d mfd->ref=%d\n",
+ task->comm, pid, mfd->ref_cnt);
+
+ if (mfd->ref_cnt)
+ mfd->ref_cnt--;
+
+ if (mfd->mdp.release_fnc) {
+ ret = mfd->mdp.release_fnc(mfd, true);
+ if (ret)
+ pr_err("error fb%d release process %s pid=%d\n",
+ mfd->index, task->comm, pid);
}
}
@@ -1216,8 +1248,8 @@
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
if (ret) {
- pr_err("can't turn off fb%d! rc=%d\n",
- mfd->index, ret);
+ pr_err("can't turn off fb%d! rc=%d process %s pid=%d\n",
+ mfd->index, ret, task->comm, pid);
return ret;
}
}
@@ -1412,7 +1444,7 @@
u32 wait_for_finish = disp_commit->wait_for_finish;
int ret = 0;
- if ((!mfd->op_enable) || (!mfd->panel_power_on))
+ if (!mfd || (!mfd->op_enable) || (!mfd->panel_power_on))
return -EPERM;
if (var->xoffset > (info->var.xres_virtual - info->var.xres))
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 8213dbe..80e6581 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -106,7 +106,7 @@
int (*on_fnc)(struct msm_fb_data_type *mfd);
int (*off_fnc)(struct msm_fb_data_type *mfd);
/* called to release resources associated to the process */
- int (*release_fnc)(struct msm_fb_data_type *mfd);
+ int (*release_fnc)(struct msm_fb_data_type *mfd, bool release_all);
int (*kickoff_fnc)(struct msm_fb_data_type *mfd,
struct mdp_display_commit *data);
int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index ca21b51..8ff9059 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -31,6 +31,8 @@
#define HDCP_KEYS_STATE_PROD_AKSV 6
#define HDCP_KEYS_STATE_RESERVED 7
+#define HDCP_INT_CLR (BIT(1) | BIT(5) | BIT(7) | BIT(9) | BIT(13))
+
struct hdmi_hdcp_ctrl {
u32 auth_retries;
u32 tp_msgid;
@@ -1139,16 +1141,15 @@
}
/*
- * Need to set the state to inactive here so that any ongoing
- * reauth works will know that the HDCP session has been turned off
+ * Disable HDCP interrupts.
+ * Also, need to set the state to inactive here so that any ongoing
+ * reauth works will know that the HDCP session has been turned off.
*/
mutex_lock(hdcp_ctrl->init_data.mutex);
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
mutex_unlock(hdcp_ctrl->init_data.mutex);
- /* Disable HDCP interrupts */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
-
/*
* Cancel any pending auth/reauth attempts.
* If one is ongoing, this will wait for it to finish.
@@ -1193,7 +1194,7 @@
if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
DEV_ERR("%s: HDCP inactive. Just clear int and return.\n",
__func__);
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, hdcp_int_val);
+ DSS_REG_W(io, HDMI_HDCP_INT_CTRL, HDCP_INT_CLR);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index abb72ad..466b8d2 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -372,6 +372,7 @@
static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl)
{
u32 status = 0;
+ u32 wait_for_vote = 50;
struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
@@ -385,6 +386,18 @@
return;
}
+ /*
+ * wait for 5 sec max for audio engine to acknowledge if hdmi tx core
+ * can be safely turned off. Sleep for a reasonable time to make sure
+ * vote_hdmi_core_on variable is updated properly by audio.
+ */
+ while (hdmi_ctrl->vote_hdmi_core_on && --wait_for_vote)
+ msleep(100);
+
+
+ if (!wait_for_vote)
+ DEV_ERR("%s: HDMI core still voted for power on\n", __func__);
+
if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status,
(status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
AUDIO_POLL_TIMEOUT_US))
@@ -1705,8 +1718,6 @@
} else {
msm_dss_enable_clk(power_data->clk_config,
power_data->num_clk, 0);
- msm_dss_clk_set_rate(power_data->clk_config,
- power_data->num_clk);
msm_dss_enable_gpio(power_data->gpio_config,
power_data->num_gpio, 0);
msm_dss_enable_vreg(power_data->vreg_config,
@@ -2238,6 +2249,29 @@
return 0;
}
+static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+ unsigned long flags;
+ u32 hpd;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
+ hpd = hdmi_ctrl->hpd_state;
+ spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
+
+ hdmi_ctrl->vote_hdmi_core_on = false;
+
+ if (vote && hpd)
+ hdmi_ctrl->vote_hdmi_core_on = true;
+
+ return hpd;
+}
+
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
struct msm_hdmi_audio_codec_ops *ops)
{
@@ -2250,6 +2284,7 @@
ops->audio_info_setup = hdmi_tx_audio_info_setup;
ops->get_audio_edid_blk = hdmi_tx_get_audio_edid_blk;
+ ops->hdmi_cable_status = hdmi_tx_get_cable_status;
return 0;
} /* hdmi_tx_audio_register */
@@ -2436,12 +2471,6 @@
hdmi_tx_powerdown_phy(hdmi_ctrl);
- /*
- * this is needed to avoid pll lock failure due to
- * clk framework's rate caching.
- */
- hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM].clk_config[0].rate = 0;
-
hdmi_cec_deconfig(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
hdmi_tx_core_off(hdmi_ctrl);
@@ -2572,6 +2601,7 @@
{
int rc = 0;
struct dss_io_data *io = NULL;
+ unsigned long flags;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2611,7 +2641,10 @@
DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
__func__, rc);
+ spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
hdmi_ctrl->hpd_state = false;
+ spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
+
hdmi_ctrl->hpd_initialized = false;
} /* hdmi_tx_hpd_off */
@@ -2737,6 +2770,7 @@
{
struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
+ unsigned long flags;
if (!hdmi_ctrl) {
DEV_WARN("%s: invalid input data, ISR ignored\n", __func__);
@@ -2751,8 +2785,10 @@
}
if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
+ spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
hdmi_ctrl->hpd_state =
(DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+ spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
/*
* Ack the current hpd interrupt and stop listening to
@@ -2851,6 +2887,8 @@
INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
+ spin_lock_init(&hdmi_ctrl->hpd_state_lock);
+
hdmi_ctrl->audio_data.sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
hdmi_ctrl->audio_data.channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index c4d0326..66071e9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -58,6 +58,7 @@
struct switch_dev sdev;
struct switch_dev audio_sdev;
struct workqueue_struct *workq;
+ spinlock_t hpd_state_lock;
uint32_t video_resolution;
@@ -68,6 +69,7 @@
u32 hpd_off_pending;
u32 hpd_feature_on;
u32 hpd_initialized;
+ u32 vote_hdmi_core_on;
u8 timing_gen_on;
u32 mhl_max_pclk;
u8 mhl_hpd_on;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index a9667a4..f36e3c5 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -37,7 +37,6 @@
#define MAX_IMG_HEIGHT 0x3FFF
#define MAX_DST_W MAX_MIXER_WIDTH
#define MAX_DST_H MAX_MIXER_HEIGHT
-#define MAX_PLANES 4
#define MAX_DOWNSCALE_RATIO 4
#define MAX_UPSCALE_RATIO 20
#define MAX_DECIMATION 4
@@ -52,6 +51,11 @@
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KOFF_TIMEOUT msecs_to_jiffies(84)
+#define OVERFETCH_DISABLE_TOP BIT(0)
+#define OVERFETCH_DISABLE_BOTTOM BIT(1)
+#define OVERFETCH_DISABLE_LEFT BIT(2)
+#define OVERFETCH_DISABLE_RIGHT BIT(3)
+
#ifdef MDSS_MDP_DEBUG_REG
static inline void mdss_mdp_reg_write(u32 addr, u32 val)
{
@@ -341,9 +345,6 @@
u8 vert_deci;
struct mdss_mdp_img_rect src;
struct mdss_mdp_img_rect dst;
- u32 phase_step_x;
- u32 phase_step_y;
-
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
@@ -370,6 +371,9 @@
struct mdp_overlay_pp_params pp_cfg;
struct mdss_pipe_pp_res pp_res;
+ struct mdp_scale_data scale;
+ u8 chroma_sample_h;
+ u8 chroma_sample_v;
};
struct mdss_mdp_writeback_arg {
@@ -629,6 +633,7 @@
int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
struct mdp_mixer_cfg *mixer_cfg);
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
(mfd->mdp.private1))->mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index aa7c4dd..1198897 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -974,6 +974,8 @@
mixer->width = sctl->width;
mixer->height = sctl->height;
+ mixer->roi = (struct mdss_mdp_img_rect)
+ {0, 0, mixer->width, mixer->height};
sctl->mixer_left = mixer;
return mdss_mdp_set_split_ctl(ctl, sctl);
@@ -1782,6 +1784,11 @@
{
int ret;
+ if (!ctl) {
+ pr_err("invalid ctl\n");
+ return -ENODEV;
+ }
+
ret = mutex_lock_interruptible(&ctl->lock);
if (ret)
return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index c8af903..8d59107 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -201,6 +201,9 @@
#define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR 0x0AC
#define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR 0x0B0
#define MDSS_MDP_REG_SSPP_DECIMATION_CONFIG 0x0B4
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR 0x100
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB 0x104
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS 0x108
#define MDSS_MDP_REG_VIG_OP_MODE 0x200
#define MDSS_MDP_REG_VIG_QSEED2_CONFIG 0x204
@@ -356,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_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f096f16..29cf99d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -282,7 +282,12 @@
int rc;
src = pipe->src.w >> pipe->horz_deci;
- rc = mdss_mdp_calc_phase_step(src, pipe->dst.w, &pipe->phase_step_x);
+
+ if (pipe->scale.enable_pxl_ext)
+ return 0;
+ memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.w,
+ &pipe->scale.phase_step_x[0]);
if (rc) {
pr_err("Horizontal scaling calculation failed=%d! %d->%d\n",
rc, src, pipe->dst.w);
@@ -290,16 +295,43 @@
}
src = pipe->src.h >> pipe->vert_deci;
- rc = mdss_mdp_calc_phase_step(src, pipe->dst.h, &pipe->phase_step_y);
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.h,
+ &pipe->scale.phase_step_y[0]);
if (rc) {
pr_err("Vertical scaling calculation failed=%d! %d->%d\n",
rc, src, pipe->dst.h);
return rc;
}
-
+ pipe->scale.init_phase_x[0] = (pipe->scale.phase_step_x[0] -
+ (1 << PHASE_STEP_SHIFT)) / 2;
+ pipe->scale.init_phase_y[0] = (pipe->scale.phase_step_y[0] -
+ (1 << PHASE_STEP_SHIFT)) / 2;
return 0;
}
+static inline void __mdss_mdp_overlay_set_chroma_sample(
+ struct mdss_mdp_pipe *pipe)
+{
+ pipe->chroma_sample_v = pipe->chroma_sample_h = 0;
+
+ switch (pipe->src_fmt->chroma_sample) {
+ case MDSS_MDP_CHROMA_H1V2:
+ pipe->chroma_sample_v = 1;
+ break;
+ case MDSS_MDP_CHROMA_H2V1:
+ pipe->chroma_sample_h = 1;
+ break;
+ case MDSS_MDP_CHROMA_420:
+ pipe->chroma_sample_v = 1;
+ pipe->chroma_sample_h = 1;
+ break;
+ }
+ if (pipe->horz_deci)
+ pipe->chroma_sample_h = 0;
+ if (pipe->vert_deci)
+ pipe->chroma_sample_v = 0;
+}
+
static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
struct mdss_mdp_pipe **ppipe)
@@ -442,7 +474,10 @@
pipe->dst.h = req->dst_rect.h;
pipe->horz_deci = req->horz_deci;
pipe->vert_deci = req->vert_deci;
+
+ memcpy(&pipe->scale, &req->scale, sizeof(struct mdp_scale_data));
pipe->src_fmt = fmt;
+ __mdss_mdp_overlay_set_chroma_sample(pipe);
pipe->mixer_stage = req->z_order;
pipe->is_fg = req->is_fg;
@@ -458,8 +493,17 @@
pr_debug("Unintended blend_op %d on layer with no alpha plane\n",
pipe->blend_op);
- pipe->overfetch_disable = fmt->is_yuv &&
- !(pipe->flags & MDP_SOURCE_ROTATED_90);
+ if (fmt->is_yuv && !(pipe->flags & MDP_SOURCE_ROTATED_90) &&
+ !pipe->scale.enable_pxl_ext) {
+ pipe->overfetch_disable = OVERFETCH_DISABLE_BOTTOM;
+
+ if (!(pipe->flags & MDSS_MDP_DUAL_PIPE) ||
+ (pipe->flags & MDSS_MDP_RIGHT_MIXER))
+ pipe->overfetch_disable |= OVERFETCH_DISABLE_RIGHT;
+ pr_debug("overfetch flags=%x\n", pipe->overfetch_disable);
+ } else {
+ pipe->overfetch_disable = 0;
+ }
req->id = pipe->ndx;
pipe->req_data = *req;
@@ -516,12 +560,16 @@
}
}
- if (pipe->flags & MDP_DEINTERLACE) {
+ if ((pipe->flags & MDP_DEINTERLACE) && !pipe->scale.enable_pxl_ext) {
if (pipe->flags & MDP_SOURCE_ROTATED_90) {
+ pipe->src.x = DIV_ROUND_UP(pipe->src.x, 2);
+ pipe->src.x &= ~1;
pipe->src.w /= 2;
pipe->img_width /= 2;
} else {
pipe->src.h /= 2;
+ pipe->src.y = DIV_ROUND_UP(pipe->src.y, 2);
+ pipe->src.y &= ~1;
}
}
@@ -539,6 +587,12 @@
!mdp5_data->mdata->has_wfd_blk)
mdss_mdp_smp_release(pipe);
+ /*
+ * Clear previous SMP reservations and reserve according to the
+ * latest configuration
+ */
+ mdss_mdp_smp_unreserve(pipe);
+
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -1103,11 +1157,13 @@
/**
* mdss_mdp_overlay_release_all() - release any overlays associated with fb dev
* @mfd: Msm frame buffer structure associated with fb device
+ * @release_all: ignore pid and release all the pipes
*
* Release any resources allocated by calling process, this can be called
* on fb_release to release any overlays/rotator sessions left open.
*/
-static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
+static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd,
+ bool release_all)
{
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_rotator_session *rot, *tmp;
@@ -1121,7 +1177,7 @@
mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
- if (!mfd->ref_cnt || (pipe->pid == pid)) {
+ if (release_all || (pipe->pid == pid)) {
unset_ndx |= pipe->ndx;
cnt++;
}
@@ -1133,6 +1189,9 @@
cnt++;
}
+ pr_debug("release_all=%d mfd->ref_cnt=%d unset_ndx=0x%x cnt=%d\n",
+ release_all, mfd->ref_cnt, unset_ndx, cnt);
+
mutex_unlock(&mfd->lock);
if (unset_ndx) {
@@ -2116,7 +2175,7 @@
u32 cmd, void __user *argp)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- struct mdp_overlay req;
+ struct mdp_overlay *req = NULL;
int val, ret = -ENOSYS;
struct msmfb_metadata metadata;
@@ -2132,12 +2191,15 @@
break;
case MSMFB_OVERLAY_GET:
- ret = copy_from_user(&req, argp, sizeof(req));
+ req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ ret = copy_from_user(req, argp, sizeof(*req));
if (!ret) {
- ret = mdss_mdp_overlay_get(mfd, &req);
+ ret = mdss_mdp_overlay_get(mfd, req);
if (!IS_ERR_VALUE(ret))
- ret = copy_to_user(argp, &req, sizeof(req));
+ ret = copy_to_user(argp, req, sizeof(*req));
}
if (ret)
@@ -2145,12 +2207,15 @@
break;
case MSMFB_OVERLAY_SET:
- ret = copy_from_user(&req, argp, sizeof(req));
+ req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ ret = copy_from_user(req, argp, sizeof(*req));
if (!ret) {
- ret = mdss_mdp_overlay_set(mfd, &req);
+ ret = mdss_mdp_overlay_set(mfd, req);
if (!IS_ERR_VALUE(ret))
- ret = copy_to_user(argp, &req, sizeof(req));
+ ret = copy_to_user(argp, req, sizeof(*req));
}
if (ret)
pr_debug("OVERLAY_SET failed (%d)\n", ret);
@@ -2235,6 +2300,7 @@
break;
}
+ kfree(req);
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 72c8759..9d30dd8 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -166,7 +166,7 @@
struct mdss_mdp_plane_sizes ps;
int i;
int rc = 0, rot_mode = 0;
- u32 nlines;
+ u32 nlines, format;
u16 width;
width = pipe->src.w >> pipe->horz_deci;
@@ -179,8 +179,25 @@
pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
ps.ystride[0], ps.ystride[1]);
} else {
- rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
- width, pipe->src.h, &ps, 0);
+ format = pipe->src_fmt->format;
+ /*
+ * when decimation block is present, all chroma planes
+ * are fetched on a single SMP plane for chroma pixels
+ */
+ if (mdata->has_decimation) {
+ switch (pipe->src_fmt->chroma_sample) {
+ case MDSS_MDP_CHROMA_H2V1:
+ format = MDP_Y_CRCB_H2V1;
+ break;
+ case MDSS_MDP_CHROMA_420:
+ format = MDP_Y_CBCR_H2V2;
+ break;
+ default:
+ break;
+ }
+ }
+ rc = mdss_mdp_get_plane_sizes(format, width, pipe->src.h,
+ &ps, 0);
if (rc)
return rc;
@@ -191,15 +208,6 @@
max(pipe->mixer->width, width);
} else if (mdata->has_decimation) {
/*
- * when decimation block is used, all chroma planes
- * are fetched on a single SMP plane for chroma pixels
- */
- if (ps.num_planes == 3) {
- ps.num_planes = 2;
- ps.ystride[1] += ps.ystride[2];
- }
-
- /*
* To avoid quailty loss, MDP does one less decimation
* on chroma components if they are subsampled.
* Account for this to have enough SMPs for latency
@@ -581,6 +589,8 @@
mdss_mdp_smp_free(pipe);
pipe->flags = 0;
pipe->bwc_mode = 0;
+ memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return 0;
@@ -736,17 +746,35 @@
dst_size = (dst.h << 16) | dst.w;
dst_xy = (dst.y << 16) | dst.x;
- img_size = (height << 16) | width;
-
ystride0 = (pipe->src_planes.ystride[0]) |
(pipe->src_planes.ystride[1] << 16);
ystride1 = (pipe->src_planes.ystride[2]) |
(pipe->src_planes.ystride[3] << 16);
- if (pipe->overfetch_disable) {
- img_size = src_size;
- src_xy = 0;
+ /*
+ * Software overfetch is used when scalar pixel extension is
+ * not enabled
+ */
+ if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_BOTTOM) {
+ height = pipe->src.h;
+ if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_TOP))
+ height += pipe->src.y;
+ }
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_RIGHT) {
+ width = pipe->src.w;
+ if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT))
+ width += pipe->src.x;
+ }
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+ src_xy &= ~0xFFFF;
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+ src_xy &= ~(0xFFFF << 16);
+
+ pr_debug("overfetch w=%d/%d h=%d/%d src_xy=0x%08x\n", width,
+ pipe->img_width, height, pipe->img_height, src_xy);
}
+ img_size = (height << 16) | width;
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
@@ -813,6 +841,9 @@
mdss_mdp_pipe_sspp_setup(pipe, &opmode);
+ if (pipe->scale.enable_pxl_ext)
+ opmode |= (1 << 31);
+
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, src_format);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
@@ -844,33 +875,42 @@
}
static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
- struct mdss_mdp_data *data)
+ struct mdss_mdp_data *src_data)
{
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ struct mdss_mdp_data data = *src_data;
int ret = 0;
pr_debug("pnum=%d\n", pipe->num);
- data->bwc_enabled = pipe->bwc_mode;
+ data.bwc_enabled = pipe->bwc_mode;
- ret = mdss_mdp_data_check(data, &pipe->src_planes);
+ ret = mdss_mdp_data_check(&data, &pipe->src_planes);
if (ret)
return ret;
- if (pipe->overfetch_disable)
- mdss_mdp_data_calc_offset(data, pipe->src.x, pipe->src.y,
+ if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+ u32 x = 0, y = 0;
+
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+ x = pipe->src.x;
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+ y = pipe->src.y;
+
+ mdss_mdp_data_calc_offset(&data, x, y,
&pipe->src_planes, pipe->src_fmt);
+ }
/* planar format expects YCbCr, swap chroma planes if YCrCb */
if (mdata->mdp_rev < MDSS_MDP_HW_REV_102 &&
(pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR)
&& (pipe->src_fmt->element[0] == C1_B_Cb))
- swap(data->p[1].addr, data->p[2].addr);
+ swap(data.p[1].addr, data.p[2].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data.p[0].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data.p[1].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data.p[2].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data.p[3].addr);
return 0;
}
@@ -901,8 +941,9 @@
struct mdss_mdp_data *src_data)
{
int ret = 0;
- u32 params_changed, opmode;
struct mdss_mdp_ctl *ctl;
+ u32 params_changed;
+ u32 opmode = 0;
if (!pipe) {
pr_err("pipe not setup properly for queue\n");
@@ -983,3 +1024,53 @@
{
return (pipe == pipe->mixer->stage_pipe[pipe->mixer_stage]);
}
+
+static inline void __mdss_mdp_pipe_program_pixel_extn_helper(
+ struct mdss_mdp_pipe *pipe, u32 plane, u32 off)
+{
+ u32 src_h = pipe->src.h >> pipe->vert_deci;
+ u32 mask = 0xFF;
+
+ /*
+ * CB CR plane required pxls need to be accounted
+ * for chroma decimation.
+ */
+ if (plane == 1)
+ src_h >>= pipe->chroma_sample_v;
+ writel_relaxed(((pipe->scale.right_ftch[plane] & mask) << 24)|
+ ((pipe->scale.right_rpt[plane] & mask) << 16)|
+ ((pipe->scale.left_ftch[plane] & mask) << 8)|
+ (pipe->scale.left_rpt[plane] & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR + off);
+ writel_relaxed(((pipe->scale.btm_ftch[plane] & mask) << 24)|
+ ((pipe->scale.btm_rpt[plane] & mask) << 16)|
+ ((pipe->scale.top_ftch[plane] & mask) << 8)|
+ (pipe->scale.top_rpt[plane] & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB + off);
+ mask = 0xFFFF;
+ writel_relaxed((((src_h + pipe->scale.num_ext_pxls_top[plane] +
+ pipe->scale.num_ext_pxls_btm[plane]) & mask) << 16) |
+ ((pipe->scale.roi_w[plane] +
+ pipe->scale.num_ext_pxls_left[plane] +
+ pipe->scale.num_ext_pxls_right[plane]) & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS + off);
+}
+
+/**
+ * mdss_mdp_pipe_program_pixel_extn - Program the source pipe's
+ * sw pixel extension
+ * @pipe: Source pipe struct containing pixel extn values
+ *
+ * Function programs the pixel extn values calculated during
+ * scale setup.
+ */
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe)
+{
+ /* Y plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 0, 0);
+ /* CB CR plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 1, 16);
+ /* Alpha plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 3, 32);
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index b31f6c1..dfeec22 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -629,7 +629,7 @@
}
}
- *op = opmode;
+ *op |= opmode;
return 0;
}
@@ -637,12 +637,15 @@
static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
{
u32 scale_config = 0;
- u32 phasex_step = 0, phasey_step = 0;
+ int init_phasex = 0, init_phasey = 0;
+ int phasex_step = 0, phasey_step = 0;
u32 chroma_sample;
u32 filter_mode;
struct mdss_data_type *mdata;
u32 src_w, src_h;
+ pr_debug("pipe=%d, change pxl ext=%d\n", pipe->num,
+ pipe->scale.enable_pxl_ext);
mdata = mdss_mdp_get_mdata();
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
filter_mode = MDSS_MDP_SCALE_FILTER_CA;
@@ -689,7 +692,8 @@
if ((src_h != pipe->dst.h) ||
(pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
- (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+ (chroma_sample == MDSS_MDP_CHROMA_H1V2) ||
+ pipe->scale.enable_pxl_ext) {
pr_debug("scale y - src_h=%d dst_h=%d\n", src_h, pipe->dst.h);
if ((src_h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
@@ -699,7 +703,8 @@
}
scale_config |= MDSS_MDP_SCALEY_EN;
- phasey_step = pipe->phase_step_y;
+ phasey_step = pipe->scale.phase_step_y[0];
+ init_phasey = pipe->scale.init_phase_y[0];
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
u32 chroma_shift = 0;
@@ -708,11 +713,11 @@
(chroma_sample == MDSS_MDP_CHROMA_H1V2)))
chroma_shift = 1; /* 2x upsample chroma */
- if (src_h <= pipe->dst.h) {
+ if (src_h <= pipe->dst.h)
scale_config |= /* G/Y, A */
(filter_mode << 10) |
(MDSS_MDP_SCALE_FILTER_BIL << 18);
- } else
+ else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
(MDSS_MDP_SCALE_FILTER_PCMN << 18);
@@ -724,6 +729,8 @@
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 14);
+ writel_relaxed(init_phasey, pipe->base +
+ MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
writel_relaxed(phasey_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
} else {
@@ -741,7 +748,8 @@
if ((src_w != pipe->dst.w) ||
(pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
- (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+ (chroma_sample == MDSS_MDP_CHROMA_H2V1) ||
+ pipe->scale.enable_pxl_ext) {
pr_debug("scale x - src_w=%d dst_w=%d\n", src_w, pipe->dst.w);
if ((src_w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
@@ -751,7 +759,8 @@
}
scale_config |= MDSS_MDP_SCALEX_EN;
- phasex_step = pipe->phase_step_x;
+ init_phasex = pipe->scale.init_phase_x[0];
+ phasex_step = pipe->scale.phase_step_x[0];
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
u32 chroma_shift = 0;
@@ -761,11 +770,11 @@
(chroma_sample == MDSS_MDP_CHROMA_H2V1)))
chroma_shift = 1; /* 2x upsample chroma */
- if (src_w <= pipe->dst.w) {
+ if (src_w <= pipe->dst.w)
scale_config |= /* G/Y, A */
(filter_mode << 8) |
(MDSS_MDP_SCALE_FILTER_BIL << 16);
- } else
+ else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
(MDSS_MDP_SCALE_FILTER_PCMN << 16);
@@ -777,6 +786,8 @@
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 12);
+ writel_relaxed(init_phasex, pipe->base +
+ MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
writel_relaxed(phasex_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
} else {
@@ -791,12 +802,44 @@
}
}
+ if (pipe->scale.enable_pxl_ext &&
+ pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+
+ /*program x,y initial phase and phase step*/
+ writel_relaxed(pipe->scale.init_phase_x[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
+ writel_relaxed(pipe->scale.phase_step_x[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
+ writel_relaxed(pipe->scale.init_phase_x[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
+ writel_relaxed(pipe->scale.phase_step_x[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
+
+ writel_relaxed(pipe->scale.init_phase_y[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
+ writel_relaxed(pipe->scale.phase_step_y[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
+ writel_relaxed(pipe->scale.init_phase_y[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
+ writel_relaxed(pipe->scale.phase_step_y[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
+
+ /*program pixel extn values for the SSPP*/
+ mdss_mdp_pipe_program_pixel_extn(pipe);
+ } else {
+ writel_relaxed(phasex_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_X);
+ writel_relaxed(phasey_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+ writel_relaxed(init_phasex, pipe->base +
+ MDSS_MDP_REG_SCALE_INIT_PHASE_X);
+ writel_relaxed(init_phasey, pipe->base +
+ MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
+ }
+
writel_relaxed(scale_config, pipe->base +
MDSS_MDP_REG_SCALE_CONFIG);
- writel_relaxed(phasex_step, pipe->base +
- MDSS_MDP_REG_SCALE_PHASE_STEP_X);
- writel_relaxed(phasey_step, pipe->base +
- MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+
return 0;
}
@@ -2248,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;
@@ -2256,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;
@@ -2278,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) {
@@ -2944,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;
@@ -2958,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;
@@ -3520,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/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 057914b..e2e41bb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -437,6 +437,7 @@
rot->flags |= MDP_DEINTERLACE;
rot->src_rect.h /= 2;
rot->src_rect.y = DIV_ROUND_UP(rot->src_rect.y, 2);
+ rot->src_rect.y &= ~1;
}
rot->dst = rot->src_rect;
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 1170d1e..b680823 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -592,7 +592,7 @@
return -EINVAL;
unit = 1 << PHASE_STEP_SHIFT;
- *out_phase = mult_frac(src, unit, dst);
+ *out_phase = mult_frac(unit, src, dst);
/* check if overflow is possible */
if (src > dst) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index c4e1956..d29323d3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -132,6 +132,16 @@
pr_debug("setting secure=%d\n", enable);
+ if (!ctl || !ctl->mdata) {
+ pr_err("%s : ctl is NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (!wb) {
+ pr_err("unable to start, writeback is not initialized\n");
+ return -ENODEV;
+ }
+
ctl->is_secure = enable;
wb->is_secure = enable;
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 9c07dce..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;
@@ -93,4 +94,43 @@
{
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.
+ * @kref: object.
+ *
+ * Return non-zero if the increment succeeded. Otherwise return 0.
+ *
+ * This function is intended to simplify locking around refcounting for
+ * objects that can be looked up from a lookup structure, and which are
+ * removed from that lookup structure in the object destructor.
+ * Operations on such objects require at least a read lock around
+ * lookup + kref_get, and a write lock around kref_put + remove from lookup
+ * structure. Furthermore, RCU implementations become extremely tricky.
+ * With a lookup followed by a kref_get_unless_zero *with return value check*
+ * locking in the kref_put path can be deferred to the actual removal from
+ * the lookup structure and RCU lookups become trivial.
+ */
+static inline int __must_check kref_get_unless_zero(struct kref *kref)
+{
+ return atomic_add_unless(&kref->refcount, 1, 0);
+}
#endif /* _KREF_H_ */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index e1dbd21..bff056d 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -300,6 +300,7 @@
#define MMC_CAP2_HS400_1_8V (1 << 21) /* can support */
#define MMC_CAP2_HS400_1_2V (1 << 22) /* can support */
+#define MMC_CAP2_CORE_PM (1 << 23) /* use PM framework */
#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
MMC_CAP2_HS400_1_2V)
mmc_pm_flag_t pm_caps; /* supported pm features */
@@ -572,4 +573,9 @@
return host->caps2 & MMC_CAP2_CORE_RUNTIME_PM;
}
+static inline int mmc_use_core_pm(struct mmc_host *host)
+{
+ return host->caps2 & MMC_CAP2_CORE_PM;
+}
+
#endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 0c08421..803ebeb 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -156,6 +156,7 @@
#define MDSS_MDP_ROT_ONLY 0x80
#define MDSS_MDP_RIGHT_MIXER 0x100
+#define MDSS_MDP_DUAL_PIPE 0x200
/* mdp_blit_req flag values */
#define MDP_ROT_NOP 0
@@ -168,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
@@ -253,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;
@@ -442,6 +452,33 @@
BLEND_OP_MAX,
};
+#define MAX_PLANES 4
+struct mdp_scale_data {
+ uint8_t enable_pxl_ext;
+
+ int init_phase_x[MAX_PLANES];
+ int phase_step_x[MAX_PLANES];
+ int init_phase_y[MAX_PLANES];
+ int phase_step_y[MAX_PLANES];
+
+ int num_ext_pxls_left[MAX_PLANES];
+ int num_ext_pxls_right[MAX_PLANES];
+ int num_ext_pxls_top[MAX_PLANES];
+ int num_ext_pxls_btm[MAX_PLANES];
+
+ int left_ftch[MAX_PLANES];
+ int left_rpt[MAX_PLANES];
+ int right_ftch[MAX_PLANES];
+ int right_rpt[MAX_PLANES];
+
+ int top_rpt[MAX_PLANES];
+ int btm_rpt[MAX_PLANES];
+ int top_ftch[MAX_PLANES];
+ int btm_ftch[MAX_PLANES];
+
+ uint32_t roi_w[MAX_PLANES];
+};
+
struct mdp_overlay {
struct msmfb_img src;
struct mdp_rect src_rect;
@@ -457,6 +494,7 @@
uint8_t horz_deci;
uint8_t vert_deci;
struct mdp_overlay_pp_params overlay_pp_cfg;
+ struct mdp_scale_data scale;
};
struct msmfb_overlay_3d {
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/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index cba4394..c940091 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -1077,7 +1077,7 @@
extern int slim_register_board_info(struct slim_boardinfo const *info,
unsigned n);
#else
-int slim_register_board_info(struct slim_boardinfo const *info,
+static inline int slim_register_board_info(struct slim_boardinfo const *info,
unsigned n)
{
return 0;
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/linux/usb/android.h b/include/linux/usb/android.h
index e17e978..8d5e51b 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -19,12 +19,16 @@
#include <linux/usb/composite.h>
+#define MAX_STREAMING_FUNCS 3
+#define FUNC_NAME_LEN 10
struct android_usb_platform_data {
int (*update_pid_and_serial_num)(uint32_t, const char *);
u32 swfi_latency;
u8 usb_core_id;
bool cdrom;
bool internal_ums;
+ char streaming_func[MAX_STREAMING_FUNCS][FUNC_NAME_LEN];
+ int streaming_func_count;
};
#ifndef CONFIG_TARGET_CORE
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index fea832e..3844f41 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -508,6 +508,7 @@
* @dev: Driver model state for this abstract device.
* @usb_core_id: Identifies the usb core controlled by this usb_gadget.
* Used in case of more then one core operates concurrently.
+ * @streaming_enabled: Enable streaming mode with usb core.
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@@ -546,6 +547,7 @@
struct device dev;
u8 usb_core_id;
bool l1_supported;
+ bool streaming_enabled;
};
static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 07f9b90..9eb9cd8 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -229,7 +229,9 @@
* between 1 to 7.
* @l1_supported: enable link power management support.
* @dpdm_pulldown_added: Indicates whether pull down resistors are
- connected on data lines or not.
+ * connected on data lines or not.
+ * @enable_ahb2ahb_bypass: Indicates whether enable AHB2AHB BYPASS
+ * mode with controller in device mode.
*/
struct msm_otg_platform_data {
int *phy_init_seq;
@@ -258,6 +260,7 @@
int log2_itc;
bool l1_supported;
bool dpdm_pulldown_added;
+ bool enable_ahb2ahb_bypass;
};
/* phy related flags */
@@ -462,6 +465,7 @@
int log2_itc;
void *prv_data;
bool l1_supported;
+ bool enable_ahb2ahb_bypass;
};
/**
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 58ab4eb..2a5ebd4 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -49,6 +49,10 @@
#define L1_CONFIG_PHY_LPM BIT(10)
#define L1_CONFIG_PLL BIT(11)
+#define AHB2AHB_BYPASS BIT(31)
+#define AHB2AHB_BYPASS_BIT_MASK BIT(31)
+#define AHB2AHB_BYPASS_CLEAR (0 << 31)
+
#define PORTSC_PHCD (1 << 23) /* phy suspend mode */
#define PORTSC_PTS_MASK (3 << 30)
#define PORTSC_PTS_ULPI (3 << 30)
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/msm_vidc.h b/include/media/msm_vidc.h
index 868be9f..bc85ebb 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -18,6 +18,41 @@
MSM_VIDC_MAX_DEVICES,
};
+/* NOTE: if you change this enum you MUST update the
+ * "buffer-type-tz-usage-table" for any affected target
+ * in arch/arm/boot/dts/<arch>.dtsi
+ */
+enum hal_buffer {
+ HAL_BUFFER_INPUT = 0x1,
+ HAL_BUFFER_OUTPUT = 0x2,
+ HAL_BUFFER_OUTPUT2 = 0x4,
+ HAL_BUFFER_EXTRADATA_INPUT = 0x8,
+ HAL_BUFFER_EXTRADATA_OUTPUT = 0x10,
+ HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20,
+ HAL_BUFFER_INTERNAL_SCRATCH = 0x40,
+ HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80,
+ HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100,
+ HAL_BUFFER_INTERNAL_PERSIST = 0x200,
+ HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
+};
+
+struct msm_smem {
+ int mem_type;
+ size_t size;
+ void *kvaddr;
+ unsigned long device_addr;
+ u32 flags;
+ void *smem_priv;
+ enum hal_buffer buffer_type;
+};
+
+enum smem_cache_ops {
+ SMEM_CACHE_CLEAN,
+ SMEM_CACHE_INVALIDATE,
+ SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
void *msm_vidc_open(int core_id, int session_type);
int msm_vidc_close(void *instance);
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
@@ -47,6 +82,18 @@
int msm_vidc_wait(void *instance);
int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
+struct msm_smem *msm_vidc_smem_alloc(void *instance,
+ size_t size, u32 align, u32 flags,
+ enum hal_buffer buffer_type, int map_kernel);
+void msm_vidc_smem_free(void *instance, struct msm_smem *mem);
+int msm_vidc_smem_cache_operations(void *instance,
+ struct msm_smem *mem, enum smem_cache_ops);
+struct msm_smem *msm_vidc_smem_user_to_kernel(void *instance,
+ int fd, u32 offset, enum hal_buffer buffer_type);
+int msm_vidc_smem_get_domain_partition(void *instance,
+ u32 flags, enum hal_buffer buffer_type,
+ int *domain_num, int *partition_num);
+void *msm_vidc_smem_get_client(void *instance);
#endif
struct msm_vidc_interlace_payload {
unsigned int format;
@@ -93,6 +140,27 @@
unsigned int num_panscan_windows;
struct msm_vidc_panscan_window wnd[1];
};
+struct msm_vidc_s3d_frame_packing_payload {
+ unsigned int fpa_id;
+ unsigned int cancel_flag;
+ unsigned int fpa_type;
+ unsigned int quin_cunx_flag;
+ unsigned int content_interprtation_type;
+ unsigned int spatial_flipping_flag;
+ unsigned int frame0_flipped_flag;
+ unsigned int field_views_flag;
+ unsigned int current_frame_is_frame0_flag;
+ unsigned int frame0_self_contained_flag;
+ unsigned int frame1_self_contained_flag;
+ unsigned int frame0_graid_pos_x;
+ unsigned int frame0_graid_pos_y;
+ unsigned int frame1_graid_pos_x;
+ unsigned int frame1_graid_pos_y;
+ unsigned int fpa_reserved_byte;
+ unsigned int fpa_repetition_period;
+ unsigned int fpa_extension_flag;
+};
+
enum msm_vidc_extradata_type {
EXTRADATA_NONE = 0x00000000,
EXTRADATA_MB_QUANTIZATION = 0x00000001,
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/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bbda72e..104f86e 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3676,6 +3676,7 @@
} __packed;
#define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
#define ASM_SESSION_CMD_GET_SESSIONTIME_V3 0x00010D9D
#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 0dd1f1c..65ca46f 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -54,6 +54,7 @@
#define CMD_EOS 0x0003
#define CMD_CLOSE 0x0004
#define CMD_OUT_FLUSH 0x0005
+#define CMD_SUSPEND 0x0006
/* bit 0:1 represents priority of stream */
#define STREAM_PRIORITY_NORMAL 0x0000
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/include/trace/events/sched.h b/include/trace/events/sched.h
index 41f8607..c549831 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -242,6 +242,56 @@
__entry->status ? "online" : "offline", __entry->error)
);
+/*
+ * Tracepoint for load balancing:
+ */
+#if NR_CPUS > 32
+#error "Unsupported NR_CPUS for lb tracepoint."
+#endif
+TRACE_EVENT(sched_load_balance,
+
+ TP_PROTO(int cpu, enum cpu_idle_type idle, int balance,
+ unsigned long group_mask, int busiest_nr_running,
+ unsigned long imbalance, unsigned int env_flags, int ld_moved,
+ unsigned int balance_interval),
+
+ TP_ARGS(cpu, idle, balance, group_mask, busiest_nr_running,
+ imbalance, env_flags, ld_moved, balance_interval),
+
+ TP_STRUCT__entry(
+ __field( int, cpu)
+ __field( enum cpu_idle_type, idle)
+ __field( int, balance)
+ __field( unsigned long, group_mask)
+ __field( int, busiest_nr_running)
+ __field( unsigned long, imbalance)
+ __field( unsigned int, env_flags)
+ __field( int, ld_moved)
+ __field( unsigned int, balance_interval)
+ ),
+
+ TP_fast_assign(
+ __entry->cpu = cpu;
+ __entry->idle = idle;
+ __entry->balance = balance;
+ __entry->group_mask = group_mask;
+ __entry->busiest_nr_running = busiest_nr_running;
+ __entry->imbalance = imbalance;
+ __entry->env_flags = env_flags;
+ __entry->ld_moved = ld_moved;
+ __entry->balance_interval = balance_interval;
+ ),
+
+ TP_printk("cpu=%d state=%s balance=%d group=%#lx busy_nr=%d imbalance=%ld flags=%#x ld_moved=%d bal_int=%d",
+ __entry->cpu,
+ __entry->idle == CPU_IDLE ? "idle" :
+ (__entry->idle == CPU_NEWLY_IDLE ? "newly_idle" : "busy"),
+ __entry->balance,
+ __entry->group_mask, __entry->busiest_nr_running,
+ __entry->imbalance, __entry->env_flags, __entry->ld_moved,
+ __entry->balance_interval)
+);
+
DECLARE_EVENT_CLASS(sched_process_template,
TP_PROTO(struct task_struct *p),
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 627dab1..89a5395 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -621,7 +621,19 @@
static inline bool got_nohz_idle_kick(void)
{
int cpu = smp_processor_id();
- return idle_cpu(cpu) && test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu));
+
+ if (!test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu)))
+ return false;
+
+ if (idle_cpu(cpu) && !need_resched())
+ return true;
+
+ /*
+ * We can't run Idle Load Balance on this CPU for this time so we
+ * cancel it and clear NOHZ_BALANCE_KICK
+ */
+ clear_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu));
+ return false;
}
#else /* CONFIG_NO_HZ */
@@ -1519,7 +1531,7 @@
/*
* Check if someone kicked us for doing the nohz idle load balance.
*/
- if (unlikely(got_nohz_idle_kick() && !need_resched())) {
+ if (unlikely(got_nohz_idle_kick())) {
this_rq()->idle_balance = 1;
raise_softirq_irqoff(SCHED_SOFTIRQ);
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 2e98983..08497b0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4422,7 +4422,7 @@
int ld_moved, active_balance = 0;
struct sched_group *group;
unsigned long imbalance;
- struct rq *busiest;
+ struct rq *busiest = NULL;
unsigned long flags;
struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
@@ -4591,6 +4591,10 @@
ld_moved = 0;
out:
+ trace_sched_load_balance(this_cpu, idle, *balance,
+ group ? group->cpumask[0] : 0,
+ busiest ? busiest->nr_running : 0, imbalance,
+ env.flags, ld_moved, sd->balance_interval);
return ld_moved;
}
diff --git a/mm/page_io.c b/mm/page_io.c
index e60e43f..1499e1c 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -20,8 +20,15 @@
#include <linux/swapops.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
+#include <linux/ratelimit.h>
#include <asm/pgtable.h>
+/*
+ * We don't need to see swap errors more than once every 1 second to know
+ * that a problem is occurring.
+ */
+#define SWAP_ERROR_LOG_RATE_MS 1000
+
static struct bio *get_swap_bio(gfp_t gfp_flags,
struct page *page, bio_end_io_t end_io)
{
@@ -46,6 +53,7 @@
{
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct page *page = bio->bi_io_vec[0].bv_page;
+ static unsigned long swap_error_rs_time;
if (!uptodate) {
SetPageError(page);
@@ -58,7 +66,9 @@
* Also clear PG_reclaim to avoid rotate_reclaimable_page()
*/
set_page_dirty(page);
- printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
+ if (printk_timed_ratelimit(&swap_error_rs_time,
+ SWAP_ERROR_LOG_RATE_MS))
+ printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
imajor(bio->bi_bdev->bd_inode),
iminor(bio->bi_bdev->bd_inode),
(unsigned long long)bio->bi_sector);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9e95109..d0e40e5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -474,6 +474,8 @@
if (!PageWriteback(page)) {
/* synchronous write or broken a_ops? */
ClearPageReclaim(page);
+ if (PageError(page))
+ return PAGE_ACTIVATE;
}
trace_mm_vmscan_writepage(page, trace_reclaim_flags(page));
inc_zone_page_state(page, NR_VMSCAN_WRITE);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e598400..04cfc69 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -191,7 +191,7 @@
size = SKB_DATA_ALIGN(size);
size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
data = kmalloc_node_track_caller(size, gfp_mask, node);
- if (!data)
+ if (unlikely(ZERO_OR_NULL_PTR(data)))
goto nodata;
/* kmalloc(size) might give us more room than requested.
* Put skb_shared_info exactly at the end of allocated zone,
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/wcd9306.c b/sound/soc/codecs/wcd9306.c
index aaa132e..abc628b 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -1323,6 +1323,9 @@
static const struct soc_enum rx4_mix1_inp2_chain_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
+static const struct soc_enum rx4_mix1_inp3_chain_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B2_CTL, 0, 13, rx_3_4_mix1_text);
+
static const struct soc_enum rx1_mix2_inp1_chain_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
@@ -1418,6 +1421,9 @@
static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
+static const struct snd_kcontrol_new rx4_mix1_inp3_mux =
+ SOC_DAPM_ENUM("RX4 MIX1 INP3 Mux", rx4_mix1_inp3_chain_enum);
+
static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
@@ -4167,7 +4173,7 @@
SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
&rx4_mix1_inp2_mux),
SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
- &rx4_mix1_inp2_mux),
+ &rx4_mix1_inp3_mux),
/* RX4 MIX2 mux inputs */
SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
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..db7a34c 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -90,7 +90,7 @@
#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
#define WCD9XXX_MUX_SWITCH_READY_WAIT_MS 50
-#define WCD9XXX_MEAS_DELTA_MAX_MV 50
+#define WCD9XXX_MEAS_DELTA_MAX_MV 120
#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
@@ -128,7 +128,7 @@
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(impedance_detect_en, "enable/disable impedance detect");
-static bool detect_use_vddio_switch = true;
+static bool detect_use_vddio_switch;
struct wcd9xxx_mbhc_detect {
u16 dce;
@@ -227,7 +227,7 @@
* setup internal micbias if codec uses internal micbias for
* headset detection
*/
- if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
+ if (mbhc->mbhc_cfg->use_int_rbias) {
if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
mbhc->mbhc_cb->setup_int_rbias(codec, true);
else
@@ -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;
@@ -972,7 +973,9 @@
if (noreldetection)
wcd9xxx_turn_onoff_rel_detection(codec, false);
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x0);
+ if (mbhc->mbhc_cfg->do_recalibration)
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
+ 0x0);
/* Turn on the override */
if (!override_bypass)
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
@@ -982,8 +985,9 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
0x0);
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
- 0x2);
+ if (mbhc->mbhc_cfg->do_recalibration)
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
+ 0x2, 0x2);
usleep_range(mbhc->mbhc_data.t_sta_dce,
mbhc->mbhc_data.t_sta_dce);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
@@ -995,8 +999,9 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
0x0);
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
- 0x2);
+ if (mbhc->mbhc_cfg->do_recalibration)
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
+ 0x2, 0x2);
usleep_range(mbhc->mbhc_data.t_sta_dce,
mbhc->mbhc_data.t_sta_dce);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
@@ -1103,7 +1108,7 @@
* setup internal micbias if codec uses internal micbias for
* headset detection
*/
- if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
+ if (mbhc->mbhc_cfg->use_int_rbias) {
if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
mbhc->mbhc_cb->setup_int_rbias(codec, true);
else
@@ -1140,48 +1145,59 @@
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ if (!mbhc->mbhc_cfg->do_recalibration) {
+ if (!is_cs_enable)
+ wcd9xxx_calibrate_hs_polling(mbhc);
+ }
+
/* don't flip override */
bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
- /* recalibrate dce_z and sta_z */
- reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
- change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
- btn_det->mbhc_nsc << 3);
- wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
- if (change)
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
- if (dce_z && sta_z) {
- pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
- __func__,
- mbhc->mbhc_data.sta_z, sta_z & 0xffff,
- mbhc->mbhc_data.dce_z, dce_z & 0xffff);
- mbhc->mbhc_data.dce_z = dce_z;
- mbhc->mbhc_data.sta_z = sta_z;
- wcd9xxx_mbhc_calc_thres(mbhc);
- wcd9xxx_calibrate_hs_polling(mbhc);
- } else {
- pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n", __func__,
- dce_z, sta_z);
- }
-
- if (is_cs_enable) {
- /* recalibrate dce_nsc_cs_z */
- reg = snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
- snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
- 0x78, WCD9XXX_MBHC_NSC_CS << 3);
- wcd9xxx_get_z(mbhc, &dce_z, NULL);
- snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
- if (dce_z) {
- pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n", __func__,
- mbhc->mbhc_data.dce_nsc_cs_z, dce_z & 0xffff);
- mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+ if (mbhc->mbhc_cfg->do_recalibration) {
+ /* recalibrate dce_z and sta_z */
+ reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+ change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+ 0x78, btn_det->mbhc_nsc << 3);
+ wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+ if (change)
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
+ if (dce_z && sta_z) {
+ pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
+ __func__,
+ mbhc->mbhc_data.sta_z, sta_z & 0xffff,
+ mbhc->mbhc_data.dce_z, dce_z & 0xffff);
+ mbhc->mbhc_data.dce_z = dce_z;
+ mbhc->mbhc_data.sta_z = sta_z;
+ wcd9xxx_mbhc_calc_thres(mbhc);
+ wcd9xxx_calibrate_hs_polling(mbhc);
} else {
- pr_debug("%s: failed get new dce_nsc_cs_z\n", __func__);
+ pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n",
+ __func__, dce_z, sta_z);
+ }
+
+ if (is_cs_enable) {
+ /* recalibrate dce_nsc_cs_z */
+ reg = snd_soc_read(mbhc->codec,
+ WCD9XXX_A_CDC_MBHC_B1_CTL);
+ snd_soc_update_bits(mbhc->codec,
+ WCD9XXX_A_CDC_MBHC_B1_CTL,
+ 0x78, WCD9XXX_MBHC_NSC_CS << 3);
+ wcd9xxx_get_z(mbhc, &dce_z, NULL);
+ snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+ reg);
+ if (dce_z) {
+ pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n",
+ __func__, mbhc->mbhc_data.dce_nsc_cs_z,
+ dce_z & 0xffff);
+ mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+ } else {
+ pr_debug("%s: failed get new dce_nsc_cs_z\n",
+ __func__);
+ }
}
}
-
return bias_value;
}
@@ -1751,6 +1767,7 @@
/* GND and MIC swap detection requires at least 2 rounds of DCE */
BUG_ON(NUM_DCE_PLUG_INS_DETECT < 2);
+ detect_use_vddio_switch = mbhc->mbhc_cfg->use_vddio_meas;
/*
* There are chances vddio switch is on and cfilt voltage is adjusted
@@ -3188,7 +3205,7 @@
* setup internal micbias if codec uses internal micbias for
* headset detection
*/
- if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
+ if (mbhc->mbhc_cfg->use_int_rbias) {
if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
mbhc->mbhc_cb->setup_int_rbias(codec, true);
else
@@ -4019,7 +4036,6 @@
if (mbhc->mbhc_cfg->use_int_rbias) {
if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias) {
mbhc->mbhc_cb->setup_int_rbias(codec, true);
- mbhc->int_rbias_on = true;
} else {
pr_info("%s: internal bias requested but codec did not provide callback\n",
__func__);
@@ -4178,7 +4194,6 @@
case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
- mbhc->int_rbias_on = true;
if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
wcd9xxx_event_to_micbias(event)) {
wcd9xxx_switch_micbias(mbhc, 0);
@@ -4206,7 +4221,6 @@
case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
- mbhc->int_rbias_on = false;
if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
wcd9xxx_event_to_micbias(event)) {
if (mbhc->event_state &
@@ -4502,7 +4516,6 @@
mbhc->mbhc_cb = mbhc_cb;
mbhc->intr_ids = mbhc_cdc_intr_ids;
mbhc->impedance_detect = impedance_det_en;
- mbhc->int_rbias_on = false;
if (mbhc->intr_ids == NULL) {
pr_err("%s: Interrupt mapping not provided\n", __func__);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 7fe9538..29dd84a 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -228,6 +228,8 @@
bool (*swap_gnd_mic) (struct snd_soc_codec *);
unsigned long cs_enable_flags;
bool use_int_rbias;
+ bool do_recalibration;
+ bool use_vddio_meas;
};
struct wcd9xxx_cfilt_mode {
@@ -336,7 +338,6 @@
u32 rco_clk_rate;
bool update_z;
- bool int_rbias_on;
/* Holds codec specific interrupt mapping */
const struct wcd9xxx_mbhc_intr *intr_ids;
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 5d74469..e18593a 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -561,8 +561,13 @@
if (--resmgr->clk_rco_users == 0 &&
resmgr->clk_type == WCD9XXX_CLK_RCO) {
wcd9xxx_disable_clock_block(resmgr);
- snd_soc_update_bits(resmgr->codec,
- WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x00);
+ /* if RCO is enabled, switch from it */
+ if (snd_soc_read(resmgr->codec, WCD9XXX_A_RC_OSC_FREQ) & 0x80) {
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+ snd_soc_write(resmgr->codec, WCD9XXX_A_CLK_BUFF_EN2,
+ 0x02);
+ wcd9xxx_resmgr_enable_config_mode(resmgr, 0);
+ }
resmgr->clk_type = WCD9XXX_CLK_OFF;
}
break;
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/msm8226.c b/sound/soc/msm/msm8226.c
index 6cd7383..05d6c62 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -94,6 +94,8 @@
.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
1 << MBHC_CS_ENABLE_INSERTION |
1 << MBHC_CS_ENABLE_REMOVAL),
+ .do_recalibration = true,
+ .use_vddio_meas = true,
};
struct msm_auxpcm_gpio {
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 7f8736c..381992d 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -129,6 +129,8 @@
.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
1 << MBHC_CS_ENABLE_INSERTION |
1 << MBHC_CS_ENABLE_REMOVAL),
+ .do_recalibration = true,
+ .use_vddio_meas = true,
};
struct msm_auxpcm_gpio {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index a1b06da..6ac86cc 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -77,6 +77,8 @@
.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
1 << MBHC_CS_ENABLE_INSERTION |
1 << MBHC_CS_ENABLE_REMOVAL),
+ .do_recalibration = false,
+ .use_vddio_meas = false,
};
/*
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/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index a632644..bb926ec 100755
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -986,7 +986,7 @@
struct snd_dec_ddp *ddp =
&compr->info.codec_param.codec.options.ddp;
uint32_t params_length = ddp->params_length*sizeof(int);
- if(params_length > MAX_AC3_PARAM_SIZE) {
+ if (params_length > MAX_AC3_PARAM_SIZE) {
/*MAX is 36*sizeof(int) this should not happen*/
pr_err("params_length(%d) is greater than %d",
params_length, MAX_AC3_PARAM_SIZE);
@@ -1023,7 +1023,7 @@
struct snd_dec_ddp *ddp =
&compr->info.codec_param.codec.options.ddp;
uint32_t params_length = ddp->params_length*sizeof(int);
- if(params_length > MAX_AC3_PARAM_SIZE) {
+ if (params_length > MAX_AC3_PARAM_SIZE) {
/*MAX is 36*sizeof(int) this should not happen*/
pr_err("params_length(%d) is greater than %d",
params_length, MAX_AC3_PARAM_SIZE);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 1b4fae9..d56ad2b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -54,6 +54,11 @@
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
+#define EC_PORT_ID_PRIMARY_MI2S_TX 1
+#define EC_PORT_ID_SECONDARY_MI2S_TX 2
+#define EC_PORT_ID_TERTIARY_MI2S_TX 3
+#define EC_PORT_ID_QUATERNARY_MI2S_TX 4
+
static struct mutex routing_lock;
static int fm_switch_enable;
@@ -63,6 +68,7 @@
static int slim0_rx_aanc_fb_port;
static int msm_route_ec_ref_rx = 3; /* NONE */
static uint32_t voc_session_id = ALL_SESSION_VSID;
+static int msm_route_ext_ec_ref = AFE_PORT_INVALID;
enum {
MADNONE,
@@ -1369,6 +1375,76 @@
msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put),
};
+static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ext_ec_ref_rx = %x\n", __func__, msm_route_ext_ec_ref);
+
+ mutex_lock(&routing_lock);
+ ucontrol->value.integer.value[0] = msm_route_ext_ec_ref;
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static int msm_routing_ext_ec_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ int mux = ucontrol->value.enumerated.item[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int ret = 0;
+ bool state = false;
+
+ pr_debug("%s: msm_route_ec_ref_rx = %d value = %ld\n",
+ __func__, msm_route_ext_ec_ref,
+ ucontrol->value.integer.value[0]);
+
+ mutex_lock(&routing_lock);
+ switch (ucontrol->value.integer.value[0]) {
+ case EC_PORT_ID_PRIMARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ state = true;
+ break;
+ case EC_PORT_ID_SECONDARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ state = true;
+ break;
+ case EC_PORT_ID_TERTIARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ state = true;
+ break;
+ case EC_PORT_ID_QUATERNARY_MI2S_TX:
+ msm_route_ext_ec_ref = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ state = true;
+ break;
+ default:
+ msm_route_ext_ec_ref = AFE_PORT_INVALID;
+ break;
+ }
+ if (voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
+ mutex_unlock(&routing_lock);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+ } else {
+ ret = -EINVAL;
+ mutex_unlock(&routing_lock);
+ }
+ return ret;
+}
+
+static const char * const ext_ec_ref_rx[] = {"NONE", "PRI_MI2S_TX",
+ "SEC_MI2S_TX", "TERT_MI2S_TX",
+ "QUAT_MI2S_TX"};
+
+static const struct soc_enum msm_route_ext_ec_ref_rx_enum[] = {
+ SOC_ENUM_SINGLE_EXT(5, ext_ec_ref_rx),
+};
+
+static const struct snd_kcontrol_new voc_ext_ec_mux =
+ SOC_DAPM_ENUM_EXT("VOC_EXT_EC MUX Mux", msm_route_ext_ec_ref_rx_enum[0],
+ msm_routing_ext_ec_get, msm_routing_ext_ec_put);
+
+
static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -3235,6 +3311,8 @@
SND_SOC_DAPM_MUX("SLIM0_RX_VI_FB_LCH_MUX", SND_SOC_NOPM, 0, 0,
&slim0_rx_vi_fb_lch_mux),
+ SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0,
+ &voc_ext_ec_mux),
};
@@ -3524,6 +3602,12 @@
{"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+ {"VOC_EXT_EC MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"VOC_EXT_EC MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"CS-VOICE_UL1", NULL, "VOC_EXT_EC MUX"},
+
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 7c4547e..7a5efb0 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1225,6 +1225,7 @@
data->payload_size))
break;
case ASM_SESSION_CMD_PAUSE:
+ case ASM_SESSION_CMD_SUSPEND:
case ASM_DATA_CMD_EOS:
case ASM_STREAM_CMD_CLOSE:
case ASM_STREAM_CMD_FLUSH:
@@ -3870,6 +3871,11 @@
hdr.opcode = ASM_SESSION_CMD_PAUSE;
state = &ac->cmd_state;
break;
+ case CMD_SUSPEND:
+ pr_debug("%s:CMD_SUSPEND\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_SUSPEND;
+ state = &ac->cmd_state;
+ break;
case CMD_FLUSH:
pr_debug("%s:CMD_FLUSH\n", __func__);
hdr.opcode = ASM_STREAM_CMD_FLUSH;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 673ecff..5aadfa5 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1861,10 +1861,18 @@
cvp_setdev_cmd.cvp_set_device_v2.tx_port_id = v->dev_tx.port_id;
cvp_setdev_cmd.cvp_set_device_v2.rx_port_id = v->dev_rx.port_id;
- cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+
+ if (common.ec_ref_ext) {
+ cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING;
+ cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+ common.ec_port_id;
+ } else {
+ cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
- cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+ cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
VSS_IVOCPROC_PORT_ID_NONE;
+ }
pr_debug("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
cvp_setdev_cmd.cvp_set_device_v2.tx_port_id,
@@ -3026,10 +3034,17 @@
cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
cvp_session_cmd.cvp_session.profile_id =
VSS_ICOMMON_CAL_NETWORK_ID_NONE;
- cvp_session_cmd.cvp_session.vocproc_mode =
+ if (common.ec_ref_ext) {
+ cvp_session_cmd.cvp_session.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING;
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
+ common.ec_port_id;
+ } else {
+ cvp_session_cmd.cvp_session.vocproc_mode =
VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
- cvp_session_cmd.cvp_session.ec_ref_port_id =
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
VSS_IVOCPROC_PORT_ID_NONE;
+ }
pr_debug("tx_topology: %d tx_port_id=%d, rx_port_id=%d, mode: 0x%x\n",
cvp_session_cmd.cvp_session.tx_topology_id,
@@ -4313,7 +4328,8 @@
v->voc_state = VOC_CHANGE;
}
-
+ if (common.ec_ref_ext)
+ voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
fail: mutex_unlock(&v->lock);
return ret;
@@ -4756,6 +4772,8 @@
ret = -EINVAL;
}
+ if (common.ec_ref_ext)
+ voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
mutex_unlock(&v->lock);
return ret;
@@ -4973,6 +4991,28 @@
return ret;
}
+int voc_set_ext_ec_ref(uint16_t port_id, bool state)
+{
+ int ret = 0;
+
+ mutex_lock(&common.common_lock);
+ if (state == true) {
+ if (port_id == AFE_PORT_INVALID) {
+ pr_err("%s: Invalid port id", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ common.ec_port_id = port_id;
+ common.ec_ref_ext = true;
+ } else {
+ common.ec_ref_ext = false;
+ common.ec_port_id = port_id;
+ }
+exit:
+ mutex_unlock(&common.common_lock);
+ return ret;
+}
+
void voc_register_mvs_cb(ul_cb_fn ul_cb,
dl_cb_fn dl_cb,
void *private_data)
@@ -5807,7 +5847,7 @@
common.default_vol_step_val = 0;
common.default_vol_ramp_duration_ms = DEFAULT_VOLUME_RAMP_DURATION;
common.default_mute_ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
-
+ common.ec_ref_ext = false;
/* Initialize MVS info. */
common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 39f0986..5c0cf21 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1328,6 +1328,8 @@
uint32_t default_vol_step_val;
uint32_t default_vol_ramp_duration_ms;
uint32_t default_mute_ramp_duration_ms;
+ bool ec_ref_ext;
+ uint16_t ec_port_id;
/* APR to MVM in the Q6 */
void *apr_q6_mvm;
@@ -1462,5 +1464,6 @@
int voc_start_playback(uint32_t set, uint16_t port_id);
int voc_start_record(uint32_t port_id, uint32_t set, uint32_t session_id);
int voice_get_idx_for_session(u32 session_id);
+int voc_set_ext_ec_ref(uint16_t port_id, bool state);
#endif
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);