Merge "msm: lpm_levels: remove debug print"
diff --git a/Documentation/csdio.txt b/Documentation/csdio.txt
deleted file mode 100644
index 22d5e35..0000000
--- a/Documentation/csdio.txt
+++ /dev/null
@@ -1,189 +0,0 @@
-Introduction
-============
-The Char SDIO Device Driver is an interface which exposes an SDIO
-card/function from kernel space as a char device in user space.
-
-The driver doesn't interact with any HW directly. It relies on SDIO
-card/function interface provided as a part of Linux kernel.
-
-Hardware description
-====================
-Each SDIO device/card contains an SDIO client HW block.
-The host interacts with the device by sending byte sequences called
-command (CMD). Some commands can be followed by data blocks. The
-device sends back a byte sequence called response (R) and a data
-block if required. CMD3, CMD5 and CMD7 are used to initialize the
-device. CMD52 and CMD53 are used to access the device. Command
-format and properties are defined by SDIO Specification document
-published by SD Association:
- http://www.sdcard.org/developers/tech/sdio/.
-
-CMD52 and CMD53 can access up to 8 address spaces called Functions.
-Function 0 contains system information predefined by SD/SDIO
-standard and Functions 1-7 are defined by the SDIO device
-manufacturer.
-
-An SDIO device/card can send an interrupt to SDIO host. This
-interrupt is intercepted and handled by SDIO host.
-
-Software description
-====================
-Linux provides a framework for handling SDIO devices. It implements
-kind of plug-and-play model in which the Linux SDIO Host Driver is
-responsible for initializing an SDIO device upon insertion. It also
-reads device/card identification information and enumerates functions
-provided by the device and then looks up in the list of
-preregistered user SDIO drivers for a suitable one.
-
-During its lifecycle the user SDIO driver interacts with the Linux
-SDIO Host Driver in order to send/receive information to/from SDIO
-device/card. The user SDIO driver doesn't work with CMD52/CMD53
-directly. Instead it uses an abstraction provided by the Linux SDIO
-Host Driver.
-
-The Linux SDIO Host Driver is also in charge of handling SDIO
-interrupts. User SDIO driver can register its own callback in SDIO
-Host Driver and get a notification about interrupt event.
-
-The Char SDIO Device Driver follows the design guidelines mentioned
-above. It provides the following functionality:
-
- - Register itself in the user SDIO drivers list;
- - Handle Probe event upon insertion of supported card/device;
- - Creates and maintains a char device driver for each SDIO Function
- found in the card/device;
- - Translates read/write/ioctl calls to appropriate SDIO call
- sequences;
-
-In order to handle general SDIO configuration functionality and
-Function 0 the Char SDIO Device Driver provides additional
-simplified char device driver.
-
-The Manufacturer and Device IDs of handled SDIO device should be
-provided as parameters for kernel module or as configuration
-parameters in case of statically linked driver.
-
-Design
-======
-The main goal of the Char SDIO Device Driver is to expose an SDIO
-card/device from kernel space to user space as a char device driver.
-The driver should be generic and simple as far as possible.
-
-The biggest design tradeoff is maintaining a balance between the
-system call overhead required to initiate an SDIO transaction from
-user space and overall SDIO communication performance. But luckily,
-because of nature of SDIO protocol, this overhead is negligible
-comparing to time required to execute SDIO transaction itself. So,
-each CMD52 (read or write) consists from single ioctl system call.
-And each CMD53 invokes single ioctl system call followed by read or
-write system call.
-
-The Char SDIO Device Driver registers its own class of the devices
-called 'csdio'. This class will serve as a common roof for all SDIO
-devices served by different instances of the Char SDIO Device Driver.
-Additional benefit from maintaining its own class is the driver
-ability to overwrite default permissions of the dev nodes created by
-the driver.
-
-Power Management
-================
-None
-
-SMP/multi-core
-==============
-The driver does not anticipate any issues related to multi-core
-since it is expected to run on one core only.
-
-Security
-========
-None
-
-Performance
-===========
-None
-
-Interface
-=========
-The Char SDIO Device Driver has two char device interfaces:
- - Control Interface;
- - Function Interface.
-
-Char SDIO Device Driver Control Interface consists of:
- - open() - device node is /dev/csdio0;
- - close()
- - ioctl() - the following options are available:
- - CSDIO_IOC_ENABLE_HIGHSPEED_MODE;
- - CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS;
- - CSDIO_IOC_ENABLE_ISR;
- - CSDIO_IOC_DISABLE_ISR.
-
-Char SDIO Device Driver Function Interface consists of:
- - open() - device node is /dev/csdiofX, where X is Function Id;
- - close()
- - read() - send CMD53 read;
- - write() - send CMD53 write;
- - ioctl() - the following options are available:
- - CSDIO_IOC_SET_OP_CODE - 0 fixed adrress, 1 autoincrement.
- - CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE;
- - CSDIO_IOC_SET_BLOCK_MODE - 0 byte mode, 1 block mode;
- - CSDIO_IOC_CMD52 - execute CMD52, receives the
- following structure as a parameter:
- struct csdio_cmd52_ctrl_t {
- uint32_t m_write; // 0 - read, 1 -write
- uint32_t m_address;
- uint32_t m_data; // data to write or read data
- uint32_t m_ret; // command execution status
- }__attribute__ ((packed));
- - CSDIO_IOC_CMD53 - setup CMD53 data transfer, receives the
- following structure as a parameter:
- struct csdio_cmd53_ctrl_t {
- uint32_t m_block_mode;
- uint32_t m_op_code;
- uint32_t m_address;
- }__attribute__ ((packed));
- - CSDIO_IOC_CONNECT_ISR;
- - CSDIO_IOC_DISCONNECT_ISR;
- - CSDIO_IOC_GET_VDD;
- - CSDIO_IOC_SET_VDD.
-
-Additionally, user space application can use fcntl system call with
-parameters F_SETOWN and F_SETFL in order to set an asynchronous
-callback for SDIO interrupt.
-
-Driver parameters
-=================
-If the driver is compiled as a kernel module, the following
-parameters can be used in order to provide Manufacturer and Device IDs
-upon module download:
- - csdio_vendor_id;
- - csdio_device_id.
-If the driver is intended to work with specific SDIO host the
-host_name parameter should be added followed by the name of the MMC
-host platform device.
-
-Config options
-==============
-These are the kernel configuration options:
- - CONFIG_CSDIO_VENDOR_ID;
- - CONFIG_CSDIO_DEVICE_ID.
-
-Dependencies
-============
-The Char SDIO Device Driver depends on Linux SDIO Host Driver.
-
-User space utilities
-====================
-None
-
-Other
-=====
-None
-
-Known issues
-============
-None
-
-To do
-=====
-Provide mechanism to support a number of SDIO devices simultaneously
-connected to different SDIO hosts.
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 99de826..3a293a3 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -198,16 +198,21 @@
- qti,cpr-uplift-speed-bin: The speed bin value corresponding to one type of processor which needs to apply the
pvs voltage uplift workaround.
This is required if cpr-fuse-uplift-disable-sel is present.
-- qti,cpr-quot-adjust-table: Array of 4-tuples in which each 4-tuple indicates the speed bin
- of the CPU, the frequency of the CPU, the quotient adjustment and the voltage corner to use.
- The 4 elements in one 4-tuple are:
- [0]: => the speed bin of the CPU;
- [1]: => the frequency in kHz of the CPU;
- [2]: => the quotient adjustment of the corresponding frequency;
- [3]: => the voltage corner to use.
- If the speed bin in a tuple is eqaul to the speed bin of the CPU, then the quotient
- adjustment would be subtracted from the quotient value of the voltage corner
- when the CPU is running at that frequency.
+- qti,cpr-quot-adjust-table: Array of triples in which each triple indicates the speed bin of the CPU, the virtual
+ corner to use and the quotient adjustment.
+ The 3 elements in one triple are:
+ [0]: => the speed bin of the CPU.
+ [1]: => the virtual voltage corner to use.
+ [2]: => the quotient adjustment for the corresponding virtual corner.
+ If the speed bin in a triple is equal to the speed bin of the CPU, the adjustment would
+ be subtracted from the quotient value of the voltage corner when the CPU is running at
+ that virtual corner. Each virtual corner value must be in the range 1 to the number of
+ elements in qti,cpr-corner-map.
+- qti,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
+ The location or 1-based index of an element in the list corresponds to
+ the virtual corner value. For example, the first element in the list is the fuse corner
+ value that virtual corner 1 maps to.
+ This is required if qti,cpr-quot-adjust-table is present.
Example:
apc_vreg_corner: regulator@f9018000 {
@@ -270,9 +275,10 @@
qti,cpr-uplift-max-volt = <1350000>;
qti,cpr-uplift-speed-bin = <1>;
qti,speed-bin-fuse-sel = <22 0 3 0>;
- qti,cpr-quot-adjust-table = <1 998400 450 3>,
- <1 1094400 375 3>, <1 1190400 300 3>,
- <1 1305600 225 3>, <1 1344000 187 3>,
- <1 1401600 150 3>, <1 1497600 75 3>;
+ qti,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
+ qti,cpr-quot-adjust-table = <1 1 0>, <1 2 0>, <1 3 0>,
+ <1 4 0>, <1 5 450>, <1 6 375>,
+ <1 7 300>, <1 8 225>, <1 9 187>,
+ <1 10 150>, <1 11 75>, <1 12 0>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 56bdc59..6277054 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -4,23 +4,29 @@
Required properties:
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
* msm-pcm-low-latency
Required properties:
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
Optional properties
- - qcom,msm-pcm-low-latency : Flag indicating whether
+ - qti,msm-pcm-low-latency : Flag indicating whether
the device node is of type low latency.
+ - qti,latency-level : Flag indicating whether the device node
+ is of type regular low latency or ultra
+ low latency.
+ regular : regular low latency stream
+ ultra : ultra low latency stream
+
* msm-pcm-routing
Required properties:
@@ -102,6 +108,12 @@
- compatible : "qcom,msm-lsm-client"
+* msm-pcm-loopback
+
+Required properties:
+
+ - compatible : "qti,msm-pcm-loopback"
+
* msm-dai-q6
[First Level Nodes]
@@ -220,16 +232,16 @@
Example:
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
- };
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ };
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
diff --git a/Makefile b/Makefile
index be32c2f..0c11d69 100644
--- a/Makefile
+++ b/Makefile
@@ -864,6 +864,7 @@
# Generate .S file with all kernel symbols
quiet_cmd_kallsyms = KSYM $@
cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
+ --page-offset=$(CONFIG_PAGE_OFFSET) \
$(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 8c79bb9..25e5072 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -17,7 +17,7 @@
*---------------------------------------------------------------------------*/
&mdss_mdp {
dsi_hx8389b_qhd_vid: qcom,mdss_dsi_hx8389b_qhd_video {
- qcom,mdss-dsi-panel-name = "HX8389b qhd video mode dsi panel";
+ qcom,mdss-dsi-panel-name = "hx8389b qhd video mode dsi panel";
qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
qcom,mdss-dsi-panel-type = "dsi_video_mode";
qcom,mdss-dsi-panel-destination = "display_1";
@@ -26,89 +26,35 @@
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <540>;
qcom,mdss-dsi-panel-height = <960>;
- qcom,mdss-dsi-h-front-porch = <48>;
- qcom,mdss-dsi-h-back-porch = <96>;
- qcom,mdss-dsi-h-pulse-width = <96>;
+ qcom,mdss-dsi-h-front-porch = <60>;
+ qcom,mdss-dsi-h-back-porch = <39>;
+ qcom,mdss-dsi-h-pulse-width = <39>;
qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <13>;
qcom,mdss-dsi-v-front-porch = <9>;
qcom,mdss-dsi-v-pulse-width = <3>;
- qcom,mdss-dsi-v-back-porch = <13>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-on-command = [
- 39 01 00 00 00 00 04
- B9 FF 83 89
- 39 01 00 00 00 00 08
- BA 41 93 00
- 16 A4 10 18
- 23 01 00 00 00 00 02
- C6 08
- 39 01 00 00 00 00 03
- BC 02 00
- 23 01 00 00 00 00 02
- CC 02
- 39 01 00 00 00 00 14
- B1 00 00 07
- E8 50 10 11
- 98 f8 21 29
- 27 27 43 01
- 58 F0 00 E6
- 39 01 00 00 00 00 08
- B2 00 00 78
- 0C 07 3F 80
- 39 01 00 00 00 00 18
- b4 82 08 00
- 32 10 04 32
- 10 00 32 10
- 00 37 0a 40
- 08 37 0a 40
- 14 46 50 0a
- 39 01 00 00 00 00 39
- d5 00 00 00
- 00 01 00 00
- 00 60 00 99
- 88 AA BB 88
- 23 88 01 88
- 67 88 45 01
- 23 88 88 88
- 88 88 88 99
- BB AA 88 54
- 88 76 88 10
- 88 32 32 10
- 88 88 88 88
- 88 00 04 00
- 00 00 00 00
- 00
- 39 01 00 00 00 00 03
- CB 07 07
- 39 01 00 00 00 00 05
- BB 00 00 FF
- 80
- 39 01 00 00 00 00 04
- DE 05 58 10
- 39 01 00 00 00 00 05
- B6 00 8A 00
- 8A
- 39 01 00 00 00 00 23
- E0 01 08 0C
- 1F 25 36 12
- 35 05 09 0D
- 10 11 0F 0F
- 1C 1D 01 08
- 0C 1F 25 36
- 12 35 05 09
- 0D 10 11 0F
- 0F 1C 1D
- 05 01 00 00 96 00 02
- 11 00
- 05 01 00 00 96 00 02
- 29 00
- ];
+ qcom,mdss-dsi-on-command = [39 01 00 00 0A 00 04 B9 FF 83 89
+ 15 01 00 00 01 00 02 CC 02
+ 39 01 00 00 01 00 03 C0 43 17
+ 39 01 00 00 01 00 08 BA 41 93 00 16 A4 10 18
+ 39 01 00 00 01 00 14 B1 00 00 06 EB 59 10 11 EE EE 3A 42 3F 3F 43 01 5A F6 00 E6
+ 39 01 00 00 01 00 08 B2 00 00 78 0C 07 3F 80
+ 39 01 00 00 01 00 04 b7 00 00 50
+ 39 01 00 00 01 00 18 B4 80 08 00 32 10 04 32 10 00 32 10 00 37 0a 40 08 37 00 46 02 58 58 02
+ 39 01 00 00 01 00 39 D5 00 00 00 00 01 00 00 00 60 00 99 88 AA BB 88 23 88 01 88 67 88 45 01 23 88 88 88 88 88 88 99 BB AA 88 54 88 76 88 10 88 32 32 10 88 88 88 88 88 3C 04 00 00 00 00 00 00
+ 39 01 00 00 01 00 23 E0 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18
+ 39 01 00 00 05 00 80 C1 01 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0
+ 39 01 00 00 01 00 05 B6 00 88 00 88
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
@@ -120,7 +66,7 @@
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
qcom,mdss-dsi-lane-1-state;
- qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 03 04 00];
+ qcom,mdss-dsi-panel-timings = [87 1E 14 00 44 4B 19 21 22 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <26>;
@@ -129,6 +75,5 @@
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
-
};
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 63da606..dbeaa97 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -36,7 +36,7 @@
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <3>;
+ regulator-max-microvolt = <12>;
qti,pvs-fuse-redun-sel = <22 24 3 2 0>;
qti,pvs-fuse = <22 6 5 0>;
@@ -91,13 +91,15 @@
qti,cpr-uplift-max-volt = <1350000>;
qti,cpr-uplift-speed-bin = <1>;
qti,speed-bin-fuse-sel = <22 0 3 0>;
- qti,cpr-quot-adjust-table = <1 300000 0 1>,
- <1 384000 0 1>, <1 600000 0 2>,
- <1 787200 0 2>, <1 998400 450 3>,
- <1 1094400 375 3>, <1 1190400 300 3>,
- <1 1305600 225 3>, <1 1344000 187 3>,
- <1 1401600 150 3>, <1 1497600 75 3>,
- <1 1593600 0 3>;
+ qti,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
+ qti,cpr-quot-adjust-table =
+ <1 5 450>,
+ <1 6 375>,
+ <1 7 300>,
+ <1 8 225>,
+ <1 9 187>,
+ <1 10 150>,
+ <1 11 75>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index 38ca03b..a1a8480 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -160,7 +160,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index a0da9cc..2e9f6db 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -162,7 +162,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index ddba542..4149169 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -102,12 +102,12 @@
< 0 0>,
< 384000000 1>,
< 787200000 2>,
- <149700000 3>;
+ <1401600000 3>;
qcom,speed7-bin-v2 =
< 0 0>,
< 384000000 1>,
< 787200000 2>,
- <1497600000 3>;
+ <1401600000 3>;
qcom,speed1-bin-v2 =
< 0 0>,
< 384000000 1>,
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 1250ed2..baa81cc 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -429,19 +429,20 @@
qcom,tapan-codec-9302;
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "regular";
};
qcom,msm-pcm-lpa {
@@ -1024,8 +1025,8 @@
qcom,cpufreq-table =
< 300000 1600 /* 200 MHz */ >,
< 384000 1600 /* 200 MHz */ >,
- < 600000 3200 /* 320 MHz */ >,
- < 787200 4264 /* 533 MHz */ >,
+ < 600000 1600 /* 200 MHz */ >,
+ < 787200 3200 /* 400 MHz */ >,
< 998400 4264 /* 533 MHz */ >,
< 1094400 4264 /* 533 MHz */ >,
< 1190400 4264 /* 533 MHz */ >,
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index d63c6e5..04eca14 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -143,7 +143,11 @@
"MIC BIAS External", "Handset Mic",
"MIC BIAS Internal2", "Headset Mic",
"AMIC1", "MIC BIAS External",
- "AMIC2", "MIC BIAS Internal2";
+ "AMIC2", "MIC BIAS Internal2",
+ "MIC BIAS External", "Digital Mic1",
+ "MIC BIAS External", "Digital Mic2",
+ "DMIC1", "MIC BIAS External",
+ "DMIC2", "MIC BIAS External";
qcom,headset-jack-type-NC;
};
};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index f9bafb4..51a9516 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -36,7 +36,7 @@
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <3>;
+ regulator-max-microvolt = <12>;
qti,pvs-fuse-redun-sel = <53 25 3 2 1>;
qti,pvs-fuse = <23 6 5 1>;
@@ -50,8 +50,8 @@
1275000 1275000 1275000 1275000 1275000
1275000 1275000>;
qti,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
- qti,pvs-corner-ceiling-nom = <1075000 1075000 1200000>;
- qti,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
+ qti,pvs-corner-ceiling-nom = <1075000 1075000 1275000>;
+ qti,pvs-corner-ceiling-fast = <1050000 1050000 1275000>;
vdd-apc-supply = <&pm8110_s2>;
vdd-mx-supply = <&pm8110_l3_ao>;
@@ -83,6 +83,7 @@
qti,cpr-fuse-redun-bp-scheme = <25>;
qti,cpr-fuse-redun-target-quot = <32 12 0>;
qti,cpr-fuse-redun-ro-sel = <44 26 29>;
+ qti,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
qti,cpr-enable;
};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index e5aa53c..ea37413 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -160,7 +160,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index c819c49..19fb185 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -162,7 +162,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
@@ -198,24 +198,40 @@
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<2 216>, /* tsens_upper_lower_int */
<41 63>, /* dino_gen_purpose_irq35 */
+ <0xff 18>, /* APC_qgicQTmrSecPhysIrptReq */
+ <0xff 19>, /* APC_qgicQTmrNonSecPhysIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtmr_phy_irq[0] */
+ <0xff 47>, /* rbif_irq[0] */
<0xff 56>, /* q6_wdog_expired_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
<0xff 60>, /* mss_to_apps_irq(3) */
<0xff 61>, /* mss_a2_bam_irq */
+ <0xff 65>, /* o_gc_sys_irq[0] */
+ <0xff 74>, /* venus0_mmu_cirpt[1] */
+ <0xff 75>, /* venus0_mmu_cirpt[0] */
+ <0xff 78>, /* mdss_mmu_cirpt[0] */
+ <0xff 79>, /* mdss_mmu_cirpt[1] */
+ <0xff 97>, /* camss_vfe_mmu_cirpt[1] */
+ <0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 131>, /* blsp1_qup_5_irq */
+ <0xff 141>, /* blsp1_uart_3_irq */
+ <0xff 155>, /* sdc1_irq(0) */
+ <0xff 157>, /* sdc2_irq(0) */
+ <0xff 161>, /* lpass_irq_out_spare[4] */
+ <0xff 162>, /* lpass_irq_out_spare[5]*/
+ <0xff 170>, /* sdc1_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
<0xff 176>, /* o_wcss_apss_smsm_irq */
<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
- <0xff 179>, /* o_wcss_apss_asic_intr
+ <0xff 179>, /* o_wcss_apss_asic_intr */
<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
- <0xff 161>, /* lpass_irq_out_spare[4] /
- <0xff 162>, /* lpass_irq_out_spare[5]*/
- <0xff 234>, /* lpass_irq_out_spare[6]*/
- <0xff 235>, /* lpass_irq_out_spare[7]*/
<0xff 188>, /* lpass_irq_out_apcs(0) */
<0xff 189>, /* lpass_irq_out_apcs(1) */
<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -230,12 +246,16 @@
<0xff 205>, /* rpm_ipc(25) */
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
+ <0xff 234>, /* lpass_irq_out_spare[6]*/
+ <0xff 235>, /* lpass_irq_out_spare[7]*/
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 253>, /* sdc2_pwr_cmd_irq */
<0xff 258>, /* rpm_ipc(28) */
<0xff 259>, /* rpm_ipc(29) */
- <0xff 275>, /* rpm_ipc(30) */
- <0xff 276>, /* rpm_ipc(31) */
<0xff 269>, /* rpm_wdog_expired_irq */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 270>, /* blsp1_bam_irq[0] */
+ <0xff 275>, /* rpm_ipc(30) */
+ <0xff 276>; /* rpm_ipc(31) */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 1>,
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 94a9db0..03ef738 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -615,15 +615,16 @@
qcom,model = "msm8x10-snd-card";
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "ultra";
};
qcom,msm-pcm-routing {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index e2a774b..a912da8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1628,15 +1628,16 @@
compatible = "qcom,msm-audio-ion";
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "regular";
};
qcom,msm-pcm-routing {
@@ -1684,6 +1685,10 @@
compatible = "qcom,msm-lsm-client";
};
+ qti,msm-pcm-loopback {
+ compatible = "qti,msm-pcm-loopback";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index fa313bf..6b62391 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -22,5 +22,5 @@
};
&sdhc_1 {
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 366faef..63cb68b 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -214,6 +214,10 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 18>, /* APCx_qgicQTmrSecPhysIrptReq */
+ <0xff 19>, /* APCx_qgicQTmrSecPhysIrptReq */
+ <0xff 25>, /* APCx_qgicExtFaultIrptReq */
+ <0xff 33>, /*l2_perf_mon*/
<0xff 34>, /* APCC_qgicL2ErrorIrptReq */
<0xff 35>, /* WDT_barkInt */
<0xff 40>, /* qtimer_phy_irq */
@@ -236,7 +240,10 @@
<0xff 105>, /* iommu_pmon_nonsecure_irq */
<0xff 109>, /* ocmem_dm_nonsec_irq */
<0xff 126>, /* bam_irq[0] */
+ <0xff 140>, /* uart_dm_intr */
<0xff 155>, /* sdcc_irq[0] */
+ <0xff 157>, /* sdcc_irq[0] */
+ <0xff 159>, /* sdcc_irq[0] */
<0xff 163>, /* usb30_ee1_irq */
<0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
@@ -269,6 +276,8 @@
<0xff 207>, /* rpm_ipc(27) */
<0xff 211>, /* usb_dwc3_otg */
<0xff 240>, /* summary_irq_kpss */
+ <0xff 253>, /* sdcc_pwr_cmd_irq */
+ <0xff 256>, /* sdcc_pwr_cmd_irq */
<0xff 268>, /* bam_irq[1] */
<0xff 270>, /* bam_irq[0] */
<0xff 271>; /* bam_irq[0] */
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 2c06c3c..2783ffd 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -60,6 +60,10 @@
vdd_cx-supply = <&pm8841_s2_corner>;
};
+&pm8841_s2_corner {
+ qcom,init-smps-mode = <0>; /* Allow AUTO mode for VDD_CX. */
+};
+
&krait_regulator_pmic {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index 8b13387..c06ebf8 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -183,10 +183,18 @@
qcom,use-phase-switching;
};
+&mdss_mdp {
+ vdd-cx-supply = <&pma8084_s2_corner>;
+};
+
&tspp {
vdd_cx-supply = <&pma8084_s2_corner>;
};
+&pma8084_s2_corner {
+ qcom,init-smps-mode = <0>; /* Allow AUTO mode for VDD_CX. */
+};
+
&krait_regulator_pmic {
status = "ok";
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 0e7baf1..dee1f68 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -686,9 +686,9 @@
qcom,adsp-state = <2>;
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 37c9554..30b2346 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -185,3 +185,5 @@
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 431ac58..9af4009 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -399,3 +399,5 @@
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 2a82d5b..1e32cfa 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -458,3 +458,5 @@
CONFIG_TOUCHSCREEN_GT9XX=y
CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 76c0f6a..e46bfef 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -64,11 +64,6 @@
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_ADSP_LOADER=y
-CONFIG_MSM_OCMEM=y
-CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
-CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
@@ -431,3 +426,5 @@
CONFIG_SENSORS_CAPELLA_CM36283=y
CONFIG_NFC_QNCI=y
CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index ff0c498..899ed30 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -61,11 +61,6 @@
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_ADSP_LOADER=y
-CONFIG_MSM_OCMEM=y
-CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
-CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index da4de08..b4f21ad 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -461,3 +461,5 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 4610597..fd8245f 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -554,3 +554,5 @@
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 200433d..10f2919 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -98,6 +98,7 @@
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -504,3 +505,5 @@
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c106913..0b9ba76 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -104,6 +104,7 @@
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 9a5aaf0..4c0a82d 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -319,3 +319,5 @@
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index da3cfba..d42e798 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -60,64 +60,64 @@
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p1[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 0, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p2[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p4[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
+ { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 6 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1497600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- { 1, 1593600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 6 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_5, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_6, 0, 7 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_7, 0, 7 },
+ { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_8, 0, 7 },
+ { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_9, 0, 7 },
+ { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_10, 0, 7 },
+ { 1, 1497600, ACPUPLL, 5, 0, CPR_CORNER_11, 0, 7 },
+ { 1, 1593600, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 7 },
{ 0 }
};
static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
- { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 3 },
- { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 3 },
- { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 4 },
- { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 4 },
- { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
- { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_2, 0, 3 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_2, 0, 3 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_4, 0, 4 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_4, 0, 4 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 5 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_12, 0, 5 },
{ 0 }
};
@@ -135,7 +135,7 @@
.freq_tbl = acpu_freq_tbl_8226_1p1,
.pvs_tables = pvs_tables_8226,
.bus_scale = &bus_client_pdata,
- .vdd_max_cpu = CPR_CORNER_TURBO,
+ .vdd_max_cpu = CPR_CORNER_12,
.src_clocks = {
[PLL0].name = "gpll0",
[ACPUPLL].name = "a7sspll",
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 03f8837..affe6bd 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -631,6 +631,28 @@
},
};
+static struct gpiomux_setting gpio_cdc_dmic_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm_cdc_dmic_configs[] __initdata = {
+ {
+ .gpio = 100, /* DMIC CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+ },
+ },
+ {
+ .gpio = 101, /* DMIC DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+ },
+ },
+};
+
void __init msm8610_init_gpiomux(void)
{
int rc;
@@ -668,4 +690,7 @@
msm_gpiomux_install(msm_non_qrd_configs,
ARRAY_SIZE(msm_non_qrd_configs));
}
+ if (of_board_is_cdp())
+ msm_gpiomux_install(msm_cdc_dmic_configs,
+ ARRAY_SIZE(msm_cdc_dmic_configs));
}
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 1cf2e41..fa132fa 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -25,7 +25,6 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <linux/cpufreq.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/cpr-regulator.h>
@@ -33,6 +32,10 @@
/* Register Offsets for RB-CPR and Bit Definitions */
+/* RBCPR Version Register */
+#define REG_RBCPR_VERSION 0
+#define RBCPR_VER_2 0x02
+
/* RBCPR Gate Count and Target Registers */
#define REG_RBCPR_GCNT_TARGET(n) (0x60 + 4 * n)
@@ -131,14 +134,14 @@
#define BYTES_PER_FUSE_ROW 8
+#define FLAGS_IGNORE_1ST_IRQ_STATUS BIT(0)
#define FLAGS_SET_MIN_VOLTAGE BIT(1)
#define FLAGS_UPLIFT_QUOT_VOLT BIT(2)
-#define FLAGS_QUOT_ADJUST_WITH_FREQ BIT(3)
-struct cpufreq_mapping_info {
- int freq;
+struct quot_adjust_info {
+ int speed_bin;
+ int virtual_corner;
int quot_adjust;
- int corner;
};
enum voltage_change_dir {
@@ -160,7 +163,7 @@
/* Process voltage parameters */
u32 pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
- u32 pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
+ u32 pvs_corner_v[NUM_APC_PVS][CPR_FUSE_CORNER_MAX];
/* Process voltage variables */
u32 pvs_bin;
u32 process;
@@ -178,9 +181,8 @@
u64 cpr_fuse_bits;
bool cpr_fuse_disable;
bool cpr_fuse_local;
- int cpr_fuse_target_quot[CPR_CORNER_MAX];
- int cpr_fuse_original_quot[CPR_CORNER_MAX];
- int cpr_fuse_ro_sel[CPR_CORNER_MAX];
+ int cpr_fuse_target_quot[CPR_FUSE_CORNER_MAX];
+ int cpr_fuse_ro_sel[CPR_FUSE_CORNER_MAX];
int gcnt;
unsigned int cpr_irq;
@@ -188,13 +190,13 @@
phys_addr_t rbcpr_clk_addr;
struct mutex cpr_mutex;
- int ceiling_volt[CPR_CORNER_MAX];
- int floor_volt[CPR_CORNER_MAX];
- int last_volt[CPR_CORNER_MAX];
+ int ceiling_volt[CPR_FUSE_CORNER_MAX];
+ int floor_volt[CPR_FUSE_CORNER_MAX];
+ int *last_volt;
int step_volt;
- int save_ctl[CPR_CORNER_MAX];
- int save_irq[CPR_CORNER_MAX];
+ int *save_ctl;
+ int *save_irq;
u32 save_regs[CPR_NUM_SAVE_REGS];
u32 save_reg_val[CPR_NUM_SAVE_REGS];
@@ -214,10 +216,9 @@
u32 vdd_apc_step_up_limit;
u32 vdd_apc_step_down_limit;
u32 flags;
- struct notifier_block freq_transition;
- unsigned int freq;
- struct cpufreq_mapping_info *cpufreq_mapping;
- u32 cpufreq_mapping_size;
+ int *corner_map;
+ u32 num_corners;
+ int *quot_adjust;
};
#define CPR_DEBUG_MASK_IRQ BIT(0)
@@ -280,28 +281,6 @@
return efuse_bits;
}
-static int cpr_get_freq_corner(struct cpr_regulator *cpr_vreg, int freq)
-{
- int i;
-
- for (i = 0; i < cpr_vreg->cpufreq_mapping_size; i++) {
- if (freq == cpr_vreg->cpufreq_mapping[i].freq)
- return cpr_vreg->cpufreq_mapping[i].corner;
- }
-
- return -EINVAL;
-}
-
-static int cpr_get_freq_quot_adjust(struct cpr_regulator *cpr_vreg, int freq)
-{
- int i;
-
- for (i = 0; i < cpr_vreg->cpufreq_mapping_size; i++) {
- if (freq == cpr_vreg->cpufreq_mapping[i].freq)
- return cpr_vreg->cpufreq_mapping[i].quot_adjust;
- }
- return 0;
-}
static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
{
@@ -362,9 +341,11 @@
static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg, int corner)
{
u32 val;
+ int fuse_corner = cpr_vreg->corner_map[corner];
if (cpr_is_allowed(cpr_vreg) &&
- (cpr_vreg->ceiling_volt[corner] > cpr_vreg->floor_volt[corner]))
+ (cpr_vreg->ceiling_volt[fuse_corner] >
+ cpr_vreg->floor_volt[fuse_corner]))
val = RBCPR_CTL_LOOP_EN;
else
val = 0;
@@ -376,13 +357,6 @@
cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
}
-static bool cpr_ctl_is_enabled(struct cpr_regulator *cpr_vreg)
-{
- u32 val;
- val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- return ((val & RBCPR_CTL_LOOP_EN) == RBCPR_CTL_LOOP_EN);
-}
-
static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
{
int i, offset;
@@ -415,16 +389,12 @@
static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
{
u32 gcnt, ctl, irq, ro_sel;
- int adjust;
+ int fuse_corner = cpr_vreg->corner_map[corner];
- if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ) {
- adjust = cpr_get_freq_quot_adjust(cpr_vreg, cpr_vreg->freq);
- cpr_vreg->cpr_fuse_target_quot[corner] =
- cpr_vreg->cpr_fuse_original_quot[corner] - adjust;
- }
+ ro_sel = cpr_vreg->cpr_fuse_ro_sel[fuse_corner];
+ gcnt = cpr_vreg->gcnt | (cpr_vreg->cpr_fuse_target_quot[fuse_corner] -
+ cpr_vreg->quot_adjust[corner]);
- ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
- gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
ctl = cpr_vreg->save_ctl[corner];
cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
@@ -462,8 +432,9 @@
goto _exit;
}
- cpr_debug("%d -> %d [corner=%d]\n",
- old_cpr_enable, cpr_enable, the_cpr->corner);
+ cpr_debug("%d -> %d [corner=%d, fuse_corner=%d]\n",
+ old_cpr_enable, cpr_enable, the_cpr->corner,
+ the_cpr->corner_map[the_cpr->corner]);
if (the_cpr->cpr_fuse_disable) {
/* Already disabled */
@@ -509,17 +480,18 @@
static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
{
int vdd_mx;
+ int fuse_corner = cpr_vreg->corner_map[corner];
switch (cpr_vreg->vdd_mx_vmin_method) {
case VDD_MX_VMIN_APC:
vdd_mx = apc_volt;
break;
case VDD_MX_VMIN_APC_CORNER_CEILING:
- vdd_mx = cpr_vreg->ceiling_volt[corner];
+ vdd_mx = cpr_vreg->ceiling_volt[fuse_corner];
break;
case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
- [CPR_CORNER_TURBO];
+ [CPR_FUSE_CORNER_TURBO];
break;
case VDD_MX_VMIN_MX_VMAX:
vdd_mx = cpr_vreg->vdd_mx_vmax;
@@ -536,15 +508,19 @@
int vdd_mx_vmin)
{
int rc;
+ int fuse_corner = cpr_vreg->corner_map[corner];
rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
cpr_vreg->vdd_mx_vmax);
- cpr_debug("[corner:%d] %d uV\n", corner, vdd_mx_vmin);
- if (!rc)
+ cpr_debug("[corner:%d, fuse_corner:%d] %d uV\n", corner,
+ fuse_corner, vdd_mx_vmin);
+
+ if (!rc) {
cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
- else
- pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
- corner, vdd_mx_vmin, rc);
+ } else {
+ pr_err("set: vdd_mx [corner:%d, fuse_corner:%d] = %d uV failed: rc=%d\n",
+ corner, fuse_corner, vdd_mx_vmin, rc);
+ }
return rc;
}
@@ -582,9 +558,11 @@
enum voltage_change_dir dir)
{
u32 reg_val, error_steps, reg_mask;
- int last_volt, new_volt, corner;
+ int last_volt, new_volt, corner, fuse_corner;
+ u32 gcnt, quot;
corner = cpr_vreg->corner;
+ fuse_corner = cpr_vreg->corner_map[corner];
reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
@@ -592,18 +570,27 @@
& RBCPR_RESULT0_ERROR_STEPS_MASK;
last_volt = cpr_vreg->last_volt[corner];
- cpr_debug_irq("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+ cpr_debug_irq("last_volt[corner:%d, fuse_corner:%d] = %d uV\n", corner,
+ fuse_corner, last_volt);
+
+ gcnt = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[fuse_corner]));
+ quot = gcnt & ((1 << RBCPR_GCNT_TARGET_GCNT_SHIFT) - 1);
if (dir == UP) {
cpr_debug_irq("Up: cpr status = 0x%08x (error_steps=%d)\n",
reg_val, error_steps);
- if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
- cpr_debug_irq("[corn:%d] @ ceiling: %d >= %d: NACK\n",
- corner, last_volt,
- cpr_vreg->ceiling_volt[corner]);
+ if (last_volt >= cpr_vreg->ceiling_volt[fuse_corner]) {
+ cpr_debug_irq(
+ "[corn:%d, fuse_corn:%d] @ ceiling: %d >= %d: NACK\n",
+ corner, fuse_corner, last_volt,
+ cpr_vreg->ceiling_volt[fuse_corner]);
cpr_irq_clr_nack(cpr_vreg);
+ cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+ quot);
+
/* Maximize the UP threshold */
reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
RBCPR_CTL_UP_THRESHOLD_SHIFT;
@@ -621,11 +608,12 @@
/* Calculate new voltage */
new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
- if (new_volt > cpr_vreg->ceiling_volt[corner]) {
+ if (new_volt > cpr_vreg->ceiling_volt[fuse_corner]) {
cpr_debug_irq("new_volt(%d) >= ceiling(%d): Clamp\n",
new_volt,
- cpr_vreg->ceiling_volt[corner]);
- new_volt = cpr_vreg->ceiling_volt[corner];
+ cpr_vreg->ceiling_volt[fuse_corner]);
+
+ new_volt = cpr_vreg->ceiling_volt[fuse_corner];
}
if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -650,22 +638,26 @@
/* Ack */
cpr_irq_clr_ack(cpr_vreg);
- cpr_debug_irq("UP: -> new_volt[corner:%d] = %d uV\n",
- corner, new_volt);
+ cpr_debug_irq(
+ "UP: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+ corner, fuse_corner, new_volt);
} else if (dir == DOWN) {
cpr_debug_irq("Down: cpr status = 0x%08x (error_steps=%d)\n",
reg_val, error_steps);
- if (last_volt <= cpr_vreg->floor_volt[corner]) {
- cpr_debug_irq("[corn:%d] @ floor: %d <= %d: NACK\n",
- corner, last_volt,
- cpr_vreg->floor_volt[corner]);
+ if (last_volt <= cpr_vreg->floor_volt[fuse_corner]) {
+ cpr_debug_irq(
+ "[corn:%d, fuse_corner:%d] @ floor: %d <= %d: NACK\n",
+ corner, fuse_corner, last_volt,
+ cpr_vreg->floor_volt[fuse_corner]);
cpr_irq_clr_nack(cpr_vreg);
/* Maximize the DOWN threshold */
reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
RBCPR_CTL_DN_THRESHOLD_SHIFT;
reg_val = reg_mask;
+ cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+ quot);
/* Enable auto nack down */
reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
@@ -688,11 +680,11 @@
/* Calculte new voltage */
new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
- if (new_volt < cpr_vreg->floor_volt[corner]) {
+ if (new_volt < cpr_vreg->floor_volt[fuse_corner]) {
cpr_debug_irq("new_volt(%d) < floor(%d): Clamp\n",
new_volt,
- cpr_vreg->floor_volt[corner]);
- new_volt = cpr_vreg->floor_volt[corner];
+ cpr_vreg->floor_volt[fuse_corner]);
+ new_volt = cpr_vreg->floor_volt[fuse_corner];
}
if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -711,8 +703,9 @@
/* Ack */
cpr_irq_clr_ack(cpr_vreg);
- cpr_debug_irq("DOWN: -> new_volt[corner:%d] = %d uV\n",
- corner, new_volt);
+ cpr_debug_irq(
+ "DOWN: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+ corner, fuse_corner, new_volt);
}
}
@@ -724,6 +717,9 @@
mutex_lock(&cpr_vreg->cpr_mutex);
reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+ if (cpr_vreg->flags & FLAGS_IGNORE_1ST_IRQ_STATUS)
+ reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+
cpr_debug_irq("IRQ_STATUS = 0x%02X\n", reg_val);
if (!cpr_is_allowed(cpr_vreg)) {
@@ -831,6 +827,7 @@
int rc;
int new_volt;
enum voltage_change_dir change_dir = NO_CHANGE;
+ int fuse_corner = cpr_vreg->corner_map[corner];
mutex_lock(&cpr_vreg->cpr_mutex);
@@ -838,10 +835,12 @@
cpr_ctl_disable(cpr_vreg);
new_volt = cpr_vreg->last_volt[corner];
} else {
- new_volt = cpr_vreg->pvs_corner_v[cpr_vreg->process][corner];
+ new_volt = cpr_vreg->pvs_corner_v
+ [cpr_vreg->process][fuse_corner];
}
- cpr_debug("[corner:%d] = %d uV\n", corner, new_volt);
+ cpr_debug("[corner:%d, fuse_corner:%d] = %d uV\n", corner, fuse_corner,
+ new_volt);
if (corner > cpr_vreg->corner)
change_dir = UP;
@@ -934,11 +933,13 @@
#define cpr_regulator_resume NULL
#endif
-static int __devinit cpr_config(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_config(struct cpr_regulator *cpr_vreg,
+ struct device *dev)
{
int i;
u32 val, gcnt, reg;
void __iomem *rbcpr_clk;
+ int size;
/* Use 19.2 MHz clock for CPR. */
rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
@@ -1009,17 +1010,26 @@
cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS]);
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_SVS]);
cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL]);
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_NORMAL]);
cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO]);
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_TURBO]);
cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
- cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
- cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
- cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+ val = cpr_read(cpr_vreg, REG_RBCPR_VERSION);
+ if (val <= RBCPR_VER_2)
+ cpr_vreg->flags |= FLAGS_IGNORE_1ST_IRQ_STATUS;
+
+ size = cpr_vreg->num_corners + 1;
+ cpr_vreg->save_ctl = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+ cpr_vreg->save_irq = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+ if (!cpr_vreg->save_ctl || !cpr_vreg->save_irq)
+ return -ENOMEM;
+
+ for (i = 1; i < size; i++)
+ cpr_corner_save(cpr_vreg, i);
return 0;
}
@@ -1135,16 +1145,18 @@
init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
- if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+ if (init_v <= cpr_vreg->pvs_corner_v
+ [process][CPR_FUSE_CORNER_TURBO])
break;
}
if (process == APC_PVS_NO) {
process = APC_PVS_SLOW;
- cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+ cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO] = init_v;
cpr_vreg->ceiling_max = init_v;
} else if (process == APC_PVS_FAST &&
- init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
+ init_v < cpr_vreg->pvs_corner_v
+ [APC_PVS_FAST][CPR_FUSE_CORNER_SVS]) {
process = APC_PVS_SLOW;
}
@@ -1152,7 +1164,7 @@
pvs_fuse[0], efuse_bits, pvs_fuse[2],
cpr_vreg->pvs_bin, process);
pr_info("pvs initial turbo voltage_= from %u to %u\n",
- init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+ init_v, cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO]);
cpr_vreg->process = process;
@@ -1245,22 +1257,68 @@
pr_err("cpr-uplift-quotient is missing: %d", rc);
return rc;
}
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++)
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
cpr_vreg->cpr_fuse_target_quot[i] += delta_quot[i-1];
return rc;
}
-static int cpr_get_of_cprfreq_mappings(struct cpr_regulator *cpr_vreg,
+static int cpr_get_of_corner_mappings(struct cpr_regulator *cpr_vreg,
struct device *dev)
{
int rc = 0;
- int i, j, size, stripe_size, length;
+ int i, size, stripe_size;
struct property *prop;
u32 *tmp;
+ bool corners_mapped;
+
+ prop = of_find_property(dev->of_node, "qti,cpr-corner-map", NULL);
+
+ if (prop) {
+ size = prop->length / sizeof(u32);
+ corners_mapped = true;
+ } else {
+ size = CPR_FUSE_CORNER_MAX - 1;
+ corners_mapped = false;
+ }
+
+ cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
+ GFP_KERNEL);
+ if (!cpr_vreg->corner_map) {
+ pr_err("Can't allocate cpr_vreg->corner_map memory\n");
+ return -ENOMEM;
+ }
+ cpr_vreg->num_corners = size;
+
+ if (!corners_mapped) {
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+ cpr_vreg->corner_map[i] = i;
+ } else {
+ rc = of_property_read_u32_array(dev->of_node,
+ "qti,cpr-corner-map", &cpr_vreg->corner_map[1], size);
+
+ if (rc) {
+ pr_err("qti,cpr-corner-map missing, rc = %d", rc);
+ return rc;
+ }
+ }
+
+ cpr_vreg->quot_adjust = devm_kzalloc(dev,
+ sizeof(int) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!cpr_vreg->quot_adjust) {
+ pr_err("Can't allocate cpr_vreg->quot_adjust memory\n");
+ return -ENOMEM;
+ }
prop = of_find_property(dev->of_node, "qti,cpr-quot-adjust-table",
NULL);
+
if (prop) {
+ if (!corners_mapped) {
+ pr_err("qti,cpr-corner-map missing\n");
+ return -EINVAL;
+ }
+
size = prop->length / sizeof(u32);
tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
if (!tmp)
@@ -1275,51 +1333,33 @@
return rc;
}
- length = 0;
- stripe_size = 1 + sizeof(struct cpufreq_mapping_info) /
- sizeof(int);
- for (i = 0; i < size; i += stripe_size) {
- if (tmp[i] == cpr_vreg->speed_bin)
- length++;
- }
- if (i != size) {
- pr_err("qti,cpr-quot-adjust-table data is not correct\n");
+ stripe_size = sizeof(struct quot_adjust_info) / sizeof(int);
+
+ if ((size % stripe_size) != 0) {
+ pr_err("qti,cpr-quot-adjust-table data is not correct");
kfree(tmp);
return -EINVAL;
}
- cpr_vreg->cpufreq_mapping_size = length;
- if (length) {
- cpr_vreg->cpufreq_mapping = devm_kzalloc(dev,
- sizeof(struct cpufreq_mapping_info) * length,
- GFP_KERNEL);
-
- if (!cpr_vreg->cpufreq_mapping) {
- kfree(tmp);
- return -ENOMEM;
- }
-
- cpr_vreg->flags |= FLAGS_QUOT_ADJUST_WITH_FREQ;
-
- for (i = 0, j = 0; i < size; i += stripe_size) {
- if (tmp[i] == cpr_vreg->speed_bin) {
- cpr_vreg->cpufreq_mapping[j].freq =
- tmp[i+1];
- cpr_vreg->cpufreq_mapping[j].quot_adjust
- = tmp[i+2];
- cpr_vreg->cpufreq_mapping[j].corner =
- tmp[i+3];
- ++j;
+ for (i = 0; i < size; i += stripe_size) {
+ if (tmp[i] == cpr_vreg->speed_bin) {
+ if (tmp[i + 1] >= 1 &&
+ tmp[i + 1] <=
+ cpr_vreg->num_corners) {
+ cpr_vreg->quot_adjust[tmp[i + 1]] =
+ tmp[i + 2];
+ } else {
+ pr_err("qti,cpr-quot-adjust-table data is not correct");
+ kfree(tmp);
+ return -EINVAL;
}
-
}
-
}
kfree(tmp);
}
- return rc;
+ return 0;
}
static int __devinit cpr_init_cpr_efuse(struct platform_device *pdev,
@@ -1332,8 +1372,8 @@
char *targ_quot_str, *ro_sel_str;
u32 cpr_fuse_row[2];
u32 bp_cpr_disable, bp_scheme;
- int bp_target_quot[CPR_CORNER_MAX];
- int bp_ro_sel[CPR_CORNER_MAX];
+ int bp_target_quot[CPR_FUSE_CORNER_MAX];
+ int bp_ro_sel[CPR_FUSE_CORNER_MAX];
u32 ro_sel, val;
u64 fuse_bits, fuse_bits_2;
@@ -1364,8 +1404,8 @@
rc = of_property_read_u32_array(of_node,
targ_quot_str,
- &bp_target_quot[CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &bp_target_quot[CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("missing %s: rc=%d\n", targ_quot_str, rc);
return rc;
@@ -1373,8 +1413,8 @@
rc = of_property_read_u32_array(of_node,
ro_sel_str,
- &bp_ro_sel[CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &bp_ro_sel[CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("missing %s: rc=%d\n", ro_sel_str, rc);
return rc;
@@ -1432,7 +1472,7 @@
pr_info("disable = %d, local = %d\n",
cpr_vreg->cpr_fuse_disable, cpr_vreg->cpr_fuse_local);
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
ro_sel = (fuse_bits >> bp_ro_sel[i])
& CPR_FUSE_RO_SEL_BITS_MASK;
val = (fuse_bits >> bp_target_quot[i])
@@ -1445,18 +1485,13 @@
if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
cpr_voltage_uplift_wa_inc_quot(cpr_vreg, of_node);
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
pr_info("Corner[%d]: uplifted target quot = %d\n",
i, cpr_vreg->cpr_fuse_target_quot[i]);
}
}
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
- cpr_vreg->cpr_fuse_original_quot[i] =
- cpr_vreg->cpr_fuse_target_quot[i];
- }
-
- rc = cpr_get_of_cprfreq_mappings(cpr_vreg, &pdev->dev);
+ rc = cpr_get_of_corner_mappings(cpr_vreg, &pdev->dev);
if (rc)
return rc;
@@ -1469,10 +1504,12 @@
int *quot = cpr_vreg->cpr_fuse_target_quot;
bool valid_fuse = true;
- if ((quot[CPR_CORNER_TURBO] > quot[CPR_CORNER_NORMAL]) &&
- (quot[CPR_CORNER_NORMAL] > quot[CPR_CORNER_SVS])) {
- if ((quot[CPR_CORNER_TURBO] -
- quot[CPR_CORNER_NORMAL])
+ if ((quot[CPR_FUSE_CORNER_TURBO] >
+ quot[CPR_FUSE_CORNER_NORMAL]) &&
+ (quot[CPR_FUSE_CORNER_NORMAL] >
+ quot[CPR_FUSE_CORNER_SVS])) {
+ if ((quot[CPR_FUSE_CORNER_TURBO] -
+ quot[CPR_FUSE_CORNER_NORMAL])
<= CPR_FUSE_MIN_QUOT_DIFF)
valid_fuse = false;
} else {
@@ -1488,18 +1525,27 @@
return 0;
}
-static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg,
+ struct device *dev)
{
int i;
+ int size = cpr_vreg->num_corners + 1;
+
+ cpr_vreg->last_volt = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+ if (!cpr_vreg->last_volt)
+ return -EINVAL;
/* Construct CPR voltage limits */
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
cpr_vreg->floor_volt[i] =
cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
cpr_vreg->ceiling_volt[i] =
cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
- cpr_vreg->last_volt[i] =
- cpr_vreg->pvs_corner_v[cpr_vreg->process][i];
+ }
+
+ for (i = 1; i < size; i++) {
+ cpr_vreg->last_volt[i] = cpr_vreg->pvs_corner_v
+ [cpr_vreg->process][cpr_vreg->corner_map[i]];
}
return 0;
@@ -1599,7 +1645,9 @@
resource_size(res));
/* Init all voltage set points of APC regulator for CPR */
- cpr_init_cpr_voltages(cpr_vreg);
+ rc = cpr_init_cpr_voltages(cpr_vreg, &pdev->dev);
+ if (rc)
+ return rc;
/* Init CPR configuration parameters */
rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
@@ -1614,7 +1662,7 @@
}
/* Configure CPR HW but keep it disabled */
- rc = cpr_config(cpr_vreg);
+ rc = cpr_config(cpr_vreg, &pdev->dev);
if (rc)
return rc;
@@ -1739,8 +1787,8 @@
rc = of_property_read_u32_array(of_node,
"qti,pvs-corner-ceiling-slow",
- &cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
return rc;
@@ -1748,8 +1796,8 @@
rc = of_property_read_u32_array(of_node,
"qti,pvs-corner-ceiling-nom",
- &cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
return rc;
@@ -1757,8 +1805,8 @@
rc = of_property_read_u32_array(of_node,
"qti,pvs-corner-ceiling-fast",
- &cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS],
- CPR_CORNER_MAX - CPR_CORNER_SVS);
+ &cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
return rc;
@@ -1775,70 +1823,26 @@
of_property_read_u32(of_node, "qti,cpr-cond-min-voltage",
&min_uv);
for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++)
- for (j = CPR_CORNER_SVS; j < CPR_CORNER_MAX; j++)
+ for (j = CPR_FUSE_CORNER_SVS; j < CPR_FUSE_CORNER_MAX;
+ j++)
if (cpr_vreg->pvs_corner_v[i][j] < min_uv)
cpr_vreg->pvs_corner_v[i][j] = min_uv;
}
/* Set ceiling max and use it for APC_PVS_NO */
cpr_vreg->ceiling_max =
- cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
+ cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_TURBO];
for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
pr_info("[%d] [%d %d %d] uV\n", i,
- cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
- cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
- cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
+ cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_SVS],
+ cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_NORMAL],
+ cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_TURBO]);
}
return 0;
}
-static int cpr_freq_transition(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- int old_corner, new_corner;
- struct cpr_regulator *cpr_vreg = container_of(nb, struct cpr_regulator,
- freq_transition);
- struct cpufreq_freqs *freqs = data;
-
- mutex_lock(&cpr_vreg->cpr_mutex);
- switch (val) {
- case CPUFREQ_PRECHANGE:
- cpr_vreg->freq = freqs->new;
- if (freqs->new > freqs->old) {
- old_corner = cpr_get_freq_corner(cpr_vreg, freqs->old);
- new_corner = cpr_get_freq_corner(cpr_vreg, freqs->new);
- if (new_corner > 0 && old_corner == new_corner &&
- cpr_ctl_is_enabled(cpr_vreg)) {
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_clr(cpr_vreg);
- cpr_corner_restore(cpr_vreg, new_corner);
- cpr_ctl_enable(cpr_vreg, new_corner);
- }
- }
- break;
- case CPUFREQ_POSTCHANGE:
- if (freqs->new < freqs->old) {
- old_corner = cpr_get_freq_corner(cpr_vreg, freqs->old);
- new_corner = cpr_get_freq_corner(cpr_vreg, freqs->new);
- if (new_corner > 0 && old_corner == new_corner &&
- cpr_ctl_is_enabled(cpr_vreg)) {
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_clr(cpr_vreg);
- cpr_corner_restore(cpr_vreg, new_corner);
- cpr_ctl_enable(cpr_vreg, new_corner);
- }
- }
- break;
- default:
- break;
- }
- mutex_unlock(&cpr_vreg->cpr_mutex);
-
- return NOTIFY_OK;
-}
-
static int __devinit cpr_regulator_probe(struct platform_device *pdev)
{
struct cpr_regulator *cpr_vreg;
@@ -1922,10 +1926,6 @@
platform_set_drvdata(pdev, cpr_vreg);
the_cpr = cpr_vreg;
- cpr_vreg->freq_transition.notifier_call = cpr_freq_transition;
- if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ)
- cpufreq_register_notifier(&cpr_vreg->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
return 0;
@@ -1946,9 +1946,6 @@
cpr_irq_set(cpr_vreg, 0);
}
- if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ)
- cpufreq_unregister_notifier(&cpr_vreg->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
cpr_apc_exit(cpr_vreg);
regulator_unregister(cpr_vreg->rdev);
}
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
index fac6575..a910cd26 100644
--- a/arch/arm/mach-msm/hsic_sysmon_test.c
+++ b/arch/arm/mach-msm/hsic_sysmon_test.c
@@ -63,9 +63,13 @@
if (!dev)
return -ENODEV;
+ /* Add check for user buf count greater than RD_BUF_SIZE */
+ if (count > RD_BUF_SIZE)
+ count = RD_BUF_SIZE;
+
if (copy_from_user(dev->buf, ubuf, count)) {
pr_err("error copying for writing");
- return 0;
+ return -EFAULT;
}
ret = hsic_sysmon_write(id, dev->buf, count, 1000);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
index 0a1cdd4..42cf6f9 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
@@ -45,7 +45,7 @@
};
void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id);
-void rtac_remove_adm_device(u32 port_id);
+void rtac_remove_adm_device(u32 port_id, u32 copp_id);
void rtac_remove_popp_from_adm_devices(u32 popp_id);
void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
u32 tx_afe_port, u32 session_id);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 2e15cae..9a27fd2 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -73,7 +73,8 @@
#define USF_TSC_PTR_EVENT_IND 1
#define USF_MOUSE_EVENT_IND 2
#define USF_KEYBOARD_EVENT_IND 3
-#define USF_MAX_EVENT_IND 4
+#define USF_TSC_EXT_EVENT_IND 4
+#define USF_MAX_EVENT_IND 5
/* Types of events, produced by the calculators */
#define USF_NO_EVENT 0
@@ -81,10 +82,12 @@
#define USF_TSC_PTR_EVENT (1 << USF_TSC_PTR_EVENT_IND)
#define USF_MOUSE_EVENT (1 << USF_MOUSE_EVENT_IND)
#define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_TSC_EXT_EVENT (1 << USF_TSC_EXT_EVENT_IND)
#define USF_ALL_EVENTS (USF_TSC_EVENT |\
USF_TSC_PTR_EVENT |\
USF_MOUSE_EVENT |\
- USF_KEYBOARD_EVENT)
+ USF_KEYBOARD_EVENT |\
+ USF_TSC_EXT_EVENT)
/* min, max array dimension */
#define MIN_MAX_DIM 2
@@ -146,6 +149,8 @@
int tsc_y_tilt[MIN_MAX_DIM];
/* Touch screen pressure limits: min & max; for input module */
int tsc_pressure[MIN_MAX_DIM];
+ /* The requested side buttons bitmap */
+ uint16_t req_side_buttons_bitmap;
/* Bitmap of types of events (USF_X_EVENT), produced by calculator */
uint16_t event_types;
/* Input event source */
@@ -174,6 +179,8 @@
int inclinations[TILTS_DIM];
/* [0-1023] (10bits); 0 - pen up */
uint32_t pressure;
+/* Bitmap for side button state. 1 - down, 0 - up */
+ uint16_t side_buttons_state_bitmap;
};
/* Mouse buttons, supported by USF */
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index ce66531..6bb4011 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -434,7 +434,7 @@
unsigned int len)
{
struct sk_buff *temp;
- int offset = 0, buf_len = 0, copy_len;
+ unsigned int offset = 0, buf_len = 0, copy_len;
void *buf;
if (!skb_head) {
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index bdae10c..06160f7 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -290,7 +290,7 @@
system_level->num_cpu_votes != num_powered_cores)
continue;
- if (latency_us < pwr_param->latency_us)
+ if (latency_us < pwr_param->latency_us && from_idle)
continue;
if (sleep_us < pwr_param->time_overhead_us)
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index ac4ed25..c4e52be 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -36,72 +36,132 @@
struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
};
+static struct msm_pm_time_stats suspend_stats;
+
static DEFINE_SPINLOCK(msm_pm_stats_lock);
static DEFINE_PER_CPU_SHARED_ALIGNED(
struct msm_pm_cpu_time_stats, msm_pm_stats);
-
/*
- * Add the given time data to the statistics collection.
+ * Function to update stats
*/
-void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+static void update_stats(struct msm_pm_time_stats *stats, int64_t t)
{
- unsigned long flags;
- struct msm_pm_time_stats *stats;
int64_t bt;
int i;
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- stats = __get_cpu_var(msm_pm_stats).stats;
+ if (!stats)
+ return;
- if (!stats[id].enabled)
- goto add_bail;
-
- stats[id].total_time += t;
- stats[id].count++;
+ stats->total_time += t;
+ stats->count++;
bt = t;
- do_div(bt, stats[id].first_bucket_time);
+ do_div(bt, stats->first_bucket_time);
if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
- (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+ (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
i = DIV_ROUND_UP(fls((uint32_t)bt),
- CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+ CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
else
i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
- stats[id].bucket[i]++;
+ stats->bucket[i]++;
- if (t < stats[id].min_time[i] || !stats[id].max_time[i])
- stats[id].min_time[i] = t;
- if (t > stats[id].max_time[i])
- stats[id].max_time[i] = t;
+ if (t < stats->min_time[i] || !stats->max_time[i])
+ stats->min_time[i] = t;
+ if (t > stats->max_time[i])
+ stats->max_time[i] = t;
+}
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+ struct msm_pm_time_stats *stats;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ if (id == MSM_PM_STAT_SUSPEND) {
+ stats = &suspend_stats;
+ } else {
+ stats = __get_cpu_var(msm_pm_stats).stats;
+ if (!stats[id].enabled)
+ goto add_bail;
+ stats = &stats[id];
+ }
+ update_stats(stats, t);
add_bail:
spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
}
-/*
- * Write out the power management statistics.
- */
-
-static int msm_pm_stats_show(struct seq_file *m, void *v)
+static void stats_show(struct seq_file *m,
+ struct msm_pm_time_stats *stats,
+ int cpu, int suspend)
{
- int cpu;
+ int64_t bucket_time;
+ int64_t s;
+ uint32_t ns;
+ int i;
int bucket_count = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
int bucket_shift = CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
- for_each_possible_cpu(cpu) {
- unsigned long flags;
- struct msm_pm_time_stats *stats;
- int i, id;
- int64_t bucket_time;
- int64_t s;
- uint32_t ns;
+ if (!stats || !m)
+ return;
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ s = stats->total_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ if (suspend)
+ seq_printf(m,
+ "%s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ stats->name,
+ stats->count,
+ s, ns);
+ else
+ seq_printf(m,
+ "[cpu %u] %s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ cpu, stats->name,
+ stats->count,
+ s, ns);
+
+ bucket_time = stats->first_bucket_time;
+ for (i = 0; i < bucket_count; i++) {
+ s = bucket_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ seq_printf(m,
+ " <%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats->bucket[i],
+ stats->min_time[i],
+ stats->max_time[i]);
+ bucket_time <<= bucket_shift;
+ }
+
+ seq_printf(m, " >=%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats->bucket[i],
+ stats->min_time[i],
+ stats->max_time[i]);
+}
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_stats_show(struct seq_file *m, void *v)
+{
+ int cpu;
+ int id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+
+ for_each_possible_cpu(cpu) {
+ struct msm_pm_time_stats *stats;
+
stats = per_cpu(msm_pm_stats, cpu).stats;
for (id = 0; id < MSM_PM_STAT_COUNT; id++) {
@@ -109,38 +169,14 @@
if (!stats[id].enabled)
continue;
- s = stats[id].total_time;
- ns = do_div(s, NSEC_PER_SEC);
- seq_printf(m,
- "[cpu %u] %s:\n"
- " count: %7d\n"
- " total_time: %lld.%09u\n",
- cpu, stats[id].name,
- stats[id].count,
- s, ns);
+ if (id == MSM_PM_STAT_SUSPEND)
+ continue;
- bucket_time = stats[id].first_bucket_time;
- for (i = 0; i < bucket_count; i++) {
- s = bucket_time;
- ns = do_div(s, NSEC_PER_SEC);
- seq_printf(m,
- " <%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
- bucket_time <<= bucket_shift;
- }
-
- seq_printf(m, " >=%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
+ stats_show(m, &stats[id], cpu, false);
}
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
}
-
+ stats_show(m, &suspend_stats, cpu, true);
+ spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
return 0;
}
@@ -259,14 +295,6 @@
first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
- stats[MSM_PM_STAT_SUSPEND].name = "suspend";
- stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
- CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
- stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
@@ -275,6 +303,9 @@
stats[enable_stats[i]].enabled = true;
}
+ suspend_stats.name = "system_suspend";
+ suspend_stats.first_bucket_time =
+ CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
d_entry = proc_create_data("msm_pm_stats", S_IRUGO | S_IWUSR | S_IWGRP,
NULL, &msm_pm_stats_fops, NULL);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index bf47366..7ab4ec3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -26,6 +26,8 @@
#define FORMAT_USPS_EPOS 0x00000000
#define FORMAT_USRAW 0x00000001
#define FORMAT_USPROX 0x00000002
+#define FORMAT_USGES_SYNC 0x00000003
+#define FORMAT_USRAW_SYNC 0x00000004
#define INVALID_FORMAT 0xffffffff
#define IN 0x000
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 1ea213a..a18d0f3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,8 +27,8 @@
#include "usfcdev.h"
/* The driver version*/
-#define DRV_VERSION "1.4.2"
-#define USF_VERSION_ID 0x0142
+#define DRV_VERSION "1.5.1"
+#define USF_VERSION_ID 0x0151
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -51,12 +51,19 @@
#define Y_IND 1
#define Z_IND 2
+/* Shared memory limits */
+/* max_buf_size = (port_size(65535*2) * port_num(8) * group_size(3) */
+#define USF_MAX_BUF_SIZE 3145680
+#define USF_MAX_BUF_NUM 32
+
/* Place for opreation result, received from QDSP6 */
#define APR_RESULT_IND 1
/* Place for US detection result, received from QDSP6 */
#define APR_US_DETECT_RESULT_IND 0
+#define BITS_IN_BYTE 8
+
/* The driver states */
enum usf_state_type {
USF_IDLE_STATE,
@@ -117,6 +124,8 @@
uint16_t conflicting_event_types;
/* Bitmap of types of events from devs, conflicting with USF */
uint16_t conflicting_event_filters;
+ /* The requested side buttons bitmap */
+ uint16_t req_side_buttons_bitmap;
};
struct usf_input_dev_type {
@@ -146,6 +155,12 @@
0, /* US_INPUT_SRC_UNDEF */
};
+/* Supported buttons container */
+static const int s_button_map[] = {
+ BTN_STYLUS,
+ BTN_STYLUS2
+};
+
/* The opened devices container */
static int s_opened_devs[MAX_DEVS_NUMBER];
@@ -176,14 +191,35 @@
struct us_input_info_type *input_info,
const char *name)
{
+ int i = 0;
+ int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(input_info->req_side_buttons_bitmap) *
+ BITS_IN_BYTE);
+ uint16_t max_side_button_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
struct input_dev *in_dev = allocate_dev(ind, name);
-
if (in_dev == NULL)
return -ENOMEM;
+ if (input_info->req_side_buttons_bitmap > max_side_button_bitmap) {
+ pr_err("%s: Requested side buttons[%d] exceeds max side buttons available[%d]\n",
+ __func__,
+ input_info->req_side_buttons_bitmap,
+ max_side_button_bitmap);
+ return -EINVAL;
+ }
+
usf_info->input_ifs[ind] = in_dev;
+ usf_info->req_side_buttons_bitmap =
+ input_info->req_side_buttons_bitmap;
in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+
+ for (i = 0; i < num_side_buttons; i++)
+ if (input_info->req_side_buttons_bitmap & (1 << i))
+ in_dev->keybit[BIT_WORD(s_button_map[i])] |=
+ BIT_MASK(s_button_map[i]);
+
input_set_abs_params(in_dev, ABS_X,
input_info->tsc_x_dim[MIN_IND],
input_info->tsc_x_dim[MAX_IND],
@@ -260,6 +296,11 @@
struct usf_event_type *event)
{
+ int i = 0;
+ int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(usf_info->req_side_buttons_bitmap) *
+ BITS_IN_BYTE);
+
struct input_dev *input_if = usf_info->input_ifs[if_ind];
struct point_event_type *pe = &(event->event_data.point_event);
@@ -273,19 +314,27 @@
input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+ for (i = 0; i < num_side_buttons; i++) {
+ uint16_t mask = (1 << i),
+ btn_state = !!(pe->side_buttons_state_bitmap & mask);
+ if (usf_info->req_side_buttons_bitmap & mask)
+ input_report_key(input_if, s_button_map[i], btn_state);
+ }
+
if (usf_info->event_src)
input_report_key(input_if, usf_info->event_src, 1);
input_sync(input_if);
- pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+ pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], side_buttons[%d]\n",
__func__,
pe->coordinates[X_IND],
pe->coordinates[Y_IND],
pe->coordinates[Z_IND],
pe->inclinations[X_IND],
pe->inclinations[Y_IND],
- pe->pressure);
+ pe->pressure,
+ pe->side_buttons_state_bitmap);
}
static void notify_mouse_event(struct usf_type *usf_info,
@@ -338,6 +387,8 @@
prepare_mouse_input_device, notify_mouse_event},
{USF_KEYBOARD_EVENT, "usf_kb",
prepare_keyboard_input_device, notify_key_event},
+ {USF_TSC_EXT_EVENT, "usf_tsc_ext",
+ prepare_tsc_input_device, notify_tsc_event},
};
static void usf_rx_cb(uint32_t opcode, uint32_t token,
@@ -436,6 +487,15 @@
(config == NULL))
return -EINVAL;
+ if ((config->buf_size == 0) ||
+ (config->buf_size > USF_MAX_BUF_SIZE) ||
+ (config->buf_num == 0) ||
+ (config->buf_num > USF_MAX_BUF_NUM)) {
+ pr_err("%s: wrong params: buf_size=%d; buf_num=%d\n",
+ __func__, config->buf_size, config->buf_num);
+ return -EINVAL;
+ }
+
data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
min_map_size = min(data_map_size, config->port_cnt);
@@ -748,6 +808,7 @@
{
uint32_t timeout = 0;
struct us_detect_info_type detect_info;
+ struct usm_session_cmd_detect_info *p_allocated_memory = NULL;
struct usm_session_cmd_detect_info usm_detect_info;
struct usm_session_cmd_detect_info *p_usm_detect_info =
&usm_detect_info;
@@ -774,12 +835,13 @@
uint8_t *p_data = NULL;
detect_info_size += detect_info.params_data_size;
- p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
- if (p_usm_detect_info == NULL) {
+ p_allocated_memory = kzalloc(detect_info_size, GFP_KERNEL);
+ if (p_allocated_memory == NULL) {
pr_err("%s: detect_info[%d] allocation failed\n",
__func__, detect_info_size);
return -ENOMEM;
}
+ p_usm_detect_info = p_allocated_memory;
p_data = (uint8_t *)p_usm_detect_info +
sizeof(struct usm_session_cmd_detect_info);
@@ -789,7 +851,7 @@
if (rc) {
pr_err("%s: copy params from user; rc=%d\n",
__func__, rc);
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return -EFAULT;
}
p_usm_detect_info->algorithm_cfg_size =
@@ -806,9 +868,7 @@
p_usm_detect_info,
detect_info_size);
if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
- if (detect_info_size >
- sizeof(struct usm_session_cmd_detect_info))
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return rc;
}
@@ -828,25 +888,24 @@
USF_US_DETECT_UNDEF),
timeout);
/* In the case of timeout, "no US" is assumed */
- if (rc < 0) {
+ if (rc < 0)
pr_err("%s: Getting US detection failed rc[%d]\n",
__func__, rc);
- return rc;
+ else {
+ usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+ detect_info.is_us =
+ (usf_xx->us_detect_type == USF_US_DETECT_YES);
+ rc = copy_to_user((void __user *)arg,
+ &detect_info,
+ sizeof(detect_info));
+ if (rc) {
+ pr_err("%s: copy detect_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
}
- usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
- detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
- rc = copy_to_user((void __user *)arg,
- &detect_info,
- sizeof(detect_info));
- if (rc) {
- pr_err("%s: copy detect_info to user; rc=%d\n",
- __func__, rc);
- rc = -EFAULT;
- }
-
- if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return rc;
} /* usf_set_us_detection */
@@ -947,16 +1006,14 @@
if (rc)
return rc;
- if (usf_xx->buffer_size && usf_xx->buffer_count) {
- rc = q6usm_us_client_buf_alloc(
- IN,
- usf_xx->usc,
- usf_xx->buffer_size,
- usf_xx->buffer_count);
- if (rc) {
- (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
- return rc;
- }
+ rc = q6usm_us_client_buf_alloc(
+ IN,
+ usf_xx->usc,
+ usf_xx->buffer_size,
+ usf_xx->buffer_count);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
}
rc = q6usm_dec_cfg_blk(usf_xx->usc,
@@ -1175,10 +1232,15 @@
return -EFAULT;
}
- /* version_info.buf is pointer to place for the version string */
+ if (version_info.buf_size < sizeof(DRV_VERSION)) {
+ pr_err("%s: buf_size (%d) < version string size (%d)\n",
+ __func__, version_info.buf_size, sizeof(DRV_VERSION));
+ return -EINVAL;
+ }
+
rc = copy_to_user(version_info.pbuf,
DRV_VERSION,
- version_info.buf_size);
+ sizeof(DRV_VERSION));
if (rc) {
pr_err("%s: copy to version_info.pbuf; rc=%d\n",
__func__, rc);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index fe7c8c2..51a51c5 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -628,6 +628,12 @@
case FORMAT_USPROX:
int_format = US_PROX_FORMAT_V2;
break;
+ case FORMAT_USGES_SYNC:
+ int_format = US_GES_SYNC_FORMAT;
+ break;
+ case FORMAT_USRAW_SYNC:
+ int_format = US_RAW_SYNC_FORMAT;
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
break;
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index cb8ed19..1447854 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -54,7 +54,7 @@
u32 num_records;
u32 read_idx;
u32 len;
- char buf[256];
+ char buf[320];
struct msm_rpmstats_platform_data *platform_data;
};
@@ -64,7 +64,8 @@
u64 last_entered_at;
u64 last_exited_at;
u64 accumulated;
- u32 reserved[4];
+ u32 client_votes;
+ u32 reserved[3];
};
static inline u64 get_time_in_sec(u64 counter)
@@ -98,10 +99,12 @@
actual_last_sleep = get_time_in_msec(data->accumulated);
return snprintf(buf , buflength,
- "RPM Mode:%s\n\t count:%d\n time in last mode(msec):%llu\n"
- "time since last mode(sec):%llu\n actual last sleep(msec):%llu\n",
+ "RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n"
+ "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n"
+ "client votes: %#010x\n\n",
stat_type, data->count, time_in_last_mode,
- time_since_last_mode, actual_last_sleep);
+ time_since_last_mode, actual_last_sleep,
+ data->client_votes);
}
static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase,
@@ -147,6 +150,9 @@
data.accumulated = msm_rpmstats_read_quad_register_v2(reg,
i, offsetof(struct msm_rpm_stats_data_v2,
accumulated));
+ data.client_votes = msm_rpmstats_read_long_register_v2(reg,
+ i, offsetof(struct msm_rpm_stats_data_v2,
+ client_votes));
length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
&data, sizeof(prvdata->buf) - length);
prvdata->read_idx++;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 97b1f39..a5748fb 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -658,13 +658,6 @@
applications DSP processor. Say M if you want to enable this
module.
-config MMC_GENERIC_CSDIO
- tristate "Generic sdio driver"
- default n
- help
- SDIO function driver that extends SDIO card as character device
- in user space.
-
config CSDIO_VENDOR_ID
hex "Card VendorId"
depends on MMC_GENERIC_CSDIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 7589946..292cc99 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -65,7 +65,6 @@
obj-$(CONFIG_TILE_SROM) += tile-srom.o
obj-$(CONFIG_MSM_ROTATOR) += msm_rotator.o
-obj-$(CONFIG_MMC_GENERIC_CSDIO) += csdio.o
obj-$(CONFIG_DIAG_CHAR) += diag/
obj-$(CONFIG_MSM_ADSPRPC) += adsprpc.o
obj-$(CONFIG_MSM_RDBG) += rdbg.o
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index b6fbb3c2..cc8cf47 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -125,16 +125,38 @@
return n;
}
+struct fastrpc_buf {
+ struct ion_handle *handle;
+ void *virt;
+ ion_phys_addr_t phys;
+ int size;
+ int used;
+};
+
+struct smq_context_list;
+
struct smq_invoke_ctx {
+ struct hlist_node hn;
struct completion work;
int retval;
- atomic_t free;
+ int pid;
+ remote_arg_t *pra;
+ remote_arg_t *rpra;
+ struct fastrpc_buf obuf;
+ struct fastrpc_buf *abufs;
+ struct fastrpc_device *dev;
+ struct fastrpc_apps *apps;
+ int *fds;
+ struct ion_handle **handles;
+ int nbufs;
+ bool smmu;
+ uint32_t sc;
};
struct smq_context_list {
- struct smq_invoke_ctx *ls;
- int size;
- int last;
+ struct hlist_head pending;
+ struct hlist_head interrupted;
+ spinlock_t hlock;
};
struct fastrpc_smmu {
@@ -165,22 +187,16 @@
struct hlist_node hn;
struct ion_handle *handle;
void *virt;
+ ion_phys_addr_t phys;
uint32_t vaddrin;
uint32_t vaddrout;
int size;
};
-struct fastrpc_buf {
- struct ion_handle *handle;
- void *virt;
- ion_phys_addr_t phys;
- int size;
- int used;
-};
-
struct file_data {
spinlock_t hlock;
struct hlist_head hlst;
+ uint32_t mode;
};
struct fastrpc_device {
@@ -214,6 +230,11 @@
{
struct fastrpc_apps *me = &gfa;
if (!IS_ERR_OR_NULL(map->handle)) {
+ if (me->smmu.enabled && map->phys) {
+ ion_unmap_iommu(me->iclient, map->handle,
+ me->smmu.domain_id, 0);
+ map->phys = 0;
+ }
if (!IS_ERR_OR_NULL(map->virt)) {
ion_unmap_kernel(me->iclient, map->handle);
map->virt = 0;
@@ -263,65 +284,186 @@
return err;
}
-static int context_list_ctor(struct smq_context_list *me, int size)
+static int context_restore_interrupted(struct fastrpc_apps *me,
+ struct fastrpc_ioctl_invoke_fd *invokefd,
+ struct smq_invoke_ctx **po)
{
int err = 0;
- VERIFY(err, 0 != (me->ls = kzalloc(size, GFP_KERNEL)));
- if (err)
- goto bail;
- me->size = size / sizeof(*me->ls);
- me->last = 0;
- bail:
+ struct smq_invoke_ctx *ctx = 0, *ictx = 0;
+ struct hlist_node *pos, *n;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
+ spin_lock(&me->clst.hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &me->clst.interrupted, hn) {
+ if (ictx->pid == current->pid) {
+ if (invoke->sc != ictx->sc)
+ err = -1;
+ else {
+ ctx = ictx;
+ hlist_del(&ctx->hn);
+ hlist_add_head(&ctx->hn, &me->clst.pending);
+ }
+ break;
+ }
+ }
+ spin_unlock(&me->clst.hlock);
+ if (ctx)
+ *po = ctx;
return err;
}
-static void context_list_dtor(struct smq_context_list *me)
+static int context_alloc(struct fastrpc_apps *me, uint32_t kernel,
+ struct fastrpc_ioctl_invoke_fd *invokefd,
+ struct smq_invoke_ctx **po)
{
- kfree(me->ls);
-}
+ int err = 0, bufs, size = 0;
+ struct smq_invoke_ctx *ctx = 0;
+ struct smq_context_list *clst = &me->clst;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
-static void context_list_alloc_ctx(struct smq_context_list *me,
- struct smq_invoke_ctx **po)
-{
- int i = me->last;
- struct smq_invoke_ctx *ctx;
-
- for (;;) {
- i = i % me->size;
- ctx = &me->ls[i];
- if (atomic_read(&ctx->free) == 0)
- if (atomic_cmpxchg(&ctx->free, 0, 1) == 0)
- break;
- i++;
+ bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
+ REMOTE_SCALARS_OUTBUFS(invoke->sc);
+ if (bufs) {
+ size = bufs * sizeof(*ctx->pra);
+ if (invokefd->fds)
+ size = size + bufs * sizeof(*ctx->fds) +
+ bufs * sizeof(*ctx->handles);
}
- me->last = i;
+
+ VERIFY(err, 0 != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL)));
+ if (err)
+ goto bail;
+
+ INIT_HLIST_NODE(&ctx->hn);
+ ctx->pra = (remote_arg_t *)(&ctx[1]);
+ ctx->fds = invokefd->fds == 0 ? 0 : (int *)(&ctx->pra[bufs]);
+ ctx->handles = invokefd->fds == 0 ? 0 :
+ (struct ion_handle **)(&ctx->fds[bufs]);
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(ctx->pra, invoke->pra,
+ bufs * sizeof(*ctx->pra)));
+ if (err)
+ goto bail;
+ } else {
+ memmove(ctx->pra, invoke->pra, bufs * sizeof(*ctx->pra));
+ }
+
+ if (invokefd->fds) {
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(ctx->fds, invokefd->fds,
+ bufs * sizeof(*ctx->fds)));
+ if (err)
+ goto bail;
+ } else {
+ memmove(ctx->fds, invokefd->fds,
+ bufs * sizeof(*ctx->fds));
+ }
+ }
+ ctx->sc = invoke->sc;
ctx->retval = -1;
+ ctx->pid = current->pid;
+ ctx->apps = me;
init_completion(&ctx->work);
+ spin_lock(&clst->hlock);
+ hlist_add_head(&ctx->hn, &clst->pending);
+ spin_unlock(&clst->hlock);
+
*po = ctx;
+bail:
+ if (ctx && err)
+ kfree(ctx);
+ return err;
}
-static void context_free(struct smq_invoke_ctx *me)
+static void context_save_interrupted(struct smq_invoke_ctx *ctx)
{
- if (me)
- atomic_set(&me->free, 0);
+ struct smq_context_list *clst = &ctx->apps->clst;
+ spin_lock(&clst->hlock);
+ hlist_del(&ctx->hn);
+ hlist_add_head(&ctx->hn, &clst->interrupted);
+ spin_unlock(&clst->hlock);
}
-static void context_notify_user(struct smq_invoke_ctx *me, int retval)
+static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev);
+
+static void context_free(struct smq_invoke_ctx *ctx, bool lock)
{
- me->retval = retval;
- complete(&me->work);
+ struct smq_context_list *clst = &ctx->apps->clst;
+ struct fastrpc_apps *apps = ctx->apps;
+ struct ion_client *clnt = apps->iclient;
+ struct fastrpc_smmu *smmu = &apps->smmu;
+ struct fastrpc_buf *b;
+ int i, bufs;
+ if (ctx->smmu) {
+ bufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
+ REMOTE_SCALARS_OUTBUFS(ctx->sc);
+ if (ctx->fds) {
+ for (i = 0; i < bufs; i++)
+ if (!IS_ERR_OR_NULL(ctx->handles[i])) {
+ ion_unmap_iommu(clnt, ctx->handles[i],
+ smmu->domain_id, 0);
+ ion_free(clnt, ctx->handles[i]);
+ }
+ }
+ iommu_detach_group(smmu->domain, smmu->group);
+ }
+ for (i = 0, b = ctx->abufs; i < ctx->nbufs; ++i, ++b)
+ free_mem(b);
+
+ kfree(ctx->abufs);
+ if (ctx->dev) {
+ add_dev(apps, ctx->dev);
+ if (ctx->obuf.handle != ctx->dev->buf.handle)
+ free_mem(&ctx->obuf);
+ }
+ if (lock)
+ spin_lock(&clst->hlock);
+ hlist_del(&ctx->hn);
+ if (lock)
+ spin_unlock(&clst->hlock);
+ kfree(ctx);
+}
+
+static void context_notify_user(struct smq_invoke_ctx *ctx, int retval)
+{
+ ctx->retval = retval;
+ complete(&ctx->work);
}
static void context_notify_all_users(struct smq_context_list *me)
{
- int i;
-
- if (!me->ls)
- return;
- for (i = 0; i < me->size; ++i) {
- if (atomic_read(&me->ls[i].free) != 0)
- complete(&me->ls[i].work);
+ struct smq_invoke_ctx *ictx = 0;
+ struct hlist_node *pos, *n;
+ spin_lock(&me->hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &me->pending, hn) {
+ complete(&ictx->work);
}
+ hlist_for_each_entry_safe(ictx, pos, n, &me->interrupted, hn) {
+ complete(&ictx->work);
+ }
+ spin_unlock(&me->hlock);
+
+}
+
+static void context_list_ctor(struct smq_context_list *me)
+{
+ INIT_HLIST_HEAD(&me->interrupted);
+ INIT_HLIST_HEAD(&me->pending);
+ spin_lock_init(&me->hlock);
+}
+
+static void context_list_dtor(struct fastrpc_apps *me,
+ struct smq_context_list *clst)
+{
+ struct smq_invoke_ctx *ictx = 0;
+ struct hlist_node *pos, *n;
+ spin_lock(&clst->hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &clst->interrupted, hn) {
+ context_free(ictx, 0);
+ }
+ hlist_for_each_entry_safe(ictx, pos, n, &clst->pending, hn) {
+ context_free(ictx, 0);
+ }
+ spin_unlock(&clst->hlock);
}
static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
@@ -400,13 +542,12 @@
static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
remote_arg_t *rpra, remote_arg_t *upra,
struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
- int *nbufs, int *fds)
+ int *nbufs, int *fds, struct ion_handle **handles)
{
struct fastrpc_apps *me = &gfa;
struct smq_invoke_buf *list;
struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
struct smq_phy_page *pages;
- struct ion_handle **handles = NULL;
void *args;
int i, rlen, size, used, inh, bufs = 0, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
@@ -418,8 +559,6 @@
used = ALIGN(pbuf->used, BALIGN);
args = (void *)((char *)pbuf->virt + used);
rlen = pbuf->size - used;
- if (fds)
- handles = (struct ion_handle **)(fds + inbufs + outbufs);
for (i = 0; i < inbufs + outbufs; ++i) {
rpra[i].buf.len = pra[i].buf.len;
@@ -614,7 +753,6 @@
struct fastrpc_apps *me = &gfa;
smd_close(me->chan);
- context_list_dtor(&me->clst);
ion_client_destroy(me->iclient);
me->iclient = 0;
me->chan = 0;
@@ -667,16 +805,14 @@
spin_lock_init(&me->wrlock);
init_completion(&me->work);
mutex_init(&me->smd_mutex);
+ context_list_ctor(&me->clst);
for (i = 0; i < RPC_HASH_SZ; ++i)
INIT_HLIST_HEAD(&me->htbl[i]);
- VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
- if (err)
- goto context_list_bail;
me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
DEVICE_NAME);
VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
if (err)
- goto ion_bail;
+ goto bail;
node = of_find_compatible_node(NULL, NULL,
"qcom,msm-audio-ion");
if (node)
@@ -697,9 +833,7 @@
return 0;
-ion_bail:
- context_list_dtor(&me->clst);
-context_list_bail:
+bail:
return err;
}
@@ -783,96 +917,88 @@
static int fastrpc_release_current_dsp_process(void);
-static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t kernel,
- struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra,
- int *fds)
+static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,
+ uint32_t kernel,
+ struct fastrpc_ioctl_invoke_fd *invokefd)
{
- remote_arg_t *rpra = 0;
- struct fastrpc_device *dev = 0;
struct smq_invoke_ctx *ctx = 0;
- struct fastrpc_buf obuf, *abufs = 0, *b;
- struct ion_handle **handles = NULL;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
int interrupted = 0;
- uint32_t sc;
- int i, bufs, nbufs = 0, err = 0;
+ int err = 0;
- sc = invoke->sc;
- obuf.handle = 0;
+ if (!kernel) {
+ VERIFY(err, 0 == context_restore_interrupted(me, invokefd,
+ &ctx));
+ if (err)
+ goto bail;
+ if (ctx)
+ goto wait;
+ }
+
+ VERIFY(err, 0 == context_alloc(me, kernel, invokefd, &ctx));
+ if (err)
+ goto bail;
+
if (me->smmu.enabled) {
VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
me->smmu.group));
if (err)
- return err;
+ goto bail;
+ ctx->smmu = 1;
}
- if (REMOTE_SCALARS_LENGTH(sc)) {
- VERIFY(err, 0 == get_dev(me, &dev));
+ if (REMOTE_SCALARS_LENGTH(ctx->sc)) {
+ VERIFY(err, 0 == get_dev(me, &ctx->dev));
if (err)
goto bail;
- VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
- &obuf));
+ VERIFY(err, 0 == get_page_list(kernel, ctx->sc, ctx->pra,
+ &ctx->dev->buf, &ctx->obuf));
if (err)
goto bail;
- rpra = (remote_arg_t *)obuf.virt;
- VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
- &obuf, &abufs, &nbufs, fds));
+ ctx->rpra = (remote_arg_t *)ctx->obuf.virt;
+ VERIFY(err, 0 == get_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+ invoke->pra, &ctx->obuf, &ctx->abufs,
+ &ctx->nbufs, ctx->fds, ctx->handles));
if (err)
goto bail;
}
- context_list_alloc_ctx(&me->clst, &ctx);
- inv_args_pre(sc, rpra);
- VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
- ctx, &obuf));
+ inv_args_pre(ctx->sc, ctx->rpra);
+ if (FASTRPC_MODE_SERIAL == mode)
+ inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle,
+ ctx->sc, ctx, &ctx->obuf));
if (err)
goto bail;
- inv_args(sc, rpra, obuf.used);
- VERIFY(err, 0 == (interrupted =
- wait_for_completion_interruptible(&ctx->work)));
- if (err)
- goto bail;
+ if (FASTRPC_MODE_PARALLEL == mode)
+ inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ wait:
+ if (kernel)
+ wait_for_completion(&ctx->work);
+ else {
+ interrupted = wait_for_completion_interruptible(&ctx->work);
+ VERIFY(err, 0 == (err = interrupted));
+ if (err)
+ goto bail;
+ }
VERIFY(err, 0 == (err = ctx->retval));
if (err)
goto bail;
- VERIFY(err, 0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ VERIFY(err, 0 == put_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+ invoke->pra));
if (err)
goto bail;
bail:
- if (interrupted) {
- if (!kernel)
- (void)fastrpc_release_current_dsp_process();
- wait_for_completion(&ctx->work);
- }
- context_free(ctx);
-
- if (me->smmu.enabled) {
- bufs = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
- if (fds) {
- handles = (struct ion_handle **)(fds + bufs);
- for (i = 0; i < bufs; i++)
- if (!IS_ERR_OR_NULL(handles[i])) {
- ion_unmap_iommu(me->iclient, handles[i],
- me->smmu.domain_id, 0);
- ion_free(me->iclient, handles[i]);
- }
- }
- iommu_detach_group(me->smmu.domain, me->smmu.group);
- }
- for (i = 0, b = abufs; i < nbufs; ++i, ++b)
- free_mem(b);
-
- kfree(abufs);
- if (dev) {
- add_dev(me, dev);
- if (obuf.handle != dev->buf.handle)
- free_mem(&obuf);
- }
+ if (ctx && interrupted == -ERESTARTSYS)
+ context_save_interrupted(ctx);
+ else if (ctx)
+ context_free(ctx, 1);
return err;
}
static int fastrpc_create_current_dsp_process(void)
{
int err = 0;
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
struct fastrpc_apps *me = &gfa;
remote_arg_t ra[1];
int tgid = 0;
@@ -880,10 +1006,12 @@
tgid = current->tgid;
ra[0].buf.pv = &tgid;
ra[0].buf.len = sizeof(tgid);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -891,17 +1019,19 @@
{
int err = 0;
struct fastrpc_apps *me = &gfa;
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[1];
int tgid = 0;
tgid = current->tgid;
ra[0].buf.pv = &tgid;
ra[0].buf.len = sizeof(tgid);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -910,7 +1040,7 @@
struct smq_phy_page *pages,
int num)
{
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[3];
int err = 0;
struct {
@@ -936,10 +1066,12 @@
ra[2].buf.pv = &routargs;
ra[2].buf.len = sizeof(routargs);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
mmap->vaddrout = routargs.vaddrout;
if (err)
goto bail;
@@ -950,7 +1082,7 @@
static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
struct fastrpc_ioctl_munmap *munmap)
{
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[1];
int err = 0;
struct {
@@ -965,10 +1097,12 @@
ra[0].buf.pv = &inargs;
ra[0].buf.len = sizeof(inargs);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -1010,7 +1144,7 @@
struct fastrpc_mmap *map = 0;
struct smq_phy_page *pages = 0;
void *buf;
- int len;
+ unsigned long len;
int num;
int err = 0;
@@ -1031,9 +1165,22 @@
VERIFY(err, 0 != (pages = kzalloc(num * sizeof(*pages), GFP_KERNEL)));
if (err)
goto bail;
- VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1, pages, num)));
- if (err)
- goto bail;
+
+ if (me->smmu.enabled) {
+ VERIFY(err, 0 == ion_map_iommu(clnt, map->handle,
+ me->smmu.domain_id, 0,
+ SZ_4K, 0, &map->phys, &len, 0, 0));
+ if (err)
+ goto bail;
+ pages->addr = map->phys;
+ pages->size = len;
+ num = 1;
+ } else {
+ VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1,
+ pages, num)));
+ if (err)
+ goto bail;
+ }
VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
if (err)
@@ -1100,7 +1247,7 @@
(void)fastrpc_release_current_dsp_process();
cleanup_current_dev();
if (fdata) {
- struct fastrpc_mmap *map;
+ struct fastrpc_mmap *map = 0;
struct hlist_node *n, *pos;
file->private_data = 0;
hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
@@ -1179,48 +1326,23 @@
{
struct fastrpc_apps *me = &gfa;
struct fastrpc_ioctl_invoke_fd invokefd;
- struct fastrpc_ioctl_invoke *invoke = &invokefd.inv;
struct fastrpc_ioctl_mmap mmap;
struct fastrpc_ioctl_munmap munmap;
- remote_arg_t *pra = 0;
void *param = (char *)ioctl_param;
struct file_data *fdata = (struct file_data *)file->private_data;
- int *fds = 0;
- int bufs, size = 0, err = 0;
+ int size = 0, err = 0;
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE_FD:
case FASTRPC_IOCTL_INVOKE:
invokefd.fds = 0;
size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ?
- sizeof(*invoke) : sizeof(invokefd);
+ sizeof(invokefd.inv) : sizeof(invokefd);
VERIFY(err, 0 == copy_from_user(&invokefd, param, size));
if (err)
goto bail;
- bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
- REMOTE_SCALARS_OUTBUFS(invoke->sc);
- if (bufs) {
- size = bufs * sizeof(*pra);
- if (invokefd.fds)
- size = size + bufs * sizeof(*fds) +
- bufs * sizeof(struct ion_handle *);
- VERIFY(err, 0 != (pra = kzalloc(size, GFP_KERNEL)));
- if (err)
- goto bail;
- }
- VERIFY(err, 0 == copy_from_user(pra, invoke->pra,
- bufs * sizeof(*pra)));
- if (err)
- goto bail;
- if (invokefd.fds) {
- fds = (int *)(pra + bufs);
- VERIFY(err, 0 == copy_from_user(fds, invokefd.fds,
- bufs * sizeof(*fds)));
- if (err)
- goto bail;
- }
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, invoke,
- pra, fds)));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, fdata->mode,
+ 0, &invokefd)));
if (err)
goto bail;
break;
@@ -1247,12 +1369,22 @@
if (err)
goto bail;
break;
+ case FASTRPC_IOCTL_SETMODE:
+ switch ((uint32_t)ioctl_param) {
+ case FASTRPC_MODE_PARALLEL:
+ case FASTRPC_MODE_SERIAL:
+ fdata->mode = (uint32_t)ioctl_param;
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+ break;
default:
err = -ENOTTY;
break;
}
bail:
- kfree(pra);
return err;
}
@@ -1307,7 +1439,9 @@
{
struct fastrpc_apps *me = &gfa;
+ context_list_dtor(me, &me->clst);
fastrpc_deinit();
+ cleanup_current_dev();
device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
class_destroy(me->class);
cdev_del(&me->cdev);
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index da70eb5..f5d7450 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -20,9 +20,16 @@
#define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap)
#define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap)
#define FASTRPC_IOCTL_INVOKE_FD _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd)
+#define FASTRPC_IOCTL_SETMODE _IOWR('R', 5, uint32_t)
#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
#define DEVICE_NAME "adsprpc-smd"
+/* Driver should operate in parallel with the co-processor */
+#define FASTRPC_MODE_PARALLEL 0
+
+/* Driver should operate in serial mode with the co-processor */
+#define FASTRPC_MODE_SERIAL 1
+
/* Retrives number of input buffers from the scalars parameter */
#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff)
diff --git a/drivers/char/csdio.c b/drivers/char/csdio.c
deleted file mode 100644
index 85306d3..0000000
--- a/drivers/char/csdio.c
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*
- * Copyright (c) 2010, 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/moduleparam.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-/* Char device */
-#include <linux/cdev.h>
-#include <linux/fs.h>
-
-/* Sdio device */
-#include <linux/mmc/core.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-
-#include <linux/csdio.h>
-
-#define FALSE 0
-#define TRUE 1
-
-#define VERSION "0.5"
-#define CSDIO_NUM_OF_SDIO_FUNCTIONS 7
-#define CSDIO_DEV_NAME "csdio"
-#define TP_DEV_NAME CSDIO_DEV_NAME"f"
-#define CSDIO_DEV_PERMISSIONS 0666
-
-#define CSDIO_SDIO_BUFFER_SIZE (64*512)
-
-int csdio_major;
-int csdio_minor;
-int csdio_transport_nr_devs = CSDIO_NUM_OF_SDIO_FUNCTIONS;
-static uint csdio_vendor_id;
-static uint csdio_device_id;
-static char *host_name;
-
-static struct csdio_func_t {
- struct sdio_func *m_func;
- int m_enabled;
- struct cdev m_cdev; /* char device structure */
- struct device *m_device;
- u32 m_block_size;
-} *g_csdio_func_table[CSDIO_NUM_OF_SDIO_FUNCTIONS] = {0};
-
-struct csdio_t {
- struct cdev m_cdev;
- struct device *m_device;
- struct class *m_driver_class;
- struct fasync_struct *m_async_queue;
- unsigned char m_current_irq_mask; /* currently enabled irqs */
- struct mmc_host *m_host;
- unsigned int m_num_of_func;
-} g_csdio;
-
-struct csdio_file_descriptor {
- struct csdio_func_t *m_port;
- u32 m_block_mode;/* data tran. byte(0)/block(1) */
- u32 m_op_code; /* address auto increment flag */
- u32 m_address;
-};
-
-static void *g_sdio_buffer;
-
-/*
- * Open and release
- */
-static int csdio_transport_open(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_func_t *port = NULL; /* device information */
- struct sdio_func *func = NULL;
- struct csdio_file_descriptor *descriptor = NULL;
-
- port = container_of(inode->i_cdev, struct csdio_func_t, m_cdev);
- func = port->m_func;
- descriptor = kzalloc(sizeof(struct csdio_file_descriptor), GFP_KERNEL);
- if (!descriptor) {
- ret = -ENOMEM;
- goto exit;
- }
-
- pr_info(TP_DEV_NAME"%d: open: func=%p, port=%p\n",
- func->num, func, port);
- sdio_claim_host(func);
- ret = sdio_enable_func(func);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:Enable func failed (%d)\n",
- func->num, ret);
- ret = -EIO;
- goto free_descriptor;
- }
- descriptor->m_port = port;
- filp->private_data = descriptor;
- goto release_host;
-
-free_descriptor:
- kfree(descriptor);
-release_host:
- sdio_release_host(func);
-exit:
- return ret;
-}
-
-static int csdio_transport_release(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
-
- pr_info(TP_DEV_NAME"%d: release\n", func->num);
- sdio_claim_host(func);
- ret = sdio_disable_func(func);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:Disable func failed(%d)\n",
- func->num, ret);
- ret = -EIO;
- }
- sdio_release_host(func);
- kfree(descriptor);
- return ret;
-}
-
-/*
- * Data management: read and write
- */
-static ssize_t csdio_transport_read(struct file *filp,
- char __user *buf,
- size_t count,
- loff_t *f_pos)
-{
- ssize_t ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
- size_t t_count = count;
-
- if (descriptor->m_block_mode) {
- pr_info(TP_DEV_NAME "%d: CMD53 read, Md:%d, Addr:0x%04X,"
- " Un:%d (Bl:%d, BlSz:%d)\n", func->num,
- descriptor->m_block_mode,
- descriptor->m_address,
- count*port->m_block_size,
- count, port->m_block_size);
- /* recalculate size */
- count *= port->m_block_size;
- }
- sdio_claim_host(func);
- if (descriptor->m_op_code) {
- /* auto increment */
- ret = sdio_memcpy_fromio(func, g_sdio_buffer,
- descriptor->m_address, count);
- } else { /* FIFO */
- ret = sdio_readsb(func, g_sdio_buffer,
- descriptor->m_address, count);
- }
- sdio_release_host(func);
- if (!ret) {
- if (copy_to_user(buf, g_sdio_buffer, count))
- ret = -EFAULT;
- else
- ret = t_count;
- }
- if (ret < 0) {
- pr_err(TP_DEV_NAME "%d: CMD53 read failed (%d)"
- "(Md:%d, Addr:0x%04X, Sz:%d)\n",
- func->num, ret,
- descriptor->m_block_mode,
- descriptor->m_address, count);
- }
- return ret;
-}
-
-static ssize_t csdio_transport_write(struct file *filp,
- const char __user *buf,
- size_t count,
- loff_t *f_pos)
-{
- ssize_t ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
- size_t t_count = count;
-
- if (descriptor->m_block_mode)
- count *= port->m_block_size;
-
- if (copy_from_user(g_sdio_buffer, buf, count)) {
- pr_err(TP_DEV_NAME"%d:copy_from_user failed\n", func->num);
- ret = -EFAULT;
- } else {
- sdio_claim_host(func);
- if (descriptor->m_op_code) {
- /* auto increment */
- ret = sdio_memcpy_toio(func, descriptor->m_address,
- g_sdio_buffer, count);
- } else {
- /* FIFO */
- ret = sdio_writesb(func, descriptor->m_address,
- g_sdio_buffer, count);
- }
- sdio_release_host(func);
- if (!ret) {
- ret = t_count;
- } else {
- pr_err(TP_DEV_NAME "%d: CMD53 write failed (%d)"
- "(Md:%d, Addr:0x%04X, Sz:%d)\n",
- func->num, ret, descriptor->m_block_mode,
- descriptor->m_address, count);
- }
- }
- return ret;
-}
-
-/* disable interrupt for sdio client */
-static int disable_sdio_client_isr(struct sdio_func *func)
-{
- int ret;
-
- /* disable for all functions, to restore interrupts
- * use g_csdio.m_current_irq_mask */
- sdio_f0_writeb(func, 0, SDIO_CCCR_IENx, &ret);
- if (ret)
- pr_err(CSDIO_DEV_NAME" Can't sdio_f0_writeb (%d)\n", ret);
-
- return ret;
-}
-
-/*
- * This handles the interrupt from SDIO.
- */
-static void csdio_sdio_irq(struct sdio_func *func)
-{
- int ret;
-
- pr_info(CSDIO_DEV_NAME" csdio_sdio_irq: func=%d\n", func->num);
- ret = disable_sdio_client_isr(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME" Can't disable client isr(%d)\n", ret);
- return;
- }
- /* signal asynchronous readers */
- if (g_csdio.m_async_queue)
- kill_fasync(&g_csdio.m_async_queue, SIGIO, POLL_IN);
-}
-
-/*
- * The ioctl() implementation
- */
-static int csdio_transport_ioctl(struct inode *inode,
- struct file *filp,
- unsigned int cmd,
- unsigned long arg)
-{
- int err = 0;
- int ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
-
- /* extract the type and number bitfields
- sanity check: return ENOTTY (inappropriate ioctl) before
- access_ok()
- */
- if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
- (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
- pr_err(TP_DEV_NAME "Wrong ioctl command parameters\n");
- ret = -ENOTTY;
- goto exit;
- }
-
- /* the direction is a bitmask, and VERIFY_WRITE catches R/W
- * transfers. `Type' is user-oriented, while access_ok is
- kernel-oriented, so the concept of "read" and "write" is reversed
- */
- if (_IOC_DIR(cmd) & _IOC_READ) {
- err = !access_ok(VERIFY_WRITE, (void __user *)arg,
- _IOC_SIZE(cmd));
- } else {
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- err = !access_ok(VERIFY_READ, (void __user *)arg,
- _IOC_SIZE(cmd));
- }
- }
- if (err) {
- pr_err(TP_DEV_NAME "Wrong ioctl access direction\n");
- ret = -EFAULT;
- goto exit;
- }
-
- switch (cmd) {
- case CSDIO_IOC_SET_OP_CODE:
- {
- pr_info(TP_DEV_NAME"%d:SET_OP_CODE=%d\n",
- func->num, descriptor->m_op_code);
- ret = get_user(descriptor->m_op_code,
- (unsigned char __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_OP_CODE get data"
- " from user space failed(%d)\n",
- func->num, ret);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE:
- {
- unsigned block_size;
-
- ret = get_user(block_size, (unsigned __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE get data"
- " from user space failed(%d)\n",
- func->num, ret);
- ret = -ENOTTY;
- break;
- }
- pr_info(TP_DEV_NAME"%d:SET_BLOCK_SIZE=%d\n",
- func->num, block_size);
- sdio_claim_host(func);
- ret = sdio_set_block_size(func, block_size);
- if (!ret) {
- port->m_block_size = block_size;
- } else {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE set block"
- " size to %d failed (%d)\n",
- func->num, block_size, ret);
- ret = -ENOTTY;
- break;
- }
- sdio_release_host(func);
- }
- break;
- case CSDIO_IOC_SET_BLOCK_MODE:
- {
- pr_info(TP_DEV_NAME"%d:SET_BLOCK_MODE=%d\n",
- func->num, descriptor->m_block_mode);
- ret = get_user(descriptor->m_block_mode,
- (unsigned char __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_MODE get data"
- " from user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_CMD52:
- {
- struct csdio_cmd52_ctrl_t cmd52ctrl;
- int cmd52ret;
-
- if (copy_from_user(&cmd52ctrl,
- (const unsigned char __user *)arg,
- sizeof(cmd52ctrl))) {
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 get data"
- " from user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- sdio_claim_host(func);
- if (cmd52ctrl.m_write)
- sdio_writeb(func, cmd52ctrl.m_data,
- cmd52ctrl.m_address, &cmd52ret);
- else
- cmd52ctrl.m_data = sdio_readb(func,
- cmd52ctrl.m_address, &cmd52ret);
-
- cmd52ctrl.m_ret = cmd52ret;
- sdio_release_host(func);
- if (cmd52ctrl.m_ret)
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 failed (%d)\n",
- func->num, cmd52ctrl.m_ret);
-
- if (copy_to_user((unsigned char __user *)arg,
- &cmd52ctrl,
- sizeof(cmd52ctrl))) {
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 put data"
- " to user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_CMD53:
- {
- struct csdio_cmd53_ctrl_t csdio_cmd53_ctrl;
-
- if (copy_from_user(&csdio_cmd53_ctrl,
- (const char __user *)arg,
- sizeof(csdio_cmd53_ctrl))) {
- ret = -EPERM;
- pr_err(TP_DEV_NAME"%d:"
- "Get data from user space failed\n",
- func->num);
- break;
- }
- descriptor->m_block_mode =
- csdio_cmd53_ctrl.m_block_mode;
- descriptor->m_op_code = csdio_cmd53_ctrl.m_op_code;
- descriptor->m_address = csdio_cmd53_ctrl.m_address;
- }
- break;
- case CSDIO_IOC_CONNECT_ISR:
- {
- pr_info(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
- " func=%d, csdio_sdio_irq=%x\n",
- func->num, (unsigned int)csdio_sdio_irq);
- sdio_claim_host(func);
- ret = sdio_claim_irq(func, csdio_sdio_irq);
- sdio_release_host(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
- " claim irq failed(%d)\n", ret);
- } else {
- /* update current irq mask for disable/enable */
- g_csdio.m_current_irq_mask |= (1 << func->num);
- }
- }
- break;
- case CSDIO_IOC_DISCONNECT_ISR:
- {
- pr_info(CSDIO_DEV_NAME " SDIO_DISCONNECT_ISR func=%d\n",
- func->num);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_release_host(func);
- /* update current irq mask for disable/enable */
- g_csdio.m_current_irq_mask &= ~(1 << func->num);
- }
- break;
- default: /* redundant, as cmd was checked against MAXNR */
- pr_warning(TP_DEV_NAME"%d: Redundant IOCTL\n",
- func->num);
- ret = -ENOTTY;
- }
-exit:
- return ret;
-}
-
-static const struct file_operations csdio_transport_fops = {
- .owner = THIS_MODULE,
- .read = csdio_transport_read,
- .write = csdio_transport_write,
- .ioctl = csdio_transport_ioctl,
- .open = csdio_transport_open,
- .release = csdio_transport_release,
-};
-
-static void csdio_transport_cleanup(struct csdio_func_t *port)
-{
- int devno = MKDEV(csdio_major, csdio_minor + port->m_func->num);
- device_destroy(g_csdio.m_driver_class, devno);
- port->m_device = NULL;
- cdev_del(&port->m_cdev);
-}
-
-#if defined(CONFIG_DEVTMPFS)
-static inline int csdio_cdev_update_permissions(
- const char *devname, int dev_minor)
-{
- return 0;
-}
-#else
-static int csdio_cdev_update_permissions(
- const char *devname, int dev_minor)
-{
- int ret = 0;
- mm_segment_t fs;
- struct file *file;
- struct inode *inode;
- struct iattr newattrs;
- int mode = CSDIO_DEV_PERMISSIONS;
- char dev_file[64];
-
- fs = get_fs();
- set_fs(get_ds());
-
- snprintf(dev_file, sizeof(dev_file), "/dev/%s%d",
- devname, dev_minor);
- file = filp_open(dev_file, O_RDWR, 0);
- if (IS_ERR(file)) {
- ret = -EFAULT;
- goto exit;
- }
-
- inode = file->f_path.dentry->d_inode;
-
- mutex_lock(&inode->i_mutex);
- newattrs.ia_mode =
- (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- ret = notify_change(file->f_path.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-
- filp_close(file, NULL);
-
-exit:
- set_fs(fs);
- return ret;
-}
-#endif
-
-static struct device *csdio_cdev_init(struct cdev *char_dev,
- const struct file_operations *file_op, int dev_minor,
- const char *devname, struct device *parent)
-{
- int ret = 0;
- struct device *new_device = NULL;
- dev_t devno = MKDEV(csdio_major, dev_minor);
-
- /* Initialize transport device */
- cdev_init(char_dev, file_op);
- char_dev->owner = THIS_MODULE;
- char_dev->ops = file_op;
- ret = cdev_add(char_dev, devno, 1);
-
- /* Fail gracefully if need be */
- if (ret) {
- pr_warning("Error %d adding CSDIO char device '%s%d'",
- ret, devname, dev_minor);
- goto exit;
- }
- pr_info("'%s%d' char driver registered\n", devname, dev_minor);
-
- /* create a /dev entry for transport drivers */
- new_device = device_create(g_csdio.m_driver_class, parent, devno, NULL,
- "%s%d", devname, dev_minor);
- if (!new_device) {
- pr_err("Can't create device node '/dev/%s%d'\n",
- devname, dev_minor);
- goto cleanup;
- }
- /* no irq attached */
- g_csdio.m_current_irq_mask = 0;
-
- if (csdio_cdev_update_permissions(devname, dev_minor)) {
- pr_warning("%s%d: Unable to update access permissions of the"
- " '/dev/%s%d'\n",
- devname, dev_minor, devname, dev_minor);
- }
-
- pr_info("%s%d: Device node '/dev/%s%d' created successfully\n",
- devname, dev_minor, devname, dev_minor);
- goto exit;
-cleanup:
- cdev_del(char_dev);
-exit:
- return new_device;
-}
-
-/* Looks for first non empty function, returns NULL otherwise */
-static struct sdio_func *get_active_func(void)
-{
- int i;
-
- for (i = 0; i < CSDIO_NUM_OF_SDIO_FUNCTIONS; i++) {
- if (g_csdio_func_table[i])
- return g_csdio_func_table[i]->m_func;
- }
- return NULL;
-}
-
-static ssize_t
-show_vdd(struct device *dev, struct device_attribute *attr, char *buf)
-{
- if (NULL == g_csdio.m_host)
- return snprintf(buf, PAGE_SIZE, "N/A\n");
- return snprintf(buf, PAGE_SIZE, "%d\n",
- g_csdio.m_host->ios.vdd);
-}
-
-static int
-set_vdd_helper(int value)
-{
- struct mmc_ios *ios = NULL;
-
- if (NULL == g_csdio.m_host) {
- pr_err("%s0: Set VDD, no MMC host assigned\n", CSDIO_DEV_NAME);
- return -ENXIO;
- }
-
- mmc_claim_host(g_csdio.m_host);
- ios = &g_csdio.m_host->ios;
- ios->vdd = value;
- g_csdio.m_host->ops->set_ios(g_csdio.m_host, ios);
- mmc_release_host(g_csdio.m_host);
- return 0;
-}
-
-static ssize_t
-set_vdd(struct device *dev, struct device_attribute *att,
- const char *buf, size_t count)
-{
- int value = 0;
-
- sscanf(buf, "%d", &value);
- if (set_vdd_helper(value))
- return -ENXIO;
- return count;
-}
-
-static DEVICE_ATTR(vdd, S_IRUGO | S_IWUSR,
- show_vdd, set_vdd);
-
-static struct attribute *dev_attrs[] = {
- &dev_attr_vdd.attr,
- NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
- .attrs = dev_attrs,
-};
-
-/*
- * The ioctl() implementation for control device
- */
-static int csdio_ctrl_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- int err = 0;
- int ret = 0;
-
- pr_info("CSDIO ctrl ioctl.\n");
-
- /* extract the type and number bitfields
- sanity check: return ENOTTY (inappropriate ioctl) before
- access_ok()
- */
- if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
- (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
- pr_err(CSDIO_DEV_NAME "Wrong ioctl command parameters\n");
- ret = -ENOTTY;
- goto exit;
- }
-
- /* the direction is a bitmask, and VERIFY_WRITE catches R/W
- transfers. `Type' is user-oriented, while access_ok is
- kernel-oriented, so the concept of "read" and "write" is reversed
- */
- if (_IOC_DIR(cmd) & _IOC_READ) {
- err = !access_ok(VERIFY_WRITE, (void __user *)arg,
- _IOC_SIZE(cmd));
- } else {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- err = !access_ok(VERIFY_READ, (void __user *)arg,
- _IOC_SIZE(cmd));
- }
- if (err) {
- pr_err(CSDIO_DEV_NAME "Wrong ioctl access direction\n");
- ret = -EFAULT;
- goto exit;
- }
-
- switch (cmd) {
- case CSDIO_IOC_ENABLE_HIGHSPEED_MODE:
- pr_info(CSDIO_DEV_NAME" ENABLE_HIGHSPEED_MODE\n");
- break;
- case CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS:
- {
- struct mmc_host *host = g_csdio.m_host;
- struct mmc_ios *ios = NULL;
-
- if (NULL == host) {
- pr_err("%s0: "
- "CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS,"
- " no MMC host assigned\n",
- CSDIO_DEV_NAME);
- ret = -EFAULT;
- goto exit;
- }
- ios = &host->ios;
-
- mmc_claim_host(host);
- ret = get_user(host->ios.clock,
- (unsigned int __user *)arg);
- if (ret) {
- pr_err(CSDIO_DEV_NAME
- " get data from user space failed\n");
- } else {
- pr_err(CSDIO_DEV_NAME
- "SET_DATA_TRANSFER_CLOCKS(%d-%d)(%d)\n",
- host->f_min, host->f_max,
- host->ios.clock);
- host->ops->set_ios(host, ios);
- }
- mmc_release_host(host);
- }
- break;
- case CSDIO_IOC_ENABLE_ISR:
- {
- int ret;
- unsigned char reg;
- struct sdio_func *func = get_active_func();
-
- if (!func) {
- pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
- " no active sdio function\n");
- ret = -EFAULT;
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME
- " CSDIO_IOC_ENABLE_ISR func=%d\n",
- func->num);
- reg = g_csdio.m_current_irq_mask | 1;
-
- sdio_claim_host(func);
- sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret);
- sdio_release_host(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME
- " Can't sdio_f0_writeb (%d)\n",
- ret);
- goto exit;
- }
- }
- break;
- case CSDIO_IOC_DISABLE_ISR:
- {
- int ret;
- struct sdio_func *func = get_active_func();
- if (!func) {
- pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
- " no active sdio function\n");
- ret = -EFAULT;
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME
- " CSDIO_IOC_DISABLE_ISR func=%p\n",
- func);
-
- sdio_claim_host(func);
- ret = disable_sdio_client_isr(func);
- sdio_release_host(func);
- if (ret) {
- pr_err("%s0: Can't disable client isr (%d)\n",
- CSDIO_DEV_NAME, ret);
- goto exit;
- }
- }
- break;
- case CSDIO_IOC_SET_VDD:
- {
- unsigned int vdd = 0;
-
- ret = get_user(vdd, (unsigned int __user *)arg);
- if (ret) {
- pr_err("%s0: CSDIO_IOC_SET_VDD,"
- " get data from user space failed\n",
- CSDIO_DEV_NAME);
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME" CSDIO_IOC_SET_VDD - %d\n", vdd);
-
- ret = set_vdd_helper(vdd);
- if (ret)
- goto exit;
- }
- break;
- case CSDIO_IOC_GET_VDD:
- {
- if (NULL == g_csdio.m_host) {
- pr_err("%s0: CSDIO_IOC_GET_VDD,"
- " no MMC host assigned\n",
- CSDIO_DEV_NAME);
- ret = -EFAULT;
- goto exit;
- }
- ret = put_user(g_csdio.m_host->ios.vdd,
- (unsigned short __user *)arg);
- if (ret) {
- pr_err("%s0: CSDIO_IOC_GET_VDD, put data"
- " to user space failed\n",
- CSDIO_DEV_NAME);
- goto exit;
- }
- }
- break;
- default: /* redundant, as cmd was checked against MAXNR */
- pr_warning(CSDIO_DEV_NAME" Redundant IOCTL\n");
- ret = -ENOTTY;
- }
-exit:
- return ret;
-}
-
-static int csdio_ctrl_fasync(int fd, struct file *filp, int mode)
-{
- pr_info(CSDIO_DEV_NAME
- " csdio_ctrl_fasync: fd=%d, filp=%p, mode=%d\n",
- fd, filp, mode);
- return fasync_helper(fd, filp, mode, &g_csdio.m_async_queue);
-}
-
-/*
- * Open and close
- */
-static int csdio_ctrl_open(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_t *csdio_ctrl_drv = NULL; /* device information */
-
- pr_info("CSDIO ctrl open.\n");
- csdio_ctrl_drv = container_of(inode->i_cdev, struct csdio_t, m_cdev);
- filp->private_data = csdio_ctrl_drv; /* for other methods */
- return ret;
-}
-
-static int csdio_ctrl_release(struct inode *inode, struct file *filp)
-{
- pr_info("CSDIO ctrl release.\n");
- /* remove this filp from the asynchronously notified filp's */
- csdio_ctrl_fasync(-1, filp, 0);
- return 0;
-}
-
-static const struct file_operations csdio_ctrl_fops = {
- .owner = THIS_MODULE,
- .ioctl = csdio_ctrl_ioctl,
- .open = csdio_ctrl_open,
- .release = csdio_ctrl_release,
- .fasync = csdio_ctrl_fasync,
-};
-
-static int csdio_probe(struct sdio_func *func,
- const struct sdio_device_id *id)
-{
- struct csdio_func_t *port;
- int ret = 0;
- struct mmc_host *host = func->card->host;
-
- if (NULL != g_csdio.m_host && g_csdio.m_host != host) {
- pr_info("%s: Device is on unexpected host\n",
- CSDIO_DEV_NAME);
- ret = -ENODEV;
- goto exit;
- }
-
- /* enforce single instance policy */
- if (g_csdio_func_table[func->num-1]) {
- pr_err("%s - only single SDIO device supported",
- sdio_func_id(func));
- ret = -EEXIST;
- goto exit;
- }
-
- port = kzalloc(sizeof(struct csdio_func_t), GFP_KERNEL);
- if (!port) {
- pr_err("Can't allocate memory\n");
- ret = -ENOMEM;
- goto exit;
- }
-
- /* initialize SDIO side */
- port->m_func = func;
- sdio_set_drvdata(func, port);
-
- pr_info("%s - SDIO device found. Function %d\n",
- sdio_func_id(func), func->num);
-
- port->m_device = csdio_cdev_init(&port->m_cdev, &csdio_transport_fops,
- csdio_minor + port->m_func->num,
- TP_DEV_NAME, &port->m_func->dev);
-
- /* create appropriate char device */
- if (!port->m_device)
- goto free;
-
- if (0 == g_csdio.m_num_of_func && NULL == host_name)
- g_csdio.m_host = host;
- g_csdio.m_num_of_func++;
- g_csdio_func_table[func->num-1] = port;
- port->m_enabled = TRUE;
- goto exit;
-free:
- kfree(port);
-exit:
- return ret;
-}
-
-static void csdio_remove(struct sdio_func *func)
-{
- struct csdio_func_t *port = sdio_get_drvdata(func);
-
- csdio_transport_cleanup(port);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_disable_func(func);
- sdio_release_host(func);
- kfree(port);
- g_csdio_func_table[func->num-1] = NULL;
- g_csdio.m_num_of_func--;
- if (0 == g_csdio.m_num_of_func && NULL == host_name)
- g_csdio.m_host = NULL;
- pr_info("%s%d: Device removed (%s). Function %d\n",
- CSDIO_DEV_NAME, func->num, sdio_func_id(func), func->num);
-}
-
-/* CONFIG_CSDIO_VENDOR_ID and CONFIG_CSDIO_DEVICE_ID are defined in Kconfig.
- * Use kernel configuration to change the values or overwrite them through
- * module parameters */
-static struct sdio_device_id csdio_ids[] = {
- { SDIO_DEVICE(CONFIG_CSDIO_VENDOR_ID, CONFIG_CSDIO_DEVICE_ID) },
- { /* end: all zeroes */},
-};
-
-MODULE_DEVICE_TABLE(sdio, csdio_ids);
-
-static struct sdio_driver csdio_driver = {
- .probe = csdio_probe,
- .remove = csdio_remove,
- .name = "csdio",
- .id_table = csdio_ids,
-};
-
-static void __exit csdio_exit(void)
-{
- dev_t devno = MKDEV(csdio_major, csdio_minor);
-
- sdio_unregister_driver(&csdio_driver);
- sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
- kfree(g_sdio_buffer);
- device_destroy(g_csdio.m_driver_class, devno);
- cdev_del(&g_csdio.m_cdev);
- class_destroy(g_csdio.m_driver_class);
- unregister_chrdev_region(devno, csdio_transport_nr_devs);
- pr_info("%s: Exit driver module\n", CSDIO_DEV_NAME);
-}
-
-static char *csdio_devnode(struct device *dev, mode_t *mode)
-{
- *mode = CSDIO_DEV_PERMISSIONS;
- return NULL;
-}
-
-static int __init csdio_init(void)
-{
- int ret = 0;
- dev_t devno = 0;
-
- pr_info("Init CSDIO driver module.\n");
-
- /* Get a range of minor numbers to work with, asking for a dynamic */
- /* major unless directed otherwise at load time. */
- if (csdio_major) {
- devno = MKDEV(csdio_major, csdio_minor);
- ret = register_chrdev_region(devno, csdio_transport_nr_devs,
- CSDIO_DEV_NAME);
- } else {
- ret = alloc_chrdev_region(&devno, csdio_minor,
- csdio_transport_nr_devs, CSDIO_DEV_NAME);
- csdio_major = MAJOR(devno);
- }
- if (ret < 0) {
- pr_err("CSDIO: can't get major %d\n", csdio_major);
- goto exit;
- }
- pr_info("CSDIO char driver major number is %d\n", csdio_major);
-
- /* kernel module got parameters: overwrite vendor and device id's */
- if ((csdio_vendor_id != 0) && (csdio_device_id != 0)) {
- csdio_ids[0].vendor = (u16)csdio_vendor_id;
- csdio_ids[0].device = (u16)csdio_device_id;
- }
-
- /* prepare create /dev/... instance */
- g_csdio.m_driver_class = class_create(THIS_MODULE, CSDIO_DEV_NAME);
- if (IS_ERR(g_csdio.m_driver_class)) {
- ret = -ENOMEM;
- pr_err(CSDIO_DEV_NAME " class_create failed\n");
- goto unregister_region;
- }
- g_csdio.m_driver_class->devnode = csdio_devnode;
-
- /* create CSDIO ctrl driver */
- g_csdio.m_device = csdio_cdev_init(&g_csdio.m_cdev,
- &csdio_ctrl_fops, csdio_minor, CSDIO_DEV_NAME, NULL);
- if (!g_csdio.m_device) {
- pr_err("%s: Unable to create ctrl driver\n",
- CSDIO_DEV_NAME);
- goto destroy_class;
- }
-
- g_sdio_buffer = kmalloc(CSDIO_SDIO_BUFFER_SIZE, GFP_KERNEL);
- if (!g_sdio_buffer) {
- pr_err("Unable to allocate %d bytes\n", CSDIO_SDIO_BUFFER_SIZE);
- ret = -ENOMEM;
- goto destroy_cdev;
- }
-
- ret = sysfs_create_group(&g_csdio.m_device->kobj, &dev_attr_grp);
- if (ret) {
- pr_err("%s: Unable to create device attribute\n",
- CSDIO_DEV_NAME);
- goto free_sdio_buff;
- }
-
- g_csdio.m_num_of_func = 0;
- g_csdio.m_host = NULL;
-
- if (NULL != host_name) {
- struct device *dev = bus_find_device_by_name(&platform_bus_type,
- NULL, host_name);
- if (NULL != dev) {
- g_csdio.m_host = dev_get_drvdata(dev);
- } else {
- pr_err("%s: Host '%s' doesn't exist!\n", CSDIO_DEV_NAME,
- host_name);
- }
- }
-
- pr_info("%s: Match with VendorId=0x%X, DeviceId=0x%X, Host = %s\n",
- CSDIO_DEV_NAME, csdio_device_id, csdio_vendor_id,
- (NULL == host_name) ? "Any" : host_name);
-
- /* register sdio driver */
- ret = sdio_register_driver(&csdio_driver);
- if (ret) {
- pr_err("%s: Unable to register as SDIO driver\n",
- CSDIO_DEV_NAME);
- goto remove_group;
- }
-
- goto exit;
-
-remove_group:
- sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
-free_sdio_buff:
- kfree(g_sdio_buffer);
-destroy_cdev:
- cdev_del(&g_csdio.m_cdev);
-destroy_class:
- class_destroy(g_csdio.m_driver_class);
-unregister_region:
- unregister_chrdev_region(devno, csdio_transport_nr_devs);
-exit:
- return ret;
-}
-module_param(csdio_vendor_id, uint, S_IRUGO);
-module_param(csdio_device_id, uint, S_IRUGO);
-module_param(host_name, charp, S_IRUGO);
-
-module_init(csdio_init);
-module_exit(csdio_exit);
-
-MODULE_AUTHOR("The Linux Foundation");
-MODULE_DESCRIPTION("CSDIO device driver version " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 03304dc..c9be39a 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -24,7 +24,7 @@
#define DISABLE_LOG_MASK 0
#define MAX_EVENT_SIZE 512
#define DCI_CLIENT_INDEX_INVALID -1
-#define DCI_PKT_REQ_MIN_LEN 8
+#define DCI_PKT_REQ_MIN_LEN 5
#define DCI_LOG_CON_MIN_LEN 14
#define DCI_EVENT_CON_MIN_LEN 16
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4f5893c..8f7d39c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -318,6 +318,7 @@
show_one(down_differential, down_differential);
show_one(sampling_down_factor, sampling_down_factor);
show_one(ignore_nice_load, ignore_nice);
+show_one(down_differential_multi_core, down_differential_multi_core);
show_one(optimal_freq, optimal_freq);
show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load);
show_one(sync_freq, sync_freq);
@@ -437,6 +438,20 @@
return count;
}
+static ssize_t store_down_differential_multi_core(struct kobject *a,
+ struct attribute *b, const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+ dbs_tuners_ins.down_differential_multi_core = input;
+ return count;
+}
+
+
static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -695,6 +710,7 @@
define_one_global_rw(ignore_nice_load);
define_one_global_rw(powersave_bias);
define_one_global_rw(up_threshold_multi_core);
+define_one_global_rw(down_differential_multi_core);
define_one_global_rw(optimal_freq);
define_one_global_rw(up_threshold_any_cpu_load);
define_one_global_rw(sync_freq);
@@ -710,6 +726,7 @@
&powersave_bias.attr,
&io_is_busy.attr,
&up_threshold_multi_core.attr,
+ &down_differential_multi_core.attr,
&optimal_freq.attr,
&up_threshold_any_cpu_load.attr,
&sync_freq.attr,
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0809308..514385c 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -36,6 +36,7 @@
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/dma-buf.h>
+#include <linux/idr.h>
#include <linux/msm_ion.h>
#include <trace/events/kmem.h>
@@ -70,6 +71,7 @@
* @node: node in the tree of all clients
* @dev: backpointer to ion device
* @handles: an rb tree of all the handles in this client
+ * @idr: an idr space for allocating handle ids
* @lock: lock protecting the tree of handles
* @name: used for debugging
* @task: used for debugging
@@ -82,6 +84,7 @@
struct rb_node node;
struct ion_device *dev;
struct rb_root handles;
+ struct idr idr;
struct mutex lock;
char *name;
struct task_struct *task;
@@ -96,7 +99,7 @@
* @buffer: pointer to the buffer
* @node: node in the client's handle rbtree
* @kmap_cnt: count of times this client has mapped to kernel
- * @dmap_cnt: count of times this client has mapped for dma
+ * @id: client-unique id allocated by client->idr
*
* Modifications to node, map_cnt or mapping should be protected by the
* lock in the client. Other fields are never changed after initialization.
@@ -107,6 +110,7 @@
struct ion_buffer *buffer;
struct rb_node node;
unsigned int kmap_cnt;
+ int id;
};
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -343,6 +347,7 @@
ion_handle_kmap_put(handle);
mutex_unlock(&buffer->lock);
+ idr_remove(&client->idr, handle->id);
if (!RB_EMPTY_NODE(&handle->node))
rb_erase(&handle->node, &client->handles);
@@ -362,9 +367,16 @@
kref_get(&handle->ref);
}
-static int ion_handle_put(struct ion_handle *handle)
+int ion_handle_put(struct ion_handle *handle)
{
- return kref_put(&handle->ref, ion_handle_destroy);
+ struct ion_client *client = handle->client;
+ int ret;
+
+ mutex_lock(&client->lock);
+ ret = kref_put(&handle->ref, ion_handle_destroy);
+ mutex_unlock(&client->lock);
+
+ return ret;
}
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
@@ -374,36 +386,52 @@
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
- node);
+ node);
if (handle->buffer == buffer)
return handle;
}
return NULL;
}
-static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+ int id)
{
- struct rb_node *n = client->handles.rb_node;
+ struct ion_handle *handle;
- while (n) {
- struct ion_handle *handle_node = rb_entry(n, struct ion_handle,
- node);
- if (handle < handle_node)
- n = n->rb_left;
- else if (handle > handle_node)
- n = n->rb_right;
- else
- return true;
- }
- return false;
+ mutex_lock(&client->lock);
+ handle = idr_find(&client->idr, id);
+ if (handle)
+ ion_handle_get(handle);
+ mutex_unlock(&client->lock);
+
+ return handle ? handle : ERR_PTR(-EINVAL);
}
-static void ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
{
+ WARN_ON(!mutex_is_locked(&client->lock));
+ return (idr_find(&client->idr, handle->id) == handle);
+}
+
+static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+{
+ int rc;
struct rb_node **p = &client->handles.rb_node;
struct rb_node *parent = NULL;
struct ion_handle *entry;
+ do {
+ int id;
+ rc = idr_pre_get(&client->idr, GFP_KERNEL);
+ if (!rc)
+ return -ENOMEM;
+ rc = idr_get_new_above(&client->idr, handle, 1, &id);
+ handle->id = id;
+ } while (rc == -EAGAIN);
+
+ if (rc < 0)
+ return rc;
+
while (*p) {
parent = *p;
entry = rb_entry(parent, struct ion_handle, node);
@@ -418,6 +446,8 @@
rb_link_node(&handle->node, parent, p);
rb_insert_color(&handle->node, &client->handles);
+
+ return 0;
}
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
@@ -428,6 +458,7 @@
struct ion_device *dev = client->dev;
struct ion_buffer *buffer = NULL;
struct ion_heap *heap;
+ int ret;
unsigned long secure_allocation = flags & ION_FLAG_SECURE;
const unsigned int MAX_DBG_STR_LEN = 64;
char dbg_str[MAX_DBG_STR_LEN];
@@ -518,12 +549,16 @@
*/
ion_buffer_put(buffer);
- if (!IS_ERR(handle)) {
- mutex_lock(&client->lock);
- ion_handle_add(client, handle);
- mutex_unlock(&client->lock);
- }
+ if (IS_ERR(handle))
+ return handle;
+ mutex_lock(&client->lock);
+ ret = ion_handle_add(client, handle);
+ mutex_unlock(&client->lock);
+ if (ret) {
+ ion_handle_put(handle);
+ handle = ERR_PTR(ret);
+ }
return handle;
}
@@ -542,8 +577,8 @@
mutex_unlock(&client->lock);
return;
}
- ion_handle_put(handle);
mutex_unlock(&client->lock);
+ ion_handle_put(handle);
}
EXPORT_SYMBOL(ion_free);
@@ -775,6 +810,7 @@
client->dev = dev;
client->handles = RB_ROOT;
+ idr_init(&client->idr);
mutex_init(&client->lock);
client->name = kzalloc(name_len+1, GFP_KERNEL);
@@ -831,6 +867,10 @@
node);
ion_handle_destroy(&handle->ref);
}
+
+ idr_remove_all(&client->idr);
+ idr_destroy(&client->idr);
+
down_write(&dev->lock);
if (client->task)
put_task_struct(client->task);
@@ -1175,14 +1215,15 @@
mutex_lock(&client->lock);
valid_handle = ion_handle_validate(client, handle);
- mutex_unlock(&client->lock);
if (!valid_handle) {
WARN(1, "%s: invalid handle passed to share.\n", __func__);
+ mutex_unlock(&client->lock);
return ERR_PTR(-EINVAL);
}
-
buffer = handle->buffer;
ion_buffer_get(buffer);
+ mutex_unlock(&client->lock);
+
dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
if (IS_ERR(dmabuf)) {
ion_buffer_put(buffer);
@@ -1215,6 +1256,7 @@
struct dma_buf *dmabuf;
struct ion_buffer *buffer;
struct ion_handle *handle;
+ int ret;
dmabuf = dma_buf_get(fd);
if (IS_ERR_OR_NULL(dmabuf))
@@ -1234,14 +1276,24 @@
handle = ion_handle_lookup(client, buffer);
if (!IS_ERR_OR_NULL(handle)) {
ion_handle_get(handle);
+ mutex_unlock(&client->lock);
goto end;
}
+ mutex_unlock(&client->lock);
+
handle = ion_handle_create(client, buffer);
if (IS_ERR_OR_NULL(handle))
goto end;
- ion_handle_add(client, handle);
-end:
+
+ mutex_lock(&client->lock);
+ ret = ion_handle_add(client, handle);
mutex_unlock(&client->lock);
+ if (ret) {
+ ion_handle_put(handle);
+ handle = ERR_PTR(ret);
+ }
+
+end:
dma_buf_put(dmabuf);
return handle;
}
@@ -1279,17 +1331,20 @@
case ION_IOC_ALLOC:
{
struct ion_allocation_data data;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
- data.handle = ion_alloc(client, data.len, data.align,
+ handle = ion_alloc(client, data.len, data.align,
data.heap_mask, data.flags);
- if (IS_ERR(data.handle))
- return PTR_ERR(data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ data.handle = (ion_user_handle_t)handle->id;
if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
- ion_free(client, data.handle);
+ ion_free(client, handle);
return -EFAULT;
}
break;
@@ -1297,28 +1352,31 @@
case ION_IOC_FREE:
{
struct ion_handle_data data;
- bool valid;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_handle_data)))
return -EFAULT;
- mutex_lock(&client->lock);
- valid = ion_handle_validate(client, data.handle);
- mutex_unlock(&client->lock);
- if (!valid)
- return -EINVAL;
- ion_free(client, data.handle);
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ion_free(client, handle);
+ ion_handle_put(handle);
break;
}
case ION_IOC_SHARE:
case ION_IOC_MAP:
{
struct ion_fd_data data;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
- data.fd = ion_share_dma_buf_fd(client, data.handle);
-
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ data.fd = ion_share_dma_buf_fd(client, handle);
+ ion_handle_put(handle);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
if (data.fd < 0)
@@ -1328,15 +1386,17 @@
case ION_IOC_IMPORT:
{
struct ion_fd_data data;
+ struct ion_handle *handle;
int ret = 0;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
- data.handle = ion_import_dma_buf(client, data.fd);
- if (IS_ERR(data.handle)) {
- ret = PTR_ERR(data.handle);
- data.handle = NULL;
- }
+ handle = ion_import_dma_buf(client, data.fd);
+ if (IS_ERR(handle))
+ ret = PTR_ERR(handle);
+ else
+ data.handle = (ion_user_handle_t)handle->id;
+
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_fd_data)))
return -EFAULT;
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index f5d0287..aa0a9e2 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -396,4 +396,9 @@
int ion_walk_heaps(struct ion_client *client, int heap_id, void *data,
int (*f)(struct ion_heap *heap, void *data));
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+ int id);
+
+int ion_handle_put(struct ion_handle *handle);
+
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 213bcb1..cdd31e1 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -973,11 +973,18 @@
sizeof(struct ion_flush_data)))
return -EFAULT;
- if (!data.handle) {
+ if (data.handle >= 0) {
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle)) {
+ pr_info("%s: Could not find handle: %d\n",
+ __func__, (int)data.handle);
+ return PTR_ERR(handle);
+ }
+ } else {
handle = ion_import_dma_buf(client, data.fd);
if (IS_ERR(handle)) {
- pr_info("%s: Could not import handle: %d\n",
- __func__, (int)handle);
+ pr_info("%s: Could not import handle: %p\n",
+ __func__, handle);
return -EINVAL;
}
}
@@ -988,28 +995,20 @@
end = (unsigned long) data.vaddr + data.length;
if (start && check_vaddr_bounds(start, end)) {
- up_read(&mm->mmap_sem);
pr_err("%s: virtual address %p is out of bounds\n",
__func__, data.vaddr);
- if (!data.handle)
- ion_free(client, handle);
- return -EINVAL;
+ ret = -EINVAL;
+ } else {
+ ret = ion_do_cache_op(client, handle, data.vaddr,
+ data.offset, data.length, cmd);
}
-
- ret = ion_do_cache_op(client,
- data.handle ? data.handle : handle,
- data.vaddr, data.offset, data.length,
- cmd);
-
up_read(&mm->mmap_sem);
- if (!data.handle)
- ion_free(client, handle);
+ ion_free(client, handle);
if (ret < 0)
return ret;
break;
-
}
case ION_IOC_PREFETCH:
{
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 070b5ac..eba60ea 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2051,6 +2051,8 @@
device->reset_counter++;
+ set_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
return 0;
error_rb_stop:
@@ -2088,7 +2090,25 @@
set_user_nice(current, _wake_nice);
mutex_lock(&device->mutex);
- _status = _adreno_start(adreno_dev);
+ /*
+ * If adreno start is already called, no need to call it again
+ * it can lead to unpredictable behavior if we try to start
+ * the device that is already started.
+ * Below is the sequence of events that can go bad without the check
+ * 1) thread 1 calls adreno_start to be scheduled on high priority wq
+ * 2) thread 2 calls adreno_start with normal priority
+ * 3) thread 1 after checking the device to be in slumber state gives
+ * up mutex to be scheduled on high priority wq
+ * 4) thread 2 after checking the device to be in slumber state gets
+ * the mutex and finishes adreno_start before thread 1 is scheduled
+ * on high priority wq.
+ * 5) thread 1 gets scheduled on high priority wq and executes
+ * adreno_start again. This leads to unpredictable behavior.
+ */
+ if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv))
+ _status = _adreno_start(adreno_dev);
+ else
+ _status = 0;
mutex_unlock(&device->mutex);
}
@@ -2149,6 +2169,8 @@
kgsl_cffdump_close(device);
+ clear_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
return 0;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 1b538a7..800caf1 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -216,6 +216,7 @@
ADRENO_DEVICE_PWRON = 0,
ADRENO_DEVICE_PWRON_FIXUP = 1,
ADRENO_DEVICE_INITIALIZED = 2,
+ ADRENO_DEVICE_STARTED = 3,
};
#define PERFCOUNTER_FLAG_NONE 0x0
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index e5f5ad7..3d4c66a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -4077,6 +4077,7 @@
static int a3xx_perfcounter_init(struct adreno_device *adreno_dev)
{
int ret;
+ struct kgsl_device *device = &adreno_dev->dev;
/* SP[3] counter is broken on a330 so disable it if a330 device */
if (adreno_is_a330(adreno_dev))
a3xx_perfcounters_sp[3].countable = KGSL_PERFCOUNTER_BROKEN;
@@ -4088,15 +4089,18 @@
ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
NULL, PERFCOUNTER_FLAG_KERNEL);
- /* VBIF waiting for RAM */
- ret |= adreno_perfcounter_get(adreno_dev,
+ if (device->pwrctrl.bus_control) {
+ /* VBIF waiting for RAM */
+ ret |= adreno_perfcounter_get(adreno_dev,
KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
NULL, PERFCOUNTER_FLAG_KERNEL);
- /* VBIF DDR cycles */
- ret |= adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF,
+ /* VBIF DDR cycles */
+ ret |= adreno_perfcounter_get(adreno_dev,
+ KGSL_PERFCOUNTER_GROUP_VBIF,
VBIF_AXI_TOTAL_BEATS,
&adreno_dev->ram_cycles_lo,
PERFCOUNTER_FLAG_KERNEL);
+ }
/* Default performance counter profiling to false */
adreno_dev->profile.enabled = false;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fe99a4b..9aefda6 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2878,7 +2878,7 @@
bool full_flush = false;
if (param->id_list == NULL || param->count == 0
- || param->count > (UINT_MAX/sizeof(unsigned int)))
+ || param->count > (PAGE_SIZE / sizeof(unsigned int)))
return -EINVAL;
id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 505be69..f0114ad 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -141,7 +141,7 @@
static inline void *kgsl_sg_alloc(unsigned int sglen)
{
- if (sglen >= ULONG_MAX / sizeof(struct scatterlist))
+ if ((sglen == 0) || (sglen >= ULONG_MAX / sizeof(struct scatterlist)))
return NULL;
if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index ceeb67b..5c89c0c 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -17,7 +17,6 @@
*/
#include <linux/delay.h>
-#include <linux/earlysuspend.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/sensors.h>
@@ -118,7 +117,6 @@
struct input_dev *ls_input_dev;
struct input_dev *ps_input_dev;
- struct early_suspend early_suspend;
struct i2c_client *i2c_client;
struct workqueue_struct *lp_wq;
@@ -1426,29 +1424,6 @@
return ret;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void cm36283_early_suspend(struct early_suspend *h)
-{
- struct cm36283_info *lpi = lp_info;
-
- D("[LS][CM36283] %s\n", __func__);
-
- if (lpi->als_enable)
- lightsensor_disable(lpi);
-
-}
-
-static void cm36283_late_resume(struct early_suspend *h)
-{
- struct cm36283_info *lpi = lp_info;
-
- D("[LS][CM36283] %s\n", __func__);
-
- if (!lpi->als_enable)
- lightsensor_enable(lpi);
-}
-#endif
-
static int cm36283_parse_dt(struct device *dev,
struct cm36283_platform_data *pdata)
{
@@ -1744,13 +1719,6 @@
if (ret)
goto err_create_ps_device_file;
-#ifdef CONFIG_HAS_EARLYSUSPEND
- lpi->early_suspend.level =
- EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- lpi->early_suspend.suspend = cm36283_early_suspend;
- lpi->early_suspend.resume = cm36283_late_resume;
- register_early_suspend(&lpi->early_suspend);
-#endif
ret = sensors_classdev_register(&client->dev, &sensors_light_cdev);
if (ret)
goto err_create_ps_device_file;
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 3b7bf5a..fab209e 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -325,32 +325,32 @@
{
struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
unsigned long val;
+ u32 enable;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
- sensor->enable = (u32)val == 0 ? 0 : 1;
- if (sensor->enable) {
+ enable = (u32)val == 0 ? 0 : 1;
+ if (enable && (!sensor->enable)) {
+ sensor->enable = enable;
pm_runtime_get_sync(sensor->dev);
- gpio_set_value(sensor->enable_gpio, 1);
if (sensor->use_poll)
schedule_delayed_work(&sensor->input_work,
msecs_to_jiffies(sensor->poll_interval));
- else {
- i2c_smbus_write_byte_data(sensor->client,
- MPU3050_INT_CFG,
- MPU3050_ACTIVE_LOW |
- MPU3050_OPEN_DRAIN |
- MPU3050_RAW_RDY_EN);
+ else
enable_irq(sensor->client->irq);
- }
- } else {
+ } else if (!enable && sensor->enable) {
if (sensor->use_poll)
cancel_delayed_work_sync(&sensor->input_work);
else
disable_irq(sensor->client->irq);
- gpio_set_value(sensor->enable_gpio, 0);
- pm_runtime_put(sensor->dev);
+ pm_runtime_put_sync(sensor->dev);
+ sensor->enable = enable;
+ } else {
+ dev_warn(&sensor->client->dev,
+ "ignore enable state change from %d to %d\n",
+ sensor->enable, enable);
}
+
return count;
}
@@ -485,54 +485,6 @@
}
/**
- * mpu3050_input_open - called on input event open
- * @input: input dev of opened device
- *
- * The input layer calls this function when input event is opened. The
- * function will push the device to resume. Then, the device is ready
- * to provide data.
- */
-static int mpu3050_input_open(struct input_dev *input)
-{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
- int error;
-
- pm_runtime_get_sync(sensor->dev);
-
- /* Enable interrupts */
- error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
- MPU3050_ACTIVE_LOW |
- MPU3050_OPEN_DRAIN |
- MPU3050_RAW_RDY_EN);
- if (error < 0) {
- pm_runtime_put(sensor->dev);
- return error;
- }
- if (sensor->use_poll)
- schedule_delayed_work(&sensor->input_work,
- msecs_to_jiffies(sensor->poll_interval));
-
- return 0;
-}
-
-/**
- * mpu3050_input_close - called on input event close
- * @input: input dev of closed device
- *
- * The input layer calls this function when input event is closed. The
- * function will push the device to suspend.
- */
-static void mpu3050_input_close(struct input_dev *input)
-{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
-
- if (sensor->use_poll)
- cancel_delayed_work_sync(&sensor->input_work);
-
- pm_runtime_put(sensor->dev);
-}
-
-/**
* mpu3050_interrupt_thread - handle an IRQ
* @irq: interrupt numner
* @data: the sensor
@@ -588,18 +540,12 @@
*
* Called during device probe; configures the sampling method.
*/
-static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
+static int mpu3050_hw_init(struct mpu3050_sensor *sensor)
{
struct i2c_client *client = sensor->client;
int ret;
u8 reg;
- /* Reset */
- ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM,
- MPU3050_PWR_MGM_RESET);
- if (ret < 0)
- return ret;
-
ret = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
if (ret < 0)
return ret;
@@ -624,6 +570,16 @@
if (ret < 0)
return ret;
+ /* Enable interrupts */
+ if (!sensor->use_poll) {
+ reg = MPU3050_ACTIVE_LOW;
+ reg |= MPU3050_OPEN_DRAIN;
+ reg |= MPU3050_RAW_RDY_EN;
+ ret = i2c_smbus_write_byte_data(client, MPU3050_INT_CFG, reg);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
#ifdef CONFIG_OF
@@ -750,9 +706,6 @@
idev->name = "MPU3050";
idev->id.bustype = BUS_I2C;
- idev->open = mpu3050_input_open;
- idev->close = mpu3050_input_close;
-
input_set_capability(idev, EV_ABS, ABS_MISC);
input_set_abs_params(idev, ABS_X,
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
@@ -813,6 +766,9 @@
disable_irq(client->irq);
}
+ sensor->enable = 0;
+ mpu3050_set_power_mode(client, 0);
+
error = input_register_device(idev);
if (error) {
dev_err(&client->dev, "failed to register input device\n");
@@ -893,10 +849,11 @@
struct i2c_client *client = to_i2c_client(dev);
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
- if (!sensor->use_poll)
- disable_irq(client->irq);
-
- mpu3050_set_power_mode(client, 0);
+ if (sensor->enable) {
+ if (!sensor->use_poll)
+ disable_irq(client->irq);
+ mpu3050_set_power_mode(client, 0);
+ }
return 0;
}
@@ -912,16 +869,64 @@
struct i2c_client *client = to_i2c_client(dev);
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
- mpu3050_set_power_mode(client, 1);
+ if (sensor->enable) {
+ mpu3050_set_power_mode(client, 1);
+ mpu3050_hw_init(sensor);
+ if (!sensor->use_poll)
+ enable_irq(client->irq);
+ }
- if (!sensor->use_poll)
- enable_irq(client->irq);
+ return 0;
+}
+
+/**
+ * mpu3050_runtime_suspend - called on device enters runtime suspend
+ * @dev: device being suspended
+ *
+ * Put the device into sleep mode.
+ */
+static int mpu3050_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (sensor->enable)
+ mpu3050_set_power_mode(client, 0);
+
+ return 0;
+}
+
+/**
+ * mpu3050_runtime_resume - called on device enters runtime resume
+ * @dev: device being resumed
+ *
+ * Put the device into powered mode.
+ */
+static int mpu3050_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (sensor->enable) {
+ mpu3050_set_power_mode(client, 1);
+ mpu3050_hw_init(sensor);
+ }
return 0;
}
#endif
-static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
+static const struct dev_pm_ops mpu3050_pm = {
+ .runtime_suspend = mpu3050_runtime_suspend,
+ .runtime_resume = mpu3050_runtime_resume,
+ .runtime_idle = NULL,
+ .suspend = mpu3050_suspend,
+ .resume = mpu3050_resume,
+ .freeze = mpu3050_suspend,
+ .thaw = mpu3050_resume,
+ .poweroff = mpu3050_suspend,
+ .restore = mpu3050_resume,
+};
static const struct i2c_device_id mpu3050_ids[] = {
{ "mpu3050", 0 },
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 755084c..7152ec8 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -2424,6 +2424,8 @@
}
}
+ INIT_LIST_HEAD(&rmi->support_fn_list);
+
retval = synaptics_rmi4_query_device(rmi4_data);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 7954296..e776dbb 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -713,7 +713,7 @@
duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
/*config pwm for brightness scaling*/
- rc = pwm_config(led->mpp_cfg->pwm_cfg->pwm_dev,
+ rc = pwm_config_us(led->mpp_cfg->pwm_cfg->pwm_dev,
duty_us,
led->mpp_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
@@ -1239,7 +1239,7 @@
if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / KPDBL_MAX_LEVEL;
- rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev,
+ rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev,
duty_us,
led->kpdbl_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
@@ -1261,7 +1261,7 @@
led->kpdbl_cfg->pwm_cfg->default_mode;
if (led->kpdbl_cfg->always_on) {
- rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
+ rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
led->kpdbl_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
@@ -1310,7 +1310,8 @@
if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
- rc = pwm_config(led->rgb_cfg->pwm_cfg->pwm_dev, duty_us,
+ rc = pwm_config_us(led->rgb_cfg->pwm_cfg->pwm_dev,
+ duty_us,
led->rgb_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 2be1f01..59b648d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -122,6 +122,8 @@
{
int i, rc = -1;
struct msm_isp_buffer_mapped_info *mapped_info;
+ struct buffer_cmd *buf_pending = NULL;
+
for (i = 0; i < v4l2_buf->length; i++) {
mapped_info = &buf_info->mapped_info[i];
mapped_info->handle =
@@ -144,6 +146,15 @@
mapped_info->paddr += v4l2_buf->m.planes[i].data_offset;
CDBG("%s: plane: %d addr:%lu\n",
__func__, i, mapped_info->paddr);
+
+ buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC);
+ if (!buf_pending) {
+ pr_err("No free memory for buf_pending\n");
+ return rc;
+ }
+
+ buf_pending->mapped_info = mapped_info;
+ list_add_tail(&buf_pending->list, &buf_mgr->buffer_q);
}
buf_info->num_planes = v4l2_buf->length;
return 0;
@@ -163,11 +174,26 @@
{
int i;
struct msm_isp_buffer_mapped_info *mapped_info;
+ struct buffer_cmd *buf_pending = NULL;
+
for (i = 0; i < buf_info->num_planes; i++) {
mapped_info = &buf_info->mapped_info[i];
- ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
- buf_mgr->iommu_domain_num, 0);
- ion_free(buf_mgr->client, mapped_info->handle);
+
+ list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+ if (!buf_pending)
+ break;
+
+ if (buf_pending->mapped_info == mapped_info) {
+ ion_unmap_iommu(buf_mgr->client,
+ mapped_info->handle,
+ buf_mgr->iommu_domain_num, 0);
+ ion_free(buf_mgr->client, mapped_info->handle);
+
+ list_del_init(&buf_pending->list);
+ kfree(buf_pending);
+ break;
+ }
+ }
}
return;
}
@@ -586,7 +612,7 @@
}
} else {
bufq = msm_isp_get_bufq(buf_mgr, info->handle);
- if (BUF_SRC(bufq->stream_id)) {
+ if (bufq && BUF_SRC(bufq->stream_id)) {
rc = msm_isp_put_buf(buf_mgr,
info->handle, info->buf_idx);
if (rc < 0) {
@@ -691,6 +717,7 @@
if (!bufq->bufq_handle)
continue;
msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle);
+
kfree(bufq->bufs);
msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle);
}
@@ -739,9 +766,10 @@
pr_err("Invalid buffer queue number\n");
return rc;
}
-
CDBG("%s: E\n", __func__);
+
msm_isp_attach_ctx(buf_mgr);
+ INIT_LIST_HEAD(&buf_mgr->buffer_q);
buf_mgr->num_buf_q = num_buf_q;
buf_mgr->bufq =
kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index 6d6ff9d..d8d3ba2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -44,6 +44,11 @@
struct ion_handle *handle;
};
+struct buffer_cmd {
+ struct list_head list;
+ struct msm_isp_buffer_mapped_info *mapped_info;
+};
+
struct msm_isp_buffer {
/*Common Data structure*/
int num_planes;
@@ -138,6 +143,7 @@
int num_iommu_ctx;
struct device *iommu_ctx[2];
+ struct list_head buffer_q;
};
int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 2c5e136..80a0073 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -140,6 +140,7 @@
&vfe_vb2_ops, &vfe_layout);
if (rc < 0) {
pr_err("%s: Unable to create buffer manager\n", __func__);
+ msm_sd_unregister(&vfe_dev->subdev);
kfree(vfe_dev);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 87bffde..9dd0085 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -106,7 +106,7 @@
uint32_t reload_mask);
void (*enable_wm) (struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
- void (*cfg_io_format) (struct vfe_device *vfe_dev,
+ int32_t (*cfg_io_format) (struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src,
uint32_t io_format);
void (*cfg_framedrop) (struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index f5529cd..410fe8f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -74,6 +74,8 @@
goto fs_failed;
}
}
+ else
+ goto fs_failed;
rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
@@ -495,12 +497,17 @@
}
}
-static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
uint32_t io_format_reg;
bpp = msm_isp_get_bit_per_pixel(io_format);
+ if (bpp < 0) {
+ pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+ io_format, bpp);
+ return -EINVAL;
+ }
switch (bpp) {
case 8:
@@ -512,6 +519,9 @@
case 12:
bpp_reg = 1 << 1;
break;
+ default:
+ pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+ return -EINVAL;
}
if (stream_src == IDEAL_RAW) {
@@ -537,7 +547,7 @@
break;
default:
pr_err("%s: invalid pack fmt!\n", __func__);
- return;
+ return -EINVAL;
}
}
@@ -558,9 +568,10 @@
case RDI_INTF_2:
default:
pr_err("%s: Invalid stream source\n", __func__);
- return;
+ return -EINVAL;
}
msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8);
+ return 0;
}
static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 50a25bd..ad4b75f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -268,6 +268,8 @@
goto fs_failed;
}
}
+ else
+ goto fs_failed;
rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe40_clk_info), 1);
@@ -724,13 +726,18 @@
VFE40_WM_BASE(stream_info->wm[i]) + 0x1C);
}
-static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
int bpp, bpp_reg = 0, pack_reg = 0;
enum msm_isp_pack_fmt pack_fmt = 0;
uint32_t io_format_reg; /*io format register bit*/
bpp = msm_isp_get_bit_per_pixel(io_format);
+ if (bpp < 0) {
+ pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+ io_format, bpp);
+ return -EINVAL;
+ }
switch (bpp) {
case 8:
@@ -742,6 +749,9 @@
case 12:
bpp_reg = 1 << 1;
break;
+ default:
+ pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+ return -EINVAL;
}
if (stream_src == IDEAL_RAW) {
@@ -768,7 +778,7 @@
break;
default:
pr_err("%s: invalid pack fmt!\n", __func__);
- return;
+ return -EINVAL;
}
}
@@ -789,9 +799,10 @@
case RDI_INTF_2:
default:
pr_err("%s: Invalid stream source\n", __func__);
- return;
+ return -EINVAL;
}
msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54);
+ return 0;
}
static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev,
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 3202cdb..97b6347 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
@@ -68,9 +68,17 @@
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
{
int rc = -1, i;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
+ struct msm_vfe_axi_stream *stream_info = NULL;
+ uint32_t idx = 0;
+
+ if (NULL == stream_cfg_cmd || NULL == axi_data)
+ return rc;
+
+ idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+ if (idx < MAX_NUM_STREAM)
+ stream_info = &axi_data->stream_info[idx];
+ else
+ return rc;
switch (stream_cfg_cmd->output_format) {
case V4L2_PIX_FMT_SBGGR8:
@@ -428,11 +436,22 @@
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
{
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
- uint32_t framedrop_period = msm_isp_get_framedrop_period(
- stream_cfg_cmd->frame_skip_pattern);
+ struct msm_vfe_axi_stream *stream_info = NULL;
+ uint32_t framedrop_period = 0;
+ uint8_t idx = 0;
+
+ if (NULL == axi_data || NULL == stream_cfg_cmd)
+ return;
+
+ idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+
+ if (idx < MAX_NUM_STREAM)
+ stream_info = &axi_data->stream_info[idx];
+ else
+ return;
+
+ framedrop_period = msm_isp_get_framedrop_period(
+ stream_cfg_cmd->frame_skip_pattern);
if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
@@ -520,8 +539,17 @@
io_format = stream_info->output_format;
}
- vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
+ rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
vfe_dev, stream_info->stream_src, io_format);
+ if (rc) {
+ pr_err("%s: cfg io format failed\n", __func__);
+ msm_isp_axi_free_wm(&vfe_dev->axi_data,
+ stream_info);
+ msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
+ HANDLE_TO_IDX(
+ stream_cfg_cmd->axi_stream_handle));
+ return rc;
+ }
}
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
@@ -763,8 +791,9 @@
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle, &buf);
if (rc < 0) {
- vfe_dev->error_info.
- stream_framedrop_count[stream_idx]++;
+ if(stream_idx < MAX_NUM_STREAM)
+ vfe_dev->error_info.
+ stream_framedrop_count[stream_idx]++;
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index b479857..8b83144 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -39,8 +39,9 @@
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle, &buf);
if (rc < 0) {
- vfe_dev->error_info.stats_framedrop_count[
- STATS_IDX(stream_info->stream_handle)]++;
+ uint8_t idx = STATS_IDX(stream_info->stream_handle);
+ if (idx < MSM_ISP_STATS_MAX)
+ vfe_dev->error_info.stats_framedrop_count[idx]++;
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ea0195d..3cb48d1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -77,6 +77,25 @@
.name = "msm_camera_isp",
};
+static void msm_isp_print_fourcc_error(const char *origin,
+ uint32_t fourcc_format)
+{
+ int i;
+ char text[5];
+ text[4] = '\0';
+ for (i = 0; i < 4; i++) {
+ text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF);
+ if ((text[i] < '0') || (text[i] > 'z')) {
+ pr_err("%s: Invalid output format %d (unprintable)\n",
+ origin, fourcc_format);
+ return;
+ }
+ }
+ pr_err("%s: Invalid output format %s\n",
+ origin, text);
+ return;
+}
+
int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client)
{
int rc = 0;
@@ -735,7 +754,7 @@
break;
/*TD: Add more image format*/
default:
- pr_err("%s: Invalid output format\n", __func__);
+ msm_isp_print_fourcc_error(__func__, output_format);
break;
}
return val;
@@ -771,7 +790,7 @@
case V4L2_PIX_FMT_QRGGB12:
return QCOM;
default:
- pr_err("%s: Invalid output format\n", __func__);
+ msm_isp_print_fourcc_error(__func__, output_format);
break;
}
return -EINVAL;
@@ -780,6 +799,10 @@
int msm_isp_get_bit_per_pixel(uint32_t output_format)
{
switch (output_format) {
+ case V4L2_PIX_FMT_Y4:
+ return 4;
+ case V4L2_PIX_FMT_Y6:
+ return 6;
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -790,6 +813,29 @@
case V4L2_PIX_FMT_QRGGB8:
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_META:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV14:
+ case V4L2_PIX_FMT_NV41:
+ case V4L2_PIX_FMT_YVU410:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YYUV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV411P:
+ case V4L2_PIX_FMT_Y41P:
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_YUV555:
+ case V4L2_PIX_FMT_YUV565:
+ case V4L2_PIX_FMT_YUV32:
+ case V4L2_PIX_FMT_YUV410:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_PAL8:
+ case MSM_V4L2_PIX_FMT_META:
return 8;
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGBRG10:
@@ -799,6 +845,8 @@
case V4L2_PIX_FMT_QGBRG10:
case V4L2_PIX_FMT_QGRBG10:
case V4L2_PIX_FMT_QRGGB10:
+ case V4L2_PIX_FMT_Y10:
+ case V4L2_PIX_FMT_Y10BPACK:
return 10;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
@@ -808,21 +856,17 @@
case V4L2_PIX_FMT_QGBRG12:
case V4L2_PIX_FMT_QGRBG12:
case V4L2_PIX_FMT_QRGGB12:
+ case V4L2_PIX_FMT_Y12:
return 12;
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV14:
- case V4L2_PIX_FMT_NV41:
- return 8;
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_Y16:
return 16;
/*TD: Add more image format*/
default:
- pr_err("%s: Invalid output format\n", __func__);
- break;
+ msm_isp_print_fourcc_error(__func__, output_format);
+ return -EINVAL;
}
- return -EINVAL;
}
void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 8f080ce..407b81f 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -31,14 +31,19 @@
int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
long clk_rate)
{
- struct msm_cam_clk_info jpeg_core_clk_info[] = {
- {"core_clk", JPEG_CLK_RATE, 0}
- };
+ int rc = 0;
+ struct clk *jpeg_clk;
- jpeg_core_clk_info[0].clk_rate = clk_rate;
+ jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk");
+ if (IS_ERR(jpeg_clk)) {
+ JPEG_PR_ERR("%s get failed\n", "core_clk");
+ rc = PTR_ERR(jpeg_clk);
+ return rc;
+ }
- return msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_core_clk_info,
- pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_core_clk_info), 1);
+ rc = clk_set_rate(jpeg_clk, clk_rate);
+
+ return rc;
}
void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index c79b3a3..8a2c8e5 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -1001,8 +1001,10 @@
video_set_drvdata(pvdev->vdev, pvdev);
msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
- if (WARN_ON(!msm_session_q))
- goto v4l2_fail;
+ if (WARN_ON(!msm_session_q)) {
+ rc = -ENOMEM;
+ goto session_fail;
+ }
msm_init_queue(msm_session_q);
spin_lock_init(&msm_eventq_lock);
@@ -1010,6 +1012,8 @@
INIT_LIST_HEAD(&ordered_sd_list);
goto probe_end;
+session_fail:
+ video_unregister_device(pvdev->vdev);
v4l2_fail:
v4l2_device_unregister(pvdev->vdev->v4l2_dev);
register_fail:
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 69f0a3d..532bebc 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
@@ -1845,6 +1845,11 @@
cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
GFP_KERNEL);
+ if (!cpp_dev->work) {
+ pr_err("cpp_dev->work is NULL\n");
+ rc = -ENOMEM;
+ goto ERROR3;
+ }
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;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index dc29199..8d14363 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -691,43 +691,47 @@
if (queue->len > 0) {
frame_qcmd = msm_dequeue(queue, list_frame);
- processed_frame = frame_qcmd->command;
- do_gettimeofday(&(processed_frame->out_time));
- kfree(frame_qcmd);
- event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
- if (!event_qcmd) {
- pr_err("%s: Insufficient memory\n", __func__);
- return -ENOMEM;
- }
- atomic_set(&event_qcmd->on_heap, 1);
- event_qcmd->command = processed_frame;
- VPE_DBG("fid %d\n", processed_frame->frame_id);
- msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+ if(frame_qcmd) {
+ processed_frame = frame_qcmd->command;
+ do_gettimeofday(&(processed_frame->out_time));
+ kfree(frame_qcmd);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+ if (!event_qcmd) {
+ pr_err("%s: Insufficient memory\n", __func__);
+ return -ENOMEM;
+ }
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = processed_frame;
+ VPE_DBG("fid %d\n", processed_frame->frame_id);
+ msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
- if (!processed_frame->output_buffer_info.processed_divert) {
- memset(&buff_mgr_info, 0 ,
- sizeof(buff_mgr_info));
- buff_mgr_info.session_id =
- ((processed_frame->identity >> 16) & 0xFFFF);
- buff_mgr_info.stream_id =
- (processed_frame->identity & 0xFFFF);
- buff_mgr_info.frame_id = processed_frame->frame_id;
- buff_mgr_info.timestamp = processed_frame->timestamp;
- buff_mgr_info.index =
- processed_frame->output_buffer_info.index;
- rc = msm_vpe_buffer_ops(vpe_dev,
+ if (!processed_frame->output_buffer_info.processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(buff_mgr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info.index;
+ rc = msm_vpe_buffer_ops(vpe_dev,
VIDIOC_MSM_BUF_MNGR_BUF_DONE,
&buff_mgr_info);
- if (rc < 0) {
- pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
- __func__);
- rc = -EINVAL;
+ if (rc < 0) {
+ pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+ __func__);
+ rc = -EINVAL;
+ }
}
- }
- v4l2_evt.id = processed_frame->inst_id;
- v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
- v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ v4l2_evt.id = processed_frame->inst_id;
+ v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+ v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ }
+ else
+ rc = -EFAULT;
}
return rc;
}
@@ -1368,6 +1372,8 @@
struct msm_vpe_frame_info_t *process_frame;
VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
event_qcmd = msm_dequeue(queue, list_eventdata);
+ if (NULL == event_qcmd)
+ break;
process_frame = event_qcmd->command;
VPE_DBG("fid %d\n", process_frame->frame_id);
if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 45db19c..69c1faa 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -809,6 +809,7 @@
e_ctrl->is_supported = 0;
if (!of_node) {
pr_err("%s dev.of_node NULL\n", __func__);
+ kfree(e_ctrl);
return -EINVAL;
}
@@ -817,6 +818,7 @@
CDBG("cell-index %d, rc %d\n", pdev->id, rc);
if (rc < 0) {
pr_err("failed rc %d\n", rc);
+ kfree(e_ctrl);
return rc;
}
e_ctrl->subdev_id = pdev->id;
@@ -826,12 +828,14 @@
CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc);
if (rc < 0) {
pr_err("%s failed rc %d\n", __func__, rc);
+ kfree(e_ctrl);
return rc;
}
rc = of_property_read_u32(of_node, "qcom,slave-addr",
&temp);
if (rc < 0) {
pr_err("%s failed rc %d\n", __func__, rc);
+ kfree(e_ctrl);
return rc;
}
@@ -844,6 +848,7 @@
struct msm_camera_cci_client), GFP_KERNEL);
if (!e_ctrl->i2c_client.cci_client) {
pr_err("%s failed no memory\n", __func__);
+ kfree(e_ctrl);
return -ENOMEM;
}
@@ -936,6 +941,7 @@
kfree(e_ctrl->eboard_info);
cciclient_free:
kfree(e_ctrl->i2c_client.cci_client);
+ kfree(e_ctrl);
return rc;
}
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 699142a..b88ac00 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
@@ -71,9 +71,9 @@
case MSM_CAMERA_LED_LOW:
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;
+ if (cfg->torch_current > 0 &&
+ cfg->torch_current < max_curr_l) {
+ curr_l = cfg->torch_current;
} else {
curr_l = fctrl->torch_op_current;
pr_err("LED current clamped to %d\n",
@@ -90,9 +90,9 @@
for (i = 0; i < fctrl->num_sources; 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;
+ if (cfg->flash_current[i] > 0 &&
+ cfg->flash_current[i] < max_curr_l) {
+ curr_l = cfg->flash_current[i];
} else {
curr_l = fctrl->flash_op_current[i];
pr_err("LED current clamped to %d\n",
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 19a378f..5694658 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -3964,6 +3964,58 @@
}
EXPORT_SYMBOL(mpq_dmx_set_cipher_ops);
+static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed)
+{
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct mpq_video_feed_info *feed_data;
+ struct dvb_ringbuffer *buffer;
+ struct ion_handle *ion_handle;
+ int ret = 0;
+ int i;
+
+ if (!dvb_dmx_is_video_feed(feed)) {
+ if (dvb_dmx_is_sec_feed(feed) ||
+ dvb_dmx_is_pcr_feed(feed)) {
+ buffer = (struct dvb_ringbuffer *)
+ &mpq_feed->sdmx_buf;
+ ion_handle = mpq_feed->sdmx_buf_handle;
+ } else {
+ buffer = (struct dvb_ringbuffer *)
+ feed->feed.ts.buffer.ringbuff;
+ ion_handle = feed->feed.ts.buffer.priv_handle;
+ }
+
+ ret = msm_ion_do_cache_op(mpq_feed->mpq_demux->ion_client,
+ ion_handle, buffer->data,
+ buffer->size, ION_IOC_INV_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Video buffers */
+ feed_data = &mpq_feed->video_info;
+ for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+ if (feed_data->buffer_desc.desc[i].base) {
+ /* Non-secured buffer */
+ ret = msm_ion_do_cache_op(
+ mpq_feed->mpq_demux->ion_client,
+ feed_data->buffer_desc.ion_handle[i],
+ feed_data->buffer_desc.desc[i].base,
+ feed_data->buffer_desc.desc[i].size,
+ ION_IOC_INV_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
struct sdmx_filter_status *filter_sts,
struct mpq_feed *mpq_feed)
@@ -4757,6 +4809,9 @@
mpq_feed->session_id))
continue;
+ /* Invalidate output buffer before processing the results */
+ mpq_sdmx_invalidate_buffer(mpq_feed);
+
if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
MPQ_DVB_ERR_PRINT(
"%s: meta-data buff for pid %d overflowed!\n",
@@ -4831,7 +4886,6 @@
for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
mpq_feed = &mpq_demux->feeds[i];
if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE)
- && (mpq_feed->dvb_demux_feed->state == DMX_STATE_GO)
&& (!mpq_feed->secondary_feed)) {
sts = mpq_demux->sdmx_filters_state.status +
filter_index;
@@ -4950,6 +5004,10 @@
const char *buf,
size_t count)
{
+ struct ion_handle *ion_handle =
+ mpq_demux->demux.dmx.dvr_input.priv_handle;
+ struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *)
+ mpq_demux->demux.dmx.dvr_input.ringbuff;
struct sdmx_buff_descr buf_desc;
u32 read_offset;
int ret;
@@ -4968,6 +5026,19 @@
}
read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread;
+
+ /*
+ * We must flush the buffer before SDMX starts reading from it
+ * so that it gets a valid data in memory.
+ */
+ ret = msm_ion_do_cache_op(mpq_demux->ion_client,
+ ion_handle, rbuf->data,
+ rbuf->size, ION_IOC_CLEAN_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+
return mpq_sdmx_process(mpq_demux, &buf_desc, count,
read_offset, mpq_demux->demux.ts_packet_size);
}
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
index 9a9b385..d3fe11c 100644
--- a/drivers/media/radio/radio-iris-transport.c
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -105,6 +105,7 @@
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
FMDERR("Memory not allocated for the socket");
+ kfree(worker);
return;
}
@@ -153,7 +154,13 @@
struct radio_hci_dev *hdev;
int rc;
+ if (hsmd == NULL)
+ return -ENODEV;
+
hdev = kmalloc(sizeof(struct radio_hci_dev), GFP_KERNEL);
+ if (hdev == NULL)
+ return -ENODEV;
+
hsmd->hdev = hdev;
tasklet_init(&hsmd->rx_task, radio_hci_smd_recv_event,
(unsigned long) hsmd);
@@ -166,6 +173,8 @@
if (rc < 0) {
FMDERR("Cannot open the command channel");
+ hsmd->hdev = NULL;
+ kfree(hdev);
return -ENODEV;
}
@@ -173,6 +182,9 @@
if (radio_hci_register_dev(hdev) < 0) {
FMDERR("Can't register HCI device");
+ smd_close(hsmd->fm_channel);
+ hsmd->hdev = NULL;
+ kfree(hdev);
return -ENODEV;
}
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index a554749..5dde469 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -88,7 +88,7 @@
struct radio_hci_dev *fm_hdev;
- struct v4l2_capability *g_cap;
+ struct v4l2_capability g_cap;
struct v4l2_control *g_ctl;
struct hci_fm_mute_mode_req mute_mode;
@@ -1825,7 +1825,7 @@
return;
}
- v4l_cap = radio->g_cap;
+ v4l_cap = &radio->g_cap;
if (rsp->status)
return;
@@ -3159,7 +3159,7 @@
struct v4l2_ext_controls *ctrl)
{
int retval = 0;
- int bytes_to_copy;
+ size_t bytes_to_copy;
struct hci_fm_tx_ps tx_ps;
struct hci_fm_tx_rt tx_rt;
struct hci_fm_def_data_wr_req default_data;
@@ -3168,18 +3168,20 @@
struct iris_device *radio = video_get_drvdata(video_devdata(file));
char *data = NULL;
- if (radio == NULL) {
- FMDERR(":radio is null");
- return -EINVAL;
+ if ((ctrl == NULL) || (ctrl->controls == NULL)
+ || (ctrl->count == 0)) {
+ retval = -EINVAL;
+ return retval;
}
+
switch ((ctrl->controls[0]).id) {
case V4L2_CID_RDS_TX_PS_NAME:
FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
/*Pass a sample PS string */
memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
- bytes_to_copy = min((int)(ctrl->controls[0]).size,
- MAX_PS_LENGTH);
+ bytes_to_copy = min(ctrl->controls[0].size,
+ (size_t)MAX_PS_LENGTH);
data = (ctrl->controls[0]).string;
if (copy_from_user(tx_ps.ps_data,
@@ -3196,7 +3198,7 @@
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
bytes_to_copy =
- min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+ min((ctrl->controls[0]).size, (size_t)MAX_RT_LENGTH);
data = (ctrl->controls[0]).string;
memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
@@ -4298,8 +4300,12 @@
}
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
- capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- radio->g_cap = capability;
+
+ strlcpy(radio->g_cap.driver, DRIVER_NAME, sizeof(radio->g_cap.driver));
+ strlcpy(radio->g_cap.card, DRIVER_CARD, sizeof(radio->g_cap.card));
+
+ radio->g_cap.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ capability->capabilities = radio->g_cap.capabilities;
return 0;
}
@@ -4470,11 +4476,11 @@
if (kfifo_alloc_rc != 0) {
FMDERR("failed allocating buffers %d\n",
kfifo_alloc_rc);
- for (; i > -1; i--) {
+ for (; i > -1; i--)
kfifo_free(&radio->data_buf[i]);
- kfree(radio);
- return -ENOMEM;
- }
+ video_device_release(radio->videodev);
+ kfree(radio);
+ return -ENOMEM;
}
}
@@ -4502,8 +4508,17 @@
} else {
priv_videodev = kzalloc(sizeof(struct video_device),
GFP_KERNEL);
- memcpy(priv_videodev, radio->videodev,
- sizeof(struct video_device));
+ if (priv_videodev != NULL) {
+ memcpy(priv_videodev, radio->videodev,
+ sizeof(struct video_device));
+ } else {
+ video_unregister_device(radio->videodev);
+ video_device_release(radio->videodev);
+ for (; i > -1; i--)
+ kfifo_free(&radio->data_buf[i]);
+ kfree(radio);
+ return -ENOMEM;
+ }
}
return 0;
}
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 6b9f2b3..c44e2a5 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -185,6 +185,10 @@
if (bahama_present == -ENODEV)
return -ENODEV;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
if (bahama_present)
radio->marimba->mod_id = SLAVE_ID_BAHAMA_FM;
else
@@ -216,6 +220,11 @@
* (otherwise, it may have already been there and will not be added a second
* time).
*/
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
queue_delayed_work(radio->wqueue, &radio->work,
msecs_to_jiffies(TAVARUA_DELAY));
return IRQ_HANDLED;
@@ -243,6 +252,12 @@
unsigned char offset, int len)
{
int retval = 0, i = 0;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -282,6 +297,12 @@
unsigned char offset, unsigned char value)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -322,6 +343,12 @@
int i;
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -358,6 +385,11 @@
*/
static int read_data_blocks(struct tavarua_device *radio, unsigned char offset)
{
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* read all 3 RDS blocks */
return tavarua_read_registers(radio, offset, RDS_BLOCK*4);
}
@@ -376,10 +408,17 @@
*/
static void tavarua_rds_read(struct tavarua_device *radio)
{
- struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+ struct kfifo *rds_buf;
unsigned char blocknum;
unsigned char tmp[3];
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+
if (read_data_blocks(radio, RAW_RDS) < 0)
return;
/* copy all four RDS blocks to internal buffer */
@@ -430,6 +469,12 @@
static int request_read_xfr(struct tavarua_device *radio,
enum tavarua_xfr_ctrl_t mode){
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
tavarua_write_register(radio, XFRCTRL, mode);
msleep(TAVARUA_DELAY);
return 0;
@@ -457,8 +502,17 @@
static int copy_from_xfr(struct tavarua_device *radio,
enum tavarua_buf_t buf_type, unsigned int n){
- struct kfifo *data_fifo = &radio->data_buf[buf_type];
- unsigned char *xfr_regs = &radio->registers[XFRCTRL+1];
+ struct kfifo *data_fifo;
+ unsigned char *xfr_regs;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ data_fifo = &radio->data_buf[buf_type];
+ xfr_regs = &radio->registers[XFRCTRL+1];
+
kfifo_in_locked(data_fifo, xfr_regs, n, &radio->buf_lock[buf_type]);
return 0;
}
@@ -496,6 +550,12 @@
char *buf, int len)
{
char buffer[len+1];
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
memcpy(buffer+1, buf, len);
/* buffer[0] corresponds to XFRCTRL register
set the CTRL bit to 1 for write mode
@@ -520,6 +580,11 @@
static int xfr_intf_own(struct tavarua_device *radio)
{
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
mutex_lock(&radio->lock);
if (radio->xfr_in_progress) {
radio->pending_xfrs[TAVARUA_XFR_SYNC] = 1;
@@ -552,6 +617,12 @@
enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = xfr_intf_own(radio);
if (retval < 0)
return retval;
@@ -590,6 +661,17 @@
enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
+
retval = xfr_intf_own(radio);
if (retval < 0)
return retval;
@@ -627,6 +709,12 @@
{
int i;
enum tavarua_xfr_t xfr;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
for (i = 0; i < TAVARUA_XFR_MAX; i++) {
if (radio->pending_xfrs[i]) {
radio->xfr_in_progress = 1;
@@ -681,8 +769,16 @@
enum tavarua_evt_t event)
{
- struct kfifo *data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+ struct kfifo *data_b;
unsigned char evt = event;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+
FMDBG("updating event_q with event %x\n", event);
if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[TAVARUA_BUF_EVENTS]))
wake_up_interruptible(&radio->event_queue);
@@ -707,12 +803,18 @@
static void tavarua_start_xfr(struct tavarua_device *radio,
enum tavarua_xfr_t pending_id, enum tavarua_xfr_ctrl_t xfr_id)
{
- if (radio->xfr_in_progress)
- radio->pending_xfrs[pending_id] = 1;
- else {
- radio->xfr_in_progress = 1;
- request_read_xfr(radio, xfr_id);
- }
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ if (radio->xfr_in_progress)
+ radio->pending_xfrs[pending_id] = 1;
+ else {
+ radio->xfr_in_progress = 1;
+ request_read_xfr(radio, xfr_id);
+ }
}
/*=============================================================================
@@ -739,6 +841,12 @@
int i;
int retval, adj_channel_tune_req = 0;
unsigned char xfr_status;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
if (!radio->handle_irq) {
FMDBG("IRQ happend, but I wont handle it\n");
return;
@@ -1143,15 +1251,34 @@
*/
static void read_int_stat(struct work_struct *work)
{
- struct tavarua_device *radio = container_of(work,
- struct tavarua_device, work.work);
+ struct tavarua_device *radio;
+
+ if (unlikely(work == NULL)) {
+ FMDERR("%s:work is null", __func__);
+ return;
+ }
+
+ radio = container_of(work, struct tavarua_device, work.work);
+
tavarua_handle_interrupts(radio);
}
static void fm_shutdown(struct work_struct *work)
{
- struct tavarua_device *radio = container_of(work,
- struct tavarua_device, work.work);
+ struct tavarua_device *radio;
+
+ if (unlikely(work == NULL)) {
+ FMDERR("%s:work is null", __func__);
+ return;
+ }
+
+ radio = container_of(work, struct tavarua_device, work.work);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
if (radio->pdata->config_i2s_gpio != NULL)
radio->pdata->config_i2s_gpio(FM_I2S_OFF);
@@ -1178,9 +1305,14 @@
static int tavarua_request_irq(struct tavarua_device *radio)
{
int retval;
- int irq = radio->pdata->irq;
- if (radio == NULL)
+ int irq;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
return -EINVAL;
+ }
+
+ irq = radio->pdata->irq;
/* A workqueue created with create_workqueue() will have one worker thread
* for each CPU on the system; create_singlethread_workqueue(), instead,
@@ -1237,8 +1369,12 @@
static int tavarua_disable_irq(struct tavarua_device *radio)
{
int irq;
- if (!radio)
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
return -EINVAL;
+ }
+
irq = radio->pdata->irq;
disable_irq_wake(irq);
free_irq(irq, radio);
@@ -1255,6 +1391,11 @@
unsigned int rdsMask = 0;
unsigned char value = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
adie_type_bahma = is_bahama();
switch (region) {
@@ -1435,9 +1576,17 @@
*/
static int tavarua_search(struct tavarua_device *radio, int on, int dir)
{
- enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+ enum search_t srch;
FMDBG("In tavarua_search\n");
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+
if (on) {
radio->registers[SRCHRDS1] = 0x00;
radio->registers[SRCHRDS2] = 0x00;
@@ -1503,6 +1652,11 @@
enum tavarua_region_t region = req_region;
unsigned char adie_type_bahma;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
adie_type_bahma = is_bahama();
/* Set freq band */
@@ -1671,6 +1825,17 @@
unsigned short chan;
unsigned int band_bottom;
unsigned int spacing;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
band_bottom = radio->region_params.band_low;
spacing = 0.100 * FREQ_MUL;
/* read channel */
@@ -1716,6 +1881,12 @@
unsigned char cmd[] = {0x00, 0x00};
unsigned int spacing;
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
band_bottom = radio->region_params.band_low;
spacing = 0.100 * FREQ_MUL;
if ((freq % 1600) == 800) {
@@ -1760,8 +1931,19 @@
size_t count, loff_t *ppos)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
- struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+ struct kfifo *rds_buf;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
+
+ rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
/* block if no new data available */
while (!kfifo_len(rds_buf)) {
if (file->f_flags & O_NONBLOCK)
@@ -1810,6 +1992,17 @@
int bytes_left;
int chunk_index = 0;
unsigned char tx_data[XFR_REG_NUM];
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(data == NULL)) {
+ FMDERR("%s:data is null", __func__);
+ return -EINVAL;
+ }
+
/* Disable TX of this type first */
switch (radio->tx_mode) {
case TAVARUA_TX_RT:
@@ -1897,6 +2090,11 @@
char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
int bahama_present = -ENODEV;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
INIT_DELAYED_WORK(&radio->work, read_int_stat);
if (!atomic_dec_and_test(&radio->users)) {
pr_err("%s: Device already in use."
@@ -2518,6 +2716,16 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(capability == NULL)) {
+ FMDERR("%s:capability is null", __func__);
+ return -EINVAL;
+ }
+
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
sprintf(capability->bus_info, "I2C");
@@ -2553,6 +2761,12 @@
unsigned char i;
int retval = -EINVAL;
+ if (unlikely(qc == NULL)) {
+ FMDERR("%s:qc is null", __func__);
+ return -EINVAL;
+ }
+
+
for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
@@ -2574,6 +2788,11 @@
int index = 0, offset = 0, addr = 0x0, val = 0;
int retval = 0, temp = 0, cnt = 0, j = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
memset(xfr_buf, 0x0, XFR_REG_NUM);
/* Read the SPUR Table Size */
@@ -2651,6 +2870,15 @@
unsigned char xfr_buf[XFR_REG_NUM + 1];
int retval = 0, temp = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
/* zero initialize the buffer */
memset(xfr_buf, 0x0, XFR_REG_NUM);
@@ -2725,6 +2953,11 @@
int ct = 0;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/*
Poking the MPX_DCC_BYPASS register to freeze the
value of MPX_DCC from changing while we access it
@@ -2844,6 +3077,16 @@
signed char ioc;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
break;
@@ -3059,6 +3302,18 @@
int extra_name_byte = 0;
int name_bytes = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL) ||
+ unlikely(ctrl->controls == NULL) ||
+ unlikely(ctrl->count <= 0)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
switch ((ctrl->controls[0]).id) {
case V4L2_CID_RDS_TX_PS_NAME: {
FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
@@ -3191,6 +3446,16 @@
unsigned int freq = 0, mpx_dcc = 0;
unsigned long curr = 0, prev = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
memset(xfr_buf, 0x0, XFR_REG_NUM);
switch (ctrl->id) {
@@ -3797,6 +4062,16 @@
char rmssi = 0;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s:tuner is null", __func__);
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -3863,6 +4138,17 @@
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int retval;
int audmode;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s:tuner is null", __func__);
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -3910,6 +4196,17 @@
struct v4l2_frequency *freq)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
freq->type = V4L2_TUNER_RADIO;
return tavarua_get_freq(radio, freq);
@@ -3945,6 +4242,16 @@
FMDBG("%s\n", __func__);
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
if (freq->type != V4L2_TUNER_RADIO)
return -EINVAL;
@@ -4108,6 +4415,17 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int dir;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(seek == NULL)) {
+ FMDERR("%s:seek is null", __func__);
+ return -EINVAL;
+ }
+
if (seek->seek_upward)
dir = SRCH_DIR_UP;
else
@@ -4159,6 +4477,11 @@
int retval;
unsigned char int_ctrl[XFR_REG_NUM];
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (!radio->lp_mode)
return 0;
@@ -4222,6 +4545,12 @@
{
unsigned char lpm_buf[XFR_REG_NUM];
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio->lp_mode)
return 0;
FMDBG("%s\n", __func__);
@@ -4270,6 +4599,12 @@
int retval;
FMDBG("%s <%d>\n", __func__, state);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* set geographic region */
radio->region_params.region = TAVARUA_REGION_US;
@@ -4305,6 +4640,12 @@
int retval;
int users = 0;
printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio) {
users = atomic_read(&radio->users);
if (!users) {
@@ -4336,6 +4677,12 @@
int retval;
int users = 0;
printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio) {
users = atomic_read(&radio->users);
@@ -4380,8 +4727,12 @@
struct tavarua_device *radio = private_data;
int rx_on = radio->registers[RDCTRL] & FM_RECV;
int retval = 0;
- if (!radio)
- return -ENOMEM;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* RX */
FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
@@ -4469,6 +4820,12 @@
int retval = 0;
int i = 0, j = 0;
FMDBG("%s: probe called\n", __func__);
+
+ if (unlikely(pdev == NULL)) {
+ FMDERR("%s:pdev is null", __func__);
+ return -EINVAL;
+ }
+
/* private data allocation */
radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
if (!radio) {
@@ -4593,6 +4950,11 @@
int i;
struct tavarua_device *radio = platform_get_drvdata(pdev);
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* disable irq */
tavarua_disable_irq(radio);
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 9dd06ee..127a231 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -310,6 +310,7 @@
"Scalable High",
"Scalable High Intra",
"Multiview High",
+ "Constrained High",
NULL,
};
static const char * const vui_sar_idc[] = {
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 3d69473..19f26f2 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1706,6 +1706,8 @@
dma_free_coherent(NULL, config->desc.size, config->desc.base,
config->desc.phys_base);
+ sps_free_endpoint(channel->pipe);
+
tspp_destroy_buffers(channel_id, channel);
if (channel->dma_pool) {
dma_pool_destroy(channel->dma_pool);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 421774f..b36faff 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -467,6 +467,7 @@
}
kfree(card->wr_pack_stats.packing_events);
+ kfree(card->cached_ext_csd);
put_device(&card->dev);
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 997e14b..b295bb8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1189,9 +1189,9 @@
mmc_set_timing(card->host, MMC_TIMING_LEGACY);
mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
- err = mmc_select_hs(card, &card->cached_ext_csd);
+ err = mmc_select_hs(card, card->cached_ext_csd);
} else {
- err = mmc_select_hs400(card, &card->cached_ext_csd);
+ err = mmc_select_hs400(card, card->cached_ext_csd);
}
return err;
@@ -1439,7 +1439,7 @@
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto free_card;
- memcpy(&card->cached_ext_csd, ext_csd, sizeof(card->ext_csd));
+ card->cached_ext_csd = ext_csd;
err = mmc_read_ext_csd(card, ext_csd);
if (err)
goto free_card;
@@ -1637,15 +1637,12 @@
if (!oldcard)
host->card = card;
- mmc_free_ext_csd(ext_csd);
return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- mmc_free_ext_csd(ext_csd);
-
return err;
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 95f0a04..c335be1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -6962,7 +6962,7 @@
static const struct of_device_id msmsdcc_dt_match[] = {
{.compatible = "qcom,msm-sdcc"},
-
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index e391a06..4d3a560 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -3113,6 +3113,7 @@
#endif
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm"},
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 76eb15b..12c5704 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -50,6 +50,7 @@
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
+#define UINT32_MAX (0xFFFFFFFFU)
static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
@@ -355,7 +356,7 @@
int fw_cal_available;
int user_cal_read;
int user_cal_available;
- int user_cal_rcvd;
+ u32 user_cal_rcvd;
int user_cal_exp_size;
int device_opened;
int iris_xo_mode_set;
@@ -2134,7 +2135,7 @@
*user_buffer, size_t count, loff_t *position)
{
int rc = 0;
- int size = 0;
+ size_t size = 0;
if (!penv || !penv->device_opened || penv->user_cal_available)
return -EFAULT;
@@ -2142,7 +2143,7 @@
if (penv->user_cal_rcvd == 0 && count >= 4
&& !penv->user_cal_data) {
rc = copy_from_user((void *)&size, user_buffer, 4);
- if (size > MAX_CALIBRATED_DATA_SIZE) {
+ if (!size || size > MAX_CALIBRATED_DATA_SIZE) {
pr_err(DEVICE " invalid size to write %d\n", size);
return -EFAULT;
}
@@ -2161,7 +2162,8 @@
} else if (penv->user_cal_rcvd == 0 && count < 4)
return -EFAULT;
- if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+ if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
+ MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
pr_err(DEVICE " invalid size to write %d\n", count +
penv->user_cal_rcvd);
rc = -ENOMEM;
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
index c55ed09..696c84f 100644
--- a/drivers/platform/msm/qpnp-clkdiv.c
+++ b/drivers/platform/msm/qpnp-clkdiv.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
@@ -202,6 +202,7 @@
if (!res) {
dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
__func__);
+ return -EINVAL;
}
q_clkdiv->slave = spmi->sid;
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 7d26bef..588afc6 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -208,6 +208,12 @@
#define QPNP_PWM_SIZE_8_BIT 8
#define QPNP_PWM_SIZE_9_BIT 9
+/* Supported time levels */
+enum time_level {
+ LVL_NSEC,
+ LVL_USEC,
+};
+
/* LPG revisions */
enum qpnp_lpg_revision {
QPNP_LPG_REVISION_0 = 0x0,
@@ -305,8 +311,8 @@
bool in_use;
const char *lable;
int pwm_value;
- int pwm_period;
- int pwm_duty;
+ int pwm_period; /* in microseconds */
+ int pwm_duty; /* in microseconds */
struct pwm_period_config period;
int force_pwm_size;
};
@@ -425,8 +431,9 @@
* This is the formula to figure out m for the best pre-divide and clock:
* (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
*/
-static void qpnp_lpg_calc_period(unsigned int period_us,
- struct pwm_device *pwm)
+static void qpnp_lpg_calc_period(enum time_level tm_lvl,
+ unsigned int period_value,
+ struct pwm_device *pwm)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
@@ -443,14 +450,18 @@
else
n = 6;
- if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
- period_n = (period_us * NSEC_PER_USEC) >> n;
+ if (tm_lvl == LVL_USEC) {
+ if (period_value < ((unsigned)(-1) / NSEC_PER_USEC)) {
+ period_n = (period_value * NSEC_PER_USEC) >> n;
+ } else {
+ if (qpnp_check_gpled_lpg_channel(id))
+ n = 8;
+ else
+ n = 9;
+ period_n = (period_value >> n) * NSEC_PER_USEC;
+ }
} else {
- if (qpnp_check_gpled_lpg_channel(id))
- n = 8;
- else
- n = 9;
- period_n = (period_us >> n) * NSEC_PER_USEC;
+ period_n = period_value >> n;
}
if (force_pwm_size != 0) {
@@ -520,20 +531,20 @@
}
static void qpnp_lpg_calc_pwm_value(struct pwm_device *pwm,
- unsigned int period_us,
- unsigned int duty_us)
+ unsigned int period_value,
+ unsigned int duty_value)
{
unsigned int max_pwm_value, tmp;
struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
/* Figure out pwm_value with overflow handling */
tmp = 1 << (sizeof(tmp) * 8 - pwm_config->period.pwm_size);
- if (duty_us < tmp) {
- tmp = duty_us << pwm_config->period.pwm_size;
- pwm_config->pwm_value = tmp / period_us;
+ if (duty_value < tmp) {
+ tmp = duty_value << pwm_config->period.pwm_size;
+ pwm_config->pwm_value = tmp / period_value;
} else {
- tmp = period_us >> pwm_config->period.pwm_size;
- pwm_config->pwm_value = duty_us / tmp;
+ tmp = period_value >> pwm_config->period.pwm_size;
+ pwm_config->pwm_value = duty_value / tmp;
}
max_pwm_value = (1 << pwm_config->period.pwm_size) - 1;
if (pwm_config->pwm_value > max_pwm_value)
@@ -1083,25 +1094,36 @@
return rc;
}
-static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+static int _pwm_config(struct pwm_device *pwm,
+ enum time_level tm_lvl,
+ int duty_value, int period_value)
{
struct qpnp_pwm_config *pwm_config;
struct qpnp_lpg_chip *chip;
struct pwm_period_config *period;
- int rc;
+ int period_us, duty_us;
+ int rc;
chip = pwm->chip;
pwm_config = &pwm->pwm_config;
period = &pwm_config->period;
+ if (tm_lvl == LVL_USEC) {
+ period_us = period_value;
+ duty_us = duty_value;
+ } else {
+ period_us = period_value / NSEC_PER_USEC;
+ duty_us = duty_value / NSEC_PER_USEC;
+ }
+
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm);
+ qpnp_lpg_calc_period(tm_lvl, period_value, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
pwm_config->pwm_duty = duty_us;
- qpnp_lpg_calc_pwm_value(pwm, period_us, duty_us);
+ qpnp_lpg_calc_pwm_value(pwm, period_value, duty_value);
rc = qpnp_lpg_save_pwm_value(pwm);
if (rc) {
@@ -1124,8 +1146,9 @@
return rc;
}
- pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
+ pr_debug("duty/period=%u/%u %s: pwm_value=%d (of %d)\n",
(unsigned)duty_us, (unsigned)period_us,
+ (tm_lvl == LVL_USEC) ? "usec" : "nsec",
pwm_config->pwm_value, 1 << period->pwm_size);
return 0;
@@ -1151,7 +1174,7 @@
period = &pwm_config->period;
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm);
+ qpnp_lpg_calc_period(LVL_USEC, period_us, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
@@ -1302,10 +1325,41 @@
/**
* pwm_config - change a PWM device configuration
* @pwm: the PWM device
+ * @period_ns: period in nanoseconds
+ * @duty_ns: duty cycle in nanoseconds
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ int rc;
+ unsigned long flags;
+
+ if (pwm == NULL || IS_ERR(pwm) || duty_ns > period_ns ||
+ (unsigned)period_ns < PM_PWM_PERIOD_MIN * NSEC_PER_USEC) {
+ pr_err("Invalid pwm handle or parameters\n");
+ return -EINVAL;
+ }
+
+ if (!pwm->pwm_config.in_use)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
+ rc = _pwm_config(pwm, LVL_NSEC, duty_ns, period_ns);
+ spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
+
+ if (rc)
+ pr_err("Failed to configure PWM mode\n");
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/**
+ * pwm_config_us - change a PWM device configuration
+ * @pwm: the PWM device
* @period_us: period in microseconds
* @duty_us: duty cycle in microseconds
*/
-int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+int pwm_config_us(struct pwm_device *pwm, int duty_us, int period_us)
{
int rc;
unsigned long flags;
@@ -1322,7 +1376,7 @@
return -EINVAL;
spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
- rc = _pwm_config(pwm, duty_us, period_us);
+ rc = _pwm_config(pwm, LVL_USEC, duty_us, period_us);
spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
if (rc)
@@ -1330,7 +1384,7 @@
return rc;
}
-EXPORT_SYMBOL_GPL(pwm_config);
+EXPORT_SYMBOL_GPL(pwm_config_us);
/**
* pwm_enable - start a PWM output toggling
@@ -1627,7 +1681,8 @@
return rc;
}
- rc = _pwm_config(pwm_dev, pwm_dev->pwm_config.pwm_duty, period);
+ rc = _pwm_config(pwm_dev, LVL_USEC,
+ pwm_dev->pwm_config.pwm_duty, period);
return rc;
}
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 8572616..6ea4ea6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1285,6 +1285,21 @@
return 0;
}
+static int
+qpnp_chg_vddmax_get(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 vddmax = 0;
+
+ rc = qpnp_chg_read(chip, &vddmax, chip->chgr_base + CHGR_VDD_MAX, 1);
+ if (rc) {
+ pr_err("Failed to write vddmax: %d\n", rc);
+ return rc;
+ }
+
+ return QPNP_CHG_V_MIN_MV + (int)vddmax * QPNP_CHG_V_STEP_MV;
+}
+
/* JEITA compliance logic */
static void
qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
@@ -2077,6 +2092,8 @@
if (battery_status != POWER_SUPPLY_STATUS_CHARGING
&& bms_status != POWER_SUPPLY_STATUS_CHARGING
&& charger_in
+ && !chip->bat_is_cool
+ && !chip->bat_is_warm
&& !chip->resuming_charging
&& !chip->charging_disabled
&& chip->soc_resume_limit
@@ -3118,10 +3135,17 @@
count = 0;
} else {
if (count == CONSECUTIVE_COUNT) {
- pr_info("End of Charging\n");
+ if (!chip->bat_is_cool && !chip->bat_is_warm) {
+ pr_info("End of Charging\n");
+ chip->chg_done = true;
+ } else {
+ pr_info("stop charging: battery is %s, vddmax = %d reached\n",
+ chip->bat_is_cool
+ ? "cool" : "warm",
+ qpnp_chg_vddmax_get(chip));
+ }
chip->delta_vddmax_mv = 0;
qpnp_chg_set_appropriate_vddmax(chip);
- chip->chg_done = true;
qpnp_chg_charge_en(chip, 0);
/* sleep for a second before enabling */
msleep(2000);
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index cf1801b..efb87a9 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1339,7 +1339,7 @@
{
u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
- u8 sensor_mask = 0;
+ u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0;
int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
uint32_t btm_chan_num = 0;
struct qpnp_adc_thr_client_info *client_info = NULL;
@@ -1368,6 +1368,20 @@
goto fail;
}
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ &adc_tm_low_thr_set);
+ if (rc) {
+ pr_err("adc-tm-tm read low thr failed with %d\n", rc);
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ &adc_tm_high_thr_set);
+ if (rc) {
+ pr_err("adc-tm-tm read high thr failed with %d\n", rc);
+ goto fail;
+ }
+
/* Check which interrupt threshold is lower and measure against the
* enabled channel */
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
@@ -1378,7 +1392,9 @@
}
adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
+ adc_tm_low_enable &= adc_tm_low_thr_set;
adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
+ adc_tm_high_enable &= adc_tm_high_thr_set;
if (adc_tm_high_enable) {
sensor_notify_num = adc_tm_high_enable;
@@ -1886,7 +1902,7 @@
pr_debug("thermal node%x\n", btm_channel_num);
chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
chip->sensor[sen_idx].thermal_node = true;
- snprintf(name, sizeof(name),
+ snprintf(name, sizeof(name), "%s",
chip->adc->adc_channels[sen_idx].name);
chip->sensor[sen_idx].meas_interval =
QPNP_ADC_TM_MEAS_INTERVAL;
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index dd04f49..7ae0a54 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1063,7 +1063,7 @@
memset(kbuf, 0, 10);
- if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
return -EFAULT;
if (sscanf(kbuf, "%x", &data) != 1)
@@ -1088,7 +1088,7 @@
memset(kbuf, 0, 10);
- if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
return -EFAULT;
if (sscanf(kbuf, "%x", &temp) != 1)
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 52c4a20..25ee3e4 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -78,6 +78,9 @@
if (status) {
MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status);
+
+ /* Writing of an extra 0 needed to clear error bits */
+ MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, 0);
pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -932,17 +935,18 @@
if (req->cb)
req->cb(len);
}
-void msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
{
struct dcs_cmd_req *req;
int dsi_on;
+ int ret = -EINVAL;
mutex_lock(&ctrl->mutex);
dsi_on = dsi_host_private->dsi_on;
mutex_unlock(&ctrl->mutex);
if (!dsi_on) {
pr_err("try to send DSI commands while dsi is off\n");
- return;
+ return ret;
}
mutex_lock(&ctrl->cmd_mutex);
@@ -950,21 +954,20 @@
if (!req) {
mutex_unlock(&ctrl->cmd_mutex);
- return;
+ return ret;
}
msm_dsi_clk_ctrl(&ctrl->panel_data, 1);
- dsi_set_tx_power_mode(0);
if (req->flags & CMD_REQ_RX)
msm_dsi_cmdlist_rx(ctrl, req);
else
msm_dsi_cmdlist_tx(ctrl, req);
- dsi_set_tx_power_mode(1);
msm_dsi_clk_ctrl(&ctrl->panel_data, 0);
mutex_unlock(&ctrl->cmd_mutex);
+ return 0;
}
static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata,
@@ -1302,6 +1305,21 @@
return rc;
}
+static struct device_node *dsi_pref_prim_panel(
+ struct platform_device *pdev)
+{
+ struct device_node *dsi_pan_node = NULL;
+
+ pr_debug("%s:%d: Select primary panel from dt\n",
+ __func__, __LINE__);
+ dsi_pan_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,dsi-pref-prim-pan", 0);
+ if (!dsi_pan_node)
+ pr_err("%s:can't find panel phandle\n", __func__);
+
+ return dsi_pan_node;
+}
+
/**
* dsi_find_panel_of_node(): find device node of dsi panel
* @pdev: platform_device of the dsi ctrl node
@@ -1331,14 +1349,7 @@
/* no panel cfg chg, parse dt */
pr_debug("%s:%d: no cmd line cfg present\n",
__func__, __LINE__);
- dsi_pan_node = of_parse_phandle(
- pdev->dev.of_node,
- "qcom,dsi-pref-prim-pan", 0);
- if (!dsi_pan_node) {
- pr_err("%s:can't find panel phandle\n",
- __func__);
- return NULL;
- }
+ dsi_pan_node = dsi_pref_prim_panel(pdev);
} else {
if (panel_cfg[0] != '0') {
pr_err("%s:%d:ctrl id=[%d] not supported\n",
@@ -1366,7 +1377,7 @@
if (!dsi_pan_node) {
pr_err("%s: invalid pan node\n",
__func__);
- return NULL;
+ dsi_pan_node = dsi_pref_prim_panel(pdev);
}
}
return dsi_pan_node;
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 3999db9..02bd7e9 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -186,6 +186,7 @@
int i = 0;
struct mdp3_hw_resource *mdata = (struct mdp3_hw_resource *)ptr;
u32 mdp_interrupt = 0;
+ u32 mdp_status = 0;
spin_lock(&mdata->irq_lock);
if (!mdata->irq_mask)
@@ -194,8 +195,8 @@
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);
+ mdp_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
+ mdp_interrupt = mdp_status;
pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
mdp_interrupt &= mdata->irq_mask;
@@ -206,6 +207,7 @@
mdp_interrupt = mdp_interrupt >> 1;
i++;
}
+ MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_status);
clk_disable(mdp3_res->clocks[MDP3_CLK_AHB]);
clk_disable(mdp3_res->clocks[MDP3_CLK_CORE]);
@@ -949,7 +951,7 @@
{
char *t = NULL;
char pan_intf_str[MDSS_MAX_PANEL_LEN];
- int rc, i;
+ int rc, i, panel_len;
char pan_name[MDSS_MAX_PANEL_LEN];
if (!pan_cfg)
@@ -986,6 +988,14 @@
strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
t, pan_cfg->arg_cfg);
+
+ panel_len = strlen(pan_cfg->arg_cfg);
+ if (!panel_len) {
+ pr_err("%s: Panel name is invalid\n", __func__);
+ pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+ return -EINVAL;
+ }
+
rc = mdp3_get_pan_intf(pan_intf_str);
pan_cfg->pan_intf = (rc < 0) ? MDSS_PANEL_INTF_INVALID : rc;
return 0;
@@ -1069,10 +1079,10 @@
of_node_put(chosen_node);
rc = mdp3_get_pan_cfg(pan_cfg);
- if (!rc)
+ if (!rc) {
pan_cfg->init_done = true;
-
- return rc;
+ return rc;
+ }
get_dt_pan:
rc = mdp3_parse_dt_pan_intf(pdev);
@@ -1443,7 +1453,9 @@
ret = 0;
} else {
ret = PTR_ERR(iommu_meta);
- goto out_unlock;
+ mutex_unlock(&mdp3_res->iommu_lock);
+ pr_err("%s: meta_create failed err=%d", __func__, ret);
+ return ret;
}
} else {
if (iommu_meta->flags != iommu_flags) {
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 28997ec..f1f0455 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -26,6 +26,7 @@
#include "mdss_fb.h"
#define MDP_VSYNC_CLK_RATE 19200000
+#define KOFF_TIMEOUT msecs_to_jiffies(84)
enum {
MDP3_CLK_AHB,
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 6219737..6fc6195 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -91,6 +91,36 @@
return bufq->count;
}
+void mdp3_ctrl_notifier_register(struct mdp3_session_data *ses,
+ struct notifier_block *notifier)
+{
+ blocking_notifier_chain_register(&ses->notifier_head, notifier);
+}
+
+void mdp3_ctrl_notifier_unregister(struct mdp3_session_data *ses,
+ struct notifier_block *notifier)
+{
+ blocking_notifier_chain_unregister(&ses->notifier_head, notifier);
+}
+
+int mdp3_ctrl_notify(struct mdp3_session_data *ses, int event)
+{
+ return blocking_notifier_call_chain(&ses->notifier_head, event, ses);
+}
+
+static void mdp3_dispatch_dma_done(struct work_struct *work)
+{
+ struct mdp3_session_data *session;
+
+ pr_debug("%s\n", __func__);
+ session = container_of(work, struct mdp3_session_data,
+ dma_done_work);
+ if (!session)
+ return;
+
+ mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+}
+
static void mdp3_dispatch_clk_off(struct work_struct *work)
{
struct mdp3_session_data *session;
@@ -121,6 +151,12 @@
sysfs_notify_dirent(session->vsync_event_sd);
}
+void dma_done_notify_handler(void *arg)
+{
+ struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+ schedule_work(&session->dma_done_work);
+}
+
void vsync_count_down(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
@@ -140,8 +176,8 @@
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
{
struct mdp3_session_data *mdp3_session;
- struct mdp3_vsync_notification vsync_client;
- struct mdp3_vsync_notification *arg = NULL;
+ struct mdp3_notification vsync_client;
+ struct mdp3_notification *arg = NULL;
pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -464,6 +500,7 @@
int frame_rate = mfd->panel_info->mipi.frame_rate;
int vbp, vfp, vspw;
int vtotal, vporch;
+ struct mdp3_notification dma_done_callback;
vbp = panel_info->lcdc.v_back_porch;
vfp = panel_info->lcdc.v_front_porch;
@@ -499,6 +536,13 @@
rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
else
rc = -EINVAL;
+
+ if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+ dma_done_callback.handler = dma_done_notify_handler;
+ dma_done_callback.arg = mfd->mdp.private1;
+ dma->dma_done_notifier(dma, &dma_done_callback);
+ }
+
return rc;
}
@@ -527,6 +571,8 @@
}
mdp3_batfet_ctrl(true);
+ mdp3_ctrl_notifier_register(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
if (rc) {
@@ -613,9 +659,6 @@
panel = mdp3_session->panel;
mutex_lock(&mdp3_session->lock);
- if (panel && panel->set_backlight)
- panel->set_backlight(panel, 0);
-
if (!mdp3_session->status) {
pr_debug("fb%d is off already", mfd->index);
goto off_error;
@@ -661,6 +704,8 @@
if (rc)
pr_err("fail to dettach MDP DMA SMMU\n");
+ mdp3_ctrl_notifier_unregister(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
mdp3_batfet_ctrl(false);
mdp3_session->vsync_enabled = 0;
atomic_set(&mdp3_session->vsync_countdown, 0);
@@ -680,7 +725,7 @@
struct mdp3_session_data *mdp3_session;
struct mdp3_dma *mdp3_dma;
struct mdss_panel_data *panel;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
pr_debug("mdp3_ctrl_reset_cmd\n");
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -730,7 +775,7 @@
struct mdp3_session_data *mdp3_session;
struct mdp3_dma *mdp3_dma;
struct mdss_panel_data *panel;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
pr_debug("mdp3_ctrl_reset\n");
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -838,6 +883,14 @@
{
int rc = 0;
struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct fb_var_screeninfo *var;
+ struct fb_fix_screeninfo *fix;
+ struct fb_info *fbi = mfd->fbi;
+ int stride;
+
+ fix = &fbi->fix;
+ var = &fbi->var;
+ stride = req->src.width * var->bits_per_pixel/8;
mutex_lock(&mdp3_session->lock);
@@ -846,6 +899,9 @@
mdp3_session->overlay = *req;
if (req->id == MSMFB_NEW_REQUEST) {
+ if (fix->line_length != stride)
+ mdp3_session->dma->config_stride(
+ mdp3_session->dma, stride);
mdp3_session->overlay.id = 1;
req->id = 1;
}
@@ -859,10 +915,15 @@
{
int rc = 0;
struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct fb_info *fbi = mfd->fbi;
+ struct fb_fix_screeninfo *fix;
+ fix = &fbi->fix;
mutex_lock(&mdp3_session->lock);
if (mdp3_session->overlay.id == ndx && ndx == 1) {
+ mdp3_session->dma->config_stride(mdp3_session->dma,
+ fix->line_length);
mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
mdp3_bufq_deinit(&mdp3_session->bufq_in);
} else {
@@ -956,17 +1017,31 @@
return -EPERM;
}
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
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,
+ rc = mdp3_session->dma->update(mdp3_session->dma,
(void *)data->addr,
mdp3_session->intf);
+ /* This is for the previous frame */
+ if (rc < 0) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_TIMEOUT);
+ } else {
+ if (mdp3_ctrl_get_intf_type(mfd) ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_DONE);
+ }
+ }
+
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
mdp3_bufq_push(&mdp3_session->bufq_out, data);
}
- if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
+ if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
data = mdp3_bufq_pop(&mdp3_session->bufq_out);
mdp3_put_img(data, MDP3_CLIENT_DMA_P);
}
@@ -985,7 +1060,7 @@
mdss_fb_update_notify_update(mfd);
- return rc;
+ return 0;
}
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
@@ -995,6 +1070,7 @@
u32 offset;
int bpp;
struct mdss_panel_info *panel_info = mfd->panel_info;
+ int rc;
pr_debug("mdp3_ctrl_pan_display\n");
if (!mfd || !mfd->mdp.private1)
@@ -1031,10 +1107,23 @@
if (mfd->fbi->screen_base) {
mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
mdp3_ctrl_clk_enable(mfd, 1);
- mdp3_session->dma->update(mdp3_session->dma,
- (void *)mfd->iova + offset,
+ rc = mdp3_session->dma->update(mdp3_session->dma,
+ (void *)(mfd->iova + offset),
mdp3_session->intf);
+ /* This is for the previous frame */
+ if (rc < 0) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_TIMEOUT);
+ } else {
+ if (mdp3_ctrl_get_intf_type(mfd) ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_DONE);
+ }
+ }
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
} else {
pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
mdp3_clk_enable(1, 0);
@@ -1645,6 +1734,7 @@
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);
+ INIT_WORK(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done);
atomic_set(&mdp3_session->vsync_countdown, 0);
mutex_init(&mdp3_session->histo_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
@@ -1680,6 +1770,7 @@
mdp3_bufq_init(&mdp3_session->bufq_out);
mdp3_session->histo_status = 0;
mdp3_session->lut_sel = 0;
+ BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head);
init_timer(&mdp3_session->vsync_timer);
mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
@@ -1708,14 +1799,17 @@
kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
+ if (mdp3_get_cont_spash_en()) {
+ mdp3_session->clk_on = 1;
+ mdp3_ctrl_notifier_register(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
+ }
+
if (splash_mismatch) {
pr_err("splash memory mismatch, stop splash\n");
mdp3_ctrl_off(mfd);
}
- if (mdp3_get_cont_spash_en())
- mdp3_session->clk_on = 1;
-
mdp3_session->vsync_before_commit = true;
init_done:
if (IS_ERR_VALUE(rc))
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index f2484ef..cfad1d3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -49,6 +49,7 @@
struct mdp3_buffer_queue bufq_in;
struct mdp3_buffer_queue bufq_out;
struct work_struct clk_off_work;
+ struct work_struct dma_done_work;
int histo_status;
struct mutex histo_lock;
int lut_sel;
@@ -56,6 +57,7 @@
bool vsync_before_commit;
bool first_commit;
int clk_on;
+ struct blocking_notifier_head notifier_head;
int vsync_enabled;
atomic_t vsync_countdown; /* Used to count down */
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 3a2c94b..5cae2de 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -27,26 +27,38 @@
static void mdp3_vsync_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
+ unsigned int wait_for_next_vs;
pr_debug("mdp3_vsync_intr_handler\n");
spin_lock(&dma->dma_lock);
vsync_client = dma->vsync_client;
- complete(&dma->vsync_comp);
+ wait_for_next_vs = !dma->vsync_status;
+ dma->vsync_status = 0;
+ if (wait_for_next_vs)
+ complete(&dma->vsync_comp);
spin_unlock(&dma->dma_lock);
- if (vsync_client.handler)
+ if (vsync_client.handler) {
vsync_client.handler(vsync_client.arg);
- else
- mdp3_irq_disable_nosync(type);
+ } else {
+ if (wait_for_next_vs)
+ mdp3_irq_disable_nosync(type);
+ }
}
static void mdp3_dma_done_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
+ struct mdp3_notification dma_client;
pr_debug("mdp3_dma_done_intr_handler\n");
+ spin_lock(&dma->dma_lock);
+ dma_client = dma->dma_notifier_client;
complete(&dma->dma_comp);
+ spin_unlock(&dma->dma_lock);
mdp3_irq_disable_nosync(type);
+ if (dma_client.handler)
+ dma_client.handler(dma_client.arg);
}
static void mdp3_hist_done_intr_handler(int type, void *arg)
@@ -189,7 +201,7 @@
}
static void mdp3_dma_vsync_enable(struct mdp3_dma *dma,
- struct mdp3_vsync_notification *vsync_client)
+ struct mdp3_notification *vsync_client)
{
unsigned long flag;
int updated = 0;
@@ -220,6 +232,21 @@
}
}
+static void mdp3_dma_done_notifier(struct mdp3_dma *dma,
+ struct mdp3_notification *dma_client)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dma->dma_lock, flag);
+ if (dma_client) {
+ dma->dma_notifier_client = *dma_client;
+ } else {
+ dma->dma_notifier_client.handler = NULL;
+ dma->dma_notifier_client.arg = NULL;
+ }
+ spin_unlock_irqrestore(&dma->dma_lock, flag);
+}
+
static void mdp3_dma_clk_auto_gating(struct mdp3_dma *dma, int enable)
{
u32 cgc;
@@ -268,6 +295,23 @@
return 0;
}
+static void mdp3_dma_stride_config(struct mdp3_dma *dma, int stride)
+{
+ struct mdp3_dma_source *source_config;
+ u32 dma_stride_offset;
+
+ if (dma->dma_sel == MDP3_DMA_P)
+ dma_stride_offset = MDP3_REG_DMA_P_IBUF_Y_STRIDE;
+ else
+ dma_stride_offset = MDP3_REG_DMA_S_IBUF_Y_STRIDE;
+
+ source_config = &dma->source_config;
+ source_config->stride = stride;
+ pr_debug("%s: Update the fb stride for DMA to %d", __func__,
+ (u32)source_config->stride);
+ MDP3_REG_WRITE(dma_stride_offset, source_config->stride);
+}
+
static int mdp3_dmap_config(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config,
struct mdp3_dma_output_config *output_config)
@@ -529,13 +573,20 @@
{
unsigned long flag;
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+ int rc = 0;
pr_debug("mdp3_dmap_update\n");
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
- if (intf->active)
- wait_for_completion_killable(&dma->dma_comp);
+ if (intf->active) {
+ rc = wait_for_completion_timeout(&dma->dma_comp,
+ KOFF_TIMEOUT);
+ if (rc <= 0) {
+ WARN(1, "cmd kickoff timed out (%d)\n", rc);
+ rc = -1;
+ }
+ }
}
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
@@ -550,16 +601,22 @@
intf->start(intf);
}
- wmb();
+ mb();
+ dma->vsync_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS) &
+ (1 << MDP3_INTR_LCDC_START_OF_FRAME);
init_completion(&dma->vsync_comp);
spin_unlock_irqrestore(&dma->dma_lock, flag);
mdp3_dma_callback_enable(dma, cb_type);
pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
- if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
- wait_for_completion_killable(&dma->vsync_comp);
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ rc = wait_for_completion_timeout(&dma->vsync_comp,
+ KOFF_TIMEOUT);
+ if (rc <= 0)
+ rc = -1;
+ }
pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
- return 0;
+ return rc;
}
static int mdp3_dmas_update(struct mdp3_dma *dma, void *buf,
@@ -853,8 +910,10 @@
dma->get_histo = mdp3_dmap_histo_get;
dma->histo_op = mdp3_dmap_histo_op;
dma->vsync_enable = mdp3_dma_vsync_enable;
+ dma->dma_done_notifier = mdp3_dma_done_notifier;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
+ dma->config_stride = mdp3_dma_stride_config;
break;
case MDP3_DMA_S:
dma->dma_config = mdp3_dmas_config;
@@ -869,6 +928,7 @@
dma->vsync_enable = mdp3_dma_vsync_enable;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
+ dma->config_stride = mdp3_dma_stride_config;
break;
case MDP3_DMA_E:
default:
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 6983e55..04955d4 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -14,6 +14,7 @@
#ifndef MDP3_DMA_H
#define MDP3_DMA_H
+#include <linux/notifier.h>
#include <linux/sched.h>
#define MDP_HISTOGRAM_BL_SCALE_MAX 1024
@@ -227,7 +228,7 @@
u32 extra[2];
};
-struct mdp3_vsync_notification {
+struct mdp3_notification {
void (*handler)(void *arg);
void *arg;
};
@@ -245,7 +246,8 @@
struct completion vsync_comp;
struct completion dma_comp;
struct completion histo_comp;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
+ struct mdp3_notification dma_notifier_client;
struct mdp3_dma_output_config output_config;
struct mdp3_dma_source source_config;
@@ -256,6 +258,7 @@
struct mdp3_dma_histogram_config histogram_config;
int histo_state;
struct mdp3_dma_histogram_data histo_data;
+ unsigned int vsync_status;
int (*dma_config)(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config,
@@ -287,8 +290,13 @@
int (*histo_op)(struct mdp3_dma *dma, u32 op);
+ void (*config_stride)(struct mdp3_dma *dma, int stride);
+
void (*vsync_enable)(struct mdp3_dma *dma,
- struct mdp3_vsync_notification *vsync_client);
+ struct mdp3_notification *vsync_client);
+
+ void (*dma_done_notifier)(struct mdp3_dma *dma,
+ struct mdp3_notification *dma_client);
};
struct mdp3_video_intf_cfg {
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index a64a6b4..d778af8 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -412,12 +412,47 @@
mdp3_ppp_kickoff();
}
-static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+static int solid_fill_workaround(struct mdp_blit_req *req,
+ struct ppp_blit_op *blit_op)
+{
+ /* Make width 2 when there is a solid fill of width 1, and make
+ sure width does not become zero while trying to avoid odd width */
+ if (blit_op->dst.roi.width == 1) {
+ if (req->dst_rect.x + 2 > req->dst.width) {
+ pr_err("%s: Unable to handle solid fill of width 1",
+ __func__);
+ return -EINVAL;
+ }
+ blit_op->dst.roi.width = 2;
+ }
+ if (blit_op->src.roi.width == 1) {
+ if (req->src_rect.x + 2 > req->src.width) {
+ pr_err("%s: Unable to handle solid fill of width 1",
+ __func__);
+ return -EINVAL;
+ }
+ blit_op->src.roi.width = 2;
+ }
+
+ /* 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;
+ return 0;
+}
+
+static int mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
struct mdp_blit_req *req, struct mdp3_img_data *src_data,
struct mdp3_img_data *dst_data)
{
unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
uint32_t dst_width, dst_height;
+ int ret = 0;
srcp0_start = (unsigned long) src_data->addr;
srcp0_len = (unsigned long) src_data->len;
@@ -510,24 +545,19 @@
blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
if (req->flags & MDP_SOLID_FILL) {
- blit_op->solid_fill = true;
+ ret = solid_fill_workaround(req, blit_op);
+ if (ret)
+ return ret;
- /* 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;
+ blit_op->solid_fill = true;
} else {
blit_op->solid_fill = false;
}
+ return ret;
}
static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
@@ -626,6 +656,7 @@
struct mdp3_img_data *dst_data)
{
struct ppp_blit_op blit_op;
+ int ret = 0;
memset(&blit_op, 0, sizeof(blit_op));
@@ -639,7 +670,11 @@
return -EINVAL;
}
- mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+ ret = mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+ if (ret) {
+ pr_err("%s: Failed to process the blit request", __func__);
+ return ret;
+ }
if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
(req->src.format == MDP_ARGB_8888) ||
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index d33aefa..54c8a06 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -793,6 +793,21 @@
return rc;
}
+static struct device_node *mdss_dsi_pref_prim_panel(
+ struct platform_device *pdev)
+{
+ struct device_node *dsi_pan_node = NULL;
+
+ pr_debug("%s:%d: Select primary panel from dt\n",
+ __func__, __LINE__);
+ dsi_pan_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,dsi-pref-prim-pan", 0);
+ if (!dsi_pan_node)
+ pr_err("%s:can't find panel phandle\n", __func__);
+
+ return dsi_pan_node;
+}
+
/**
* mdss_dsi_find_panel_of_node(): find device node of dsi panel
* @pdev: platform_device of the dsi ctrl node
@@ -820,14 +835,7 @@
/* no panel cfg chg, parse dt */
pr_debug("%s:%d: no cmd line cfg present\n",
__func__, __LINE__);
- dsi_pan_node = of_parse_phandle(
- pdev->dev.of_node,
- "qcom,dsi-pref-prim-pan", 0);
- if (!dsi_pan_node) {
- pr_err("%s:can't find panel phandle\n",
- __func__);
- return NULL;
- }
+ dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
} else {
if (panel_cfg[0] == '0') {
pr_debug("%s:%d: DSI ctrl 1\n", __func__, __LINE__);
@@ -860,11 +868,12 @@
dsi_pan_node = of_find_node_by_name(mdss_node,
panel_name);
if (!dsi_pan_node) {
- pr_err("%s: invalid pan node\n",
+ pr_err("%s: invalid pan node, selecting prim panel\n",
__func__);
- return NULL;
+ dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
}
}
+
return dsi_pan_node;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index d743c42..855ec6c 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -233,7 +233,7 @@
int (*off) (struct mdss_panel_data *pdata);
int (*partial_update_fnc) (struct mdss_panel_data *pdata);
int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
- void (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+ int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
int reg_size;
@@ -336,7 +336,7 @@
void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c
index 9a3e638..8fc1115c0 100644
--- a/drivers/video/msm/mdss/mdss_dsi_cmd.c
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c
@@ -655,7 +655,7 @@
{
struct dcs_cmd_req *req;
struct dcs_cmd_list *clist;
- int ret = 0;
+ int ret = -EINVAL;
mutex_lock(&ctrl->cmd_mutex);
clist = &ctrl->cmdlist;
@@ -674,7 +674,6 @@
}
mutex_unlock(&ctrl->cmd_mutex);
- ret++;
pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
clist->tot, clist->put, clist->get);
@@ -682,7 +681,7 @@
if (!ctrl->cmdlist_commit)
pr_err("cmdlist_commit not implemented!\n");
else
- ctrl->cmdlist_commit(ctrl, 0);
+ ret = ctrl->cmdlist_commit(ctrl, 0);
}
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 37ccd4f..65e6214 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1155,38 +1155,55 @@
__func__, current->pid);
}
-void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dcs_cmd_req *req)
{
- int ret;
+ int ret, ret_val = -EINVAL;
ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
+ if (!IS_ERR_VALUE(ret))
+ ret_val = 0;
+
if (req->cb)
req->cb(ret);
+
+ return ret_val;
}
-void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dcs_cmd_req *req)
{
struct dsi_buf *rp;
- int len = 0;
+ int len = 0, ret = -EINVAL;
if (req->rbuf) {
rp = &ctrl->rx_buf;
len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
memcpy(req->rbuf, rp->data, rp->len);
+ /*
+ * For dual DSI cases, early return of controller - 0
+ * is valid. Hence, for those cases the return value
+ * is zero even though we don't send any commands.
+ *
+ */
+ if ((ctrl->shared_pdata.broadcast_enable &&
+ ctrl->ndx == DSI_CTRL_0) || (len != 0))
+ ret = 0;
} else {
pr_err("%s: No rx buffer provided\n", __func__);
}
if (req->cb)
req->cb(len);
+
+ return ret;
}
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
{
struct dcs_cmd_req *req;
+ int ret = -EINVAL;
mutex_lock(&ctrl->cmd_mutex);
req = mdss_dsi_cmdlist_get(ctrl);
@@ -1211,9 +1228,9 @@
mdss_dsi_clk_ctrl(ctrl, 1);
if (req->flags & CMD_REQ_RX)
- mdss_dsi_cmdlist_rx(ctrl, req);
+ ret = mdss_dsi_cmdlist_rx(ctrl, req);
else
- mdss_dsi_cmdlist_tx(ctrl, req);
+ ret = mdss_dsi_cmdlist_tx(ctrl, req);
mdss_dsi_clk_ctrl(ctrl, 0);
mdss_bus_bandwidth_ctrl(0);
@@ -1224,6 +1241,7 @@
mdss_dsi_cmd_mdp_start(ctrl);
mutex_unlock(&ctrl->cmd_mutex);
+ return ret;
}
static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events)
@@ -1313,6 +1331,8 @@
if (status) {
MIPI_OUTP(base + 0x0068, status);
+ /* Writing of an extra 0 needed to clear error bits */
+ MIPI_OUTP(base + 0x0068, 0);
pr_err("%s: status=%x\n", __func__, status);
}
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 06f6959..3c7d17c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -19,7 +19,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/leds.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
#include <linux/err.h>
#include "mdss_dsi.h"
@@ -69,9 +69,9 @@
ctrl->pwm_enabled = 0;
}
- ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
+ ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period);
if (ret) {
- pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+ pr_err("%s: pwm_config_us() failed err=%d.\n", __func__, ret);
return;
}
@@ -459,7 +459,7 @@
}
data = of_get_property(np, link_key, NULL);
- if (!strncmp(data, "dsi_hs_mode", 11))
+ if (data && !strcmp(data, "dsi_hs_mode"))
pcmds->link_state = DSI_HS_MODE;
else
pcmds->link_state = DSI_LP_MODE;
@@ -695,19 +695,24 @@
pdest = of_get_property(np,
"qcom,mdss-dsi-panel-destination", NULL);
- if (strlen(pdest) != 9) {
- pr_err("%s: Unknown pdest specified\n", __func__);
+ if (pdest) {
+ if (strlen(pdest) != 9) {
+ pr_err("%s: Unknown pdest specified\n", __func__);
+ return -EINVAL;
+ }
+ if (!strcmp(pdest, "display_1"))
+ pinfo->pdest = DISPLAY_1;
+ else if (!strcmp(pdest, "display_2"))
+ pinfo->pdest = DISPLAY_2;
+ else {
+ pr_debug("%s: pdest not specified. Set Default\n",
+ __func__);
+ pinfo->pdest = DISPLAY_1;
+ }
+ } else {
+ pr_err("%s: pdest not specified\n", __func__);
return -EINVAL;
}
- if (!strncmp(pdest, "display_1", 9))
- pinfo->pdest = DISPLAY_1;
- else if (!strncmp(pdest, "display_2", 9))
- pinfo->pdest = DISPLAY_2;
- else {
- pr_debug("%s: pdest not specified. Set Default\n",
- __func__);
- pinfo->pdest = DISPLAY_1;
- }
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
pinfo->lcdc.h_front_porch = (!rc ? tmp : 6);
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp);
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index bb27e6b..6dbca10 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -23,7 +23,7 @@
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/regulator/consumer.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
#include <linux/clk.h>
#include <linux/spinlock_types.h>
#include <linux/kthread.h>
@@ -210,11 +210,11 @@
if (bl_level > bl_max)
bl_level = bl_max;
- ret = pwm_config(edp_drv->bl_pwm,
+ ret = pwm_config_us(edp_drv->bl_pwm,
bl_level * edp_drv->pwm_period / bl_max,
edp_drv->pwm_period);
if (ret) {
- pr_err("%s: pwm_config() failed err=%d.\n", __func__,
+ pr_err("%s: pwm_config_us() failed err=%d.\n", __func__,
ret);
return;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index c15c02b..54e3bc8 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1836,11 +1836,11 @@
int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
{
- int ret = -EINVAL;
+ int ret = 0;
if (req_state == mfd->dcm_state) {
- pr_warn("Already in correct DCM state");
- ret = 0;
+ pr_warn("Already in correct DCM/DTM state");
+ return ret;
}
switch (req_state) {
@@ -1856,11 +1856,12 @@
break;
case DCM_ENTER:
if (mfd->dcm_state == DCM_UNBLANK) {
- /* Keep unblank path available for only
- DCM operation */
+ /*
+ * Keep unblank path available for only
+ * DCM operation
+ */
mfd->panel_power_on = false;
mfd->dcm_state = DCM_ENTER;
- ret = 0;
}
break;
case DCM_EXIT:
@@ -1868,7 +1869,6 @@
/* Release the unblank path for exit */
mfd->panel_power_on = true;
mfd->dcm_state = DCM_EXIT;
- ret = 0;
}
break;
case DCM_BLANK:
@@ -1882,7 +1882,16 @@
}
}
break;
+ case DTM_ENTER:
+ if (mfd->dcm_state == DCM_UNINIT)
+ mfd->dcm_state = DTM_ENTER;
+ break;
+ case DTM_EXIT:
+ if (mfd->dcm_state == DTM_ENTER)
+ mfd->dcm_state = DCM_UNINIT;
+ break;
}
+
return ret;
}
@@ -2187,6 +2196,7 @@
struct platform_device *fb_pdev, *mdss_pdev;
struct device_node *node;
int rc = 0;
+ bool master_panel = true;
if (!pdev || !pdev->dev.of_node) {
pr_err("Invalid device node\n");
@@ -2214,6 +2224,8 @@
fb_pdev = of_find_device_by_node(node);
if (fb_pdev) {
rc = mdss_fb_register_extra_panel(fb_pdev, pdata);
+ if (rc == 0)
+ master_panel = false;
} else {
pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
fb_pdev = of_platform_device_create(node, NULL,
@@ -2221,7 +2233,7 @@
fb_pdev->dev.platform_data = pdata;
}
- if (mdp_instance->panel_register_done)
+ if (master_panel && mdp_instance->panel_register_done)
mdp_instance->panel_register_done(pdata);
mdss_notfound:
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index b218b1e..3269eec 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1316,7 +1316,7 @@
{
char *t = NULL;
char pan_intf_str[MDSS_MAX_PANEL_LEN];
- int rc, i;
+ int rc, i, panel_len;
char pan_name[MDSS_MAX_PANEL_LEN];
if (!pan_cfg)
@@ -1353,6 +1353,14 @@
strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
t, pan_cfg->arg_cfg);
+
+ panel_len = strlen(pan_cfg->arg_cfg);
+ if (!panel_len) {
+ pr_err("%s: Panel name is invalid\n", __func__);
+ pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+ return -EINVAL;
+ }
+
rc = mdss_mdp_get_pan_intf(pan_intf_str);
pan_cfg->pan_intf = (rc < 0) ? MDSS_PANEL_INTF_INVALID : rc;
return 0;
@@ -1457,10 +1465,10 @@
of_node_put(chosen_node);
rc = mdss_mdp_get_pan_cfg(pan_cfg);
- if (!rc)
+ if (!rc) {
pan_cfg->init_done = true;
-
- return rc;
+ return rc;
+ }
get_dt_pan:
rc = mdss_mdp_parse_dt_pan_intf(pdev);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 769f9b2..fad6b0c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -289,6 +289,7 @@
struct mdss_ad_info {
u8 num;
u8 calc_hw_num;
+ u32 ops;
u32 sts;
u32 reg_sts;
u32 state;
@@ -516,7 +517,7 @@
int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata);
int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index bad4d06..d57e4fb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1062,26 +1062,34 @@
return rc;
}
-static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_mixer *mixer;
u32 outsize, temp;
int ret = 0;
int i, nmixers;
- if (ctl->start_fnc)
- ret = ctl->start_fnc(ctl);
- else
- pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
- ctl->panel_data->panel_info.type);
-
- if (ret) {
- pr_err("unable to start intf\n");
- return ret;
- }
-
pr_debug("ctl_num=%d\n", ctl->num);
+ /*
+ * Need start_fnc in 2 cases:
+ * (1) handoff
+ * (2) continuous splash finished.
+ */
+ if (handoff || !ctl->panel_data->panel_info.cont_splash_enabled) {
+ if (ctl->start_fnc)
+ ret = ctl->start_fnc(ctl);
+ else
+ pr_warn("no start function for ctl=%d type=%d\n",
+ ctl->num,
+ ctl->panel_data->panel_info.type);
+
+ if (ret) {
+ pr_err("unable to start intf\n");
+ return ret;
+ }
+ }
+
if (!ctl->panel_data->panel_info.cont_splash_enabled) {
nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER +
MDSS_MDP_WB_MAX_LAYERMIXER;
@@ -1108,7 +1116,7 @@
return ret;
}
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_ctl *sctl;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -1123,12 +1131,17 @@
if (ret)
return ret;
-
sctl = mdss_mdp_get_split_ctl(ctl);
mutex_lock(&ctl->lock);
- ctl->power_on = true;
+ /*
+ * keep power_on false during handoff to avoid unexpected
+ * operations to overlay.
+ */
+ if (!handoff)
+ ctl->power_on = true;
+
ctl->bus_ab_quota = 0;
ctl->bus_ib_quota = 0;
ctl->clk_rate = 0;
@@ -1141,10 +1154,10 @@
goto error;
}
- ret = mdss_mdp_ctl_start_sub(ctl);
+ ret = mdss_mdp_ctl_start_sub(ctl, handoff);
if (ret == 0) {
if (sctl) { /* split display is available */
- ret = mdss_mdp_ctl_start_sub(sctl);
+ ret = mdss_mdp_ctl_start_sub(sctl, handoff);
if (!ret)
mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
} else if (ctl->mixer_right) {
@@ -1900,8 +1913,10 @@
if (ctl->wait_pingpong)
ctl->wait_pingpong(ctl, NULL);
- /* postprocessing setup, including dspp */
- mdss_mdp_pp_setup_locked(ctl);
+ if (ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
+ /* postprocessing setup, including dspp */
+ mdss_mdp_pp_setup_locked(ctl);
+
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
if (sctl) {
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index b6f94d0..bcd3cf4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -108,7 +108,9 @@
MDSS_MDP_MAX_CTL
};
-#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
+#define MDSS_MDP_CTL_ADDRESS_OFFSET 0x100
+#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * \
+ MDSS_MDP_CTL_ADDRESS_OFFSET))
#define MDSS_MDP_REG_CTL_LAYER(lm) ((lm) * 0x004)
#define MDSS_MDP_REG_CTL_TOP 0x014
@@ -159,7 +161,10 @@
MDSS_MDP_CHROMA_420
};
-#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
+
+#define MDSS_MDP_SSPP_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * \
+ MDSS_MDP_SSPP_ADDRESS_OFFSET))
#define MDSS_MDP_REG_SSPP_SRC_SIZE 0x000
#define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE 0x004
@@ -175,6 +180,7 @@
#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C
#define MDSS_MDP_REG_SSPP_SRC_FORMAT 0x030
#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034
+#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR 0x03C
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0 0x050
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1 0x054
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2 0x058
@@ -280,8 +286,9 @@
MDSS_MDP_MAX_STAGE
};
-#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
-
+#define MDSS_MDP_LM_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * \
+ MDSS_MDP_LM_ADDRESS_OFFSET))
#define MDSS_MDP_REG_LM_OP_MODE 0x000
#define MDSS_MDP_REG_LM_OUT_SIZE 0x004
#define MDSS_MDP_REG_LM_BORDER_COLOR_0 0x008
@@ -423,7 +430,9 @@
MDSS_MDP_MAX_DSPP
};
-#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * 0x400))
+#define MDSS_MDP_DSPP_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * \
+ MDSS_MDP_DSPP_ADDRESS_OFFSET))
#define MDSS_MDP_REG_DSPP_OP_MODE 0x000
#define MDSS_MDP_REG_DSPP_PCC_BASE 0x030
#define MDSS_MDP_REG_DSPP_DITHER_DEPTH 0x150
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 14b486a..4c89064 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -859,7 +859,7 @@
mdss_hw_init(mdss_res);
}
- rc = mdss_mdp_ctl_start(ctl);
+ rc = mdss_mdp_ctl_start(ctl, false);
if (rc == 0) {
atomic_inc(&ov_active_panels);
@@ -1580,8 +1580,8 @@
return -ENODEV;
if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
return -EOPNOTSUPP;
-
- if (!ctl->power_on) {
+ if (!ctl->panel_data->panel_info.cont_splash_enabled
+ && !ctl->power_on) {
pr_debug("fb%d vsync pending first update en=%d\n",
mfd->index, en);
return -EPERM;
@@ -1698,7 +1698,9 @@
u64 vsync_ticks;
int ret;
- if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+ if (!mdp5_data->ctl ||
+ (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
+ && !mdp5_data->ctl->power_on))
return -EAGAIN;
vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
@@ -2535,9 +2537,15 @@
mdp5_data->ctl = ctl;
}
- rc = mdss_mdp_ctl_setup(ctl);
- if (rc)
+ /*
+ * vsync interrupt needs on during continuous splash, this is
+ * to initialize necessary ctl members here.
+ */
+ rc = mdss_mdp_ctl_start(ctl, true);
+ if (rc) {
+ pr_err("Failed to initialize ctl\n");
goto error;
+ }
ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0dc61d0..555974b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -173,6 +173,13 @@
GAMUT_T2_SIZE + GAMUT_T3_SIZE + GAMUT_T4_SIZE + \
GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
+#define MDSS_MDP_PA_SIZE 0xC
+#define MDSS_MDP_GC_SIZE 0x28
+#define MDSS_MDP_PCC_SIZE 0xB8
+#define MDSS_MDP_GAMUT_SIZE 0x5C
+#define MDSS_MDP_IGC_DSPP_COLORS 0x3
+#define TOTAL_BLEND_STAGES 0x4
+
#define PP_FLAGS_DIRTY_PA 0x1
#define PP_FLAGS_DIRTY_PCC 0x2
#define PP_FLAGS_DIRTY_IGC 0x4
@@ -205,6 +212,10 @@
#define PP_AD_BAD_HW_NUM 255
+#define MDSS_SIDE_NONE 0
+#define MDSS_SIDE_LEFT 1
+#define MDSS_SIDE_RIGHT 2
+
#define PP_AD_STATE_INIT 0x2
#define PP_AD_STATE_CFG 0x4
#define PP_AD_STATE_DATA 0x8
@@ -293,15 +304,15 @@
struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
- /* physical info */
struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM];
+ /* physical info */
struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
};
static DEFINE_MUTEX(mdss_pp_mutex);
static struct mdss_pp_res_type *mdss_pp_res;
-static void pp_hist_read(char __iomem *v_addr,
+static u32 pp_hist_read(char __iomem *v_addr,
struct pp_hist_col_info *hist_info);
static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix);
static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
@@ -340,8 +351,9 @@
static void pp_dither_config(char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_dither_cfg_data *dither_cfg);
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
- int mdp_rev);
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+ struct pp_sts_type *pp_sts, int mdp_rev,
+ u32 *opmode);
static void pp_sharp_config(char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_sharp_cfg *sharp_config);
@@ -375,11 +387,15 @@
struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl);
static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
struct mdss_ad_info *ad);
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode);
static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
struct mdss_ad_info *ad);
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+ struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
+static inline bool pp_sts_is_enabled(u32 sts, int side);
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
static u32 last_sts, last_state;
@@ -511,6 +527,7 @@
pp_sts->gamut_sts &= ~PP_STS_ENABLE;
else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
pp_sts->gamut_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->gamut_sts, gamut_cfg->flags);
}
static void pp_pa_config(unsigned long flags, char __iomem *addr,
@@ -679,6 +696,7 @@
if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK)
pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK;
+ pp_sts_set_split_bits(&pp_sts->pa_sts, pa_v2_config->flags);
}
static void pp_pcc_config(unsigned long flags, char __iomem *addr,
@@ -693,6 +711,7 @@
pp_sts->pcc_sts &= ~PP_STS_ENABLE;
else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
pp_sts->pcc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->pcc_sts, pcc_config->ops);
}
}
@@ -720,6 +739,7 @@
pp_sts->igc_sts &= ~PP_STS_ENABLE;
else if (igc_config->ops & MDP_PP_OPS_ENABLE)
pp_sts->igc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
}
}
@@ -1324,12 +1344,20 @@
pp_sts->dither_sts &= ~PP_STS_ENABLE;
else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
pp_sts->dither_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->dither_sts, dither_cfg->flags);
}
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
- int mdp_rev)
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+ struct pp_sts_type *pp_sts, int mdp_rev,
+ u32 *opmode)
{
- if (pp_sts->pa_sts & PP_STS_ENABLE)
+ int side;
+ side = pp_num_to_side(ctl, num);
+
+ if (side < 0)
+ return;
+
+ if (pp_sts_is_enabled(pp_sts->pa_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
if (mdp_rev >= MDSS_MDP_HW_REV_103) {
if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
@@ -1357,10 +1385,10 @@
if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK)
*opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK;
}
- if (pp_sts->pcc_sts & PP_STS_ENABLE)
+ if (pp_sts_is_enabled(pp_sts->pcc_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */
- if (pp_sts->igc_sts & PP_STS_ENABLE) {
+ if (pp_sts_is_enabled(pp_sts->igc_sts, side)) {
*opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */
(pp_sts->igc_tbl_idx << 1);
}
@@ -1368,14 +1396,14 @@
*opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */
MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
}
- if (pp_sts->dither_sts & PP_STS_ENABLE)
+ if (pp_sts_is_enabled(pp_sts->dither_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */
- if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+ if (pp_sts_is_enabled(pp_sts->gamut_sts, side)) {
*opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */
if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
*opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER;
}
- if (pp_sts->pgc_sts & PP_STS_ENABLE)
+ if (pp_sts_is_enabled(pp_sts->pgc_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN;
}
@@ -1481,6 +1509,7 @@
pp_sts->pgc_sts &= ~PP_STS_ENABLE;
else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
pp_sts->pgc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->pgc_sts, pgc_config->flags);
}
if (ad_hw) {
@@ -1492,12 +1521,12 @@
pp_ad_init_write(ad_hw, ad, ctl);
if (ad_flags & PP_AD_STS_DIRTY_CFG)
pp_ad_cfg_write(ad_hw, ad);
- pp_ad_bypass_config(ad, &ad_bypass);
+ pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass);
writel_relaxed(ad_bypass, ad_hw->base);
mutex_unlock(&ad->lock);
}
- pp_dspp_opmode_config(pp_sts, &opmode, mdata->mdp_rev);
+ pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
flush_exit:
writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
ctl->flush_bits |= BIT(13 + dspp_num);
@@ -1705,11 +1734,13 @@
if (mdss_pp_res == NULL) {
pr_err("%s mdss_pp_res allocation failed!", __func__);
ret = -ENOMEM;
- }
-
- for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
- mutex_init(&mdss_pp_res->dspp_hist[i].hist_mutex);
- spin_lock_init(&mdss_pp_res->dspp_hist[i].hist_lock);
+ } else {
+ for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
+ mutex_init(
+ &mdss_pp_res->dspp_hist[i].hist_mutex);
+ spin_lock_init(
+ &mdss_pp_res->dspp_hist[i].hist_lock);
+ }
}
}
if (mdata) {
@@ -1836,6 +1867,12 @@
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->pa_v2_data.flags & MDSS_PP_SPLIT_MASK) ==
+ MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2119,6 +2156,11 @@
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2238,6 +2280,11 @@
if (config->len != IGC_LUT_ENTRIES)
return -EINVAL;
+ if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2437,6 +2484,11 @@
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2608,6 +2660,11 @@
if (config->flags & MDP_PP_OPS_READ)
return -ENOTSUPP;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
mdss_pp_res->dither_disp_cfg[disp_num] = *config;
@@ -2657,6 +2714,11 @@
if (pp_gm_has_invalid_lut_size(config))
return -EINVAL;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2773,19 +2835,27 @@
mutex_unlock(&mdss_pp_mutex);
return ret;
}
-static void pp_hist_read(char __iomem *v_addr,
+
+static u32 pp_hist_read(char __iomem *v_addr,
struct pp_hist_col_info *hist_info)
{
int i, i_start;
+ u32 sum = 0;
u32 data;
data = readl_relaxed(v_addr);
i_start = data >> 24;
hist_info->data[i_start] = data & 0xFFFFFF;
- for (i = i_start + 1; i < HIST_V_SIZE; i++)
+ sum += hist_info->data[i_start];
+ for (i = i_start + 1; i < HIST_V_SIZE; i++) {
hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
- for (i = 0; i < i_start - 1; i++)
+ sum += hist_info->data[i];
+ }
+ for (i = 0; i < i_start; i++) {
hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
+ sum += hist_info->data[i];
+ }
hist_info->hist_cnt_read++;
+ return sum;
}
/* Assumes that relevant clocks are enabled */
@@ -3168,10 +3238,10 @@
static int pp_hist_collect(struct mdp_histogram_data *hist,
struct pp_hist_col_info *hist_info,
- char __iomem *ctl_base)
+ char __iomem *ctl_base, u32 expect_sum)
{
int wait_ret, ret = 0;
- u32 timeout;
+ u32 timeout, sum;
char __iomem *v_base;
unsigned long flag;
struct mdss_pipe_pp_res *res;
@@ -3238,10 +3308,13 @@
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
v_base = ctl_base + 0x1C;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- pp_hist_read(v_base, hist_info);
+ sum = pp_hist_read(v_base, hist_info);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
spin_lock_irqsave(&hist_info->hist_lock, flag);
- hist_info->read_request = false;
+ if (!expect_sum || sum == expect_sum)
+ hist_info->read_request = false;
+ else
+ ret = -ENODATA;
hist_info->col_state = HIST_IDLE;
}
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -3261,6 +3334,7 @@
u32 *hist_data_addr;
u32 pipe_cnt = 0;
u32 pipe_num = MDSS_MDP_SSPP_VIG0;
+ u32 exp_sum = 0;
struct mdss_mdp_pipe *pipe;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -3290,7 +3364,10 @@
hist_info = &mdss_pp_res->dspp_hist[dspp_num];
ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
- ret = pp_hist_collect(hist, hist_info, ctl_base);
+ exp_sum = (mdata->mixer_intf[dspp_num].width *
+ mdata->mixer_intf[dspp_num].height);
+ ret = pp_hist_collect(hist, hist_info, ctl_base,
+ exp_sum);
if (ret)
goto hist_collect_exit;
}
@@ -3359,7 +3436,8 @@
hist_info = &pipe->pp_res.hist;
ctl_base = pipe->base +
MDSS_MDP_REG_VIG_HIST_CTL_BASE;
- ret = pp_hist_collect(hist, hist_info, ctl_base);
+ ret = pp_hist_collect(hist, hist_info, ctl_base,
+ exp_sum);
mdss_mdp_pipe_unmap(pipe);
if (ret)
goto hist_collect_exit;
@@ -3490,6 +3568,53 @@
return out;
}
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num)
+{
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 mixer_num;
+
+ if (!ctl || !ctl->mfd)
+ return -EINVAL;
+ mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
+ if (mixer_num < 2)
+ return MDSS_SIDE_NONE;
+ else if (mixer_id[1] == num)
+ return MDSS_SIDE_RIGHT;
+ else if (mixer_id[0] == num)
+ return MDSS_SIDE_LEFT;
+ else
+ pr_err("invalid, not on any side");
+ return -EINVAL;
+}
+
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits)
+{
+ u32 tmp = *sts;
+ tmp &= ~MDSS_PP_SPLIT_MASK;
+ tmp |= bits & MDSS_PP_SPLIT_MASK;
+ *sts = tmp;
+}
+
+static inline bool pp_sts_is_enabled(u32 sts, int side)
+{
+ bool ret = false;
+ /*
+ * If there are no sides, or if there are no split mode bits set, the
+ * side can't be disabled via split mode.
+ *
+ * Otherwise, if the side being checked opposes the split mode
+ * configuration, the side is disabled.
+ */
+ if ((side == MDSS_SIDE_NONE) || !(sts & MDSS_PP_SPLIT_MASK))
+ ret = true;
+ else if ((sts & MDSS_PP_SPLIT_RIGHT_ONLY) && (side == MDSS_SIDE_RIGHT))
+ ret = true;
+ else if ((sts & MDSS_PP_SPLIT_LEFT_ONLY) && (side == MDSS_SIDE_LEFT))
+ ret = true;
+
+ return ret && (sts & PP_STS_ENABLE);
+}
+
static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
{
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -3586,7 +3711,7 @@
struct mdss_mdp_ctl *ctl;
struct msm_fb_data_type *bl_mfd;
int lin_ret = -1, inv_ret = -1, ret = 0;
- u32 ratio_temp, shift = 0;
+ u32 ratio_temp, shift = 0, last_ops;
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret)
@@ -3599,6 +3724,11 @@
bl_mfd = mfd;
}
+ if ((init_cfg->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&ad->lock);
if (init_cfg->ops & MDP_PP_AD_INIT) {
memcpy(&ad->init, &init_cfg->params.init,
@@ -3638,6 +3768,22 @@
ad->sts |= PP_AD_STS_DIRTY_CFG;
}
+ last_ops = ad->ops & MDSS_PP_SPLIT_MASK;
+ ad->ops = init_cfg->ops & MDSS_PP_SPLIT_MASK;
+ /*
+ * if there is a change in the split mode config, the init values
+ * need to be re-written to hardware (if they have already been
+ * written or if there is data pending to be written). Check for
+ * pending data (DIRTY_INIT) is not checked here since it will not
+ * affect the outcome of this conditional (i.e. if init hasn't
+ * already been written (*_STATE_INIT is set), this conditional will
+ * only evaluate to true (and set the DIRTY bit) if the DIRTY bit has
+ * already been set).
+ */
+ if ((last_ops ^ ad->ops) && (ad->state & PP_AD_STATE_INIT))
+ ad->sts |= PP_AD_STS_DIRTY_INIT;
+
+
if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
ad->sts &= ~PP_STS_ENABLE;
mutex_unlock(&ad->lock);
@@ -3792,8 +3938,9 @@
u32 temp;
u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl;
u32 num;
+ int side;
char __iomem *base;
- bool is_calc, is_dual_pipe;
+ bool is_calc, is_dual_pipe, split_mode;
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
u32 mixer_num;
mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
@@ -3804,6 +3951,7 @@
base = ad_hw->base;
is_calc = ad->calc_hw_num == ad_hw->num;
+ split_mode = !!(ad->ops & MDSS_PP_SPLIT_MASK);
writel_relaxed(ad->init.i_control[0] & 0x1F,
base + MDSS_MDP_REG_AD_CON_CTRL_0);
@@ -3829,7 +3977,10 @@
writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
- temp = ad->init.frame_w << 16;
+ if (split_mode)
+ temp = mdata->mixer_intf[ad_hw->num].width << 16;
+ else
+ temp = ad->init.frame_w << 16;
temp |= ad->init.frame_h & 0xFFFF;
writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
@@ -3841,17 +3992,26 @@
pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
- if (is_dual_pipe) {
+ if (is_dual_pipe && !split_mode) {
num = ad_hw->num;
+ side = pp_num_to_side(ctl, num);
tile_ctrl = 0x5;
- if (is_calc) {
+ if ((ad->calc_hw_num + 1) == num)
+ tile_ctrl |= 0x10;
+
+ if (side <= MDSS_SIDE_NONE) {
+ WARN(1, "error finding sides, %d", side);
+ frame_start = 0;
+ procs_start = frame_start;
+ frame_end = 0;
+ procs_end = frame_end;
+ } else if (side == MDSS_SIDE_LEFT) {
frame_start = 0;
procs_start = 0;
frame_end = mdata->mixer_intf[num].width +
MDSS_AD_MERGED_WIDTH;
procs_end = mdata->mixer_intf[num].width;
} else {
- tile_ctrl |= 0x10;
procs_start = ad->init.frame_w -
(mdata->mixer_intf[num].width);
procs_end = ad->init.frame_w;
@@ -3866,8 +4026,13 @@
frame_end = 0xFFFF;
procs_start = 0x0;
procs_end = 0xFFFF;
- tile_ctrl = 0x1;
+ if (split_mode)
+ tile_ctrl = 0x0;
+ else
+ tile_ctrl = 0x1;
}
+
+
writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START);
writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END);
writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START);
@@ -3931,12 +4096,17 @@
}
#define MDSS_PP_AD_BYPASS_DEF 0x101
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode)
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+ struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode)
{
- if (ad->reg_sts & PP_STS_ENABLE)
+ int side = pp_num_to_side(ctl, num);
+
+ if (pp_sts_is_enabled(ad->reg_sts | (ad->ops & MDSS_PP_SPLIT_MASK),
+ side)) {
*opmode = 0;
- else
+ } else {
*opmode = MDSS_PP_AD_BYPASS_DEF;
+ }
}
static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
@@ -3951,6 +4121,8 @@
/* default to left mixer */
ad->calc_hw_num = mixer_id[0];
+ if ((mixer_num > 1) && (ad->ops & MDSS_PP_SPLIT_RIGHT_ONLY))
+ ad->calc_hw_num = mixer_id[1];
return 0;
}
@@ -4258,6 +4430,7 @@
mdata->ad_off[i].base = mdata->mdp_base + ad_offsets[i];
mdata->ad_off[i].num = i;
mdata->ad_cfgs[i].num = i;
+ mdata->ad_cfgs[i].ops = 0;
mdata->ad_cfgs[i].reg_sts = 0;
mdata->ad_cfgs[i].calc_itr = 0;
mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
@@ -4270,71 +4443,271 @@
return rc;
}
-static int is_valid_calib_addr(void *addr)
+static int is_valid_calib_ctrl_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ int stage = 0;
+ struct mdss_mdp_ctl *ctl;
+
+ /* Controller */
+ for (counter = 0; counter < mdss_res->nctl; counter++) {
+ ctl = mdss_res->ctl_off + counter;
+ base = ctl->base;
+
+ if (ptr == base + MDSS_MDP_REG_CTL_TOP) {
+ ret = MDP_PP_OPS_READ;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_CTL_FLUSH) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+
+ for (stage = 0; stage < mdss_res->nmixers_intf; stage++)
+ if (ptr == base + MDSS_MDP_REG_CTL_LAYER(stage)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ }
+ }
+
+End:
+ return ret;
+}
+
+static int is_valid_calib_dspp_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_mixer *mixer;
+
+ for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+ mixer = mdss_res->mixer_intf + counter;
+ base = mixer->dspp_base;
+
+ if (ptr == base) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PA range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_PA_BASE +
+ MDSS_MDP_PA_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PCC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PCC_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_PCC_BASE +
+ MDSS_MDP_PCC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Gamut range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GAMUT_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_GAMUT_BASE +
+ MDSS_MDP_GAMUT_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* GC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GC_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_GC_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Dither enable/disable */
+ } else if ((ptr == base + MDSS_MDP_REG_DSPP_DITHER_DEPTH)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_vig_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->nvig_pipes; counter++) {
+ pipe = mdss_res->vig_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if ((ptr == base + MDSS_MDP_REG_VIG_QSEED2_SHARP)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PA range */
+ } else if ((ptr >= base + MDSS_MDP_REG_VIG_PA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_VIG_PA_BASE +
+ MDSS_MDP_PA_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_VIG_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_VIG_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_rgb_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->nrgb_pipes; counter++) {
+ pipe = mdss_res->rgb_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_RGB_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_RGB_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_dma_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->ndma_pipes; counter++) {
+ pipe = mdss_res->dma_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_DMA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_DMA_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_mixer_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ int stage = 0;
+ struct mdss_mdp_mixer *mixer;
+
+ for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+ mixer = mdss_res->mixer_intf + counter;
+ base = mixer->base;
+
+ if (ptr == base + MDSS_MDP_REG_LM_OP_MODE) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* GC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_LM_GC_LUT_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_LM_GC_LUT_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+
+ for (stage = 0; stage < TOTAL_BLEND_STAGES; stage++)
+ if (ptr == base + MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_OP) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ } else if (ptr == base +
+ MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_FG_ALPHA) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ } else if (ptr == base +
+ MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_BG_ALPHA) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ }
+ }
+
+End:
+ return ret;
+}
+
+static int is_valid_calib_addr(void *addr, u32 operation)
{
int ret = 0;
- unsigned int ptr;
- ptr = (unsigned int) addr;
- /* if request is outside the MDP reg-map or is not aligned 4 */
- if (ptr > 0x5138 || ptr % 0x4)
- goto end;
- if (ptr >= 0x100 && ptr <= 0x5138) {
- /* if ptr is in dspp range */
- if (ptr >= 0x4600 && ptr <= 0x5138) {
- /* if ptr is in dspp0 range*/
- if (ptr >= 0x4600 && ptr <= 0x4938)
- ptr -= 0x4600;
- /* if ptr is in dspp1 range */
- else if (ptr >= 0x4a00 && ptr <= 0x4d38)
- ptr -= 0x4a00;
- /* if ptr is in dspp2 range */
- else if (ptr >= 0x4e00 && ptr <= 0x5138)
- ptr -= 0x4e00;
- /* if ptr is in pcc plane rgb coeff.range */
- if (ptr >= 0x30 && ptr <= 0xe8)
- ret = 1;
- /* if ptr is in ARLUT red range */
- else if (ptr >= 0x2b0 && ptr <= 0x2b8)
- ret = 1;
- /* if ptr is in PA range */
- else if (ptr >= 0x238 && ptr <= 0x244)
- ret = 1;
- /* if ptr is in ARLUT green range */
- else if (ptr >= 0x2c0 && ptr <= 0x2c8)
- ret = 1;
- /* if ptr is in ARLUT blue range or
- gamut map table range */
- else if (ptr >= 0x2d0 && ptr <= 0x338)
- ret = 1;
- /* if ptr is dspp0,dspp1,dspp2 op mode
- register */
- else if (ptr == 0)
- ret = 1;
- } else if (ptr >= 0x600 && ptr <= 0x608)
- ret = 1;
- else if (ptr >= 0x400 && ptr <= 0x408)
- ret = 1;
- else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
- (ptr == 0x1430) || (ptr == 0x1e38))
- ret = 1;
- else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
- ret = 1;
- else if (ptr >= 0x3220 && ptr <= 0x3228)
- ret = 1;
- else if (ptr == 0x3200 || ptr == 0x100)
- ret = 1;
- else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
- ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
- ret = 1;
- else if (ptr == 0x618 || ptr == 0x718 || ptr == 0x818 ||
- ptr == 0x918 || ptr == 0xa18)
- ret = 1;
- else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
- ret = 1;
- } else if (ptr == 0x0)
- ret = 1;
-end:
- return ret;
+ char __iomem *ptr = addr;
+ char __iomem *mixer_base = mdss_res->mixer_intf->base;
+ char __iomem *rgb_base = mdss_res->rgb_pipes->base;
+ char __iomem *dma_base = mdss_res->dma_pipes->base;
+ char __iomem *vig_base = mdss_res->vig_pipes->base;
+ char __iomem *ctl_base = mdss_res->ctl_off->base;
+ char __iomem *dspp_base = mdss_res->mixer_intf->dspp_base;
+
+ if ((unsigned int)addr % 4) {
+ ret = 0;
+ } else if (ptr == (mdss_res->mdp_base + MDSS_MDP_REG_HW_VERSION) ||
+ ptr == (mdss_res->mdp_base + MDSS_MDP_REG_DISP_INTF_SEL)) {
+ ret = MDP_PP_OPS_READ;
+ } else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE) &&
+ ptr < (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
+ MDSS_MDP_IGC_DSPP_COLORS)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ } else if (ptr >= dspp_base && ptr < (dspp_base +
+ (mdss_res->nmixers_intf * MDSS_MDP_DSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_dspp_addr(ptr);
+ } else if (ptr >= ctl_base && ptr < (ctl_base + (mdss_res->nctl
+ * MDSS_MDP_CTL_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_ctrl_addr(ptr);
+ } else if (ptr >= vig_base && ptr < (vig_base + (mdss_res->nvig_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_vig_addr(ptr);
+ } else if (ptr >= rgb_base && ptr < (rgb_base + (mdss_res->nrgb_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_rgb_addr(ptr);
+ } else if (ptr >= dma_base && ptr < (dma_base + (mdss_res->ndma_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_dma_addr(ptr);
+ } else if (ptr >= mixer_base && ptr < (mixer_base +
+ (mdss_res->nmixers_intf * MDSS_MDP_LM_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_mixer_addr(ptr);
+ }
+
+ return ret & operation;
}
int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
@@ -4342,11 +4715,12 @@
int ret = -1;
void *ptr = (void *) cfg->addr;
- if (is_valid_calib_addr(ptr))
+ ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+ if (is_valid_calib_addr(ptr, cfg->ops))
ret = 0;
else
return ret;
- ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (cfg->ops & MDP_PP_OPS_READ) {
@@ -4381,65 +4755,50 @@
int i = 0;
if (!cfg) {
- pr_err("Invalid buffer pointer");
+ pr_err("Invalid buffer pointer\n");
return ret;
}
- if (cfg->size == 0 || cfg->size > PAGE_SIZE) {
- pr_err("Invalid buffer size %d", cfg->size);
+ if (cfg->size == 0) {
+ pr_err("Invalid buffer size\n");
return ret;
}
counter = cfg->size / (sizeof(uint32_t) * 2);
buff_org = buff = kzalloc(cfg->size, GFP_KERNEL);
if (buff == NULL) {
- pr_err("Allocation failed");
+ pr_err("Config buffer allocation failed\n");
return ret;
}
if (copy_from_user(buff, cfg->buffer, cfg->size)) {
kfree(buff);
- pr_err("Copy failed");
+ pr_err("config buffer copy failed\n");
return ret;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- if (cfg->ops & MDP_PP_OPS_READ) {
- for (i = 0 ; i < counter ; i++) {
- if (is_valid_calib_addr((void *) *buff)) {
- ret = 0;
- } else {
- ret = -1;
- pr_err("Address validation failed");
- break;
- }
+ for (i = 0; i < counter; i++) {
+ ptr = (void *) (((unsigned int) *buff) + mdss_res->mdp_base);
- ptr = (void *)(((unsigned int) *buff) +
- (mdss_res->mdp_base));
- buff++;
+ if (!is_valid_calib_addr(ptr, cfg->ops)) {
+ ret = -1;
+ pr_err("Address validation failed or access not permitted\n");
+ break;
+ }
+
+ buff++;
+ if (cfg->ops & MDP_PP_OPS_READ)
*buff = readl_relaxed(ptr);
- buff++;
- }
- if (!ret)
- ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
- *copyback = 1;
- } else if (cfg->ops & MDP_PP_OPS_WRITE) {
- for (i = 0 ; i < counter ; i++) {
- if (is_valid_calib_addr((void *) *buff)) {
- ret = 0;
- } else {
- ret = -1;
- pr_err("Address validation failed");
- break;
- }
-
- ptr = (void *)(((unsigned int) *buff) +
- (mdss_res->mdp_base));
- buff++;
+ else if (cfg->ops & MDP_PP_OPS_WRITE)
writel_relaxed(*buff, ptr);
- buff++;
- }
+ buff++;
+ }
+
+ if (ret & MDP_PP_OPS_READ) {
+ ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
+ *copyback = 1;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 329b58e..4640d3b 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -99,7 +99,6 @@
header-y += connector.h
header-y += const.h
header-y += cramfs_fs.h
-header-y += csdio.h
header-y += cuda.h
header-y += cyclades.h
header-y += cycx_cfm.h
diff --git a/include/linux/csdio.h b/include/linux/csdio.h
deleted file mode 100644
index 260c49d..0000000
--- a/include/linux/csdio.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef CSDIO_H
-#define CSDIO_H
-
-#include <linux/ioctl.h>
-
-#define CSDIO_IOC_MAGIC 'm'
-
-#define CSDIO_IOC_ENABLE_HIGHSPEED_MODE _IO(CSDIO_IOC_MAGIC, 0)
-#define CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS _IO(CSDIO_IOC_MAGIC, 1)
-#define CSDIO_IOC_SET_OP_CODE _IO(CSDIO_IOC_MAGIC, 2)
-#define CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE _IO(CSDIO_IOC_MAGIC, 3)
-#define CSDIO_IOC_SET_BLOCK_MODE _IO(CSDIO_IOC_MAGIC, 4)
-#define CSDIO_IOC_CONNECT_ISR _IO(CSDIO_IOC_MAGIC, 5)
-#define CSDIO_IOC_DISCONNECT_ISR _IO(CSDIO_IOC_MAGIC, 6)
-#define CSDIO_IOC_CMD52 _IO(CSDIO_IOC_MAGIC, 7)
-#define CSDIO_IOC_CMD53 _IO(CSDIO_IOC_MAGIC, 8)
-#define CSDIO_IOC_ENABLE_ISR _IO(CSDIO_IOC_MAGIC, 9)
-#define CSDIO_IOC_DISABLE_ISR _IO(CSDIO_IOC_MAGIC, 10)
-#define CSDIO_IOC_SET_VDD _IO(CSDIO_IOC_MAGIC, 11)
-#define CSDIO_IOC_GET_VDD _IO(CSDIO_IOC_MAGIC, 12)
-
-#define CSDIO_IOC_MAXNR 12
-
-struct csdio_cmd53_ctrl_t {
- uint32_t m_block_mode; /* data tran. byte(0)/block(1) mode */
- uint32_t m_op_code; /* address auto increment flag */
- uint32_t m_address;
-} __attribute__ ((packed));
-
-struct csdio_cmd52_ctrl_t {
- uint32_t m_write;
- uint32_t m_address;
- uint32_t m_data;
- uint32_t m_ret;
-} __attribute__ ((packed));
-
-#endif
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f36298b..7131da3 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -22,6 +22,8 @@
#include <linux/types.h>
struct ion_handle;
+typedef struct ion_handle *ion_user_handle_t;
+
/**
* enum ion_heap_types - list of all possible types of heaps
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
@@ -350,7 +352,7 @@
size_t align;
unsigned int heap_mask;
unsigned int flags;
- struct ion_handle *handle;
+ ion_user_handle_t handle;
};
/**
@@ -364,7 +366,7 @@
* provides the file descriptor and the kernel returns the handle.
*/
struct ion_fd_data {
- struct ion_handle *handle;
+ ion_user_handle_t handle;
int fd;
};
@@ -373,7 +375,7 @@
* @handle: a handle
*/
struct ion_handle_data {
- struct ion_handle *handle;
+ ion_user_handle_t handle;
};
/**
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 1bcfd28..43aebb5 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -392,7 +392,7 @@
unsigned int idle_timeout;
struct notifier_block reboot_notify;
bool issue_long_pon;
- u8 cached_ext_csd;
+ u8 *cached_ext_csd;
};
/*
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 724e573..0791545 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -800,8 +800,14 @@
DCM_ENTER,
DCM_EXIT,
DCM_BLANK,
+ DTM_ENTER,
+ DTM_EXIT,
};
+#define MDSS_PP_SPLIT_LEFT_ONLY 0x10000000
+#define MDSS_PP_SPLIT_RIGHT_ONLY 0x20000000
+#define MDSS_PP_SPLIT_MASK 0x30000000
+
#define MDSS_MAX_BL_BRIGHTNESS 255
#define AD_BL_LIN_LEN 256
diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h
index bf7908b..50fb2e5 100644
--- a/include/linux/qpnp/pwm.h
+++ b/include/linux/qpnp/pwm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -146,6 +146,12 @@
int pwm_lut_config(struct pwm_device *pwm, int period_us,
int duty_pct[], struct lut_params lut_params);
+/*
+ * support microsecond level configuration
+ */
+int pwm_config_us(struct pwm_device *pwm,
+ int duty_us, int period_us);
+
/* Standard APIs supported */
/*
* pwm_request - request a PWM device
@@ -161,8 +167,8 @@
/*
* pwm_config - change a PWM device configuration
* @pwm: the PWM device
- * @period_us: period in microsecond
- * @duty_us: duty cycle in microsecond
+ * @period_ns: period in nanosecond
+ * @duty_ns: duty cycle in nanosecond
*/
/*
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index 624860e..2e2d931 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -22,20 +22,51 @@
#define CPR_PVS_EFUSE_BINS_MAX (1 << CPR_PVS_EFUSE_BITS_MAX)
/**
+ * enum cpr_fuse_corner_enum - CPR fuse corner enum values
+ * %CPR_FUSE_CORNER_SVS: Lowest voltage for APC
+ * %CPR_FUSE_CORNER_NORMAL: Normal mode voltage
+ * %CPR_FUSE_CORNER_TURBO: Turbo mode voltage
+ * %CPR_FUSE_CORNER_SUPER_TURBO: Super Turbo mode voltage
+ *
+ */
+enum cpr_fuse_corner_enum {
+ CPR_FUSE_CORNER_SVS = 1,
+ CPR_FUSE_CORNER_NORMAL,
+ CPR_FUSE_CORNER_TURBO,
+ CPR_FUSE_CORNER_MAX,
+};
+
+/**
* enum cpr_corner_enum - CPR corner enum values
- * %CPR_CORNER_SVS: Lowest voltage for APC
- * %CPR_CORNER_NORMAL: Normal mode voltage
- * %CPR_CORNER_TURBO: Turbo mode voltage
- * %CPR_CORNER_SUPER_TURBO: Super Turbo mode voltage
+ * %CPR_CORNER_1: Lowest voltage for APC
+ * %CPR_CORNER_2: Second lowest voltage for APC
+ * %CPR_CORNER_3: Third lowest voltage for APC
+ * %CPR_CORNER_4: Forth lowest voltage for APC
+ * %CPR_CORNER_5: Fifth lowest voltage for APC
+ * %CPR_CORNER_6: Sixth lowest voltage for APC
+ * %CPR_CORNER_7: Seventh lowest voltage for APC
+ * %CPR_CORNER_8: Eighth lowest voltage for APC
+ * %CPR_CORNER_9: Ninth lowest voltage for APC
+ * %CPR_CORNER_10: Tenth lowest voltage for APC
+ * %CPR_CORNER_11: Eleventh lowest voltage for APC
+ * %CPR_CORNER_12: Twelfth lowest voltage for APC
*
* These should be used in regulator_set_voltage() for CPR
* regulator as if they had units of uV.
*/
enum cpr_corner_enum {
- CPR_CORNER_SVS = 1,
- CPR_CORNER_NORMAL,
- CPR_CORNER_TURBO,
- CPR_CORNER_MAX,
+ CPR_CORNER_1 = 1,
+ CPR_CORNER_2,
+ CPR_CORNER_3,
+ CPR_CORNER_4,
+ CPR_CORNER_5,
+ CPR_CORNER_6,
+ CPR_CORNER_7,
+ CPR_CORNER_8,
+ CPR_CORNER_9,
+ CPR_CORNER_10,
+ CPR_CORNER_11,
+ CPR_CORNER_12,
};
/**
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 560accb..bfafe00 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1904,6 +1904,9 @@
V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index c48586e..a01dd9a 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -571,7 +571,8 @@
struct msm_camera_led_cfg_t {
enum msm_camera_led_config_t cfgtype;
- uint32_t led_current;
+ uint32_t torch_current;
+ uint32_t flash_current[2];
};
#define VIDIOC_MSM_SENSOR_CFG \
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 75fe3a2..2c969cd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -7172,5 +7172,7 @@
#define US_POINT_EPOS_FORMAT_V2 0x0001272D
#define US_RAW_FORMAT_V2 0x0001272C
#define US_PROX_FORMAT_V2 0x0001272E
+#define US_RAW_SYNC_FORMAT 0x0001272F
+#define US_GES_SYNC_FORMAT 0x00012730
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 6f121b3..5941f71 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -31,7 +31,7 @@
int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
int adm_open(int port, int path, int rate, int mode, int topology,
- bool perf_mode, uint16_t bits_per_sample);
+ int perf_mode, uint16_t bits_per_sample);
int adm_get_params(int port_id, uint32_t module_id, uint32_t param_id,
uint32_t params_length, char *params);
@@ -40,7 +40,7 @@
uint32_t params_length);
int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
- int topology, bool perf_mode, uint16_t bits_per_sample);
+ int topology, int perf_mode, uint16_t bits_per_sample);
int adm_unmap_cal_blocks(void);
@@ -53,10 +53,10 @@
int adm_memory_unmap_regions(int port_id);
-int adm_close(int port, bool perf_mode);
+int adm_close(int port, int perf_mode);
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id, bool perf_mode);
+ unsigned int *port_id, int copp_id, int perf_mode);
int adm_connect_afe_port(int mode, int session_id, int port_id);
@@ -64,6 +64,8 @@
int adm_get_copp_id(int port_id);
+int adm_get_lowlatency_copp_id(int port_id);
+
void adm_set_multi_ch_map(char *channel_map);
void adm_get_multi_ch_map(char *channel_map);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 9a459b8..a78c333 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -67,6 +67,8 @@
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE 0x0004
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
#define SYNC_IO_MODE 0x0001
#define ASYNC_IO_MODE 0x0002
#define COMPRESSED_IO 0x0040
@@ -173,7 +175,7 @@
struct audio_port_data port[2];
wait_queue_head_t cmd_wait;
wait_queue_head_t time_wait;
- bool perf_mode;
+ int perf_mode;
int stream_id;
/* audio cache operations fptr*/
int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
@@ -218,6 +220,9 @@
uint32_t rd_format,
uint32_t wr_format);
+int q6asm_open_loopback_v2(struct audio_client *ac,
+ uint16_t bits_per_sample);
+
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags);
int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
index fd6a490..8ac835c 100644
--- a/include/sound/q6audio-v2.h
+++ b/include/sound/q6audio-v2.h
@@ -15,6 +15,13 @@
#include <mach/qdsp6v2/apr.h>
+enum {
+ LEGACY_PCM_MODE = 0,
+ LOW_LATENCY_PCM_MODE,
+ ULTRA_LOW_LATENCY_PCM_MODE,
+};
+
+
int q6audio_get_port_index(u16 port_id);
int q6audio_convert_virtual_to_portid(u16 port_id);
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 6d22836..955a47b 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -108,7 +108,7 @@
static void __spin_lock_debug(raw_spinlock_t *lock)
{
u64 i;
- u64 loops = (loops_per_jiffy * HZ) >> 1;
+ u64 loops = (loops_per_jiffy * HZ);
for (i = 0; i < loops; i++) {
if (arch_spin_trylock(&lock->raw_lock))
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9962c88..6c78c0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1457,7 +1457,7 @@
head = p; id++;
}
- sprintf(hdev->name, "hci%d", id);
+ snprintf(hdev->name, sizeof(hdev->name), "hci%d", id);
hdev->id = id;
list_add(&hdev->list, head);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2628937..b2b0e99 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3443,10 +3443,7 @@
tcp_done(sk);
bh_unlock_sock(sk);
local_bh_enable();
- if (!sock_flag(sk, SOCK_DEAD)) {
- sock_orphan(sk);
- sock_put(sk);
- }
+ sock_put(sk);
goto restart;
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bddb720..b094741 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1510,8 +1510,8 @@
if (wiphy_idx_valid(reg_request->wiphy_idx))
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
- if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER &&
- !wiphy) {
+ if ((reg_initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+ reg_initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) && !wiphy) {
kfree(reg_request);
return;
}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 487ac6f..9a11f9f 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -55,6 +55,7 @@
static unsigned int table_size, table_cnt;
static int all_symbols = 0;
static char symbol_prefix_char = '\0';
+static unsigned long long kernel_start_addr = 0;
int token_profit[0x10000];
@@ -65,7 +66,10 @@
static void usage(void)
{
- fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+ fprintf(stderr, "Usage: kallsyms [--all-symbols] "
+ "[--symbol-prefix=<prefix char>] "
+ "[--page-offset=<CONFIG_PAGE_OFFSET>] "
+ "< in.map > out.S\n");
exit(1);
}
@@ -194,6 +198,9 @@
int i;
int offset = 1;
+ if (s->addr < kernel_start_addr)
+ return 0;
+
/* skip prefix char */
if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
offset++;
@@ -646,6 +653,9 @@
if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
p++;
symbol_prefix_char = *p;
+ } else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+ const char *p = &argv[i][14];
+ kernel_start_addr = strtoull(p, NULL, 16);
} else
usage();
}
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 55fec32..1962ff0 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1396,7 +1396,10 @@
switch (decimator) {
case 1:
case 2:
- adc_dmic_sel = 0x0;
+ if ((dec_mux == 3) || (dec_mux == 4))
+ adc_dmic_sel = 0x1;
+ else
+ adc_dmic_sel = 0x0;
break;
default:
dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index c62f875..f874c43 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -3404,6 +3404,7 @@
TAIKO_A_TX_7_MBHC_EN, 0x80, 00);
ret |= taiko_codec_enable_anc(w, kcontrol, event);
}
+ break;
case SND_SOC_DAPM_POST_PMD:
ret = taiko_hph_pa_event(w, kcontrol, event);
break;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 28d4c84..14218d8 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -213,7 +213,6 @@
/* called under codec_resource_lock acquisition */
static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
- s16 v_brh, v_b1_hu;
struct snd_soc_codec *codec = mbhc->codec;
int mbhc_state = mbhc->mbhc_state;
@@ -254,17 +253,6 @@
/* set to max */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
-
- v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- v_brh & 0xFF);
- v_b1_hu = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
}
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
@@ -325,22 +313,32 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
0xFF);
- /* Threshods for button press */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
- 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
- 0xFF);
- /* Threshods for button release */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
+
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /* Threshods for button press */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ /* Threshods for button release */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ }
pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
__func__);
}
@@ -376,22 +374,31 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
0xFF);
- /* Revert threshods for button press */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
- 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
- 0xFF);
- /* Revert threshods for button release */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /* Revert threshods for button press */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ /* Revert threshods for button release */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ }
pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
__func__);
}
@@ -489,19 +496,25 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(v_ins_hu >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (v_b1_h >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
- mbhc->mbhc_data.v_brl & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
- (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (v_b1_hu >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (v_b1_h >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (v_brh >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
+ mbhc->mbhc_data.v_brl & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
+ (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+ }
}
static void wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
@@ -3148,15 +3161,22 @@
mv = ceilmv + btn_det->v_btn_press_delta_cic;
pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
- /* update LSB first so mbhc hardware block doesn't see too low value */
- v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
- v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /*
+ * update LSB first so mbhc hardware block
+ * doesn't see too low value.
+ */
+ v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (v_b1_hu >> 8) & 0xFF);
+ v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (v_brh >> 8) & 0xFF);
+ }
return 0;
}
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 39cb470..6f94d99 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -422,6 +422,30 @@
},
{
.playback = {
+ .stream_name = "INT_HFP_BT Hostless Playback",
+ .aif_name = "INTHFP_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .capture = {
+ .stream_name = "INT_HFP_BT Hostless Capture",
+ .aif_name = "INTHFP_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT_HFP_BT_HOSTLESS",
+ },
+ {
+ .playback = {
.stream_name = "AFE-PROXY Playback",
.aif_name = "PCM_RX",
.rates = (SNDRV_PCM_RATE_8000 |
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index c120e0c..4c3a72e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2203,6 +2203,53 @@
.codec_name = "snd-soc-dummy",
},
{
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICE2,
+ },
+ {
+ .name = "INT_HFP_BT Hostless",
+ .stream_name = "INT_HFP_BT Hostless",
+ .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM8974 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ {
.name = LPASS_BE_SLIMBUS_4_TX,
.stream_name = "Slimbus4 Capture",
.cpu_dai_name = "msm-dai-q6-dev.16393",
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 408ec03..c1ba26a 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -163,6 +163,8 @@
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
};
static int msm8x10_ext_spk_power_amp_init(void)
{
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index ea16f47..f0f5db6 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -3,7 +3,8 @@
msm-multi-ch-pcm-q6-v2.o msm-pcm-lpa-v2.o \
msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
- msm-lsm-client.o msm-audio-effects-q6-v2.o
+ msm-lsm-client.o msm-audio-effects-q6-v2.o \
+ msm-pcm-loopback-v2.o
obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
msm-dai-stub-v2.o
obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58c3cdf..4e04bef 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -405,9 +405,9 @@
done:
mutex_unlock(&acdb_data.acdb_mutex);
-ret:
pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
__func__, path, entry->sample_rate, entry->delay_usec, result);
+ret:
return result;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
new file mode 100644
index 0000000..57fc268
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -0,0 +1,441 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-routing-v2.h"
+
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+ LOOPBACK_VOL_MAX_STEPS);
+
+struct msm_pcm_loopback {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+ int session_id;
+ struct audio_client *audio_client;
+ int volume;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+ .formats = 0xffffffff,
+ .channels_min = 1,
+ .channels_max = UINT_MAX,
+
+ /* Random values to keep userspace happy when checking constraints */
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 1024*2,
+ .periods_min = 2,
+ .periods_max = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_pcm_loopback *pcm = priv_data;
+
+ BUG_ON(!pcm);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_DEVSWITCH:
+ q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+ q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+ q6asm_run(pcm->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ pr_debug("%s\n", __func__);
+ switch (opcode) {
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
+{
+ int rc = -EINVAL;
+
+ pr_debug("%s Setting volume 0x%x\n", __func__, volume);
+
+ if (prtd && prtd->audio_client) {
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct msm_pcm_loopback *pcm;
+ int ret = 0;
+ uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_evt event;
+
+ pcm = dev_get_drvdata(rtd->platform->dev);
+ mutex_lock(&pcm->lock);
+
+ snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+ pcm->volume = 0x2000;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_substream = substream;
+
+ pcm->instance++;
+ dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+ pcm->instance, substream->stream);
+ if (pcm->instance == 2) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ if (pcm->audio_client != NULL)
+ stop_pcm(pcm);
+
+ pcm->audio_client = q6asm_audio_client_alloc(
+ (app_cb)msm_pcm_loopback_event_handler, pcm);
+ if (!pcm->audio_client) {
+ dev_err(rtd->platform->dev,
+ "%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ pcm->session_id = pcm->audio_client->session;
+ pcm->audio_client->perf_mode = false;
+ ret = q6asm_open_loopback_v2(pcm->audio_client,
+ bits_per_sample);
+ if (ret < 0) {
+ dev_err(rtd->platform->dev,
+ "%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(pcm->audio_client);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) pcm;
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream,
+ event);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pcm->playback_substream = substream;
+ ret = pcm_loopback_set_volume(pcm, pcm->volume);
+ if (ret < 0)
+ dev_err(rtd->platform->dev,
+ "Error %d setting volume", ret);
+ }
+ }
+ dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+ __func__ , pcm->instance, substream->pcm->id);
+ runtime->private_data = pcm;
+
+ mutex_unlock(&pcm->lock);
+
+ return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+
+ if (pcm->audio_client == NULL)
+ return;
+ q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(pcm->audio_client);
+ pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ int ret = 0;
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_start = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_start = 0;
+
+ pcm->instance--;
+ if (!pcm->playback_start || !pcm->capture_start) {
+ dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+ stop_pcm(pcm);
+ }
+
+ mutex_unlock(&pcm->lock);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!pcm->playback_start)
+ pcm->playback_start = 1;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!pcm->capture_start)
+ pcm->capture_start = 1;
+ }
+ mutex_unlock(&pcm->lock);
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(rtd->platform->dev,
+ "%s: playback_start:%d,capture_start:%d\n", __func__,
+ pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(rtd->platform->dev,
+ "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+ __func__, pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .hw_free = msm_pcm_hw_free,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+};
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = kcontrol->private_data;
+ struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+ struct msm_pcm_loopback *prtd = substream->runtime->private_data;
+ int volume = ucontrol->value.integer.value[0];
+
+ rc = pcm_loopback_set_volume(prtd, volume);
+ return rc;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+ int ret = 0;
+
+ dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1,
+ rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0)
+ return ret;
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->tlv.p = loopback_rx_vol_gain;
+ return 0;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_controls(rtd);
+ if (ret)
+ dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ dev_set_name(&pdev->dev, "%s", "msm-pcm-loopback");
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+ if (!pcm) {
+ dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+ __func__);
+ return -ENOMEM;
+ } else {
+ mutex_init(&pcm->lock);
+ dev_set_drvdata(&pdev->dev, pcm);
+ }
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ pcm = dev_get_drvdata(&pdev->dev);
+ mutex_destroy(&pcm->lock);
+ kfree(pcm);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_loopback_dt_match[] = {
+ {.compatible = "qti,msm-pcm-loopback"},
+ {}
+};
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-loopback",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_loopback_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index dc41948..3ddc3e0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -25,6 +25,7 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/q6audio-v2.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/msm_audio_ion.h>
@@ -109,6 +110,25 @@
.mask = 0,
};
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_audio *prtd = priv_data;
+
+ BUG_ON(!prtd);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_BUF_RECFG:
+ q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+ q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ q6asm_run(prtd->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
static void event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -151,18 +171,31 @@
pr_debug("token = 0x%08x\n", token);
in_frame_info[token][0] = payload[4];
in_frame_info[token][1] = payload[5];
- prtd->pcm_irq_pos += in_frame_info[token][0];
- pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
- if (atomic_read(&prtd->in_count) <= prtd->periods)
- atomic_inc(&prtd->in_count);
- wake_up(&the_locks.read_wait);
- if (prtd->mmap_flag
- && q6asm_is_cpu_buf_avail_nolock(OUT,
+ /* assume data size = 0 during flushing */
+ if (in_frame_info[token][0]) {
+ prtd->pcm_irq_pos += in_frame_info[token][0];
+ pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ if (atomic_read(&prtd->in_count) <= prtd->periods)
+ atomic_inc(&prtd->in_count);
+ wake_up(&the_locks.read_wait);
+ if (prtd->mmap_flag &&
+ q6asm_is_cpu_buf_avail_nolock(OUT,
prtd->audio_client,
&size, &idx))
- q6asm_read_nolock(prtd->audio_client);
+ q6asm_read_nolock(prtd->audio_client);
+ } else {
+ pr_debug("%s: reclaim flushed buf in_count %x\n",
+ __func__, atomic_read(&prtd->in_count));
+ atomic_inc(&prtd->in_count);
+ if (atomic_read(&prtd->in_count) == prtd->periods) {
+ pr_info("%s: reclaimed all bufs\n", __func__);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ wake_up(&the_locks.read_wait);
+ }
+ }
break;
}
case APR_BASIC_RSP_RESULT: {
@@ -681,6 +714,7 @@
int dir, ret;
struct msm_plat_data *pdata;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_evt event;
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
@@ -737,9 +771,12 @@
pr_debug("%s: session ID %d\n",
__func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) prtd;
+ msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
prtd->audio_client->perf_mode,
- prtd->session_id, substream->stream);
+ prtd->session_id, substream->stream,
+ event);
}
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
@@ -880,11 +917,12 @@
int rc;
int id;
struct msm_plat_data *pdata;
+ const char *latency_level;
rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-pcm-dsp-id", &id);
+ "qti,msm-pcm-dsp-id", &id);
if (rc) {
- dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
+ dev_err(&pdev->dev, "%s: qti,msm-pcm-dsp-id missing in DT node\n",
__func__);
return rc;
}
@@ -896,10 +934,17 @@
}
if (of_property_read_bool(pdev->dev.of_node,
- "qcom,msm-pcm-low-latency"))
- pdata->perf_mode = 1;
- else
- pdata->perf_mode = 0;
+ "qti,msm-pcm-low-latency")) {
+
+ pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qti,latency-level", &latency_level);
+ if (!rc) {
+ if (!strcmp(latency_level, "ultra"))
+ pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ }
+ } else
+ pdata->perf_mode = LEGACY_PCM_MODE;
dev_set_drvdata(&pdev->dev, pdata);
@@ -921,7 +966,7 @@
return 0;
}
static const struct of_device_id msm_pcm_dt_match[] = {
- {.compatible = "qcom,msm-pcm-dsp"},
+ {.compatible = "qti,msm-pcm-dsp"},
{}
};
MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 537719f..91c0744 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -50,6 +50,12 @@
unsigned int format;
};
+struct msm_pcm_routing_fdai_data {
+ u16 be_srate; /* track prior backend sample rate for flushing purpose */
+ int strm_id; /* ASM stream ID */
+ struct msm_pcm_routing_evt event_info;
+};
+
#define INVALID_SESSION -1
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
@@ -250,31 +256,41 @@
/* Track ASM playback & capture sessions of DAI */
-static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+static struct msm_pcm_routing_fdai_data
+ fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
/* MULTIMEDIA1 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA2 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA3 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA4 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA5 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA6 */
- {INVALID_SESSION, INVALID_SESSION},
- /* MULTIMEDIA7 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
+ /* MULTIMEDIA7*/
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA8 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA9 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
};
/* Track performance mode of all front-end multimedia sessions.
* Performance mode is only valid when session is valid.
*/
-static bool fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
+static int fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
static uint8_t is_be_dai_extproc(int be_dai)
{
@@ -287,7 +303,7 @@
}
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
- int path_type, bool perf_mode)
+ int path_type, int perf_mode)
{
int i, port_type;
struct route_payload payload;
@@ -334,7 +350,7 @@
mutex_lock(&routing_lock);
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
@@ -349,7 +365,7 @@
mutex_unlock(&routing_lock);
}
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
int dspst_id, int stream_type)
{
int i, session_type, path_type, port_type, port_id, topology;
@@ -376,7 +392,7 @@
mutex_lock(&routing_lock);
payload.num_copps = 0; /* only RX needs to use payload */
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
fe_dai_perf_mode[fedai_id][session_type] = perf_mode;
/* re-enable EQ if active */
@@ -421,7 +437,7 @@
port_id = srs_port_id = msm_bedais[i].port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (!perf_mode))
+ (perf_mode == LEGACY_PCM_MODE))
if (dolby_dap_init(port_id,
msm_bedais[i].channel) < 0)
pr_err("%s: Err init dolby dap\n",
@@ -435,6 +451,19 @@
mutex_unlock(&routing_lock);
}
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info)
+{
+ msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+ stream_type);
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+ fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+ else
+ fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+}
+
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
{
int i, port_type, session_type, path_type, topology;
@@ -465,13 +494,14 @@
adm_close(msm_bedais[i].port_id,
fe_dai_perf_mode[fedai_id][session_type]);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[fedai_id][session_type] == false))
+ (fe_dai_perf_mode[fedai_id][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(msm_bedais[i].port_id);
}
}
- fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
-
+ fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+ fe_dai_map[fedai_id][session_type].be_srate = 0;
mutex_unlock(&routing_lock);
}
@@ -497,6 +527,7 @@
int session_type, path_type, port_id, topology;
u32 channels;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_fdai_data *fdai;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -523,10 +554,23 @@
(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
voc_start_playback(set, msm_bedais[reg].port_id);
set_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
channels = msm_bedais[reg].channel;
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__, fdai->strm_id);
+
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
@@ -549,13 +593,20 @@
msm_bedais[reg].sample_rate, channels,
topology, false, bits_per_sample);
+ if (session_type == SESSION_TYPE_RX &&
+ fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ fdai->event_info.priv_data);
+
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[val][session_type]);
port_id = srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[val][session_type] == false))
+ (fe_dai_perf_mode[val][session_type] ==
+ LEGACY_PCM_MODE))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
@@ -566,15 +617,17 @@
(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
voc_start_playback(set, msm_bedais[reg].port_id);
clear_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
adm_close(msm_bedais[reg].port_id,
fe_dai_perf_mode[val][session_type]);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[val][session_type] == false))
+ (fe_dai_perf_mode[val][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[val][session_type]);
}
}
@@ -1203,12 +1256,12 @@
static void msm_send_eq_values(int eq_idx)
{
int result;
- struct audio_client *ac =
- q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ struct audio_client *ac = q6asm_get_audio_client(
+ fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
if (ac == NULL) {
pr_err("%s: Could not get audio client for session: %d\n",
- __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
goto done;
}
@@ -2034,6 +2087,15 @@
};
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -3040,6 +3102,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
@@ -3068,6 +3131,10 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
@@ -3218,6 +3285,8 @@
mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3474,6 +3543,7 @@
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3484,6 +3554,7 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_UL6"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3516,6 +3587,7 @@
{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3527,6 +3599,7 @@
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+ {"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3716,6 +3789,8 @@
{"INT_FM_RX", NULL, "INTFM_DL_HL"},
{"INTFM_UL_HL", NULL, "INT_FM_TX"},
+ {"INTHFP_UL_HL", NULL, "INT_BT_SCO_TX"},
+ {"INT_BT_SCO_RX", NULL, "MM_DL6"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
{"MI2S_RX", NULL, "MI2S_DL_HL"},
@@ -3881,12 +3956,15 @@
mutex_lock(&routing_lock);
topology = get_topology(path_type);
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
- if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
+ fe_dai_map[i][session_type].be_srate =
+ bedai->sample_rate;
adm_close(bedai->port_id,
fe_dai_perf_mode[i][session_type]);
srs_port_id = -1;
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[i][session_type] == false))
+ (fe_dai_perf_mode[i][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(bedai->port_id);
}
}
@@ -3908,6 +3986,7 @@
u32 channels;
bool playback, capture;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_fdai_data *fdai;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3939,8 +4018,21 @@
capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
- if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ fdai = &fe_dai_map[i][session_type];
+ if (fdai->strm_id != INVALID_SESSION) {
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != bedai->sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__,
+ fdai->strm_id);
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
channels = bedai->channel;
if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
@@ -3967,12 +4059,13 @@
}
msm_pcm_routing_build_matrix(i,
- fe_dai_map[i][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[i][session_type]);
port_id = srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[i][session_type] == false))
+ (fe_dai_perf_mode[i][session_type] ==
+ LEGACY_PCM_MODE))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 10be150..54f5e4a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -133,15 +133,30 @@
MSM_BACKEND_DAI_MAX,
};
+enum msm_pcm_routing_event {
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ MSM_PCM_RT_EVT_MAX,
+};
+
/* dai_id: front-end ID,
* dspst_id: DSP audio stream ID
* stream_type: playback or capture
*/
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id,
int stream_type);
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
int stream_type);
+struct msm_pcm_routing_evt {
+ void (*event_func)(enum msm_pcm_routing_event, void *);
+ void *priv_data;
+};
+
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info);
+
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
int msm_routing_check_backend_enabled(int fedai_id);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 6cb7ce1..54b1263 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -702,7 +702,8 @@
return;
}
-static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal,
+ int perf_mode)
{
s32 result = 0;
struct adm_cmd_set_pp_params_v5 adm_params;
@@ -731,7 +732,14 @@
adm_params.hdr.src_port = port_id;
adm_params.hdr.dest_svc = APR_SVC_ADM;
adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
- adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+
+ if (perf_mode == LEGACY_PCM_MODE)
+ adm_params.hdr.dest_port =
+ atomic_read(&this_adm.copp_id[index]);
+ else
+ adm_params.hdr.dest_port =
+ atomic_read(&this_adm.copp_low_latency_id[index]);
+
adm_params.hdr.token = port_id;
adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
adm_params.payload_addr_lsw = aud_cal->cal_paddr;
@@ -767,7 +775,7 @@
return result;
}
-static void send_adm_cal(int port_id, int path)
+static void send_adm_cal(int port_id, int path, int perf_mode)
{
int result = 0;
s32 acdb_path;
@@ -808,7 +816,7 @@
}
}
- if (!send_adm_cal_block(port_id, &aud_cal))
+ if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
pr_debug("%s: Audproc cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
@@ -842,7 +850,7 @@
}
}
- if (!send_adm_cal_block(port_id, &aud_cal))
+ if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
pr_debug("%s: Audvol cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
@@ -1048,7 +1056,7 @@
}
int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
- bool perf_mode, uint16_t bits_per_sample)
+ int perf_mode, uint16_t bits_per_sample)
{
struct adm_cmd_device_open_v5 open;
int ret = 0;
@@ -1079,7 +1087,7 @@
rtac_set_adm_handle(this_adm.apr);
}
- if (!perf_mode) {
+ if (perf_mode == LEGACY_PCM_MODE) {
atomic_set(&this_adm.copp_perf_mode[index], 0);
send_adm_custom_topology(port_id);
} else {
@@ -1087,8 +1095,9 @@
}
/* Create a COPP if port id are not enabled */
- if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
- (perf_mode &&
+ if ((perf_mode == LEGACY_PCM_MODE &&
+ (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+ (perf_mode != LEGACY_PCM_MODE &&
(atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
perf_mode);
@@ -1103,12 +1112,12 @@
open.hdr.dest_port = tmp_port;
open.hdr.token = port_id;
open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
- open.flags = 0x00;
- if (perf_mode) {
- open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
- } else {
- open.flags |= ADM_LEGACY_DEVICE_SESSION;
- }
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
+ open.flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
+ else if (perf_mode == LOW_LATENCY_PCM_MODE)
+ open.flags = ADM_LOW_LATENCY_DEVICE_SESSION;
+ else
+ open.flags = ADM_LEGACY_DEVICE_SESSION;
open.mode_of_operation = path;
open.endpoint_id_1 = tmp_port;
@@ -1125,7 +1134,7 @@
(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
rate = 16000;
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
open.topology_id = NULL_COPP_TOPOLOGY;
rate = ULL_SUPPORTED_SAMPLE_RATE;
if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
@@ -1133,7 +1142,8 @@
}
open.dev_num_channel = channel_mode & 0x00FF;
open.bit_width = bits_per_sample;
- WARN_ON(perf_mode && (rate != 48000));
+ WARN_ON(perf_mode == ULTRA_LOW_LATENCY_PCM_MODE &&
+ (rate != 48000));
open.sample_rate = rate;
memset(open.dev_channel_mapping, 0, 8);
@@ -1208,7 +1218,8 @@
goto fail_cmd;
}
}
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
atomic_inc(&this_adm.copp_low_latency_cnt[index]);
pr_debug("%s: index: %d coppid: %d", __func__, index,
atomic_read(&this_adm.copp_low_latency_id[index]));
@@ -1225,7 +1236,7 @@
}
int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
- int topology, bool perf_mode, uint16_t bits_per_sample)
+ int topology, int perf_mode, uint16_t bits_per_sample)
{
int ret = 0;
@@ -1236,7 +1247,7 @@
}
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id, bool perf_mode)
+ unsigned int *port_id, int copp_id, int perf_mode)
{
struct adm_cmd_matrix_map_routings_v5 *route;
struct adm_session_map_node_v5 *node;
@@ -1275,7 +1286,8 @@
route->hdr.src_port = copp_id;
route->hdr.dest_svc = APR_SVC_ADM;
route->hdr.dest_domain = APR_DOMAIN_ADSP;
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
route->hdr.dest_port =
atomic_read(&this_adm.copp_low_latency_id[index]);
} else {
@@ -1313,7 +1325,8 @@
if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
- if (perf_mode)
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE)
copps_list[i] =
atomic_read(&this_adm.copp_low_latency_id[tmp]);
else
@@ -1323,8 +1336,7 @@
else
continue;
pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
- __func__, i, port_id[i], tmp,
- atomic_read(&this_adm.copp_id[tmp]));
+ __func__, i, port_id[i], tmp, copps_list[i]);
}
atomic_set(&this_adm.copp_stat[index], 0);
@@ -1344,25 +1356,31 @@
ret = -EINVAL;
goto fail_cmd;
}
- if (!perf_mode) {
+
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
for (i = 0; i < num_copps; i++)
- send_adm_cal(port_id[i], path);
+ send_adm_cal(port_id[i], path, perf_mode);
for (i = 0; i < num_copps; i++) {
- int tmp;
+ int tmp, copp_id;
tmp = afe_get_port_index(port_id[i]);
if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ if (perf_mode == LEGACY_PCM_MODE)
+ copp_id = atomic_read(
+ &this_adm.copp_id[tmp]);
+ else
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[tmp]);
rtac_add_adm_device(port_id[i],
- atomic_read(&this_adm.copp_id[tmp]),
- path, session_id);
- pr_debug("%s, copp_id: %d\n", __func__,
- atomic_read(&this_adm.copp_id[tmp]));
- } else {
+ copp_id, path, session_id);
+ pr_debug("%s, copp_id: %d\n",
+ __func__, copp_id);
+ } else
pr_debug("%s: Invalid port index %d",
- __func__, tmp);
- }
+ __func__, tmp);
}
}
+
fail_cmd:
kfree(matrix_map);
return ret;
@@ -1514,8 +1532,26 @@
return ret;
}
+#ifdef CONFIG_RTAC
int adm_get_copp_id(int port_index)
{
+ int copp_id;
+ pr_debug("%s\n", __func__);
+
+ if (port_index < 0) {
+ pr_err("%s: invalid port_id = %d\n", __func__, port_index);
+ return -EINVAL;
+ }
+
+ copp_id = atomic_read(&this_adm.copp_id[port_index]);
+ if (copp_id == RESET_COPP_ID)
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[port_index]);
+ return copp_id;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
pr_debug("%s\n", __func__);
if (port_index < 0) {
@@ -1523,8 +1559,19 @@
return -EINVAL;
}
- return atomic_read(&this_adm.copp_id[port_index]);
+ return atomic_read(&this_adm.copp_low_latency_id[port_index]);
}
+#else
+int adm_get_copp_id(int port_index)
+{
+ return -EINVAL;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
+ return -EINVAL;
+}
+#endif /* #ifdef CONFIG_RTAC */
void adm_ec_ref_rx_id(int port_id)
{
@@ -1532,12 +1579,13 @@
pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
}
-int adm_close(int port_id, bool perf_mode)
+int adm_close(int port_id, int perf_mode)
{
struct apr_hdr close;
int ret = 0;
int index = 0;
+ int copp_id = RESET_COPP_ID;
port_id = q6audio_convert_virtual_to_portid(port_id);
@@ -1548,7 +1596,8 @@
pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
index, perf_mode);
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
pr_err("%s: copp count for port[%#x]is 0\n", __func__,
port_id);
@@ -1563,8 +1612,9 @@
}
atomic_dec(&this_adm.copp_cnt[index]);
}
- if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
- (perf_mode &&
+ if ((perf_mode == LEGACY_PCM_MODE &&
+ !(atomic_read(&this_adm.copp_cnt[index]))) ||
+ ((perf_mode != LEGACY_PCM_MODE) &&
!(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
@@ -1577,7 +1627,8 @@
close.src_port = port_id;
close.dest_svc = APR_SVC_ADM;
close.dest_domain = APR_DOMAIN_ADSP;
- if (perf_mode)
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE)
close.dest_port =
atomic_read(&this_adm.copp_low_latency_id[index]);
else
@@ -1587,18 +1638,23 @@
atomic_set(&this_adm.copp_stat[index], 0);
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[index]);
pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
- __func__,
- atomic_read(&this_adm.copp_low_latency_id[index]),
- port_id, index,
- atomic_read(&this_adm.copp_low_latency_cnt[index]));
+ __func__,
+ copp_id,
+ port_id, index,
+ atomic_read(
+ &this_adm.copp_low_latency_cnt[index]));
atomic_set(&this_adm.copp_low_latency_id[index],
RESET_COPP_ID);
} else {
+ copp_id = atomic_read(&this_adm.copp_id[index]);
pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
__func__,
- atomic_read(&this_adm.copp_id[index]),
+ copp_id,
port_id, index,
atomic_read(&this_adm.copp_cnt[index]));
atomic_set(&this_adm.copp_id[index],
@@ -1623,9 +1679,9 @@
}
}
- if (!perf_mode) {
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
pr_debug("%s: remove adm device from rtac\n", __func__);
- rtac_remove_adm_device(port_id);
+ rtac_remove_adm_device(port_id, copp_id);
}
fail_cmd:
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 95114e0..24f5f3b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -39,6 +39,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>
+#include <sound/q6audio-v2.h>
#include "audio_acdb.h"
@@ -354,7 +355,7 @@
session[ac->session] = 0;
mutex_unlock(&session_lock);
ac->session = 0;
- ac->perf_mode = 0;
+ ac->perf_mode = LEGACY_PCM_MODE;
ac->fptr_cache_ops = NULL;
return;
}
@@ -810,7 +811,7 @@
ac->cb = cb;
ac->priv = priv;
ac->io_mode = SYNC_IO_MODE;
- ac->perf_mode = false;
+ ac->perf_mode = LEGACY_PCM_MODE;
ac->fptr_cache_ops = NULL;
ac->apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
@@ -1256,6 +1257,7 @@
case ASM_STREAM_CMD_OPEN_READ_V3:
case ASM_STREAM_CMD_OPEN_WRITE_V3:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+ case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_CMD_ADD_TOPOLOGIES:
@@ -1694,7 +1696,7 @@
open.bits_per_sample = bits_per_sample;
open.mode_flags = 0x0;
- if (ac->perf_mode) {
+ if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION <<
ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
} else {
@@ -1744,6 +1746,7 @@
rc);
goto fail_cmd;
}
+ ac->io_mode |= TUN_READ_IO_MODE;
return 0;
fail_cmd:
return -EINVAL;
@@ -1779,8 +1782,10 @@
open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
open.mode_flags = 0x00;
- if (ac->perf_mode)
+ if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
+ else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+ open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
else {
open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
if (is_gapless_mode)
@@ -1837,6 +1842,7 @@
rc);
goto fail_cmd;
}
+ ac->io_mode |= TUN_WRITE_IO_MODE;
return 0;
fail_cmd:
return -EINVAL;
@@ -1977,6 +1983,49 @@
return -EINVAL;
}
+int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_loopback_v2 open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("%s APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+
+ open.mode_flags = 0;
+ open.src_endpointype = 0;
+ open.sink_endpointype = 0;
+ /* source endpoint : matrix */
+ open.postprocopo_id = get_asm_topology();
+ if (open.postprocopo_id == 0)
+ open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+ open.bits_per_sample = bits_per_sample;
+ open.reserved = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s open failed op[0x%x]rc[%d]\n", __func__,
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s timeout. waited for open_loopback rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_run(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
@@ -4217,9 +4266,11 @@
{
int cnt = 0;
int loopcnt = 0;
+ int used;
struct audio_port_data *port = NULL;
if (ac->io_mode & SYNC_IO_MODE) {
+ used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
mutex_lock(&ac->cmd_lock);
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
@@ -4229,7 +4280,7 @@
while (cnt >= 0) {
if (!port->buf)
continue;
- port->buf[cnt].used = 1;
+ port->buf[cnt].used = used;
cnt--;
}
}
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index f74dbe2..701dfef 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -556,7 +556,8 @@
/* Check if device already added */
if (rtac_adm_data.num_of_dev != 0) {
for (; i < rtac_adm_data.num_of_dev; i++) {
- if (rtac_adm_data.device[i].afe_port == port_id) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
add_popp(i, port_id, popp_id);
goto done;
}
@@ -609,7 +610,7 @@
}
}
-void rtac_remove_adm_device(u32 port_id)
+void rtac_remove_adm_device(u32 port_id, u32 copp_id)
{
s32 i;
pr_debug("%s: port_id = %d\n", __func__, port_id);
@@ -619,7 +620,8 @@
/* look for device */
for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
- if (rtac_adm_data.device[i].afe_port == port_id) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
memset(&rtac_adm_data.device[i], 0,
sizeof(rtac_adm_data.device[i]));
rtac_adm_data.num_of_dev--;
@@ -870,6 +872,8 @@
for (port_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
if (adm_get_copp_id(port_index) == copp_id)
break;
+ if (adm_get_lowlatency_copp_id(port_index) == copp_id)
+ break;
}
if (port_index >= AFE_MAX_PORTS) {
pr_err("%s: Could not find port index for copp = %d\n",